react-native-zeroconf 0.13.8 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +49 -0
- package/README.md +473 -65
- package/android/build.gradle +28 -22
- package/android/src/main/AndroidManifest.xml +1 -2
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/rx2dnssd/DnssdImpl.java +19 -3
- package/android/src/main/java/com/github/druk/dnssd/BaseListener.java +33 -0
- package/android/src/main/java/com/github/druk/dnssd/BrowseListener.java +67 -0
- package/android/src/main/java/com/github/druk/dnssd/DNSRecord.java +47 -0
- package/android/src/main/java/com/github/druk/dnssd/DNSSD.java +650 -0
- package/android/src/main/java/com/github/druk/dnssd/DNSSDBindable.java +67 -0
- package/android/src/main/java/com/github/druk/dnssd/DNSSDEmbedded.java +135 -0
- package/android/src/main/java/com/github/druk/dnssd/DNSSDException.java +66 -0
- package/android/src/main/java/com/github/druk/dnssd/DNSSDRecordRegistrar.java +55 -0
- package/android/src/main/java/com/github/druk/dnssd/DNSSDRegistration.java +54 -0
- package/android/src/main/java/com/github/druk/dnssd/DNSSDService.java +35 -0
- package/android/src/main/java/com/github/druk/dnssd/DomainListener.java +57 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalBrowseListener.java +76 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSD.java +870 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRecordRegistrar.java +30 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRegistration.java +34 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDService.java +29 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalDomainListener.java +62 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalQueryListener.java +61 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalRegisterListener.java +51 -0
- package/android/src/main/java/com/github/druk/dnssd/InternalResolveListener.java +58 -0
- package/android/src/main/java/com/github/druk/dnssd/NSClass.java +16 -0
- package/android/src/main/java/com/github/druk/dnssd/NSType.java +58 -0
- package/android/src/main/java/com/github/druk/dnssd/QueryListener.java +54 -0
- package/android/src/main/java/com/github/druk/dnssd/RegisterListener.java +46 -0
- package/android/src/main/java/com/github/druk/dnssd/RegisterRecordListener.java +35 -0
- package/android/src/main/java/com/github/druk/dnssd/ResolveListener.java +55 -0
- package/android/src/main/java/com/github/druk/dnssd/TXTRecord.java +293 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/BonjourService.java +400 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/Rx2BrowseListener.java +55 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/Rx2Dnssd.java +127 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/Rx2DnssdBindable.java +35 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/Rx2DnssdCommon.java +280 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/Rx2DnssdEmbedded.java +31 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/Rx2QueryListener.java +70 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/Rx2RegisterListener.java +47 -0
- package/android/src/main/java/com/github/druk/rx2dnssd/Rx2ResolveListener.java +51 -0
- package/android/src/main/jni/Android.mk +95 -0
- package/android/src/main/jni/Application.mk +3 -0
- package/android/src/main/jni/DNSSD.java.h +290 -0
- package/android/src/main/jni/JNISupport.c +1140 -0
- package/android/src/main/jni/mdnsresponder/Android.bp +215 -0
- package/android/src/main/jni/mdnsresponder/Clients/ClientCommon.c +75 -0
- package/android/src/main/jni/mdnsresponder/Clients/ClientCommon.h +41 -0
- package/android/src/main/jni/mdnsresponder/Clients/Makefile +54 -0
- package/android/src/main/jni/mdnsresponder/Clients/ReadMe.txt +25 -0
- package/android/src/main/jni/mdnsresponder/Clients/dns-sd.c +1351 -0
- package/android/src/main/jni/mdnsresponder/LICENSE +13 -0
- package/android/src/main/jni/mdnsresponder/MODULE_LICENSE_APACHE2 +0 -0
- package/android/src/main/jni/mdnsresponder/Makefile +41 -0
- package/android/src/main/jni/mdnsresponder/NOTICE +13 -0
- package/android/src/main/jni/mdnsresponder/PrivateDNS.txt +275 -0
- package/android/src/main/jni/mdnsresponder/README.txt +166 -0
- package/android/src/main/jni/mdnsresponder/README.version +3 -0
- package/android/src/main/jni/mdnsresponder/android/caseMapping/Iphlpapi.h +1 -0
- package/android/src/main/jni/mdnsresponder/android/caseMapping/README +3 -0
- package/android/src/main/jni/mdnsresponder/android/caseMapping/Resource.h +1 -0
- package/android/src/main/jni/mdnsresponder/android/caseMapping/Ws2tcpip.h +1 -0
- package/android/src/main/jni/mdnsresponder/android/caseMapping/ipExport.h +1 -0
- package/android/src/main/jni/mdnsresponder/android/windows_firewall_dummy.c +10 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/DNSCommon.c +3157 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/DNSCommon.h +292 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/DNSDigest.c +1579 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/Implementer Notes.txt +66 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/mDNS.c +11469 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/mDNSDebug.h +164 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/mDNSEmbeddedAPI.h +2974 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/uDNS.c +4969 -0
- package/android/src/main/jni/mdnsresponder/mDNSCore/uDNS.h +132 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/Client.c +223 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/ExampleClientApp.c +91 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/ExampleClientApp.h +18 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/Identify.c +378 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/Makefile +520 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/NetMonitor.c +1010 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/PosixDaemon.c +329 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/ProxyResponder.c +300 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/ReadMe.txt +314 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/Responder.c +792 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/Services.txt +36 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/libnss_mdns.8 +148 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/mDNSPosix.c +1685 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/mDNSPosix.h +88 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/mDNSUNP.c +726 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/mDNSUNP.h +130 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/mdnsd.sh +73 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/nss_ReadMe.txt +125 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/nss_mdns.c +2723 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/nss_mdns.conf +13 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/nss_mdns.conf.5 +135 -0
- package/android/src/main/jni/mdnsresponder/mDNSPosix/parselog.py +247 -0
- package/android/src/main/jni/mdnsresponder/mDNSResponder.sln +400 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/CommonServices.h +1537 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/DebugServices.c +3075 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/DebugServices.h +1607 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/GenLinkedList.c +319 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/GenLinkedList.h +90 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/PlatformCommon.c +220 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/PlatformCommon.h +18 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dns-sd.1 +194 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dns_sd.h +2452 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnsextd.8 +69 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnsextd.c +3146 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnsextd.conf +60 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnsextd.h +163 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnsextd_lexer.l +84 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnsextd_parser.y +585 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_clientlib.c +368 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_clientshim.c +802 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_clientstub.c +1988 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_ipc.c +161 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_ipc.h +219 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/mDNS.1 +198 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/mDNSDebug.c +93 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/mDNSResponder.8 +116 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/uds_daemon.c +4758 -0
- package/android/src/main/jni/mdnsresponder/mDNSShared/uds_daemon.h +80 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/BrowsingPage.cpp +441 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/BrowsingPage.h +156 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ConfigDialog.cpp +59 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ConfigDialog.h +48 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp +301 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ConfigPropertySheet.h +105 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanel.cpp +380 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanel.def +20 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanel.h +84 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanel.rc +141 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanel.vcproj +727 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelDll.rc +123 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelExe.cpp +373 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelExe.h +48 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelExe.rc +123 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelExe.vcproj +764 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelLocRes.rc +270 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj +487 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelRes.rc +134 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ControlPanelRes.vcproj +518 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/FourthPage.cpp +197 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/FourthPage.h +87 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/RegistrationPage.cpp +387 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/RegistrationPage.h +75 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/SecondPage.cpp +544 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/SecondPage.h +107 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ServicesPage.cpp +273 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/ServicesPage.h +123 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/SharedSecret.cpp +115 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/SharedSecret.h +54 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/ControlPanel.dll.manifest +10 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/ControlPanel.exe.manifest +17 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/ControlPanel.manifest +17 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/ControlPanel.rc2 +13 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/ControlPanel64.manifest +17 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/EnergySaver.ico +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/controlpanel.ico +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/failure.ico +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/res/success.ico +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/resource.h +56 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/stdafx.cpp +20 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/ControlPanel/stdafx.h +64 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL/dll.aps +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL/dll.rc +102 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL/dllmain.c +112 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL/dnssd.def +48 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL/dnssd.vcproj +472 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL/resource.h +27 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/AssemblyInfo.cpp +84 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/PString.h +70 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/Stdafx.cpp +22 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/Stdafx.h +33 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/dnssd_NET.cpp +1234 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/dnssd_NET.h +1392 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/dnssd_NET.ico +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/dnssd_NET.rc +113 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/dnssd_NET.vcproj +446 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLL.NET/resource.h +3 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLStub/DLLStub.cpp +693 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLStub/DLLStub.h +52 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLStub/DLLStub.vcproj +324 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DLLX.cpp +208 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DLLX.def +35 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DLLX.idl +491 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DLLX.rc +126 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DLLX.rgs +11 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DLLX.vcproj +625 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSD.cpp +892 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDEventManager.cpp +31 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDEventManager.h +133 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDEventManager.rgs +27 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDRecord.cpp +101 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDRecord.h +185 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDRecord.rgs +27 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDService.cpp +2095 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDService.h +429 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/DNSSDService.rgs +27 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/StringServices.cpp +344 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/StringServices.h +102 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/TXTRecord.cpp +381 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/TXTRecord.h +203 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/TXTRecord.rgs +27 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/_IDNSSDEvents_CP.h +358 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/dlldatax.c +51 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/dlldatax.h +49 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/resource.h +30 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DLLX/stdafx.h +88 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.sln +21 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj +253 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.sln +21 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj +267 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.ico +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc +323 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2 +20 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Resources/Resource.h +53 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp +71 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h +62 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp +111 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h +68 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp +1426 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h +131 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp +109 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h +53 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp +18 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h +48 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcc +37 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcp +868 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcw +29 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.ico +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc +194 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc2 +13 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/newres.h +28 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/resource.h +22 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp +92 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h +57 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp +394 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h +84 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp +18 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h +46 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/Java/Java.vcproj +111 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/Java/jdns_sd.rc +62 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/Java/makefile +143 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/Java/makefile64 +143 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/NSPTool/NSPTool.aps +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/NSPTool/NSPTool.c +581 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/NSPTool/NSPTool.rc +103 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/NSPTool/NSPTool.vcproj +409 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/NSPTool/Prefix.h +28 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/NSPTool/resource.h +27 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/PosixCompat.c +128 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/PosixCompat.h +70 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/README.txt +85 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/RegNames.h +57 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/Secret.c +338 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/Secret.h +42 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/EventLog.mc +11 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/EventLogMessages.bin +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Firewall.cpp +484 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Firewall.h +79 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Prefix.h +30 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Service.aps +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Service.c +2669 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Service.h +30 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Service.mcp +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Service.rc +114 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/Service.vcproj +562 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/main.c +32 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/res/mDNSResponder.manifest +12 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/res/mDNSResponder64.manifest +12 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/resource.h +17 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/SystemService/resrc1.h +15 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/VPCDetect.cpp +165 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/VPCDetect.h +36 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/WinServices.cpp +93 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/WinServices.h +34 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/WinVersRes.h +35 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/isocode.h +135 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/loclibrary.c +268 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/loclibrary.h +54 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mDNSWin32.c +5200 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mDNSWin32.h +208 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mdnsNSP/ReadMe.txt +15 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mdnsNSP/mdnsNSP.aps +0 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mdnsNSP/mdnsNSP.c +2430 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mdnsNSP/mdnsNSP.def +24 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mdnsNSP/mdnsNSP.rc +104 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mdnsNSP/mdnsNSP.vcproj +457 -0
- package/android/src/main/jni/mdnsresponder/mDNSWindows/mdnsNSP/resource.h +27 -0
- package/android/src/main/jni/mdnsresponder/mdnsd.rc +7 -0
- package/android/src/main/jni/nameser.h +588 -0
- package/dist/index.js +148 -1
- package/package.json +23 -17
- package/src/index.js +166 -0
|
@@ -0,0 +1,4758 @@
|
|
|
1
|
+
/* -*- Mode: C; tab-width: 4 -*-
|
|
2
|
+
*
|
|
3
|
+
* Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#if defined(_WIN32)
|
|
19
|
+
#include <process.h>
|
|
20
|
+
#define usleep(X) Sleep(((X)+999)/1000)
|
|
21
|
+
#else
|
|
22
|
+
#include <fcntl.h>
|
|
23
|
+
#include <errno.h>
|
|
24
|
+
#include <sys/ioctl.h>
|
|
25
|
+
#include <sys/types.h>
|
|
26
|
+
#include <sys/time.h>
|
|
27
|
+
#include <sys/resource.h>
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
#include <stdlib.h>
|
|
31
|
+
#include <stdio.h>
|
|
32
|
+
|
|
33
|
+
#include "mDNSEmbeddedAPI.h"
|
|
34
|
+
#include "DNSCommon.h"
|
|
35
|
+
#include "uDNS.h"
|
|
36
|
+
#include "uds_daemon.h"
|
|
37
|
+
|
|
38
|
+
#ifndef EMBEDDED
|
|
39
|
+
#ifdef __ANDROID__
|
|
40
|
+
#include "cutils/sockets.h"
|
|
41
|
+
#endif
|
|
42
|
+
#endif
|
|
43
|
+
|
|
44
|
+
// Normally we append search domains only for queries with a single label that are not
|
|
45
|
+
// fully qualified. This can be overridden to apply search domains for queries (that are
|
|
46
|
+
// not fully qualified) with any number of labels e.g., moon, moon.cs, moon.cs.be, etc.
|
|
47
|
+
mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
|
|
48
|
+
|
|
49
|
+
// Apple-specific functionality, not required for other platforms
|
|
50
|
+
#if APPLE_OSX_mDNSResponder
|
|
51
|
+
#include <sys/ucred.h>
|
|
52
|
+
#ifndef PID_FILE
|
|
53
|
+
#define PID_FILE ""
|
|
54
|
+
#endif
|
|
55
|
+
#endif
|
|
56
|
+
|
|
57
|
+
#if APPLE_OSX_mDNSResponder
|
|
58
|
+
#include <WebFilterDNS/WebFilterDNS.h>
|
|
59
|
+
|
|
60
|
+
#if ! NO_WCF
|
|
61
|
+
|
|
62
|
+
int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
|
|
63
|
+
int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
|
|
64
|
+
int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
|
|
65
|
+
|
|
66
|
+
// Do we really need to define a macro for "if"?
|
|
67
|
+
#define CHECK_WCF_FUNCTION(X) if (X)
|
|
68
|
+
#endif // ! NO_WCF
|
|
69
|
+
|
|
70
|
+
#else
|
|
71
|
+
#define NO_WCF 1
|
|
72
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
73
|
+
|
|
74
|
+
// User IDs 0-500 are system-wide processes, not actual users in the usual sense
|
|
75
|
+
// User IDs for real user accounts start at 501 and count up from there
|
|
76
|
+
#define SystemUID(X) ((X) <= 500)
|
|
77
|
+
|
|
78
|
+
// ***************************************************************************
|
|
79
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
80
|
+
#pragma mark -
|
|
81
|
+
#pragma mark - Types and Data Structures
|
|
82
|
+
#endif
|
|
83
|
+
|
|
84
|
+
typedef enum
|
|
85
|
+
{
|
|
86
|
+
t_uninitialized,
|
|
87
|
+
t_morecoming,
|
|
88
|
+
t_complete,
|
|
89
|
+
t_error,
|
|
90
|
+
t_terminated
|
|
91
|
+
} transfer_state;
|
|
92
|
+
|
|
93
|
+
typedef struct request_state request_state;
|
|
94
|
+
|
|
95
|
+
typedef void (*req_termination_fn)(request_state *request);
|
|
96
|
+
|
|
97
|
+
typedef struct registered_record_entry
|
|
98
|
+
{
|
|
99
|
+
struct registered_record_entry *next;
|
|
100
|
+
mDNSu32 key;
|
|
101
|
+
client_context_t regrec_client_context;
|
|
102
|
+
request_state *request;
|
|
103
|
+
mDNSBool external_advertise;
|
|
104
|
+
mDNSInterfaceID origInterfaceID;
|
|
105
|
+
AuthRecord *rr; // Pointer to variable-sized AuthRecord (Why a pointer? Why not just embed it here?)
|
|
106
|
+
} registered_record_entry;
|
|
107
|
+
|
|
108
|
+
// A single registered service: ServiceRecordSet + bookkeeping
|
|
109
|
+
// Note that we duplicate some fields from parent service_info object
|
|
110
|
+
// to facilitate cleanup, when instances and parent may be deallocated at different times.
|
|
111
|
+
typedef struct service_instance
|
|
112
|
+
{
|
|
113
|
+
struct service_instance *next;
|
|
114
|
+
request_state *request;
|
|
115
|
+
AuthRecord *subtypes;
|
|
116
|
+
mDNSBool renameonmemfree; // Set on config change when we deregister original name
|
|
117
|
+
mDNSBool clientnotified; // Has client been notified of successful registration yet?
|
|
118
|
+
mDNSBool default_local; // is this the "local." from an empty-string registration?
|
|
119
|
+
mDNSBool external_advertise; // is this is being advertised externally?
|
|
120
|
+
domainname domain;
|
|
121
|
+
ServiceRecordSet srs; // note -- variable-sized object -- must be last field in struct
|
|
122
|
+
} service_instance;
|
|
123
|
+
|
|
124
|
+
// for multi-domain default browsing
|
|
125
|
+
typedef struct browser_t
|
|
126
|
+
{
|
|
127
|
+
struct browser_t *next;
|
|
128
|
+
domainname domain;
|
|
129
|
+
DNSQuestion q;
|
|
130
|
+
} browser_t;
|
|
131
|
+
|
|
132
|
+
struct request_state
|
|
133
|
+
{
|
|
134
|
+
request_state *next;
|
|
135
|
+
request_state *primary; // If this operation is on a shared socket, pointer to primary
|
|
136
|
+
// request_state for the original DNSServiceCreateConnection() operation
|
|
137
|
+
dnssd_sock_t sd;
|
|
138
|
+
dnssd_sock_t errsd;
|
|
139
|
+
mDNSu32 uid;
|
|
140
|
+
void * platform_data;
|
|
141
|
+
|
|
142
|
+
// Note: On a shared connection these fields in the primary structure, including hdr, are re-used
|
|
143
|
+
// for each new request. This is because, until we've read the ipc_msg_hdr to find out what the
|
|
144
|
+
// operation is, we don't know if we're going to need to allocate a new request_state or not.
|
|
145
|
+
transfer_state ts;
|
|
146
|
+
mDNSu32 hdr_bytes; // bytes of header already read
|
|
147
|
+
ipc_msg_hdr hdr;
|
|
148
|
+
mDNSu32 data_bytes; // bytes of message data already read
|
|
149
|
+
char *msgbuf; // pointer to data storage to pass to free()
|
|
150
|
+
const char *msgptr; // pointer to data to be read from (may be modified)
|
|
151
|
+
char *msgend; // pointer to byte after last byte of message
|
|
152
|
+
|
|
153
|
+
// reply, termination, error, and client context info
|
|
154
|
+
int no_reply; // don't send asynchronous replies to client
|
|
155
|
+
mDNSs32 time_blocked; // record time of a blocked client
|
|
156
|
+
int unresponsiveness_reports;
|
|
157
|
+
struct reply_state *replies; // corresponding (active) reply list
|
|
158
|
+
req_termination_fn terminate;
|
|
159
|
+
DNSServiceFlags flags;
|
|
160
|
+
|
|
161
|
+
union
|
|
162
|
+
{
|
|
163
|
+
registered_record_entry *reg_recs; // list of registrations for a connection-oriented request
|
|
164
|
+
struct
|
|
165
|
+
{
|
|
166
|
+
mDNSInterfaceID interface_id;
|
|
167
|
+
mDNSBool default_domain;
|
|
168
|
+
mDNSBool ForceMCast;
|
|
169
|
+
domainname regtype;
|
|
170
|
+
browser_t *browsers;
|
|
171
|
+
} browser;
|
|
172
|
+
struct
|
|
173
|
+
{
|
|
174
|
+
mDNSInterfaceID InterfaceID;
|
|
175
|
+
mDNSu16 txtlen;
|
|
176
|
+
void *txtdata;
|
|
177
|
+
mDNSIPPort port;
|
|
178
|
+
domainlabel name;
|
|
179
|
+
char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
|
|
180
|
+
domainname type;
|
|
181
|
+
mDNSBool default_domain;
|
|
182
|
+
domainname host;
|
|
183
|
+
mDNSBool autoname; // Set if this name is tied to the Computer Name
|
|
184
|
+
mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
|
|
185
|
+
mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
|
|
186
|
+
int num_subtypes;
|
|
187
|
+
service_instance *instances;
|
|
188
|
+
} servicereg;
|
|
189
|
+
struct
|
|
190
|
+
{
|
|
191
|
+
mDNSInterfaceID interface_id;
|
|
192
|
+
mDNSu32 flags;
|
|
193
|
+
mDNSu32 protocol;
|
|
194
|
+
DNSQuestion q4;
|
|
195
|
+
DNSQuestion *q42;
|
|
196
|
+
DNSQuestion q6;
|
|
197
|
+
DNSQuestion *q62;
|
|
198
|
+
} addrinfo;
|
|
199
|
+
struct
|
|
200
|
+
{
|
|
201
|
+
mDNSIPPort ReqExt; // External port we originally requested, for logging purposes
|
|
202
|
+
NATTraversalInfo NATinfo;
|
|
203
|
+
} pm;
|
|
204
|
+
struct
|
|
205
|
+
{
|
|
206
|
+
#if 0
|
|
207
|
+
DNSServiceFlags flags;
|
|
208
|
+
#endif
|
|
209
|
+
DNSQuestion q_all;
|
|
210
|
+
DNSQuestion q_default;
|
|
211
|
+
} enumeration;
|
|
212
|
+
struct
|
|
213
|
+
{
|
|
214
|
+
DNSQuestion q;
|
|
215
|
+
DNSQuestion *q2;
|
|
216
|
+
} queryrecord;
|
|
217
|
+
struct
|
|
218
|
+
{
|
|
219
|
+
DNSQuestion qtxt;
|
|
220
|
+
DNSQuestion qsrv;
|
|
221
|
+
const ResourceRecord *txt;
|
|
222
|
+
const ResourceRecord *srv;
|
|
223
|
+
mDNSs32 ReportTime;
|
|
224
|
+
mDNSBool external_advertise;
|
|
225
|
+
} resolve;
|
|
226
|
+
} u;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// struct physically sits between ipc message header and call-specific fields in the message buffer
|
|
230
|
+
typedef struct
|
|
231
|
+
{
|
|
232
|
+
DNSServiceFlags flags; // Note: This field is in NETWORK byte order
|
|
233
|
+
mDNSu32 ifi; // Note: This field is in NETWORK byte order
|
|
234
|
+
DNSServiceErrorType error; // Note: This field is in NETWORK byte order
|
|
235
|
+
} reply_hdr;
|
|
236
|
+
|
|
237
|
+
typedef struct reply_state
|
|
238
|
+
{
|
|
239
|
+
struct reply_state *next; // If there are multiple unsent replies
|
|
240
|
+
mDNSu32 totallen;
|
|
241
|
+
mDNSu32 nwriten;
|
|
242
|
+
ipc_msg_hdr mhdr[1];
|
|
243
|
+
reply_hdr rhdr[1];
|
|
244
|
+
} reply_state;
|
|
245
|
+
|
|
246
|
+
// ***************************************************************************
|
|
247
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
248
|
+
#pragma mark -
|
|
249
|
+
#pragma mark - Globals
|
|
250
|
+
#endif
|
|
251
|
+
|
|
252
|
+
// globals
|
|
253
|
+
mDNSexport mDNS mDNSStorage;
|
|
254
|
+
mDNSexport const char ProgramName[] = "mDNSResponder";
|
|
255
|
+
|
|
256
|
+
static dnssd_sock_t listenfd = dnssd_InvalidSocket;
|
|
257
|
+
static request_state *all_requests = NULL;
|
|
258
|
+
|
|
259
|
+
// Note asymmetry here between registration and browsing.
|
|
260
|
+
// For service registrations we only automatically register in domains that explicitly appear in local configuration data
|
|
261
|
+
// (so AutoRegistrationDomains could equally well be called SCPrefRegDomains)
|
|
262
|
+
// For service browsing we also learn automatic browsing domains from the network, so for that case we have:
|
|
263
|
+
// 1. SCPrefBrowseDomains (local configuration data)
|
|
264
|
+
// 2. LocalDomainEnumRecords (locally-generated local-only PTR records -- equivalent to slElem->AuthRecs in uDNS.c)
|
|
265
|
+
// 3. AutoBrowseDomains, which is populated by tracking add/rmv events in AutomaticBrowseDomainChange, the callback function for our mDNS_GetDomains call.
|
|
266
|
+
// By creating and removing our own LocalDomainEnumRecords, we trigger AutomaticBrowseDomainChange callbacks just like domains learned from the network would.
|
|
267
|
+
|
|
268
|
+
mDNSexport DNameListElem *AutoRegistrationDomains; // Domains where we automatically register for empty-string registrations
|
|
269
|
+
|
|
270
|
+
static DNameListElem *SCPrefBrowseDomains; // List of automatic browsing domains read from SCPreferences for "empty string" browsing
|
|
271
|
+
static ARListElem *LocalDomainEnumRecords; // List of locally-generated PTR records to augment those we learn from the network
|
|
272
|
+
mDNSexport DNameListElem *AutoBrowseDomains; // List created from those local-only PTR records plus records we get from the network
|
|
273
|
+
|
|
274
|
+
#define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
|
|
275
|
+
// n get_string() calls w/o buffer overrun
|
|
276
|
+
// initialization, setup/teardown functions
|
|
277
|
+
|
|
278
|
+
// If a platform specifies its own PID file name, we use that
|
|
279
|
+
#ifndef PID_FILE
|
|
280
|
+
#define PID_FILE "/var/run/mDNSResponder.pid"
|
|
281
|
+
#endif
|
|
282
|
+
|
|
283
|
+
// ***************************************************************************
|
|
284
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
285
|
+
#pragma mark -
|
|
286
|
+
#pragma mark - General Utility Functions
|
|
287
|
+
#endif
|
|
288
|
+
|
|
289
|
+
mDNSlocal void FatalError(char *errmsg)
|
|
290
|
+
{
|
|
291
|
+
LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno));
|
|
292
|
+
*(volatile long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
|
|
293
|
+
abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
mDNSlocal mDNSu32 dnssd_htonl(mDNSu32 l)
|
|
297
|
+
{
|
|
298
|
+
mDNSu32 ret;
|
|
299
|
+
char *data = (char*) &ret;
|
|
300
|
+
put_uint32(l, &data);
|
|
301
|
+
return ret;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// hack to search-replace perror's to LogMsg's
|
|
305
|
+
mDNSlocal void my_perror(char *errmsg)
|
|
306
|
+
{
|
|
307
|
+
LogMsg("%s: %d (%s)", errmsg, dnssd_errno, dnssd_strerror(dnssd_errno));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
mDNSlocal void abort_request(request_state *req)
|
|
311
|
+
{
|
|
312
|
+
if (req->terminate == (req_termination_fn)~0)
|
|
313
|
+
{ LogMsg("abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req, req->terminate); return; }
|
|
314
|
+
|
|
315
|
+
// First stop whatever mDNSCore operation we were doing
|
|
316
|
+
// If this is actually a shared connection operation, then its req->terminate function will scan
|
|
317
|
+
// the all_requests list and terminate any subbordinate operations sharing this file descriptor
|
|
318
|
+
if (req->terminate) req->terminate(req);
|
|
319
|
+
|
|
320
|
+
if (!dnssd_SocketValid(req->sd))
|
|
321
|
+
{ LogMsg("abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req, req->sd); return; }
|
|
322
|
+
|
|
323
|
+
// Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies
|
|
324
|
+
if (!req->primary)
|
|
325
|
+
{
|
|
326
|
+
if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
|
|
327
|
+
else LogOperation("%3d: Removing FD", req->sd);
|
|
328
|
+
udsSupportRemoveFDFromEventLoop(req->sd, req->platform_data); // Note: This also closes file descriptor req->sd for us
|
|
329
|
+
if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
|
|
330
|
+
|
|
331
|
+
while (req->replies) // free pending replies
|
|
332
|
+
{
|
|
333
|
+
reply_state *ptr = req->replies;
|
|
334
|
+
req->replies = req->replies->next;
|
|
335
|
+
freeL("reply_state (abort)", ptr);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure
|
|
340
|
+
#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
|
|
341
|
+
// Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
|
|
342
|
+
// for detecting when the memory for an object is inadvertently freed while the object is still on some list
|
|
343
|
+
req->sd = req->errsd = -2;
|
|
344
|
+
#else
|
|
345
|
+
req->sd = req->errsd = dnssd_InvalidSocket;
|
|
346
|
+
#endif
|
|
347
|
+
// We also set req->terminate to a bogus value so we know if abort_request() gets called again for this request
|
|
348
|
+
req->terminate = (req_termination_fn)~0;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
mDNSlocal void AbortUnlinkAndFree(request_state *req)
|
|
352
|
+
{
|
|
353
|
+
request_state **p = &all_requests;
|
|
354
|
+
abort_request(req);
|
|
355
|
+
while (*p && *p != req) p=&(*p)->next;
|
|
356
|
+
if (*p) { *p = req->next; freeL("request_state/AbortUnlinkAndFree", req); }
|
|
357
|
+
else LogMsg("AbortUnlinkAndFree: ERROR: Attempt to abort operation %p not in list", req);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, request_state *const request)
|
|
361
|
+
{
|
|
362
|
+
reply_state *reply;
|
|
363
|
+
|
|
364
|
+
if ((unsigned)datalen < sizeof(reply_hdr))
|
|
365
|
+
{
|
|
366
|
+
LogMsg("ERROR: create_reply - data length less than length of required fields");
|
|
367
|
+
return NULL;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
reply = mallocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
|
|
371
|
+
if (!reply) FatalError("ERROR: malloc");
|
|
372
|
+
|
|
373
|
+
reply->next = mDNSNULL;
|
|
374
|
+
reply->totallen = (mDNSu32)datalen + sizeof(ipc_msg_hdr);
|
|
375
|
+
reply->nwriten = 0;
|
|
376
|
+
|
|
377
|
+
reply->mhdr->version = VERSION;
|
|
378
|
+
reply->mhdr->datalen = (mDNSu32)datalen;
|
|
379
|
+
reply->mhdr->ipc_flags = 0;
|
|
380
|
+
reply->mhdr->op = op;
|
|
381
|
+
reply->mhdr->client_context = request->hdr.client_context;
|
|
382
|
+
reply->mhdr->reg_index = 0;
|
|
383
|
+
|
|
384
|
+
return reply;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Append a reply to the list in a request object
|
|
388
|
+
// If our request is sharing a connection, then we append our reply_state onto the primary's list
|
|
389
|
+
mDNSlocal void append_reply(request_state *req, reply_state *rep)
|
|
390
|
+
{
|
|
391
|
+
request_state *r = req->primary ? req->primary : req;
|
|
392
|
+
reply_state **ptr = &r->replies;
|
|
393
|
+
while (*ptr) ptr = &(*ptr)->next;
|
|
394
|
+
*ptr = rep;
|
|
395
|
+
rep->next = NULL;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Generates a response message giving name, type, domain, plus interface index,
|
|
399
|
+
// suitable for a browse result or service registration result.
|
|
400
|
+
// On successful completion rep is set to point to a malloc'd reply_state struct
|
|
401
|
+
mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const mDNSInterfaceID id,
|
|
402
|
+
request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
|
|
403
|
+
{
|
|
404
|
+
domainlabel name;
|
|
405
|
+
domainname type, dom;
|
|
406
|
+
*rep = NULL;
|
|
407
|
+
if (!DeconstructServiceName(servicename, &name, &type, &dom))
|
|
408
|
+
return kDNSServiceErr_Invalid;
|
|
409
|
+
else
|
|
410
|
+
{
|
|
411
|
+
char namestr[MAX_DOMAIN_LABEL+1];
|
|
412
|
+
char typestr[MAX_ESCAPED_DOMAIN_NAME];
|
|
413
|
+
char domstr [MAX_ESCAPED_DOMAIN_NAME];
|
|
414
|
+
int len;
|
|
415
|
+
char *data;
|
|
416
|
+
|
|
417
|
+
ConvertDomainLabelToCString_unescaped(&name, namestr);
|
|
418
|
+
ConvertDomainNameToCString(&type, typestr);
|
|
419
|
+
ConvertDomainNameToCString(&dom, domstr);
|
|
420
|
+
|
|
421
|
+
// Calculate reply data length
|
|
422
|
+
len = sizeof(DNSServiceFlags);
|
|
423
|
+
len += sizeof(mDNSu32); // if index
|
|
424
|
+
len += sizeof(DNSServiceErrorType);
|
|
425
|
+
len += (int) (strlen(namestr) + 1);
|
|
426
|
+
len += (int) (strlen(typestr) + 1);
|
|
427
|
+
len += (int) (strlen(domstr) + 1);
|
|
428
|
+
|
|
429
|
+
// Build reply header
|
|
430
|
+
*rep = create_reply(op, len, request);
|
|
431
|
+
(*rep)->rhdr->flags = dnssd_htonl(flags);
|
|
432
|
+
(*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id, mDNSfalse));
|
|
433
|
+
(*rep)->rhdr->error = dnssd_htonl(err);
|
|
434
|
+
|
|
435
|
+
// Build reply body
|
|
436
|
+
data = (char *)&(*rep)->rhdr[1];
|
|
437
|
+
put_string(namestr, &data);
|
|
438
|
+
put_string(typestr, &data);
|
|
439
|
+
put_string(domstr, &data);
|
|
440
|
+
|
|
441
|
+
return mStatus_NoError;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Special support to enable the DNSServiceBrowse call made by Bonjour Browser
|
|
446
|
+
// Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
|
|
447
|
+
mDNSlocal void GenerateBonjourBrowserResponse(const domainname *const servicename, const mDNSInterfaceID id,
|
|
448
|
+
request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
|
|
449
|
+
{
|
|
450
|
+
char namestr[MAX_DOMAIN_LABEL+1];
|
|
451
|
+
char typestr[MAX_ESCAPED_DOMAIN_NAME];
|
|
452
|
+
static const char domstr[] = ".";
|
|
453
|
+
int len;
|
|
454
|
+
char *data;
|
|
455
|
+
|
|
456
|
+
*rep = NULL;
|
|
457
|
+
|
|
458
|
+
// 1. Put first label in namestr
|
|
459
|
+
ConvertDomainLabelToCString_unescaped((const domainlabel *)servicename, namestr);
|
|
460
|
+
|
|
461
|
+
// 2. Put second label and "local" into typestr
|
|
462
|
+
mDNS_snprintf(typestr, sizeof(typestr), "%#s.local.", SecondLabel(servicename));
|
|
463
|
+
|
|
464
|
+
// Calculate reply data length
|
|
465
|
+
len = sizeof(DNSServiceFlags);
|
|
466
|
+
len += sizeof(mDNSu32); // if index
|
|
467
|
+
len += sizeof(DNSServiceErrorType);
|
|
468
|
+
len += (int) (strlen(namestr) + 1);
|
|
469
|
+
len += (int) (strlen(typestr) + 1);
|
|
470
|
+
len += (int) (strlen(domstr) + 1);
|
|
471
|
+
|
|
472
|
+
// Build reply header
|
|
473
|
+
*rep = create_reply(op, len, request);
|
|
474
|
+
(*rep)->rhdr->flags = dnssd_htonl(flags);
|
|
475
|
+
(*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id, mDNSfalse));
|
|
476
|
+
(*rep)->rhdr->error = dnssd_htonl(err);
|
|
477
|
+
|
|
478
|
+
// Build reply body
|
|
479
|
+
data = (char *)&(*rep)->rhdr[1];
|
|
480
|
+
put_string(namestr, &data);
|
|
481
|
+
put_string(typestr, &data);
|
|
482
|
+
put_string(domstr, &data);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Returns a resource record (allocated w/ malloc) containing the data found in an IPC message
|
|
486
|
+
// Data must be in the following format: flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional) ttl
|
|
487
|
+
// (ttl only extracted/set if ttl argument is non-zero). Returns NULL for a bad-parameter error
|
|
488
|
+
mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, int validate_flags)
|
|
489
|
+
{
|
|
490
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
491
|
+
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
|
|
492
|
+
char name[256];
|
|
493
|
+
int str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name));
|
|
494
|
+
mDNSu16 type = get_uint16(&request->msgptr, request->msgend);
|
|
495
|
+
mDNSu16 class = get_uint16(&request->msgptr, request->msgend);
|
|
496
|
+
mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
|
|
497
|
+
const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen);
|
|
498
|
+
mDNSu32 ttl = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0;
|
|
499
|
+
int storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
|
|
500
|
+
AuthRecord *rr;
|
|
501
|
+
mDNSInterfaceID InterfaceID;
|
|
502
|
+
AuthRecType artype;
|
|
503
|
+
|
|
504
|
+
request->flags = flags;
|
|
505
|
+
|
|
506
|
+
if (str_err) { LogMsg("ERROR: read_rr_from_ipc_msg - get_string"); return NULL; }
|
|
507
|
+
|
|
508
|
+
if (!request->msgptr) { LogMsg("Error reading Resource Record from client"); return NULL; }
|
|
509
|
+
|
|
510
|
+
if (validate_flags &&
|
|
511
|
+
!((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
|
|
512
|
+
!((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
|
|
513
|
+
{
|
|
514
|
+
LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
|
|
515
|
+
return NULL;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
rr = mallocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
|
|
519
|
+
if (!rr) FatalError("ERROR: malloc");
|
|
520
|
+
|
|
521
|
+
InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
|
|
522
|
+
if (InterfaceID == mDNSInterface_LocalOnly)
|
|
523
|
+
artype = AuthRecordLocalOnly;
|
|
524
|
+
else if (InterfaceID == mDNSInterface_P2P)
|
|
525
|
+
artype = AuthRecordP2P;
|
|
526
|
+
else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P))
|
|
527
|
+
artype = AuthRecordAnyIncludeP2P;
|
|
528
|
+
else
|
|
529
|
+
artype = AuthRecordAny;
|
|
530
|
+
|
|
531
|
+
mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0,
|
|
532
|
+
(mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), artype, mDNSNULL, mDNSNULL);
|
|
533
|
+
|
|
534
|
+
if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
|
|
535
|
+
{
|
|
536
|
+
LogMsg("ERROR: bad name: %s", name);
|
|
537
|
+
freeL("AuthRecord/read_rr_from_ipc_msg", rr);
|
|
538
|
+
return NULL;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
|
|
542
|
+
rr->resrec.rrclass = class;
|
|
543
|
+
rr->resrec.rdlength = rdlen;
|
|
544
|
+
rr->resrec.rdata->MaxRDLength = rdlen;
|
|
545
|
+
mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlen);
|
|
546
|
+
if (GetTTL) rr->resrec.rroriginalttl = ttl;
|
|
547
|
+
rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
|
|
548
|
+
SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
|
|
549
|
+
return rr;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
|
|
553
|
+
{
|
|
554
|
+
domainlabel n;
|
|
555
|
+
domainname d, t;
|
|
556
|
+
|
|
557
|
+
if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
|
|
558
|
+
if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
|
|
559
|
+
if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
|
|
560
|
+
if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
|
|
561
|
+
return 0;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len)
|
|
565
|
+
{
|
|
566
|
+
int n = send(s, ptr, len, 0);
|
|
567
|
+
// On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a small write for us
|
|
568
|
+
// (four bytes for a typical error code return, 12 bytes for DNSServiceGetProperty(DaemonVersion)).
|
|
569
|
+
// If it does fail, we don't attempt to handle this failure, but we do log it so we know something is wrong.
|
|
570
|
+
if (n < len)
|
|
571
|
+
LogMsg("ERROR: send_all(%d) wrote %d of %d errno %d (%s)",
|
|
572
|
+
s, n, len, dnssd_errno, dnssd_strerror(dnssd_errno));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
#if 0
|
|
576
|
+
mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const domainname * const d, const DNameListElem * const doms)
|
|
577
|
+
{
|
|
578
|
+
const DNameListElem *delem = mDNSNULL;
|
|
579
|
+
int bestDelta = -1; // the delta of the best match, lower is better
|
|
580
|
+
int dLabels = 0;
|
|
581
|
+
mDNSBool allow = mDNSfalse;
|
|
582
|
+
|
|
583
|
+
if (SystemUID(request->uid)) return mDNStrue;
|
|
584
|
+
|
|
585
|
+
dLabels = CountLabels(d);
|
|
586
|
+
for (delem = doms; delem; delem = delem->next)
|
|
587
|
+
{
|
|
588
|
+
if (delem->uid)
|
|
589
|
+
{
|
|
590
|
+
int delemLabels = CountLabels(&delem->name);
|
|
591
|
+
int delta = dLabels - delemLabels;
|
|
592
|
+
if ((bestDelta == -1 || delta <= bestDelta) && SameDomainName(&delem->name, SkipLeadingLabels(d, delta)))
|
|
593
|
+
{
|
|
594
|
+
bestDelta = delta;
|
|
595
|
+
allow = (allow || (delem->uid == request->uid));
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return bestDelta == -1 ? mDNStrue : allow;
|
|
601
|
+
}
|
|
602
|
+
#endif
|
|
603
|
+
|
|
604
|
+
// ***************************************************************************
|
|
605
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
606
|
+
#pragma mark -
|
|
607
|
+
#pragma mark - external helpers
|
|
608
|
+
#endif
|
|
609
|
+
|
|
610
|
+
mDNSlocal void external_start_advertising_helper(service_instance *const instance)
|
|
611
|
+
{
|
|
612
|
+
AuthRecord *st = instance->subtypes;
|
|
613
|
+
ExtraResourceRecord *e;
|
|
614
|
+
int i;
|
|
615
|
+
|
|
616
|
+
if (mDNSIPPortIsZero(instance->request->u.servicereg.port))
|
|
617
|
+
{
|
|
618
|
+
LogInfo("external_start_advertising_helper: Not registering service with port number zero");
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
#if APPLE_OSX_mDNSResponder
|
|
623
|
+
// Update packet filter if p2p interface already exists, otherwise,
|
|
624
|
+
// if will be updated when we get the KEV_DL_IF_ATTACHED event for
|
|
625
|
+
// the interface. Called here since we don't call external_start_advertising_service()
|
|
626
|
+
// with the SRV record when advertising a service.
|
|
627
|
+
mDNSInitPacketFilter();
|
|
628
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
629
|
+
|
|
630
|
+
if (instance->external_advertise) LogMsg("external_start_advertising_helper: external_advertise already set!");
|
|
631
|
+
|
|
632
|
+
for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
|
|
633
|
+
external_start_advertising_service(&st[i].resrec);
|
|
634
|
+
|
|
635
|
+
external_start_advertising_service(&instance->srs.RR_PTR.resrec);
|
|
636
|
+
external_start_advertising_service(&instance->srs.RR_TXT.resrec);
|
|
637
|
+
|
|
638
|
+
for (e = instance->srs.Extras; e; e = e->next)
|
|
639
|
+
external_start_advertising_service(&e->r.resrec);
|
|
640
|
+
|
|
641
|
+
instance->external_advertise = mDNStrue;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
mDNSlocal void external_stop_advertising_helper(service_instance *const instance)
|
|
645
|
+
{
|
|
646
|
+
AuthRecord *st = instance->subtypes;
|
|
647
|
+
ExtraResourceRecord *e;
|
|
648
|
+
int i;
|
|
649
|
+
|
|
650
|
+
if (!instance->external_advertise) return;
|
|
651
|
+
|
|
652
|
+
LogInfo("external_stop_advertising_helper: calling external_stop_advertising_service");
|
|
653
|
+
|
|
654
|
+
for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
|
|
655
|
+
external_stop_advertising_service(&st[i].resrec);
|
|
656
|
+
|
|
657
|
+
external_stop_advertising_service(&instance->srs.RR_PTR.resrec);
|
|
658
|
+
external_stop_advertising_service(&instance->srs.RR_TXT.resrec);
|
|
659
|
+
|
|
660
|
+
for (e = instance->srs.Extras; e; e = e->next)
|
|
661
|
+
external_stop_advertising_service(&e->r.resrec);
|
|
662
|
+
|
|
663
|
+
instance->external_advertise = mDNSfalse;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// ***************************************************************************
|
|
667
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
668
|
+
#pragma mark -
|
|
669
|
+
#pragma mark - DNSServiceRegister
|
|
670
|
+
#endif
|
|
671
|
+
|
|
672
|
+
mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
|
|
673
|
+
{
|
|
674
|
+
ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
|
|
675
|
+
(void)m; // Unused
|
|
676
|
+
|
|
677
|
+
if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
|
|
678
|
+
|
|
679
|
+
LogInfo(" FreeExtraRR %s", RRDisplayString(m, &rr->resrec));
|
|
680
|
+
|
|
681
|
+
if (rr->resrec.rdata != &rr->rdatastorage)
|
|
682
|
+
freeL("Extra RData", rr->resrec.rdata);
|
|
683
|
+
freeL("ExtraResourceRecord/FreeExtraRR", extra);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
|
|
687
|
+
{
|
|
688
|
+
ExtraResourceRecord *e = srv->srs.Extras, *tmp;
|
|
689
|
+
|
|
690
|
+
external_stop_advertising_helper(srv);
|
|
691
|
+
|
|
692
|
+
// clear pointers from parent struct
|
|
693
|
+
if (srv->request)
|
|
694
|
+
{
|
|
695
|
+
service_instance **p = &srv->request->u.servicereg.instances;
|
|
696
|
+
while (*p)
|
|
697
|
+
{
|
|
698
|
+
if (*p == srv) { *p = (*p)->next; break; }
|
|
699
|
+
p = &(*p)->next;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
while (e)
|
|
704
|
+
{
|
|
705
|
+
e->r.RecordContext = e;
|
|
706
|
+
tmp = e;
|
|
707
|
+
e = e->next;
|
|
708
|
+
FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if (srv->srs.RR_TXT.resrec.rdata != &srv->srs.RR_TXT.rdatastorage)
|
|
712
|
+
freeL("TXT RData", srv->srs.RR_TXT.resrec.rdata);
|
|
713
|
+
|
|
714
|
+
if (srv->subtypes) { freeL("ServiceSubTypes", srv->subtypes); srv->subtypes = NULL; }
|
|
715
|
+
freeL("service_instance", srv);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// Count how many other service records we have locally with the same name, but different rdata.
|
|
719
|
+
// For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
|
|
720
|
+
// the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
|
|
721
|
+
mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
|
|
722
|
+
{
|
|
723
|
+
int count = 0;
|
|
724
|
+
ResourceRecord *r = &srs->RR_SRV.resrec;
|
|
725
|
+
AuthRecord *rr;
|
|
726
|
+
|
|
727
|
+
for (rr = m->ResourceRecords; rr; rr=rr->next)
|
|
728
|
+
if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !IdenticalSameNameRecord(&rr->resrec, r))
|
|
729
|
+
count++;
|
|
730
|
+
|
|
731
|
+
verbosedebugf("%d peer registrations for %##s", count, r->name->c);
|
|
732
|
+
return(count);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
|
|
736
|
+
{
|
|
737
|
+
int count = 0;
|
|
738
|
+
AuthRecord *rr;
|
|
739
|
+
for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
|
|
740
|
+
if (rr->resrec.rrtype == kDNSType_SRV &&
|
|
741
|
+
mDNSSameIPPort(rr->resrec.rdata->u.srv.port, port) &&
|
|
742
|
+
SameDomainName(rr->resrec.name, srv))
|
|
743
|
+
count++;
|
|
744
|
+
return(count);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
mDNSlocal void SendServiceRemovalNotification(ServiceRecordSet *const srs)
|
|
748
|
+
{
|
|
749
|
+
reply_state *rep;
|
|
750
|
+
service_instance *instance = srs->ServiceContext;
|
|
751
|
+
if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, 0, mStatus_NoError) != mStatus_NoError)
|
|
752
|
+
LogMsg("%3d: SendServiceRemovalNotification: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
|
|
753
|
+
else { append_reply(instance->request, rep); instance->clientnotified = mDNSfalse; }
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// service registration callback performs three duties - frees memory for deregistered services,
|
|
757
|
+
// handles name conflicts, and delivers completed registration information to the client
|
|
758
|
+
mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
|
|
759
|
+
{
|
|
760
|
+
mStatus err;
|
|
761
|
+
mDNSBool SuppressError = mDNSfalse;
|
|
762
|
+
service_instance *instance;
|
|
763
|
+
reply_state *rep;
|
|
764
|
+
(void)m; // Unused
|
|
765
|
+
|
|
766
|
+
if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
|
|
767
|
+
|
|
768
|
+
instance = srs->ServiceContext;
|
|
769
|
+
if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
|
|
770
|
+
|
|
771
|
+
// don't send errors up to client for wide-area, empty-string registrations
|
|
772
|
+
if (instance->request &&
|
|
773
|
+
instance->request->u.servicereg.default_domain &&
|
|
774
|
+
!instance->default_local)
|
|
775
|
+
SuppressError = mDNStrue;
|
|
776
|
+
|
|
777
|
+
if (mDNS_LoggingEnabled)
|
|
778
|
+
{
|
|
779
|
+
const char *const fmt =
|
|
780
|
+
(result == mStatus_NoError) ? "%s DNSServiceRegister(%##s, %u) REGISTERED" :
|
|
781
|
+
(result == mStatus_MemFree) ? "%s DNSServiceRegister(%##s, %u) DEREGISTERED" :
|
|
782
|
+
(result == mStatus_NameConflict) ? "%s DNSServiceRegister(%##s, %u) NAME CONFLICT" :
|
|
783
|
+
"%s DNSServiceRegister(%##s, %u) %s %d";
|
|
784
|
+
char prefix[16] = "---:";
|
|
785
|
+
if (instance->request) mDNS_snprintf(prefix, sizeof(prefix), "%3d:", instance->request->sd);
|
|
786
|
+
LogOperation(fmt, prefix, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port),
|
|
787
|
+
SuppressError ? "suppressed error" : "CALLBACK", result);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
|
|
791
|
+
|
|
792
|
+
if (result == mStatus_NoError)
|
|
793
|
+
{
|
|
794
|
+
if (instance->request->u.servicereg.allowremotequery)
|
|
795
|
+
{
|
|
796
|
+
ExtraResourceRecord *e;
|
|
797
|
+
srs->RR_ADV.AllowRemoteQuery = mDNStrue;
|
|
798
|
+
srs->RR_PTR.AllowRemoteQuery = mDNStrue;
|
|
799
|
+
srs->RR_SRV.AllowRemoteQuery = mDNStrue;
|
|
800
|
+
srs->RR_TXT.AllowRemoteQuery = mDNStrue;
|
|
801
|
+
for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
|
|
805
|
+
LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
|
|
806
|
+
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
|
|
807
|
+
|
|
808
|
+
if (instance->request->u.servicereg.InterfaceID == mDNSInterface_P2P || (!instance->request->u.servicereg.InterfaceID && SameDomainName(&instance->domain, &localdomain) && (instance->request->flags & kDNSServiceFlagsIncludeP2P)))
|
|
809
|
+
{
|
|
810
|
+
LogInfo("regservice_callback: calling external_start_advertising_helper()");
|
|
811
|
+
external_start_advertising_helper(instance);
|
|
812
|
+
}
|
|
813
|
+
if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
|
|
814
|
+
RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
|
|
815
|
+
}
|
|
816
|
+
else if (result == mStatus_MemFree)
|
|
817
|
+
{
|
|
818
|
+
if (instance->request && instance->renameonmemfree)
|
|
819
|
+
{
|
|
820
|
+
external_stop_advertising_helper(instance);
|
|
821
|
+
instance->renameonmemfree = 0;
|
|
822
|
+
err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
|
|
823
|
+
if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
|
|
824
|
+
// error should never happen - safest to log and continue
|
|
825
|
+
}
|
|
826
|
+
else
|
|
827
|
+
unlink_and_free_service_instance(instance);
|
|
828
|
+
}
|
|
829
|
+
else if (result == mStatus_NameConflict)
|
|
830
|
+
{
|
|
831
|
+
if (instance->request->u.servicereg.autorename)
|
|
832
|
+
{
|
|
833
|
+
external_stop_advertising_helper(instance);
|
|
834
|
+
if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
|
|
835
|
+
{
|
|
836
|
+
// On conflict for an autoname service, rename and reregister *all* autoname services
|
|
837
|
+
IncrementLabelSuffix(&m->nicelabel, mDNStrue);
|
|
838
|
+
mDNS_ConfigChanged(m); // Will call back into udsserver_handle_configchange()
|
|
839
|
+
}
|
|
840
|
+
else // On conflict for a non-autoname service, rename and reregister just that one service
|
|
841
|
+
{
|
|
842
|
+
if (instance->clientnotified) SendServiceRemovalNotification(srs);
|
|
843
|
+
mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
else
|
|
847
|
+
{
|
|
848
|
+
if (!SuppressError)
|
|
849
|
+
{
|
|
850
|
+
if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
|
|
851
|
+
LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
|
|
852
|
+
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
|
|
853
|
+
}
|
|
854
|
+
unlink_and_free_service_instance(instance);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
else // Not mStatus_NoError, mStatus_MemFree, or mStatus_NameConflict
|
|
858
|
+
{
|
|
859
|
+
if (!SuppressError)
|
|
860
|
+
{
|
|
861
|
+
if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
|
|
862
|
+
LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
|
|
863
|
+
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
|
|
869
|
+
{
|
|
870
|
+
(void)m; // Unused
|
|
871
|
+
if (!rr->RecordContext) // parent struct already freed by termination callback
|
|
872
|
+
{
|
|
873
|
+
if (result == mStatus_NoError)
|
|
874
|
+
LogMsg("Error: regrecord_callback: successful registration of orphaned record %s", ARDisplayString(m, rr));
|
|
875
|
+
else
|
|
876
|
+
{
|
|
877
|
+
if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
|
|
878
|
+
|
|
879
|
+
// We come here when the record is being deregistered either from DNSServiceRemoveRecord or connection_termination.
|
|
880
|
+
// If the record has been updated, we need to free the rdata. Everytime we call mDNS_Update, it calls update_callback
|
|
881
|
+
// with the old rdata (so that we can free it) and stores the new rdata in "rr->resrec.rdata". This means, we need
|
|
882
|
+
// to free the latest rdata for which the update_callback was never called with.
|
|
883
|
+
if (rr->resrec.rdata != &rr->rdatastorage) freeL("RData/regrecord_callback", rr->resrec.rdata);
|
|
884
|
+
freeL("AuthRecord/regrecord_callback", rr);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
else
|
|
888
|
+
{
|
|
889
|
+
registered_record_entry *re = rr->RecordContext;
|
|
890
|
+
request_state *request = re->request;
|
|
891
|
+
|
|
892
|
+
if (mDNS_LoggingEnabled)
|
|
893
|
+
{
|
|
894
|
+
char *fmt = (result == mStatus_NoError) ? "%3d: DNSServiceRegisterRecord(%u %s) REGISTERED" :
|
|
895
|
+
(result == mStatus_MemFree) ? "%3d: DNSServiceRegisterRecord(%u %s) DEREGISTERED" :
|
|
896
|
+
(result == mStatus_NameConflict) ? "%3d: DNSServiceRegisterRecord(%u %s) NAME CONFLICT" :
|
|
897
|
+
"%3d: DNSServiceRegisterRecord(%u %s) %d";
|
|
898
|
+
LogOperation(fmt, request->sd, re->key, RRDisplayString(m, &rr->resrec), result);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if (result != mStatus_MemFree)
|
|
902
|
+
{
|
|
903
|
+
int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
|
|
904
|
+
reply_state *reply = create_reply(reg_record_reply_op, len, request);
|
|
905
|
+
reply->mhdr->client_context = re->regrec_client_context;
|
|
906
|
+
reply->rhdr->flags = dnssd_htonl(0);
|
|
907
|
+
reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID, mDNSfalse));
|
|
908
|
+
reply->rhdr->error = dnssd_htonl(result);
|
|
909
|
+
append_reply(request, reply);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (result)
|
|
913
|
+
{
|
|
914
|
+
// unlink from list, free memory
|
|
915
|
+
registered_record_entry **ptr = &request->u.reg_recs;
|
|
916
|
+
while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
|
|
917
|
+
if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
|
|
918
|
+
*ptr = (*ptr)->next;
|
|
919
|
+
freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
|
|
920
|
+
freeL("registered_record_entry regrecord_callback", re);
|
|
921
|
+
}
|
|
922
|
+
else
|
|
923
|
+
{
|
|
924
|
+
if (re->external_advertise) LogMsg("regrecord_callback: external_advertise already set!");
|
|
925
|
+
|
|
926
|
+
if (re->origInterfaceID == mDNSInterface_P2P || (!re->origInterfaceID && IsLocalDomain(&rr->namestorage) && (request->flags & kDNSServiceFlagsIncludeP2P)))
|
|
927
|
+
{
|
|
928
|
+
LogInfo("regrecord_callback: calling external_start_advertising_service");
|
|
929
|
+
external_start_advertising_service(&rr->resrec);
|
|
930
|
+
re->external_advertise = mDNStrue;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
mDNSlocal void connection_termination(request_state *request)
|
|
937
|
+
{
|
|
938
|
+
// When terminating a shared connection, we need to scan the all_requests list
|
|
939
|
+
// and terminate any subbordinate operations sharing this file descriptor
|
|
940
|
+
request_state **req = &all_requests;
|
|
941
|
+
|
|
942
|
+
LogOperation("%3d: DNSServiceCreateConnection STOP", request->sd);
|
|
943
|
+
|
|
944
|
+
while (*req)
|
|
945
|
+
{
|
|
946
|
+
if ((*req)->primary == request)
|
|
947
|
+
{
|
|
948
|
+
// Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
|
|
949
|
+
request_state *tmp = *req;
|
|
950
|
+
if (tmp->primary == tmp) LogMsg("connection_termination ERROR (*req)->primary == *req for %p %d", tmp, tmp->sd);
|
|
951
|
+
if (tmp->replies) LogMsg("connection_termination ERROR How can subordinate req %p %d have replies queued?", tmp, tmp->sd);
|
|
952
|
+
abort_request(tmp);
|
|
953
|
+
*req = tmp->next;
|
|
954
|
+
freeL("request_state/connection_termination", tmp);
|
|
955
|
+
}
|
|
956
|
+
else
|
|
957
|
+
req = &(*req)->next;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
while (request->u.reg_recs)
|
|
961
|
+
{
|
|
962
|
+
registered_record_entry *ptr = request->u.reg_recs;
|
|
963
|
+
LogOperation("%3d: DNSServiceRegisterRecord(%u %s) STOP", request->sd, ptr->key, RRDisplayString(&mDNSStorage, &ptr->rr->resrec));
|
|
964
|
+
request->u.reg_recs = request->u.reg_recs->next;
|
|
965
|
+
ptr->rr->RecordContext = NULL;
|
|
966
|
+
if (ptr->external_advertise)
|
|
967
|
+
{
|
|
968
|
+
ptr->external_advertise = mDNSfalse;
|
|
969
|
+
external_stop_advertising_service(&ptr->rr->resrec);
|
|
970
|
+
}
|
|
971
|
+
mDNS_Deregister(&mDNSStorage, ptr->rr); // Will free ptr->rr for us
|
|
972
|
+
freeL("registered_record_entry/connection_termination", ptr);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
mDNSlocal void handle_cancel_request(request_state *request)
|
|
977
|
+
{
|
|
978
|
+
request_state **req = &all_requests;
|
|
979
|
+
LogOperation("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
|
|
980
|
+
while (*req)
|
|
981
|
+
{
|
|
982
|
+
if ((*req)->primary == request &&
|
|
983
|
+
(*req)->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
|
|
984
|
+
(*req)->hdr.client_context.u32[1] == request->hdr.client_context.u32[1])
|
|
985
|
+
{
|
|
986
|
+
// Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
|
|
987
|
+
request_state *tmp = *req;
|
|
988
|
+
abort_request(tmp);
|
|
989
|
+
*req = tmp->next;
|
|
990
|
+
freeL("request_state/handle_cancel_request", tmp);
|
|
991
|
+
}
|
|
992
|
+
else
|
|
993
|
+
req = &(*req)->next;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
mDNSlocal mStatus handle_regrecord_request(request_state *request)
|
|
998
|
+
{
|
|
999
|
+
mStatus err = mStatus_BadParamErr;
|
|
1000
|
+
AuthRecord *rr = read_rr_from_ipc_msg(request, 1, 1);
|
|
1001
|
+
if (rr)
|
|
1002
|
+
{
|
|
1003
|
+
registered_record_entry *re;
|
|
1004
|
+
// Don't allow non-local domains to be regsitered as LocalOnly. Allowing this would permit
|
|
1005
|
+
// clients to register records such as www.bigbank.com A w.x.y.z to redirect Safari.
|
|
1006
|
+
if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly && !IsLocalDomain(rr->resrec.name) &&
|
|
1007
|
+
rr->resrec.rrclass == kDNSClass_IN && (rr->resrec.rrtype == kDNSType_A || rr->resrec.rrtype == kDNSType_AAAA ||
|
|
1008
|
+
rr->resrec.rrtype == kDNSType_CNAME))
|
|
1009
|
+
{
|
|
1010
|
+
freeL("AuthRecord/handle_regrecord_request", rr);
|
|
1011
|
+
return (mStatus_BadParamErr);
|
|
1012
|
+
}
|
|
1013
|
+
// allocate registration entry, link into list
|
|
1014
|
+
re = mallocL("registered_record_entry", sizeof(registered_record_entry));
|
|
1015
|
+
if (!re) FatalError("ERROR: malloc");
|
|
1016
|
+
re->key = request->hdr.reg_index;
|
|
1017
|
+
re->rr = rr;
|
|
1018
|
+
re->regrec_client_context = request->hdr.client_context;
|
|
1019
|
+
re->request = request;
|
|
1020
|
+
re->external_advertise = mDNSfalse;
|
|
1021
|
+
rr->RecordContext = re;
|
|
1022
|
+
rr->RecordCallback = regrecord_callback;
|
|
1023
|
+
|
|
1024
|
+
re->origInterfaceID = rr->resrec.InterfaceID;
|
|
1025
|
+
if (rr->resrec.InterfaceID == mDNSInterface_P2P) rr->resrec.InterfaceID = mDNSInterface_Any;
|
|
1026
|
+
#if 0
|
|
1027
|
+
if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains)) return (mStatus_NoError);
|
|
1028
|
+
#endif
|
|
1029
|
+
if (rr->resrec.rroriginalttl == 0)
|
|
1030
|
+
rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
|
|
1031
|
+
|
|
1032
|
+
LogOperation("%3d: DNSServiceRegisterRecord(%u %s) START", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec));
|
|
1033
|
+
err = mDNS_Register(&mDNSStorage, rr);
|
|
1034
|
+
if (err)
|
|
1035
|
+
{
|
|
1036
|
+
LogOperation("%3d: DNSServiceRegisterRecord(%u %s) ERROR (%d)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec), err);
|
|
1037
|
+
freeL("registered_record_entry", re);
|
|
1038
|
+
freeL("registered_record_entry/AuthRecord", rr);
|
|
1039
|
+
}
|
|
1040
|
+
else
|
|
1041
|
+
{
|
|
1042
|
+
re->next = request->u.reg_recs;
|
|
1043
|
+
request->u.reg_recs = re;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return(err);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m);
|
|
1050
|
+
|
|
1051
|
+
mDNSlocal void regservice_termination_callback(request_state *request)
|
|
1052
|
+
{
|
|
1053
|
+
if (!request) { LogMsg("regservice_termination_callback context is NULL"); return; }
|
|
1054
|
+
while (request->u.servicereg.instances)
|
|
1055
|
+
{
|
|
1056
|
+
service_instance *p = request->u.servicereg.instances;
|
|
1057
|
+
request->u.servicereg.instances = request->u.servicereg.instances->next;
|
|
1058
|
+
// only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
|
|
1059
|
+
LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP",
|
|
1060
|
+
request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
|
|
1061
|
+
|
|
1062
|
+
external_stop_advertising_helper(p);
|
|
1063
|
+
|
|
1064
|
+
// Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance
|
|
1065
|
+
// We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing
|
|
1066
|
+
// request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time
|
|
1067
|
+
// We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance
|
|
1068
|
+
// because by then we might have already freed p
|
|
1069
|
+
p->request = NULL;
|
|
1070
|
+
if (mDNS_DeregisterService(&mDNSStorage, &p->srs)) unlink_and_free_service_instance(p);
|
|
1071
|
+
// Don't touch service_instance *p after this -- it's likely to have been freed already
|
|
1072
|
+
}
|
|
1073
|
+
if (request->u.servicereg.txtdata)
|
|
1074
|
+
{ freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
|
|
1075
|
+
if (request->u.servicereg.autoname)
|
|
1076
|
+
{
|
|
1077
|
+
// Clear autoname before calling UpdateDeviceInfoRecord() so it doesn't mistakenly include this in its count of active autoname registrations
|
|
1078
|
+
request->u.servicereg.autoname = mDNSfalse;
|
|
1079
|
+
UpdateDeviceInfoRecord(&mDNSStorage);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
mDNSlocal request_state *LocateSubordinateRequest(request_state *request)
|
|
1084
|
+
{
|
|
1085
|
+
request_state *req;
|
|
1086
|
+
for (req = all_requests; req; req = req->next)
|
|
1087
|
+
if (req->primary == request &&
|
|
1088
|
+
req->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
|
|
1089
|
+
req->hdr.client_context.u32[1] == request->hdr.client_context.u32[1]) return(req);
|
|
1090
|
+
return(request);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl)
|
|
1094
|
+
{
|
|
1095
|
+
ServiceRecordSet *srs = &instance->srs;
|
|
1096
|
+
mStatus result;
|
|
1097
|
+
int size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
|
|
1098
|
+
ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
|
|
1099
|
+
if (!extra) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
|
|
1100
|
+
|
|
1101
|
+
mDNSPlatformMemZero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
|
|
1102
|
+
extra->r.resrec.rrtype = rrtype;
|
|
1103
|
+
extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
|
|
1104
|
+
extra->r.resrec.rdlength = rdlen;
|
|
1105
|
+
mDNSPlatformMemCopy(&extra->r.rdatastorage.u.data, rdata, rdlen);
|
|
1106
|
+
|
|
1107
|
+
result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl,
|
|
1108
|
+
(request->flags & kDNSServiceFlagsIncludeP2P) ? 1: 0);
|
|
1109
|
+
if (result) { freeL("ExtraResourceRecord/add_record_to_service", extra); return result; }
|
|
1110
|
+
|
|
1111
|
+
extra->ClientID = request->hdr.reg_index;
|
|
1112
|
+
if (instance->external_advertise && (instance->request->u.servicereg.InterfaceID == mDNSInterface_P2P || (!instance->request->u.servicereg.InterfaceID && SameDomainName(&instance->domain, &localdomain) && (instance->request->flags & kDNSServiceFlagsIncludeP2P))))
|
|
1113
|
+
{
|
|
1114
|
+
LogInfo("add_record_to_service: calling external_start_advertising_service");
|
|
1115
|
+
external_start_advertising_service(&extra->r.resrec);
|
|
1116
|
+
}
|
|
1117
|
+
return result;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
mDNSlocal mStatus handle_add_request(request_state *request)
|
|
1121
|
+
{
|
|
1122
|
+
service_instance *i;
|
|
1123
|
+
mStatus result = mStatus_UnknownErr;
|
|
1124
|
+
DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend);
|
|
1125
|
+
mDNSu16 rrtype = get_uint16(&request->msgptr, request->msgend);
|
|
1126
|
+
mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
|
|
1127
|
+
const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen);
|
|
1128
|
+
mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend);
|
|
1129
|
+
if (!ttl) ttl = DefaultTTLforRRType(rrtype);
|
|
1130
|
+
(void)flags; // Unused
|
|
1131
|
+
|
|
1132
|
+
if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
1133
|
+
|
|
1134
|
+
// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
|
|
1135
|
+
if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
|
|
1136
|
+
|
|
1137
|
+
if (request->terminate != regservice_termination_callback)
|
|
1138
|
+
{ LogMsg("%3d: DNSServiceAddRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
|
|
1139
|
+
|
|
1140
|
+
// For a service registered with zero port, don't allow adding records. This mostly happens due to a bug
|
|
1141
|
+
// in the application. See radar://9165807.
|
|
1142
|
+
if (mDNSIPPortIsZero(request->u.servicereg.port))
|
|
1143
|
+
{ LogMsg("%3d: DNSServiceAddRecord: adding record to a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
|
|
1144
|
+
|
|
1145
|
+
LogOperation("%3d: DNSServiceAddRecord(%X, %##s, %s, %d)", request->sd, flags,
|
|
1146
|
+
(request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen);
|
|
1147
|
+
|
|
1148
|
+
for (i = request->u.servicereg.instances; i; i = i->next)
|
|
1149
|
+
{
|
|
1150
|
+
result = add_record_to_service(request, i, rrtype, rdlen, rdata, ttl);
|
|
1151
|
+
if (result && i->default_local) break;
|
|
1152
|
+
else result = mStatus_NoError; // suppress non-local default errors
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
return(result);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd, mDNSu16 oldrdlen)
|
|
1159
|
+
{
|
|
1160
|
+
mDNSBool external_advertise = (rr->UpdateContext) ? *((mDNSBool *)rr->UpdateContext) : mDNSfalse;
|
|
1161
|
+
(void)m; // Unused
|
|
1162
|
+
|
|
1163
|
+
// There are three cases.
|
|
1164
|
+
//
|
|
1165
|
+
// 1. We have updated the primary TXT record of the service
|
|
1166
|
+
// 2. We have updated the TXT record that was added to the service using DNSServiceAddRecord
|
|
1167
|
+
// 3. We have updated the TXT record that was registered using DNSServiceRegisterRecord
|
|
1168
|
+
//
|
|
1169
|
+
// external_advertise is set if we have advertised at least once during the initial addition
|
|
1170
|
+
// of the record in all of the three cases above. We should have checked for InterfaceID/LocalDomain
|
|
1171
|
+
// checks during the first time and hence we don't do any checks here
|
|
1172
|
+
if (external_advertise)
|
|
1173
|
+
{
|
|
1174
|
+
ResourceRecord ext = rr->resrec;
|
|
1175
|
+
if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit;
|
|
1176
|
+
SetNewRData(&ext, oldrd, oldrdlen);
|
|
1177
|
+
external_stop_advertising_service(&ext);
|
|
1178
|
+
LogInfo("update_callback: calling external_start_advertising_service");
|
|
1179
|
+
external_start_advertising_service(&rr->resrec);
|
|
1180
|
+
}
|
|
1181
|
+
exit:
|
|
1182
|
+
if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl, const mDNSBool *const external_advertise)
|
|
1186
|
+
{
|
|
1187
|
+
mStatus result;
|
|
1188
|
+
const int rdsize = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
|
|
1189
|
+
RData *newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
|
|
1190
|
+
if (!newrd) FatalError("ERROR: malloc");
|
|
1191
|
+
newrd->MaxRDLength = (mDNSu16) rdsize;
|
|
1192
|
+
mDNSPlatformMemCopy(&newrd->u, rdata, rdlen);
|
|
1193
|
+
|
|
1194
|
+
// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
|
|
1195
|
+
// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
|
|
1196
|
+
// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
|
|
1197
|
+
if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
|
|
1198
|
+
|
|
1199
|
+
if (external_advertise) rr->UpdateContext = (void *)external_advertise;
|
|
1200
|
+
|
|
1201
|
+
result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
|
|
1202
|
+
if (result) { LogMsg("update_record: Error %d for %s", (int)result, ARDisplayString(&mDNSStorage, rr)); freeL("RData/update_record", newrd); }
|
|
1203
|
+
return result;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
mDNSlocal mStatus handle_update_request(request_state *request)
|
|
1207
|
+
{
|
|
1208
|
+
const ipc_msg_hdr *const hdr = &request->hdr;
|
|
1209
|
+
mStatus result = mStatus_BadReferenceErr;
|
|
1210
|
+
service_instance *i;
|
|
1211
|
+
AuthRecord *rr = NULL;
|
|
1212
|
+
|
|
1213
|
+
// get the message data
|
|
1214
|
+
DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend); // flags unused
|
|
1215
|
+
mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
|
|
1216
|
+
const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen);
|
|
1217
|
+
mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend);
|
|
1218
|
+
(void)flags; // Unused
|
|
1219
|
+
|
|
1220
|
+
if (!request->msgptr) { LogMsg("%3d: DNSServiceUpdateRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
1221
|
+
|
|
1222
|
+
// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
|
|
1223
|
+
if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
|
|
1224
|
+
|
|
1225
|
+
if (request->terminate == connection_termination)
|
|
1226
|
+
{
|
|
1227
|
+
// update an individually registered record
|
|
1228
|
+
registered_record_entry *reptr;
|
|
1229
|
+
for (reptr = request->u.reg_recs; reptr; reptr = reptr->next)
|
|
1230
|
+
{
|
|
1231
|
+
if (reptr->key == hdr->reg_index)
|
|
1232
|
+
{
|
|
1233
|
+
result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise);
|
|
1234
|
+
LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)",
|
|
1235
|
+
request->sd, reptr->rr->resrec.name->c, reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>");
|
|
1236
|
+
goto end;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
result = mStatus_BadReferenceErr;
|
|
1240
|
+
goto end;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
if (request->terminate != regservice_termination_callback)
|
|
1244
|
+
{ LogMsg("%3d: DNSServiceUpdateRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
|
|
1245
|
+
|
|
1246
|
+
// For a service registered with zero port, only SRV record is initialized. Don't allow any updates.
|
|
1247
|
+
if (mDNSIPPortIsZero(request->u.servicereg.port))
|
|
1248
|
+
{ LogMsg("%3d: DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
|
|
1249
|
+
|
|
1250
|
+
// update the saved off TXT data for the service
|
|
1251
|
+
if (hdr->reg_index == TXT_RECORD_INDEX)
|
|
1252
|
+
{
|
|
1253
|
+
if (request->u.servicereg.txtdata)
|
|
1254
|
+
{ freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
|
|
1255
|
+
if (rdlen > 0)
|
|
1256
|
+
{
|
|
1257
|
+
request->u.servicereg.txtdata = mallocL("service_info txtdata", rdlen);
|
|
1258
|
+
if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_update_request - malloc");
|
|
1259
|
+
mDNSPlatformMemCopy(request->u.servicereg.txtdata, rdata, rdlen);
|
|
1260
|
+
}
|
|
1261
|
+
request->u.servicereg.txtlen = rdlen;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// update a record from a service record set
|
|
1265
|
+
for (i = request->u.servicereg.instances; i; i = i->next)
|
|
1266
|
+
{
|
|
1267
|
+
if (hdr->reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
|
|
1268
|
+
else
|
|
1269
|
+
{
|
|
1270
|
+
ExtraResourceRecord *e;
|
|
1271
|
+
for (e = i->srs.Extras; e; e = e->next)
|
|
1272
|
+
if (e->ClientID == hdr->reg_index) { rr = &e->r; break; }
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
if (!rr) { result = mStatus_BadReferenceErr; goto end; }
|
|
1276
|
+
result = update_record(rr, rdlen, rdata, ttl, &i->external_advertise);
|
|
1277
|
+
if (result && i->default_local) goto end;
|
|
1278
|
+
else result = mStatus_NoError; // suppress non-local default errors
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
end:
|
|
1282
|
+
if (request->terminate == regservice_termination_callback)
|
|
1283
|
+
LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", request->sd,
|
|
1284
|
+
(request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
|
|
1285
|
+
rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
|
|
1286
|
+
|
|
1287
|
+
return(result);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// remove a resource record registered via DNSServiceRegisterRecord()
|
|
1291
|
+
mDNSlocal mStatus remove_record(request_state *request)
|
|
1292
|
+
{
|
|
1293
|
+
mStatus err = mStatus_UnknownErr;
|
|
1294
|
+
registered_record_entry *e, **ptr = &request->u.reg_recs;
|
|
1295
|
+
|
|
1296
|
+
while (*ptr && (*ptr)->key != request->hdr.reg_index) ptr = &(*ptr)->next;
|
|
1297
|
+
if (!*ptr) { LogMsg("%3d: DNSServiceRemoveRecord(%u) not found", request->sd, request->hdr.reg_index); return mStatus_BadReferenceErr; }
|
|
1298
|
+
e = *ptr;
|
|
1299
|
+
*ptr = e->next; // unlink
|
|
1300
|
+
|
|
1301
|
+
LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, e->key, RRDisplayString(&mDNSStorage, &e->rr->resrec));
|
|
1302
|
+
e->rr->RecordContext = NULL;
|
|
1303
|
+
if (e->external_advertise)
|
|
1304
|
+
{
|
|
1305
|
+
external_stop_advertising_service(&e->rr->resrec);
|
|
1306
|
+
e->external_advertise = mDNSfalse;
|
|
1307
|
+
}
|
|
1308
|
+
err = mDNS_Deregister(&mDNSStorage, e->rr); // Will free e->rr for us; we're responsible for freeing e
|
|
1309
|
+
if (err)
|
|
1310
|
+
{
|
|
1311
|
+
LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err);
|
|
1312
|
+
freeL("registered_record_entry AuthRecord remove_record", e->rr);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
freeL("registered_record_entry remove_record", e);
|
|
1316
|
+
return err;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
mDNSlocal mStatus remove_extra(const request_state *const request, service_instance *const serv, mDNSu16 *const rrtype)
|
|
1320
|
+
{
|
|
1321
|
+
mStatus err = mStatus_BadReferenceErr;
|
|
1322
|
+
ExtraResourceRecord *ptr;
|
|
1323
|
+
|
|
1324
|
+
for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
|
|
1325
|
+
{
|
|
1326
|
+
if (ptr->ClientID == request->hdr.reg_index) // found match
|
|
1327
|
+
{
|
|
1328
|
+
*rrtype = ptr->r.resrec.rrtype;
|
|
1329
|
+
if (serv->external_advertise) external_stop_advertising_service(&ptr->r.resrec);
|
|
1330
|
+
err = mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
|
|
1331
|
+
break;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
return err;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
mDNSlocal mStatus handle_removerecord_request(request_state *request)
|
|
1338
|
+
{
|
|
1339
|
+
mStatus err = mStatus_BadReferenceErr;
|
|
1340
|
+
get_flags(&request->msgptr, request->msgend); // flags unused
|
|
1341
|
+
|
|
1342
|
+
if (!request->msgptr) { LogMsg("%3d: DNSServiceRemoveRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
1343
|
+
|
|
1344
|
+
// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
|
|
1345
|
+
if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
|
|
1346
|
+
|
|
1347
|
+
if (request->terminate == connection_termination)
|
|
1348
|
+
err = remove_record(request); // remove individually registered record
|
|
1349
|
+
else if (request->terminate != regservice_termination_callback)
|
|
1350
|
+
{ LogMsg("%3d: DNSServiceRemoveRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
|
|
1351
|
+
else
|
|
1352
|
+
{
|
|
1353
|
+
service_instance *i;
|
|
1354
|
+
mDNSu16 rrtype = 0;
|
|
1355
|
+
LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s)", request->sd,
|
|
1356
|
+
(request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
|
|
1357
|
+
rrtype ? DNSTypeName(rrtype) : "<NONE>");
|
|
1358
|
+
for (i = request->u.servicereg.instances; i; i = i->next)
|
|
1359
|
+
{
|
|
1360
|
+
err = remove_extra(request, i, &rrtype);
|
|
1361
|
+
if (err && i->default_local) break;
|
|
1362
|
+
else err = mStatus_NoError; // suppress non-local default errors
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
return(err);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// If there's a comma followed by another character,
|
|
1370
|
+
// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
|
|
1371
|
+
// Otherwise, it returns a pointer to the final nul at the end of the string
|
|
1372
|
+
mDNSlocal char *FindFirstSubType(char *p)
|
|
1373
|
+
{
|
|
1374
|
+
while (*p)
|
|
1375
|
+
{
|
|
1376
|
+
if (p[0] == '\\' && p[1]) p += 2;
|
|
1377
|
+
else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
|
|
1378
|
+
else p++;
|
|
1379
|
+
}
|
|
1380
|
+
return(p);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// If there's a comma followed by another character,
|
|
1384
|
+
// FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
|
|
1385
|
+
// If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
|
|
1386
|
+
// Otherwise, it returns a pointer to the final nul at the end of the string
|
|
1387
|
+
mDNSlocal char *FindNextSubType(char *p)
|
|
1388
|
+
{
|
|
1389
|
+
while (*p)
|
|
1390
|
+
{
|
|
1391
|
+
if (p[0] == '\\' && p[1]) // If escape character
|
|
1392
|
+
p += 2; // ignore following character
|
|
1393
|
+
else if (p[0] == ',') // If we found a comma
|
|
1394
|
+
{
|
|
1395
|
+
if (p[1]) *p++ = 0;
|
|
1396
|
+
return(p);
|
|
1397
|
+
}
|
|
1398
|
+
else if (p[0] == '.')
|
|
1399
|
+
return(mDNSNULL);
|
|
1400
|
+
else p++;
|
|
1401
|
+
}
|
|
1402
|
+
return(p);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
// Returns -1 if illegal subtype found
|
|
1406
|
+
mDNSexport mDNSs32 ChopSubTypes(char *regtype)
|
|
1407
|
+
{
|
|
1408
|
+
mDNSs32 NumSubTypes = 0;
|
|
1409
|
+
char *stp = FindFirstSubType(regtype);
|
|
1410
|
+
while (stp && *stp) // If we found a comma...
|
|
1411
|
+
{
|
|
1412
|
+
if (*stp == ',') return(-1);
|
|
1413
|
+
NumSubTypes++;
|
|
1414
|
+
stp = FindNextSubType(stp);
|
|
1415
|
+
}
|
|
1416
|
+
if (!stp) return(-1);
|
|
1417
|
+
return(NumSubTypes);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
|
|
1421
|
+
{
|
|
1422
|
+
AuthRecord *st = mDNSNULL;
|
|
1423
|
+
if (NumSubTypes)
|
|
1424
|
+
{
|
|
1425
|
+
mDNSs32 i;
|
|
1426
|
+
st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
|
|
1427
|
+
if (!st) return(mDNSNULL);
|
|
1428
|
+
for (i = 0; i < NumSubTypes; i++)
|
|
1429
|
+
{
|
|
1430
|
+
mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
|
|
1431
|
+
while (*p) p++;
|
|
1432
|
+
p++;
|
|
1433
|
+
if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
|
|
1434
|
+
{ freeL("ServiceSubTypes", st); return(mDNSNULL); }
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
return(st);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
|
|
1441
|
+
{
|
|
1442
|
+
service_instance **ptr, *instance;
|
|
1443
|
+
const int extra_size = (request->u.servicereg.txtlen > sizeof(RDataBody)) ? (request->u.servicereg.txtlen - sizeof(RDataBody)) : 0;
|
|
1444
|
+
const mDNSBool DomainIsLocal = SameDomainName(domain, &localdomain);
|
|
1445
|
+
mStatus result;
|
|
1446
|
+
mDNSInterfaceID interfaceID = request->u.servicereg.InterfaceID;
|
|
1447
|
+
mDNSu32 regFlags = 0;
|
|
1448
|
+
|
|
1449
|
+
if (interfaceID == mDNSInterface_P2P)
|
|
1450
|
+
{
|
|
1451
|
+
interfaceID = mDNSInterface_Any;
|
|
1452
|
+
regFlags |= regFlagIncludeP2P;
|
|
1453
|
+
}
|
|
1454
|
+
else if (request->flags & kDNSServiceFlagsIncludeP2P)
|
|
1455
|
+
regFlags |= regFlagIncludeP2P;
|
|
1456
|
+
|
|
1457
|
+
// client guarantees that record names are unique
|
|
1458
|
+
if (request->flags & kDNSServiceFlagsForce)
|
|
1459
|
+
regFlags |= regFlagKnownUnique;
|
|
1460
|
+
|
|
1461
|
+
// If the client specified an interface, but no domain, then we honor the specified interface for the "local" (mDNS)
|
|
1462
|
+
// registration but for the wide-area registrations we don't (currently) have any concept of a wide-area unicast
|
|
1463
|
+
// registrations scoped to a specific interface, so for the automatic domains we add we must *not* specify an interface.
|
|
1464
|
+
// (Specifying an interface with an apparently wide-area domain (i.e. something other than "local")
|
|
1465
|
+
// currently forces the registration to use mDNS multicast despite the apparently wide-area domain.)
|
|
1466
|
+
if (request->u.servicereg.default_domain && !DomainIsLocal) interfaceID = mDNSInterface_Any;
|
|
1467
|
+
|
|
1468
|
+
for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next)
|
|
1469
|
+
{
|
|
1470
|
+
if (SameDomainName(&(*ptr)->domain, domain))
|
|
1471
|
+
{
|
|
1472
|
+
LogMsg("register_service_instance: domain %##s already registered for %#s.%##s",
|
|
1473
|
+
domain->c, &request->u.servicereg.name, &request->u.servicereg.type);
|
|
1474
|
+
return mStatus_AlreadyRegistered;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
if (mDNSStorage.KnownBugs & mDNS_KnownBug_LimitedIPv6)
|
|
1479
|
+
{
|
|
1480
|
+
// Special-case hack: On Mac OS X 10.6.x and earlier we don't advertise SMB service in AutoTunnel domains,
|
|
1481
|
+
// because AutoTunnel services have to support IPv6, and in Mac OS X 10.6.x the SMB server does not.
|
|
1482
|
+
// <rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
|
|
1483
|
+
if (SameDomainName(&request->u.servicereg.type, (const domainname *) "\x4" "_smb" "\x4" "_tcp"))
|
|
1484
|
+
{
|
|
1485
|
+
DomainAuthInfo *AuthInfo = GetAuthInfoForName(&mDNSStorage, domain);
|
|
1486
|
+
if (AuthInfo && AuthInfo->AutoTunnel) return(kDNSServiceErr_Unsupported);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
instance = mallocL("service_instance", sizeof(*instance) + extra_size);
|
|
1491
|
+
if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
|
|
1492
|
+
|
|
1493
|
+
instance->next = mDNSNULL;
|
|
1494
|
+
instance->request = request;
|
|
1495
|
+
instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
|
|
1496
|
+
instance->renameonmemfree = 0;
|
|
1497
|
+
instance->clientnotified = mDNSfalse;
|
|
1498
|
+
instance->default_local = (request->u.servicereg.default_domain && DomainIsLocal);
|
|
1499
|
+
instance->external_advertise = mDNSfalse;
|
|
1500
|
+
AssignDomainName(&instance->domain, domain);
|
|
1501
|
+
|
|
1502
|
+
if (request->u.servicereg.num_subtypes && !instance->subtypes)
|
|
1503
|
+
{ unlink_and_free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
|
|
1504
|
+
|
|
1505
|
+
result = mDNS_RegisterService(&mDNSStorage, &instance->srs,
|
|
1506
|
+
&request->u.servicereg.name, &request->u.servicereg.type, domain,
|
|
1507
|
+
request->u.servicereg.host.c[0] ? &request->u.servicereg.host : NULL,
|
|
1508
|
+
request->u.servicereg.port,
|
|
1509
|
+
request->u.servicereg.txtdata, request->u.servicereg.txtlen,
|
|
1510
|
+
instance->subtypes, request->u.servicereg.num_subtypes,
|
|
1511
|
+
interfaceID, regservice_callback, instance, regFlags);
|
|
1512
|
+
|
|
1513
|
+
if (!result)
|
|
1514
|
+
{
|
|
1515
|
+
*ptr = instance; // Append this to the end of our request->u.servicereg.instances list
|
|
1516
|
+
LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED",
|
|
1517
|
+
instance->request->sd, instance->srs.RR_SRV.resrec.name->c, mDNSVal16(request->u.servicereg.port));
|
|
1518
|
+
}
|
|
1519
|
+
else
|
|
1520
|
+
{
|
|
1521
|
+
LogMsg("register_service_instance %#s.%##s%##s error %d",
|
|
1522
|
+
&request->u.servicereg.name, &request->u.servicereg.type, domain->c, result);
|
|
1523
|
+
unlink_and_free_service_instance(instance);
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
return result;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d, const mDNSBool add)
|
|
1530
|
+
{
|
|
1531
|
+
request_state *request;
|
|
1532
|
+
|
|
1533
|
+
#if APPLE_OSX_mDNSResponder
|
|
1534
|
+
machserver_automatic_registration_domain_changed(&d->name, add);
|
|
1535
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
1536
|
+
|
|
1537
|
+
LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->name.c);
|
|
1538
|
+
for (request = all_requests; request; request = request->next)
|
|
1539
|
+
{
|
|
1540
|
+
if (request->terminate != regservice_termination_callback) continue;
|
|
1541
|
+
if (!request->u.servicereg.default_domain) continue;
|
|
1542
|
+
if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
|
|
1543
|
+
{
|
|
1544
|
+
service_instance **ptr = &request->u.servicereg.instances;
|
|
1545
|
+
while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
|
|
1546
|
+
if (add)
|
|
1547
|
+
{
|
|
1548
|
+
// If we don't already have this domain in our list for this registration, add it now
|
|
1549
|
+
if (!*ptr) register_service_instance(request, &d->name);
|
|
1550
|
+
else debugf("udsserver_default_reg_domain_changed %##s already in list, not re-adding", &d->name);
|
|
1551
|
+
}
|
|
1552
|
+
else
|
|
1553
|
+
{
|
|
1554
|
+
// Normally we should not fail to find the specified instance
|
|
1555
|
+
// One case where this can happen is if a uDNS update fails for some reason,
|
|
1556
|
+
// and regservice_callback then calls unlink_and_free_service_instance and disposes of that instance.
|
|
1557
|
+
if (!*ptr)
|
|
1558
|
+
LogMsg("udsserver_default_reg_domain_changed domain %##s not found for service %#s type %s",
|
|
1559
|
+
&d->name, request->u.servicereg.name.c, request->u.servicereg.type_as_string);
|
|
1560
|
+
else
|
|
1561
|
+
{
|
|
1562
|
+
DNameListElem *p;
|
|
1563
|
+
for (p = AutoRegistrationDomains; p; p=p->next)
|
|
1564
|
+
if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
|
|
1565
|
+
if (SameDomainName(&d->name, &p->name)) break;
|
|
1566
|
+
if (p) debugf("udsserver_default_reg_domain_changed %##s still in list, not removing", &d->name);
|
|
1567
|
+
else
|
|
1568
|
+
{
|
|
1569
|
+
mStatus err;
|
|
1570
|
+
service_instance *si = *ptr;
|
|
1571
|
+
*ptr = si->next;
|
|
1572
|
+
if (si->clientnotified) SendServiceRemovalNotification(&si->srs); // Do this *before* clearing si->request backpointer
|
|
1573
|
+
// Now that we've cut this service_instance from the list, we MUST clear the si->request backpointer.
|
|
1574
|
+
// Otherwise what can happen is this: While our mDNS_DeregisterService is in the
|
|
1575
|
+
// process of completing asynchronously, the client cancels the entire operation, so
|
|
1576
|
+
// regservice_termination_callback then runs through the whole list deregistering each
|
|
1577
|
+
// instance, clearing the backpointers, and then disposing the parent request_state object.
|
|
1578
|
+
// However, because this service_instance isn't in the list any more, regservice_termination_callback
|
|
1579
|
+
// has no way to find it and clear its backpointer, and then when our mDNS_DeregisterService finally
|
|
1580
|
+
// completes later with a mStatus_MemFree message, it calls unlink_and_free_service_instance() with
|
|
1581
|
+
// a service_instance with a stale si->request backpointer pointing to memory that's already been freed.
|
|
1582
|
+
si->request = NULL;
|
|
1583
|
+
err = mDNS_DeregisterService(&mDNSStorage, &si->srs);
|
|
1584
|
+
if (err) { LogMsg("udsserver_default_reg_domain_changed err %d", err); unlink_and_free_service_instance(si); }
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
mDNSlocal mStatus handle_regservice_request(request_state *request)
|
|
1593
|
+
{
|
|
1594
|
+
char name[256]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
|
|
1595
|
+
char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
|
|
1596
|
+
char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
|
|
1597
|
+
domainname d, srv;
|
|
1598
|
+
mStatus err;
|
|
1599
|
+
const char *msgTXTData;
|
|
1600
|
+
|
|
1601
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
1602
|
+
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
|
|
1603
|
+
mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
|
|
1604
|
+
if (interfaceIndex && !InterfaceID)
|
|
1605
|
+
{ LogMsg("ERROR: handle_regservice_request - Couldn't find interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
|
|
1606
|
+
|
|
1607
|
+
if (get_string(&request->msgptr, request->msgend, name, sizeof(name)) < 0 ||
|
|
1608
|
+
get_string(&request->msgptr, request->msgend, type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
|
|
1609
|
+
get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
|
|
1610
|
+
get_string(&request->msgptr, request->msgend, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
|
|
1611
|
+
{ LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
|
|
1612
|
+
|
|
1613
|
+
request->flags = flags;
|
|
1614
|
+
request->u.servicereg.InterfaceID = InterfaceID;
|
|
1615
|
+
request->u.servicereg.instances = NULL;
|
|
1616
|
+
request->u.servicereg.txtlen = 0;
|
|
1617
|
+
request->u.servicereg.txtdata = NULL;
|
|
1618
|
+
mDNSPlatformStrLCopy(request->u.servicereg.type_as_string, type_as_string, sizeof(request->u.servicereg.type_as_string));
|
|
1619
|
+
|
|
1620
|
+
if (request->msgptr + 2 > request->msgend) request->msgptr = NULL;
|
|
1621
|
+
else
|
|
1622
|
+
{
|
|
1623
|
+
request->u.servicereg.port.b[0] = *request->msgptr++;
|
|
1624
|
+
request->u.servicereg.port.b[1] = *request->msgptr++;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
request->u.servicereg.txtlen = get_uint16(&request->msgptr, request->msgend);
|
|
1628
|
+
msgTXTData = get_rdata(&request->msgptr, request->msgend, request->u.servicereg.txtlen);
|
|
1629
|
+
if (!request->msgptr)
|
|
1630
|
+
{
|
|
1631
|
+
LogMsg("%3d: DNSServiceRegister(unreadable parameters)", request->sd);
|
|
1632
|
+
return(mStatus_BadParamErr);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
if (request->u.servicereg.txtlen)
|
|
1636
|
+
{
|
|
1637
|
+
request->u.servicereg.txtdata = mallocL("service_info txtdata", request->u.servicereg.txtlen);
|
|
1638
|
+
if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_regservice_request - malloc");
|
|
1639
|
+
mDNSPlatformMemCopy(request->u.servicereg.txtdata, msgTXTData, request->u.servicereg.txtlen);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
// Check for sub-types after the service type
|
|
1643
|
+
request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string); // Note: Modifies regtype string to remove trailing subtypes
|
|
1644
|
+
if (request->u.servicereg.num_subtypes < 0)
|
|
1645
|
+
{ LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", request->u.servicereg.type_as_string); return(mStatus_BadParamErr); }
|
|
1646
|
+
|
|
1647
|
+
// Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
|
|
1648
|
+
if (!*request->u.servicereg.type_as_string || !MakeDomainNameFromDNSNameString(&request->u.servicereg.type, request->u.servicereg.type_as_string))
|
|
1649
|
+
{ LogMsg("ERROR: handle_regservice_request - type_as_string bad %s", request->u.servicereg.type_as_string); return(mStatus_BadParamErr); }
|
|
1650
|
+
|
|
1651
|
+
if (!name[0])
|
|
1652
|
+
{
|
|
1653
|
+
request->u.servicereg.name = mDNSStorage.nicelabel;
|
|
1654
|
+
request->u.servicereg.autoname = mDNStrue;
|
|
1655
|
+
}
|
|
1656
|
+
else
|
|
1657
|
+
{
|
|
1658
|
+
// If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
|
|
1659
|
+
if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
|
|
1660
|
+
{
|
|
1661
|
+
int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
|
|
1662
|
+
name[newlen] = 0;
|
|
1663
|
+
}
|
|
1664
|
+
if (!MakeDomainLabelFromLiteralString(&request->u.servicereg.name, name))
|
|
1665
|
+
{ LogMsg("ERROR: handle_regservice_request - name bad %s", name); return(mStatus_BadParamErr); }
|
|
1666
|
+
request->u.servicereg.autoname = mDNSfalse;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
if (*domain)
|
|
1670
|
+
{
|
|
1671
|
+
request->u.servicereg.default_domain = mDNSfalse;
|
|
1672
|
+
if (!MakeDomainNameFromDNSNameString(&d, domain))
|
|
1673
|
+
{ LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); return(mStatus_BadParamErr); }
|
|
1674
|
+
}
|
|
1675
|
+
else
|
|
1676
|
+
{
|
|
1677
|
+
request->u.servicereg.default_domain = mDNStrue;
|
|
1678
|
+
MakeDomainNameFromDNSNameString(&d, "local.");
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
|
|
1682
|
+
{
|
|
1683
|
+
LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
|
|
1684
|
+
request->u.servicereg.name.c, request->u.servicereg.type.c, d.c); return(mStatus_BadParamErr);
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
if (!MakeDomainNameFromDNSNameString(&request->u.servicereg.host, host))
|
|
1688
|
+
{ LogMsg("ERROR: handle_regservice_request - host bad %s", host); return(mStatus_BadParamErr); }
|
|
1689
|
+
request->u.servicereg.autorename = (flags & kDNSServiceFlagsNoAutoRename ) == 0;
|
|
1690
|
+
request->u.servicereg.allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
|
|
1691
|
+
|
|
1692
|
+
// Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
|
|
1693
|
+
// a port number of zero. When two instances of the protected client are allowed to run on one
|
|
1694
|
+
// machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
|
|
1695
|
+
if (!mDNSIPPortIsZero(request->u.servicereg.port))
|
|
1696
|
+
{
|
|
1697
|
+
int count = CountExistingRegistrations(&srv, request->u.servicereg.port);
|
|
1698
|
+
if (count)
|
|
1699
|
+
LogMsg("Client application registered %d identical instances of service %##s port %u.",
|
|
1700
|
+
count+1, srv.c, mDNSVal16(request->u.servicereg.port));
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
LogOperation("%3d: DNSServiceRegister(%X, %d, \"%s\", \"%s\", \"%s\", \"%s\", %u) START",
|
|
1704
|
+
request->sd, flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host, mDNSVal16(request->u.servicereg.port));
|
|
1705
|
+
|
|
1706
|
+
// We need to unconditionally set request->terminate, because even if we didn't successfully
|
|
1707
|
+
// start any registrations right now, subsequent configuration changes may cause successful
|
|
1708
|
+
// registrations to be added, and we'll need to cancel them before freeing this memory.
|
|
1709
|
+
// We also need to set request->terminate first, before adding additional service instances,
|
|
1710
|
+
// because the uds_validatelists uses the request->terminate function pointer to determine
|
|
1711
|
+
// what kind of request this is, and therefore what kind of list validation is required.
|
|
1712
|
+
request->terminate = regservice_termination_callback;
|
|
1713
|
+
|
|
1714
|
+
err = register_service_instance(request, &d);
|
|
1715
|
+
|
|
1716
|
+
#if 0
|
|
1717
|
+
err = AuthorizedDomain(request, &d, AutoRegistrationDomains) ? register_service_instance(request, &d) : mStatus_NoError;
|
|
1718
|
+
#endif
|
|
1719
|
+
if (!err)
|
|
1720
|
+
{
|
|
1721
|
+
if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
|
|
1722
|
+
|
|
1723
|
+
if (!*domain)
|
|
1724
|
+
{
|
|
1725
|
+
DNameListElem *ptr;
|
|
1726
|
+
// Note that we don't report errors for non-local, non-explicit domains
|
|
1727
|
+
for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
|
|
1728
|
+
if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
|
|
1729
|
+
register_service_instance(request, &ptr->name);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
return(err);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// ***************************************************************************
|
|
1737
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
1738
|
+
#pragma mark -
|
|
1739
|
+
#pragma mark - DNSServiceBrowse
|
|
1740
|
+
#endif
|
|
1741
|
+
|
|
1742
|
+
mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
|
|
1743
|
+
{
|
|
1744
|
+
const DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : 0;
|
|
1745
|
+
request_state *req = question->QuestionContext;
|
|
1746
|
+
reply_state *rep;
|
|
1747
|
+
(void)m; // Unused
|
|
1748
|
+
|
|
1749
|
+
if (answer->rrtype != kDNSType_PTR)
|
|
1750
|
+
{ LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
|
|
1751
|
+
|
|
1752
|
+
if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError) != mStatus_NoError)
|
|
1753
|
+
{
|
|
1754
|
+
if (SameDomainName(&req->u.browser.regtype, (const domainname*)"\x09_services\x07_dns-sd\x04_udp"))
|
|
1755
|
+
{
|
|
1756
|
+
// Special support to enable the DNSServiceBrowse call made by Bonjour Browser
|
|
1757
|
+
// Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
|
|
1758
|
+
GenerateBonjourBrowserResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError);
|
|
1759
|
+
goto bonjourbrowserhack;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
|
|
1763
|
+
req->sd, answer->name->c, answer->rdata->u.name.c);
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
bonjourbrowserhack:
|
|
1768
|
+
|
|
1769
|
+
LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %d: %s",
|
|
1770
|
+
req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv",
|
|
1771
|
+
mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer));
|
|
1772
|
+
|
|
1773
|
+
append_reply(req, rep);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d)
|
|
1777
|
+
{
|
|
1778
|
+
browser_t *b, *p;
|
|
1779
|
+
mStatus err;
|
|
1780
|
+
|
|
1781
|
+
for (p = info->u.browser.browsers; p; p = p->next)
|
|
1782
|
+
{
|
|
1783
|
+
if (SameDomainName(&p->domain, d))
|
|
1784
|
+
{ debugf("add_domain_to_browser %##s already in list", d->c); return mStatus_AlreadyRegistered; }
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
b = mallocL("browser_t", sizeof(*b));
|
|
1788
|
+
if (!b) return mStatus_NoMemoryErr;
|
|
1789
|
+
AssignDomainName(&b->domain, d);
|
|
1790
|
+
err = mDNS_StartBrowse(&mDNSStorage, &b->q,
|
|
1791
|
+
&info->u.browser.regtype, d, info->u.browser.interface_id, info->u.browser.ForceMCast, FoundInstance, info);
|
|
1792
|
+
if (err)
|
|
1793
|
+
{
|
|
1794
|
+
LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->u.browser.regtype.c, d->c);
|
|
1795
|
+
freeL("browser_t/add_domain_to_browser", b);
|
|
1796
|
+
}
|
|
1797
|
+
else
|
|
1798
|
+
{
|
|
1799
|
+
b->next = info->u.browser.browsers;
|
|
1800
|
+
info->u.browser.browsers = b;
|
|
1801
|
+
LogOperation("%3d: DNSServiceBrowse(%##s) START", info->sd, b->q.qname.c);
|
|
1802
|
+
if (info->u.browser.interface_id == mDNSInterface_P2P || (!info->u.browser.interface_id && SameDomainName(&b->domain, &localdomain) && (info->flags & kDNSServiceFlagsIncludeP2P)))
|
|
1803
|
+
{
|
|
1804
|
+
domainname tmp;
|
|
1805
|
+
ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &b->domain);
|
|
1806
|
+
LogInfo("add_domain_to_browser: calling external_start_browsing_for_service()");
|
|
1807
|
+
external_start_browsing_for_service(&mDNSStorage, &tmp, kDNSType_PTR);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
return err;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
mDNSlocal void browse_termination_callback(request_state *info)
|
|
1814
|
+
{
|
|
1815
|
+
while (info->u.browser.browsers)
|
|
1816
|
+
{
|
|
1817
|
+
browser_t *ptr = info->u.browser.browsers;
|
|
1818
|
+
|
|
1819
|
+
if (info->u.browser.interface_id == mDNSInterface_P2P || (!info->u.browser.interface_id && SameDomainName(&ptr->domain, &localdomain) && (info->flags & kDNSServiceFlagsIncludeP2P)))
|
|
1820
|
+
{
|
|
1821
|
+
domainname tmp;
|
|
1822
|
+
ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &ptr->domain);
|
|
1823
|
+
LogInfo("browse_termination_callback: calling external_stop_browsing_for_service()");
|
|
1824
|
+
external_stop_browsing_for_service(&mDNSStorage, &tmp, kDNSType_PTR);
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
info->u.browser.browsers = ptr->next;
|
|
1828
|
+
LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->sd, ptr->q.qname.c);
|
|
1829
|
+
mDNS_StopBrowse(&mDNSStorage, &ptr->q); // no need to error-check result
|
|
1830
|
+
freeL("browser_t/browse_termination_callback", ptr);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
mDNSlocal void udsserver_automatic_browse_domain_changed(const DNameListElem *const d, const mDNSBool add)
|
|
1835
|
+
{
|
|
1836
|
+
request_state *request;
|
|
1837
|
+
debugf("udsserver_automatic_browse_domain_changed: %s default browse domain %##s", add ? "Adding" : "Removing", d->name.c);
|
|
1838
|
+
|
|
1839
|
+
#if APPLE_OSX_mDNSResponder
|
|
1840
|
+
machserver_automatic_browse_domain_changed(&d->name, add);
|
|
1841
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
1842
|
+
|
|
1843
|
+
for (request = all_requests; request; request = request->next)
|
|
1844
|
+
{
|
|
1845
|
+
if (request->terminate != browse_termination_callback) continue; // Not a browse operation
|
|
1846
|
+
if (!request->u.browser.default_domain) continue; // Not an auto-browse operation
|
|
1847
|
+
if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
|
|
1848
|
+
{
|
|
1849
|
+
browser_t **ptr = &request->u.browser.browsers;
|
|
1850
|
+
while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
|
|
1851
|
+
if (add)
|
|
1852
|
+
{
|
|
1853
|
+
// If we don't already have this domain in our list for this browse operation, add it now
|
|
1854
|
+
if (!*ptr) add_domain_to_browser(request, &d->name);
|
|
1855
|
+
else debugf("udsserver_automatic_browse_domain_changed %##s already in list, not re-adding", &d->name);
|
|
1856
|
+
}
|
|
1857
|
+
else
|
|
1858
|
+
{
|
|
1859
|
+
if (!*ptr) LogMsg("udsserver_automatic_browse_domain_changed ERROR %##s not found", &d->name);
|
|
1860
|
+
else
|
|
1861
|
+
{
|
|
1862
|
+
DNameListElem *p;
|
|
1863
|
+
for (p = AutoBrowseDomains; p; p=p->next)
|
|
1864
|
+
if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
|
|
1865
|
+
if (SameDomainName(&d->name, &p->name)) break;
|
|
1866
|
+
if (p) debugf("udsserver_automatic_browse_domain_changed %##s still in list, not removing", &d->name);
|
|
1867
|
+
else
|
|
1868
|
+
{
|
|
1869
|
+
browser_t *rem = *ptr;
|
|
1870
|
+
*ptr = (*ptr)->next;
|
|
1871
|
+
mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q);
|
|
1872
|
+
freeL("browser_t/udsserver_automatic_browse_domain_changed", rem);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
|
|
1881
|
+
{
|
|
1882
|
+
(void)m; // unused
|
|
1883
|
+
if (result == mStatus_MemFree)
|
|
1884
|
+
{
|
|
1885
|
+
// On shutdown, mDNS_Close automatically deregisters all records
|
|
1886
|
+
// Since in this case no one has called DeregisterLocalOnlyDomainEnumPTR to cut the record
|
|
1887
|
+
// from the LocalDomainEnumRecords list, we do this here before we free the memory.
|
|
1888
|
+
// (This should actually no longer be necessary, now that we do the proper cleanup in
|
|
1889
|
+
// udsserver_exit. To confirm this, we'll log an error message if we do find a record that
|
|
1890
|
+
// hasn't been cut from the list yet. If these messages don't appear, we can delete this code.)
|
|
1891
|
+
ARListElem **ptr = &LocalDomainEnumRecords;
|
|
1892
|
+
while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
|
|
1893
|
+
if (*ptr) { *ptr = (*ptr)->next; LogMsg("FreeARElemCallback: Have to cut %s", ARDisplayString(m, rr)); }
|
|
1894
|
+
mDNSPlatformMemFree(rr->RecordContext);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// RegisterLocalOnlyDomainEnumPTR and DeregisterLocalOnlyDomainEnumPTR largely duplicate code in
|
|
1899
|
+
// "FoundDomain" in uDNS.c for creating and destroying these special mDNSInterface_LocalOnly records.
|
|
1900
|
+
// We may want to turn the common code into a subroutine.
|
|
1901
|
+
|
|
1902
|
+
mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
|
|
1903
|
+
{
|
|
1904
|
+
// allocate/register legacy and non-legacy _browse PTR record
|
|
1905
|
+
mStatus err;
|
|
1906
|
+
ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr));
|
|
1907
|
+
|
|
1908
|
+
debugf("Incrementing %s refcount for %##s",
|
|
1909
|
+
(type == mDNS_DomainTypeBrowse ) ? "browse domain " :
|
|
1910
|
+
(type == mDNS_DomainTypeRegistration ) ? "registration dom" :
|
|
1911
|
+
(type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
|
|
1912
|
+
|
|
1913
|
+
mDNS_SetupResourceRecord(&ptr->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, AuthRecordLocalOnly, FreeARElemCallback, ptr);
|
|
1914
|
+
MakeDomainNameFromDNSNameString(&ptr->ar.namestorage, mDNS_DomainTypeNames[type]);
|
|
1915
|
+
AppendDNSNameString (&ptr->ar.namestorage, "local");
|
|
1916
|
+
AssignDomainName(&ptr->ar.resrec.rdata->u.name, d);
|
|
1917
|
+
err = mDNS_Register(m, &ptr->ar);
|
|
1918
|
+
if (err)
|
|
1919
|
+
{
|
|
1920
|
+
LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
|
|
1921
|
+
mDNSPlatformMemFree(ptr);
|
|
1922
|
+
}
|
|
1923
|
+
else
|
|
1924
|
+
{
|
|
1925
|
+
ptr->next = LocalDomainEnumRecords;
|
|
1926
|
+
LocalDomainEnumRecords = ptr;
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
|
|
1931
|
+
{
|
|
1932
|
+
ARListElem **ptr = &LocalDomainEnumRecords;
|
|
1933
|
+
domainname lhs; // left-hand side of PTR, for comparison
|
|
1934
|
+
|
|
1935
|
+
debugf("Decrementing %s refcount for %##s",
|
|
1936
|
+
(type == mDNS_DomainTypeBrowse ) ? "browse domain " :
|
|
1937
|
+
(type == mDNS_DomainTypeRegistration ) ? "registration dom" :
|
|
1938
|
+
(type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
|
|
1939
|
+
|
|
1940
|
+
MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
|
|
1941
|
+
AppendDNSNameString (&lhs, "local");
|
|
1942
|
+
|
|
1943
|
+
while (*ptr)
|
|
1944
|
+
{
|
|
1945
|
+
if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
|
|
1946
|
+
{
|
|
1947
|
+
ARListElem *rem = *ptr;
|
|
1948
|
+
*ptr = (*ptr)->next;
|
|
1949
|
+
mDNS_Deregister(m, &rem->ar);
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1952
|
+
else ptr = &(*ptr)->next;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
mDNSlocal void AddAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
|
|
1957
|
+
{
|
|
1958
|
+
DNameListElem *new = mDNSPlatformMemAllocate(sizeof(DNameListElem));
|
|
1959
|
+
if (!new) { LogMsg("ERROR: malloc"); return; }
|
|
1960
|
+
AssignDomainName(&new->name, name);
|
|
1961
|
+
new->uid = uid;
|
|
1962
|
+
new->next = AutoBrowseDomains;
|
|
1963
|
+
AutoBrowseDomains = new;
|
|
1964
|
+
udsserver_automatic_browse_domain_changed(new, mDNStrue);
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
mDNSlocal void RmvAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
|
|
1968
|
+
{
|
|
1969
|
+
DNameListElem **p = &AutoBrowseDomains;
|
|
1970
|
+
while (*p && (!SameDomainName(&(*p)->name, name) || (*p)->uid != uid)) p = &(*p)->next;
|
|
1971
|
+
if (!*p) LogMsg("RmvAutoBrowseDomain: Got remove event for domain %##s not in list", name->c);
|
|
1972
|
+
else
|
|
1973
|
+
{
|
|
1974
|
+
DNameListElem *ptr = *p;
|
|
1975
|
+
*p = ptr->next;
|
|
1976
|
+
udsserver_automatic_browse_domain_changed(ptr, mDNSfalse);
|
|
1977
|
+
mDNSPlatformMemFree(ptr);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
mDNSlocal void SetPrefsBrowseDomains(mDNS *m, DNameListElem *browseDomains, mDNSBool add)
|
|
1982
|
+
{
|
|
1983
|
+
DNameListElem *d;
|
|
1984
|
+
for (d = browseDomains; d; d = d->next)
|
|
1985
|
+
{
|
|
1986
|
+
if (add)
|
|
1987
|
+
{
|
|
1988
|
+
RegisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
|
|
1989
|
+
AddAutoBrowseDomain(d->uid, &d->name);
|
|
1990
|
+
}
|
|
1991
|
+
else
|
|
1992
|
+
{
|
|
1993
|
+
DeregisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
|
|
1994
|
+
RmvAutoBrowseDomain(d->uid, &d->name);
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m)
|
|
2000
|
+
{
|
|
2001
|
+
int num_autoname = 0;
|
|
2002
|
+
request_state *req;
|
|
2003
|
+
for (req = all_requests; req; req = req->next)
|
|
2004
|
+
if (req->terminate == regservice_termination_callback && req->u.servicereg.autoname)
|
|
2005
|
+
num_autoname++;
|
|
2006
|
+
|
|
2007
|
+
// If DeviceInfo record is currently registered, see if we need to deregister it
|
|
2008
|
+
if (m->DeviceInfo.resrec.RecordType != kDNSRecordTypeUnregistered)
|
|
2009
|
+
if (num_autoname == 0 || !SameDomainLabelCS(m->DeviceInfo.resrec.name->c, m->nicelabel.c))
|
|
2010
|
+
{
|
|
2011
|
+
LogOperation("UpdateDeviceInfoRecord Deregister %##s", m->DeviceInfo.resrec.name);
|
|
2012
|
+
mDNS_Deregister(m, &m->DeviceInfo);
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
// If DeviceInfo record is not currently registered, see if we need to register it
|
|
2016
|
+
if (m->DeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
|
|
2017
|
+
if (num_autoname > 0)
|
|
2018
|
+
{
|
|
2019
|
+
mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
|
|
2020
|
+
mDNS_SetupResourceRecord(&m->DeviceInfo, mDNSNULL, mDNSNULL, kDNSType_TXT, kStandardTTL, kDNSRecordTypeAdvisory, AuthRecordAny, mDNSNULL, mDNSNULL);
|
|
2021
|
+
ConstructServiceName(&m->DeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &localdomain);
|
|
2022
|
+
mDNSPlatformMemCopy(m->DeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
|
|
2023
|
+
mDNSPlatformMemCopy(m->DeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
|
|
2024
|
+
m->DeviceInfo.resrec.rdata->u.data[0] = 6 + len; // "model=" plus the device string
|
|
2025
|
+
m->DeviceInfo.resrec.rdlength = 7 + len; // One extra for the length byte at the start of the string
|
|
2026
|
+
LogOperation("UpdateDeviceInfoRecord Register %##s", m->DeviceInfo.resrec.name);
|
|
2027
|
+
mDNS_Register(m, &m->DeviceInfo);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
mDNSexport void udsserver_handle_configchange(mDNS *const m)
|
|
2032
|
+
{
|
|
2033
|
+
request_state *req;
|
|
2034
|
+
service_instance *ptr;
|
|
2035
|
+
DNameListElem *RegDomains = NULL;
|
|
2036
|
+
DNameListElem *BrowseDomains = NULL;
|
|
2037
|
+
DNameListElem *p;
|
|
2038
|
+
|
|
2039
|
+
UpdateDeviceInfoRecord(m);
|
|
2040
|
+
|
|
2041
|
+
// For autoname services, see if the default service name has changed, necessitating an automatic update
|
|
2042
|
+
for (req = all_requests; req; req = req->next)
|
|
2043
|
+
if (req->terminate == regservice_termination_callback)
|
|
2044
|
+
if (req->u.servicereg.autoname && !SameDomainLabelCS(req->u.servicereg.name.c, m->nicelabel.c))
|
|
2045
|
+
{
|
|
2046
|
+
req->u.servicereg.name = m->nicelabel;
|
|
2047
|
+
for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
|
|
2048
|
+
{
|
|
2049
|
+
ptr->renameonmemfree = 1;
|
|
2050
|
+
if (ptr->clientnotified) SendServiceRemovalNotification(&ptr->srs);
|
|
2051
|
+
LogInfo("udsserver_handle_configchange: Calling deregister for Service %##s", ptr->srs.RR_PTR.resrec.name->c);
|
|
2052
|
+
if (mDNS_DeregisterService_drt(m, &ptr->srs, mDNS_Dereg_rapid))
|
|
2053
|
+
regservice_callback(m, &ptr->srs, mStatus_MemFree); // If service deregistered already, we can re-register immediately
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
// Let the platform layer get the current DNS information
|
|
2058
|
+
mDNS_Lock(m);
|
|
2059
|
+
mDNSPlatformSetDNSConfig(m, mDNSfalse, mDNSfalse, mDNSNULL, &RegDomains, &BrowseDomains);
|
|
2060
|
+
mDNS_Unlock(m);
|
|
2061
|
+
|
|
2062
|
+
// Any automatic registration domains are also implicitly automatic browsing domains
|
|
2063
|
+
if (RegDomains) SetPrefsBrowseDomains(m, RegDomains, mDNStrue); // Add the new list first
|
|
2064
|
+
if (AutoRegistrationDomains) SetPrefsBrowseDomains(m, AutoRegistrationDomains, mDNSfalse); // Then clear the old list
|
|
2065
|
+
|
|
2066
|
+
// Add any new domains not already in our AutoRegistrationDomains list
|
|
2067
|
+
for (p=RegDomains; p; p=p->next)
|
|
2068
|
+
{
|
|
2069
|
+
DNameListElem **pp = &AutoRegistrationDomains;
|
|
2070
|
+
while (*pp && ((*pp)->uid != p->uid || !SameDomainName(&(*pp)->name, &p->name))) pp = &(*pp)->next;
|
|
2071
|
+
if (!*pp) // If not found in our existing list, this is a new default registration domain
|
|
2072
|
+
{
|
|
2073
|
+
RegisterLocalOnlyDomainEnumPTR(m, &p->name, mDNS_DomainTypeRegistration);
|
|
2074
|
+
udsserver_default_reg_domain_changed(p, mDNStrue);
|
|
2075
|
+
}
|
|
2076
|
+
else // else found same domainname in both old and new lists, so no change, just delete old copy
|
|
2077
|
+
{
|
|
2078
|
+
DNameListElem *del = *pp;
|
|
2079
|
+
*pp = (*pp)->next;
|
|
2080
|
+
mDNSPlatformMemFree(del);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
// Delete any domains in our old AutoRegistrationDomains list that are now gone
|
|
2085
|
+
while (AutoRegistrationDomains)
|
|
2086
|
+
{
|
|
2087
|
+
DNameListElem *del = AutoRegistrationDomains;
|
|
2088
|
+
AutoRegistrationDomains = AutoRegistrationDomains->next; // Cut record from list FIRST,
|
|
2089
|
+
DeregisterLocalOnlyDomainEnumPTR(m, &del->name, mDNS_DomainTypeRegistration);
|
|
2090
|
+
udsserver_default_reg_domain_changed(del, mDNSfalse); // before calling udsserver_default_reg_domain_changed()
|
|
2091
|
+
mDNSPlatformMemFree(del);
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
// Now we have our new updated automatic registration domain list
|
|
2095
|
+
AutoRegistrationDomains = RegDomains;
|
|
2096
|
+
|
|
2097
|
+
// Add new browse domains to internal list
|
|
2098
|
+
if (BrowseDomains) SetPrefsBrowseDomains(m, BrowseDomains, mDNStrue);
|
|
2099
|
+
|
|
2100
|
+
// Remove old browse domains from internal list
|
|
2101
|
+
if (SCPrefBrowseDomains)
|
|
2102
|
+
{
|
|
2103
|
+
SetPrefsBrowseDomains(m, SCPrefBrowseDomains, mDNSfalse);
|
|
2104
|
+
while (SCPrefBrowseDomains)
|
|
2105
|
+
{
|
|
2106
|
+
DNameListElem *fptr = SCPrefBrowseDomains;
|
|
2107
|
+
SCPrefBrowseDomains = SCPrefBrowseDomains->next;
|
|
2108
|
+
mDNSPlatformMemFree(fptr);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
// Replace the old browse domains array with the new array
|
|
2113
|
+
SCPrefBrowseDomains = BrowseDomains;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
mDNSlocal void AutomaticBrowseDomainChange(mDNS *const m, DNSQuestion *q, const ResourceRecord *const answer, QC_result AddRecord)
|
|
2117
|
+
{
|
|
2118
|
+
(void)m; // unused;
|
|
2119
|
+
(void)q; // unused
|
|
2120
|
+
|
|
2121
|
+
LogOperation("AutomaticBrowseDomainChange: %s automatic browse domain %##s",
|
|
2122
|
+
AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
|
|
2123
|
+
|
|
2124
|
+
if (AddRecord) AddAutoBrowseDomain(0, &answer->rdata->u.name);
|
|
2125
|
+
else RmvAutoBrowseDomain(0, &answer->rdata->u.name);
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
mDNSlocal mStatus handle_sethost_request(request_state *request)
|
|
2129
|
+
{
|
|
2130
|
+
get_flags(&request->msgptr, request->msgend);
|
|
2131
|
+
char hostName[MAX_DOMAIN_LABEL];
|
|
2132
|
+
int len = 0;
|
|
2133
|
+
if (get_string(&request->msgptr, request->msgend, hostName,
|
|
2134
|
+
MAX_DOMAIN_LABEL) < 0) return (mStatus_BadParamErr);
|
|
2135
|
+
LogOperation("%3d: DNSSetHostname(%X, %d, nonstr ) START",
|
|
2136
|
+
request->sd, request->flags);
|
|
2137
|
+
// if we start using this as a callback for notification when the
|
|
2138
|
+
// hostname changes we may need to cleanup from it
|
|
2139
|
+
// request->terminate = sethost_termination_callback;
|
|
2140
|
+
if(hostName[0] == 0) return mStatus_BadParamErr;
|
|
2141
|
+
while (len < MAX_DOMAIN_LABEL && hostName[len+1]
|
|
2142
|
+
&& hostName[len+1] != '.') len++;
|
|
2143
|
+
strncpy(&(mDNSStorage.nicelabel.c[1]), hostName, len);
|
|
2144
|
+
mDNSStorage.nicelabel.c[0] = len;
|
|
2145
|
+
strncpy(&(mDNSStorage.hostlabel.c[1]), hostName, len);
|
|
2146
|
+
mDNSStorage.hostlabel.c[0] = len;
|
|
2147
|
+
mDNS_SetFQDN(&mDNSStorage);
|
|
2148
|
+
return mStatus_NoError;
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
mDNSlocal mStatus handle_browse_request(request_state *request)
|
|
2152
|
+
{
|
|
2153
|
+
char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
|
|
2154
|
+
domainname typedn, d, temp;
|
|
2155
|
+
mDNSs32 NumSubTypes;
|
|
2156
|
+
mStatus err = mStatus_NoError;
|
|
2157
|
+
|
|
2158
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
2159
|
+
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
|
|
2160
|
+
mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
|
|
2161
|
+
if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
|
|
2162
|
+
|
|
2163
|
+
if (get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
|
|
2164
|
+
get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0) return(mStatus_BadParamErr);
|
|
2165
|
+
|
|
2166
|
+
if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
2167
|
+
|
|
2168
|
+
if (domain[0] == '\0') uDNS_SetupSearchDomains(&mDNSStorage, UDNS_START_WAB_QUERY);
|
|
2169
|
+
|
|
2170
|
+
request->flags = flags;
|
|
2171
|
+
typedn.c[0] = 0;
|
|
2172
|
+
NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
|
|
2173
|
+
if (NumSubTypes < 0 || NumSubTypes > 1) return(mStatus_BadParamErr);
|
|
2174
|
+
if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1)) return(mStatus_BadParamErr);
|
|
2175
|
+
|
|
2176
|
+
if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) return(mStatus_BadParamErr);
|
|
2177
|
+
|
|
2178
|
+
if (!MakeDomainNameFromDNSNameString(&temp, regtype)) return(mStatus_BadParamErr);
|
|
2179
|
+
// For over-long service types, we only allow domain "local"
|
|
2180
|
+
if (temp.c[0] > 15 && domain[0] == 0) mDNSPlatformStrLCopy(domain, "local.", sizeof(domain));
|
|
2181
|
+
|
|
2182
|
+
// Set up browser info
|
|
2183
|
+
request->u.browser.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
|
|
2184
|
+
request->u.browser.interface_id = InterfaceID;
|
|
2185
|
+
AssignDomainName(&request->u.browser.regtype, &typedn);
|
|
2186
|
+
request->u.browser.default_domain = !domain[0];
|
|
2187
|
+
request->u.browser.browsers = NULL;
|
|
2188
|
+
|
|
2189
|
+
LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\", \"%s\") START",
|
|
2190
|
+
request->sd, request->flags, interfaceIndex, request->u.browser.regtype.c, domain);
|
|
2191
|
+
|
|
2192
|
+
// We need to unconditionally set request->terminate, because even if we didn't successfully
|
|
2193
|
+
// start any browses right now, subsequent configuration changes may cause successful
|
|
2194
|
+
// browses to be added, and we'll need to cancel them before freeing this memory.
|
|
2195
|
+
request->terminate = browse_termination_callback;
|
|
2196
|
+
|
|
2197
|
+
if (domain[0])
|
|
2198
|
+
{
|
|
2199
|
+
if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
|
|
2200
|
+
err = add_domain_to_browser(request, &d);
|
|
2201
|
+
#if 0
|
|
2202
|
+
err = AuthorizedDomain(request, &d, AutoBrowseDomains) ? add_domain_to_browser(request, &d) : mStatus_NoError;
|
|
2203
|
+
#endif
|
|
2204
|
+
}
|
|
2205
|
+
else
|
|
2206
|
+
{
|
|
2207
|
+
DNameListElem *sdom;
|
|
2208
|
+
for (sdom = AutoBrowseDomains; sdom; sdom = sdom->next)
|
|
2209
|
+
if (!sdom->uid || SystemUID(request->uid) || request->uid == sdom->uid)
|
|
2210
|
+
{
|
|
2211
|
+
err = add_domain_to_browser(request, &sdom->name);
|
|
2212
|
+
if (err)
|
|
2213
|
+
{
|
|
2214
|
+
if (SameDomainName(&sdom->name, &localdomain)) break;
|
|
2215
|
+
else err = mStatus_NoError; // suppress errors for non-local "default" domains
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
return(err);
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
// ***************************************************************************
|
|
2224
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
2225
|
+
#pragma mark -
|
|
2226
|
+
#pragma mark - DNSServiceResolve
|
|
2227
|
+
#endif
|
|
2228
|
+
|
|
2229
|
+
mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
|
|
2230
|
+
{
|
|
2231
|
+
size_t len = 0;
|
|
2232
|
+
char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
|
|
2233
|
+
char *data;
|
|
2234
|
+
reply_state *rep;
|
|
2235
|
+
request_state *req = question->QuestionContext;
|
|
2236
|
+
(void)m; // Unused
|
|
2237
|
+
|
|
2238
|
+
LogOperation("%3d: DNSServiceResolve(%##s) %s %s", req->sd, question->qname.c, AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
|
|
2239
|
+
|
|
2240
|
+
if (!AddRecord)
|
|
2241
|
+
{
|
|
2242
|
+
if (req->u.resolve.srv == answer) req->u.resolve.srv = mDNSNULL;
|
|
2243
|
+
if (req->u.resolve.txt == answer) req->u.resolve.txt = mDNSNULL;
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
if (answer->rrtype == kDNSType_SRV) req->u.resolve.srv = answer;
|
|
2248
|
+
if (answer->rrtype == kDNSType_TXT) req->u.resolve.txt = answer;
|
|
2249
|
+
|
|
2250
|
+
if (!req->u.resolve.txt || !req->u.resolve.srv) return; // only deliver result to client if we have both answers
|
|
2251
|
+
|
|
2252
|
+
ConvertDomainNameToCString(answer->name, fullname);
|
|
2253
|
+
ConvertDomainNameToCString(&req->u.resolve.srv->rdata->u.srv.target, target);
|
|
2254
|
+
|
|
2255
|
+
// calculate reply length
|
|
2256
|
+
len += sizeof(DNSServiceFlags);
|
|
2257
|
+
len += sizeof(mDNSu32); // interface index
|
|
2258
|
+
len += sizeof(DNSServiceErrorType);
|
|
2259
|
+
len += strlen(fullname) + 1;
|
|
2260
|
+
len += strlen(target) + 1;
|
|
2261
|
+
len += 2 * sizeof(mDNSu16); // port, txtLen
|
|
2262
|
+
len += req->u.resolve.txt->rdlength;
|
|
2263
|
+
|
|
2264
|
+
// allocate/init reply header
|
|
2265
|
+
rep = create_reply(resolve_reply_op, len, req);
|
|
2266
|
+
rep->rhdr->flags = dnssd_htonl(0);
|
|
2267
|
+
rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse));
|
|
2268
|
+
rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
|
|
2269
|
+
|
|
2270
|
+
data = (char *)&rep->rhdr[1];
|
|
2271
|
+
|
|
2272
|
+
// write reply data to message
|
|
2273
|
+
put_string(fullname, &data);
|
|
2274
|
+
put_string(target, &data);
|
|
2275
|
+
*data++ = req->u.resolve.srv->rdata->u.srv.port.b[0];
|
|
2276
|
+
*data++ = req->u.resolve.srv->rdata->u.srv.port.b[1];
|
|
2277
|
+
put_uint16(req->u.resolve.txt->rdlength, &data);
|
|
2278
|
+
put_rdata (req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
|
|
2279
|
+
|
|
2280
|
+
LogOperation("%3d: DNSServiceResolve(%s) RESULT %s:%d", req->sd, fullname, target, mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
|
|
2281
|
+
append_reply(req, rep);
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
mDNSlocal void resolve_termination_callback(request_state *request)
|
|
2285
|
+
{
|
|
2286
|
+
LogOperation("%3d: DNSServiceResolve(%##s) STOP", request->sd, request->u.resolve.qtxt.qname.c);
|
|
2287
|
+
mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
|
|
2288
|
+
mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
|
|
2289
|
+
if (request->u.resolve.external_advertise) external_stop_resolving_service(&request->u.resolve.qsrv.qname);
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
mDNSlocal mStatus handle_resolve_request(request_state *request)
|
|
2293
|
+
{
|
|
2294
|
+
char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
|
|
2295
|
+
domainname fqdn;
|
|
2296
|
+
mStatus err;
|
|
2297
|
+
|
|
2298
|
+
// extract the data from the message
|
|
2299
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
2300
|
+
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
|
|
2301
|
+
mDNSInterfaceID InterfaceID;
|
|
2302
|
+
mDNSBool wasP2P = (interfaceIndex == kDNSServiceInterfaceIndexP2P);
|
|
2303
|
+
|
|
2304
|
+
|
|
2305
|
+
request->flags = flags;
|
|
2306
|
+
if (wasP2P) interfaceIndex = kDNSServiceInterfaceIndexAny;
|
|
2307
|
+
|
|
2308
|
+
InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
|
|
2309
|
+
if (interfaceIndex && !InterfaceID)
|
|
2310
|
+
{ LogMsg("ERROR: handle_resolve_request bad interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
|
|
2311
|
+
|
|
2312
|
+
if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
|
|
2313
|
+
get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
|
|
2314
|
+
get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
|
|
2315
|
+
{ LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
|
|
2316
|
+
|
|
2317
|
+
if (!request->msgptr) { LogMsg("%3d: DNSServiceResolve(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
2318
|
+
|
|
2319
|
+
if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
|
|
2320
|
+
{ LogMsg("ERROR: handle_resolve_request bad “%s” “%s” “%s”", name, regtype, domain); return(mStatus_BadParamErr); }
|
|
2321
|
+
|
|
2322
|
+
mDNSPlatformMemZero(&request->u.resolve, sizeof(request->u.resolve));
|
|
2323
|
+
|
|
2324
|
+
// format questions
|
|
2325
|
+
request->u.resolve.qsrv.InterfaceID = InterfaceID;
|
|
2326
|
+
request->u.resolve.qsrv.Target = zeroAddr;
|
|
2327
|
+
AssignDomainName(&request->u.resolve.qsrv.qname, &fqdn);
|
|
2328
|
+
request->u.resolve.qsrv.qtype = kDNSType_SRV;
|
|
2329
|
+
request->u.resolve.qsrv.qclass = kDNSClass_IN;
|
|
2330
|
+
request->u.resolve.qsrv.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
|
|
2331
|
+
request->u.resolve.qsrv.ExpectUnique = mDNStrue;
|
|
2332
|
+
request->u.resolve.qsrv.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
|
|
2333
|
+
request->u.resolve.qsrv.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
|
|
2334
|
+
request->u.resolve.qsrv.SuppressUnusable = mDNSfalse;
|
|
2335
|
+
request->u.resolve.qsrv.SearchListIndex = 0;
|
|
2336
|
+
request->u.resolve.qsrv.AppendSearchDomains = 0;
|
|
2337
|
+
request->u.resolve.qsrv.RetryWithSearchDomains = mDNSfalse;
|
|
2338
|
+
request->u.resolve.qsrv.TimeoutQuestion = 0;
|
|
2339
|
+
request->u.resolve.qsrv.WakeOnResolve = (flags & kDNSServiceFlagsWakeOnResolve) != 0;
|
|
2340
|
+
request->u.resolve.qsrv.qnameOrig = mDNSNULL;
|
|
2341
|
+
request->u.resolve.qsrv.QuestionCallback = resolve_result_callback;
|
|
2342
|
+
request->u.resolve.qsrv.QuestionContext = request;
|
|
2343
|
+
|
|
2344
|
+
request->u.resolve.qtxt.InterfaceID = InterfaceID;
|
|
2345
|
+
request->u.resolve.qtxt.Target = zeroAddr;
|
|
2346
|
+
AssignDomainName(&request->u.resolve.qtxt.qname, &fqdn);
|
|
2347
|
+
request->u.resolve.qtxt.qtype = kDNSType_TXT;
|
|
2348
|
+
request->u.resolve.qtxt.qclass = kDNSClass_IN;
|
|
2349
|
+
request->u.resolve.qtxt.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
|
|
2350
|
+
request->u.resolve.qtxt.ExpectUnique = mDNStrue;
|
|
2351
|
+
request->u.resolve.qtxt.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
|
|
2352
|
+
request->u.resolve.qtxt.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
|
|
2353
|
+
request->u.resolve.qtxt.SuppressUnusable = mDNSfalse;
|
|
2354
|
+
request->u.resolve.qtxt.SearchListIndex = 0;
|
|
2355
|
+
request->u.resolve.qtxt.AppendSearchDomains = 0;
|
|
2356
|
+
request->u.resolve.qtxt.RetryWithSearchDomains = mDNSfalse;
|
|
2357
|
+
request->u.resolve.qtxt.TimeoutQuestion = 0;
|
|
2358
|
+
request->u.resolve.qtxt.WakeOnResolve = 0;
|
|
2359
|
+
request->u.resolve.qtxt.qnameOrig = mDNSNULL;
|
|
2360
|
+
request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
|
|
2361
|
+
request->u.resolve.qtxt.QuestionContext = request;
|
|
2362
|
+
|
|
2363
|
+
request->u.resolve.ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
|
|
2364
|
+
|
|
2365
|
+
request->u.resolve.external_advertise = mDNSfalse;
|
|
2366
|
+
|
|
2367
|
+
#if 0
|
|
2368
|
+
if (!AuthorizedDomain(request, &fqdn, AutoBrowseDomains)) return(mStatus_NoError);
|
|
2369
|
+
#endif
|
|
2370
|
+
|
|
2371
|
+
// ask the questions
|
|
2372
|
+
LogOperation("%3d: DNSServiceResolve(%##s) START", request->sd, request->u.resolve.qsrv.qname.c);
|
|
2373
|
+
err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
|
|
2374
|
+
if (!err)
|
|
2375
|
+
{
|
|
2376
|
+
err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
|
|
2377
|
+
if (err) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
|
|
2378
|
+
else
|
|
2379
|
+
{
|
|
2380
|
+
request->terminate = resolve_termination_callback;
|
|
2381
|
+
// If the user explicitly passed in P2P, we don't restrict the domain in which we resolve.
|
|
2382
|
+
if (wasP2P || (!InterfaceID && IsLocalDomain(&fqdn) && (request->flags & kDNSServiceFlagsIncludeP2P)))
|
|
2383
|
+
{
|
|
2384
|
+
request->u.resolve.external_advertise = mDNStrue;
|
|
2385
|
+
LogInfo("handle_resolve_request: calling external_start_resolving_service()");
|
|
2386
|
+
external_start_resolving_service(&fqdn);
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
return(err);
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
// ***************************************************************************
|
|
2395
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
2396
|
+
#pragma mark -
|
|
2397
|
+
#pragma mark - DNSServiceQueryRecord
|
|
2398
|
+
#endif
|
|
2399
|
+
|
|
2400
|
+
// mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
|
|
2401
|
+
// the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
|
|
2402
|
+
// to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
|
|
2403
|
+
// the mDNSCore operation if the client dies or closes its socket.
|
|
2404
|
+
|
|
2405
|
+
// Returns -1 to tell the caller that it should not try to reissue the query anymore
|
|
2406
|
+
// Returns 1 on successfully appending a search domain and the caller should reissue the new query
|
|
2407
|
+
// Returns 0 when there are no more search domains and the caller should reissue the query
|
|
2408
|
+
mDNSlocal int AppendNewSearchDomain(mDNS *const m, DNSQuestion *question)
|
|
2409
|
+
{
|
|
2410
|
+
domainname *sd;
|
|
2411
|
+
mStatus err;
|
|
2412
|
+
|
|
2413
|
+
// Sanity check: The caller already checks this. We use -1 to indicate that we have searched all
|
|
2414
|
+
// the domains and should try the single label query directly on the wire.
|
|
2415
|
+
if (question->SearchListIndex == -1)
|
|
2416
|
+
{
|
|
2417
|
+
LogMsg("AppendNewSearchDomain: question %##s (%s) SearchListIndex is -1", question->qname.c, DNSTypeName(question->qtype));
|
|
2418
|
+
return -1;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
if (!question->AppendSearchDomains)
|
|
2422
|
+
{
|
|
2423
|
+
LogMsg("AppendNewSearchDomain: question %##s (%s) AppendSearchDoamins is 0", question->qname.c, DNSTypeName(question->qtype));
|
|
2424
|
+
return -1;
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
// Save the original name, before we modify them below.
|
|
2428
|
+
if (!question->qnameOrig)
|
|
2429
|
+
{
|
|
2430
|
+
question->qnameOrig = mallocL("AppendNewSearchDomain", sizeof(domainname));
|
|
2431
|
+
if (!question->qnameOrig) { LogMsg("AppendNewSearchDomain: ERROR!! malloc failure"); return -1; }
|
|
2432
|
+
question->qnameOrig->c[0] = 0;
|
|
2433
|
+
AssignDomainName(question->qnameOrig, &question->qname);
|
|
2434
|
+
LogInfo("AppendSearchDomain: qnameOrig %##s", question->qnameOrig->c);
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
sd = uDNS_GetNextSearchDomain(m, question->InterfaceID, &question->SearchListIndex, !question->AppendLocalSearchDomains);
|
|
2438
|
+
// We use -1 to indicate that we have searched all the domains and should try the single label
|
|
2439
|
+
// query directly on the wire. uDNS_GetNextSearchDomain should never return a negative value
|
|
2440
|
+
if (question->SearchListIndex == -1)
|
|
2441
|
+
{
|
|
2442
|
+
LogMsg("AppendNewSearchDomain: ERROR!! uDNS_GetNextSearchDomain returned -1");
|
|
2443
|
+
return -1;
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
// Not a common case. Perhaps, we should try the next search domain if it exceeds ?
|
|
2447
|
+
if (sd && (DomainNameLength(question->qnameOrig) + DomainNameLength(sd)) > MAX_DOMAIN_NAME)
|
|
2448
|
+
{
|
|
2449
|
+
LogMsg("AppendNewSearchDomain: ERROR!! exceeding max domain length for %##s (%s) SearchDomain %##s length %d, Question name length %d", question->qnameOrig->c, DNSTypeName(question->qtype), sd->c, DomainNameLength(question->qnameOrig), DomainNameLength(sd));
|
|
2450
|
+
return -1;
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
// if there are no more search domains and we have already tried this question
|
|
2454
|
+
// without appending search domains, then we are done.
|
|
2455
|
+
if (!sd && !ApplySearchDomainsFirst(question))
|
|
2456
|
+
{
|
|
2457
|
+
LogInfo("AppnedNewSearchDomain: No more search domains for question with name %##s (%s), not trying anymore", question->qname.c, DNSTypeName(question->qtype));
|
|
2458
|
+
return -1;
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
// Stop the question before changing the name as negative cache entries could be pointing at this question.
|
|
2462
|
+
// Even if we don't change the question in the case of returning 0, the caller is going to restart the
|
|
2463
|
+
// question.
|
|
2464
|
+
err = mDNS_StopQuery(&mDNSStorage, question);
|
|
2465
|
+
if (err) { LogMsg("AppendNewSearchDomain: ERROR!! %##s %s mDNS_StopQuery: %d, while retrying with search domains", question->qname.c, DNSTypeName(question->qtype), (int)err); }
|
|
2466
|
+
|
|
2467
|
+
AssignDomainName(&question->qname, question->qnameOrig);
|
|
2468
|
+
if (sd)
|
|
2469
|
+
{
|
|
2470
|
+
AppendDomainName(&question->qname, sd);
|
|
2471
|
+
LogInfo("AppnedNewSearchDomain: Returning question with name %##s, SearchListIndex %d", question->qname.c, question->SearchListIndex);
|
|
2472
|
+
return 1;
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
// Try the question as single label
|
|
2476
|
+
LogInfo("AppnedNewSearchDomain: No more search domains for question with name %##s (%s), trying one last time", question->qname.c, DNSTypeName(question->qtype));
|
|
2477
|
+
return 0;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
#if APPLE_OSX_mDNSResponder
|
|
2481
|
+
|
|
2482
|
+
mDNSlocal mDNSBool DomainInSearchList(domainname *domain)
|
|
2483
|
+
{
|
|
2484
|
+
const SearchListElem *s;
|
|
2485
|
+
for (s=SearchList; s; s=s->next)
|
|
2486
|
+
if (SameDomainName(&s->domain, domain)) return mDNStrue;
|
|
2487
|
+
return mDNSfalse;
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
// Workaround for networks using Microsoft Active Directory using "local" as a private internal
|
|
2491
|
+
// top-level domain
|
|
2492
|
+
mDNSlocal mStatus SendAdditionalQuery(DNSQuestion *q, request_state *request, mStatus err)
|
|
2493
|
+
{
|
|
2494
|
+
extern domainname ActiveDirectoryPrimaryDomain;
|
|
2495
|
+
DNSQuestion **question2;
|
|
2496
|
+
#define VALID_MSAD_SRV_TRANSPORT(T) (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
|
|
2497
|
+
#define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
|
|
2498
|
+
|
|
2499
|
+
question2 = mDNSNULL;
|
|
2500
|
+
if (request->hdr.op == query_request)
|
|
2501
|
+
question2 = &request->u.queryrecord.q2;
|
|
2502
|
+
else if (request->hdr.op == addrinfo_request)
|
|
2503
|
+
{
|
|
2504
|
+
if (q->qtype == kDNSType_A)
|
|
2505
|
+
question2 = &request->u.addrinfo.q42;
|
|
2506
|
+
else if (q->qtype == kDNSType_AAAA)
|
|
2507
|
+
question2 = &request->u.addrinfo.q62;
|
|
2508
|
+
}
|
|
2509
|
+
if (!question2)
|
|
2510
|
+
{
|
|
2511
|
+
LogMsg("SendAdditionalQuery: question2 NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
|
|
2512
|
+
return mStatus_BadParamErr;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
// Sanity check: If we already sent an additonal query, we don't need to send one more.
|
|
2516
|
+
//
|
|
2517
|
+
// 1. When the application calls DNSServiceQueryRecord or DNSServiceGetAddrInfo with a .local name, this function
|
|
2518
|
+
// is called to see whether a unicast query should be sent or not.
|
|
2519
|
+
//
|
|
2520
|
+
// 2. As a result of appending search domains, the question may be end up with a .local suffix even though it
|
|
2521
|
+
// was not a .local name to start with. In that case, queryrecord_result_callback calls this function to
|
|
2522
|
+
// send the additional query.
|
|
2523
|
+
//
|
|
2524
|
+
// Thus, it should not be called more than once.
|
|
2525
|
+
if (*question2)
|
|
2526
|
+
{
|
|
2527
|
+
LogInfo("SendAdditionalQuery: question2 already sent for %##s (%s), no more q2", q->qname.c, DNSTypeName(q->qtype));
|
|
2528
|
+
return err;
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
if (!q->ForceMCast && SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
|
|
2532
|
+
if (q->qtype == kDNSType_A || q->qtype == kDNSType_AAAA || VALID_MSAD_SRV(q))
|
|
2533
|
+
{
|
|
2534
|
+
DNSQuestion *q2;
|
|
2535
|
+
int labels = CountLabels(&q->qname);
|
|
2536
|
+
q2 = mallocL("DNSQuestion", sizeof(DNSQuestion));
|
|
2537
|
+
if (!q2) FatalError("ERROR: SendAdditionalQuery malloc");
|
|
2538
|
+
*question2 = q2;
|
|
2539
|
+
*q2 = *q;
|
|
2540
|
+
q2->InterfaceID = mDNSInterface_Unicast;
|
|
2541
|
+
q2->ExpectUnique = mDNStrue;
|
|
2542
|
+
// If the query starts as a single label e.g., somehost, and we have search domains with .local,
|
|
2543
|
+
// queryrecord_result_callback calls this function when .local is appended to "somehost".
|
|
2544
|
+
// At that time, the name in "q" is pointing at somehost.local and its qnameOrig pointing at
|
|
2545
|
+
// "somehost". We need to copy that information so that when we retry with a different search
|
|
2546
|
+
// domain e.g., mycompany.local, we get "somehost.mycompany.local".
|
|
2547
|
+
if (q->qnameOrig)
|
|
2548
|
+
{
|
|
2549
|
+
(*question2)->qnameOrig = mallocL("SendAdditionalQuery", DomainNameLength(q->qnameOrig));
|
|
2550
|
+
if (!(*question2)->qnameOrig) { LogMsg("SendAdditionalQuery: ERROR!! malloc failure"); return mStatus_NoMemoryErr; }
|
|
2551
|
+
(*question2)->qnameOrig->c[0] = 0;
|
|
2552
|
+
AssignDomainName((*question2)->qnameOrig, q->qnameOrig);
|
|
2553
|
+
LogInfo("SendAdditionalQuery: qnameOrig %##s", (*question2)->qnameOrig->c);
|
|
2554
|
+
}
|
|
2555
|
+
// For names of the form "<one-or-more-labels>.bar.local." we always do a second unicast query in parallel.
|
|
2556
|
+
// For names of the form "<one-label>.local." it's less clear whether we should do a unicast query.
|
|
2557
|
+
// If the name being queried is exactly the same as the name in the DHCP "domain" option (e.g. the DHCP
|
|
2558
|
+
// "domain" is my-small-company.local, and the user types "my-small-company.local" into their web browser)
|
|
2559
|
+
// then that's a hint that it's worth doing a unicast query. Otherwise, we first check to see if the
|
|
2560
|
+
// site's DNS server claims there's an SOA record for "local", and if so, that's also a hint that queries
|
|
2561
|
+
// for names in the "local" domain will be safely answered privately before they hit the root name servers.
|
|
2562
|
+
// Note that in the "my-small-company.local" example above there will typically be an SOA record for
|
|
2563
|
+
// "my-small-company.local" but *not* for "local", which is why the "local SOA" check would fail in that case.
|
|
2564
|
+
// We need to check against both ActiveDirectoryPrimaryDomain and SearchList. If it matches against either
|
|
2565
|
+
// of those, we don't want do the SOA check for the local
|
|
2566
|
+
if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain) && !DomainInSearchList(&q->qname))
|
|
2567
|
+
{
|
|
2568
|
+
AssignDomainName(&q2->qname, &localdomain);
|
|
2569
|
+
q2->qtype = kDNSType_SOA;
|
|
2570
|
+
q2->LongLived = mDNSfalse;
|
|
2571
|
+
q2->ForceMCast = mDNSfalse;
|
|
2572
|
+
q2->ReturnIntermed = mDNStrue;
|
|
2573
|
+
// Don't append search domains for the .local SOA query
|
|
2574
|
+
q2->AppendSearchDomains = 0;
|
|
2575
|
+
q2->AppendLocalSearchDomains = 0;
|
|
2576
|
+
q2->RetryWithSearchDomains = mDNSfalse;
|
|
2577
|
+
q2->SearchListIndex = 0;
|
|
2578
|
+
q2->TimeoutQuestion = 0;
|
|
2579
|
+
}
|
|
2580
|
+
LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
|
|
2581
|
+
err = mDNS_StartQuery(&mDNSStorage, q2);
|
|
2582
|
+
if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
|
|
2583
|
+
}
|
|
2584
|
+
return(err);
|
|
2585
|
+
}
|
|
2586
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
2587
|
+
|
|
2588
|
+
// This function tries to append a search domain if valid and possible. If so, returns true.
|
|
2589
|
+
mDNSlocal mDNSBool RetryQuestionWithSearchDomains(mDNS *const m, DNSQuestion *question, request_state *req)
|
|
2590
|
+
{
|
|
2591
|
+
int result;
|
|
2592
|
+
// RetryWithSearchDomains tells the core to call us back so that we can retry with search domains if there is no
|
|
2593
|
+
// answer in the cache or /etc/hosts. In the first call back from the core, we clear RetryWithSearchDomains so
|
|
2594
|
+
// that we don't get called back repeatedly. If we got an answer from the cache or /etc/hosts, we don't touch
|
|
2595
|
+
// RetryWithSearchDomains which may or may not be set.
|
|
2596
|
+
//
|
|
2597
|
+
// If we get e.g., NXDOMAIN and the query is neither suppressed nor exhausted the domain search list and
|
|
2598
|
+
// is a valid question for appending search domains, retry by appending domains
|
|
2599
|
+
|
|
2600
|
+
if (!question->SuppressQuery && question->SearchListIndex != -1 && question->AppendSearchDomains)
|
|
2601
|
+
{
|
|
2602
|
+
question->RetryWithSearchDomains = 0;
|
|
2603
|
+
result = AppendNewSearchDomain(m, question);
|
|
2604
|
+
// As long as the result is either zero or 1, we retry the question. If we exahaust the search
|
|
2605
|
+
// domains (result is zero) we try the original query (as it was before appending the search
|
|
2606
|
+
// domains) as such on the wire as a last resort if we have not tried them before. For queries
|
|
2607
|
+
// with more than one label, we have already tried them before appending search domains and
|
|
2608
|
+
// hence don't retry again
|
|
2609
|
+
if (result != -1)
|
|
2610
|
+
{
|
|
2611
|
+
mStatus err;
|
|
2612
|
+
err = mDNS_StartQuery(m, question);
|
|
2613
|
+
if (!err)
|
|
2614
|
+
{
|
|
2615
|
+
LogOperation("%3d: RetryQuestionWithSearchDomains(%##s, %s), retrying after appending search domain", req->sd, question->qname.c, DNSTypeName(question->qtype));
|
|
2616
|
+
// If the result was zero, it meant that there are no search domains and we just retried the question
|
|
2617
|
+
// as a single label and we should not retry with search domains anymore.
|
|
2618
|
+
if (!result) question->SearchListIndex = -1;
|
|
2619
|
+
return mDNStrue;
|
|
2620
|
+
}
|
|
2621
|
+
else
|
|
2622
|
+
{
|
|
2623
|
+
LogMsg("%3d: ERROR: RetryQuestionWithSearchDomains %##s %s mDNS_StartQuery: %d, while retrying with search domains", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
|
|
2624
|
+
// We have already stopped the query and could not restart. Reset the appropriate pointers
|
|
2625
|
+
// so that we don't call stop again when the question terminates
|
|
2626
|
+
question->QuestionContext = mDNSNULL;
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
else
|
|
2631
|
+
{
|
|
2632
|
+
LogInfo("%3d: RetryQuestionWithSearchDomains: Not appending search domains - SuppressQuery %d, SearchListIndex %d, AppendSearchDomains %d", req->sd, question->SuppressQuery, question->SearchListIndex, question->AppendSearchDomains);
|
|
2633
|
+
}
|
|
2634
|
+
return mDNSfalse;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
|
|
2638
|
+
{
|
|
2639
|
+
char name[MAX_ESCAPED_DOMAIN_NAME];
|
|
2640
|
+
request_state *req = question->QuestionContext;
|
|
2641
|
+
reply_state *rep;
|
|
2642
|
+
char *data;
|
|
2643
|
+
size_t len;
|
|
2644
|
+
DNSServiceErrorType error = kDNSServiceErr_NoError;
|
|
2645
|
+
DNSQuestion *q = mDNSNULL;
|
|
2646
|
+
|
|
2647
|
+
#if APPLE_OSX_mDNSResponder
|
|
2648
|
+
{
|
|
2649
|
+
// Sanity check: QuestionContext is set to NULL after we stop the question and hence we should not
|
|
2650
|
+
// get any callbacks from the core after this.
|
|
2651
|
+
if (!req)
|
|
2652
|
+
{
|
|
2653
|
+
LogMsg("queryrecord_result_callback: ERROR!! QuestionContext NULL for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
|
|
2654
|
+
return;
|
|
2655
|
+
}
|
|
2656
|
+
if (req->hdr.op == query_request && question == req->u.queryrecord.q2)
|
|
2657
|
+
q = &req->u.queryrecord.q;
|
|
2658
|
+
else if (req->hdr.op == addrinfo_request && question == req->u.addrinfo.q42)
|
|
2659
|
+
q = &req->u.addrinfo.q4;
|
|
2660
|
+
else if (req->hdr.op == addrinfo_request && question == req->u.addrinfo.q62)
|
|
2661
|
+
q = &req->u.addrinfo.q6;
|
|
2662
|
+
|
|
2663
|
+
if (q && question->qtype != q->qtype && !SameDomainName(&question->qname, &q->qname))
|
|
2664
|
+
{
|
|
2665
|
+
mStatus err;
|
|
2666
|
+
domainname *orig = question->qnameOrig;
|
|
2667
|
+
|
|
2668
|
+
LogInfo("queryrecord_result_callback: Stopping q2 local %##s", question->qname.c);
|
|
2669
|
+
mDNS_StopQuery(m, question);
|
|
2670
|
+
question->QuestionContext = mDNSNULL;
|
|
2671
|
+
|
|
2672
|
+
// We got a negative response for the SOA record indicating that .local does not exist.
|
|
2673
|
+
// But we might have other search domains (that does not end in .local) that can be
|
|
2674
|
+
// appended to this question. In that case, we want to retry the question. Otherwise,
|
|
2675
|
+
// we don't want to try this question as unicast.
|
|
2676
|
+
if (answer->RecordType == kDNSRecordTypePacketNegative && !q->AppendSearchDomains)
|
|
2677
|
+
{
|
|
2678
|
+
LogInfo("queryrecord_result_callback: question %##s AppendSearchDomains zero", q->qname.c);
|
|
2679
|
+
return;
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
// If we got a non-negative answer for our "local SOA" test query, start an additional parallel unicast query
|
|
2683
|
+
//
|
|
2684
|
+
// Note: When we copy the original question, we copy everything including the AppendSearchDomains,
|
|
2685
|
+
// RetryWithSearchDomains except for qnameOrig which can be non-NULL if the original question is
|
|
2686
|
+
// e.g., somehost and then we appended e.g., ".local" and retried that question. See comment in
|
|
2687
|
+
// SendAdditionalQuery as to how qnameOrig gets initialized.
|
|
2688
|
+
*question = *q;
|
|
2689
|
+
question->InterfaceID = mDNSInterface_Unicast;
|
|
2690
|
+
question->ExpectUnique = mDNStrue;
|
|
2691
|
+
question->qnameOrig = orig;
|
|
2692
|
+
|
|
2693
|
+
LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast, context %p", req->sd, question->qname.c, DNSTypeName(question->qtype), question->QuestionContext);
|
|
2694
|
+
|
|
2695
|
+
// If the original question timed out, its QuestionContext would already be set to NULL and that's what we copied above.
|
|
2696
|
+
// Hence, we need to set it explicitly here.
|
|
2697
|
+
question->QuestionContext = req;
|
|
2698
|
+
err = mDNS_StartQuery(m, question);
|
|
2699
|
+
if (err) LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
|
|
2700
|
+
|
|
2701
|
+
// If we got a positive response to local SOA, then try the .local question as unicast
|
|
2702
|
+
if (answer->RecordType != kDNSRecordTypePacketNegative) return;
|
|
2703
|
+
|
|
2704
|
+
// Fall through and get the next search domain. The question is pointing at .local
|
|
2705
|
+
// and we don't want to try that. Try the next search domain. Don't try with local
|
|
2706
|
+
// search domains for the unicast question anymore.
|
|
2707
|
+
//
|
|
2708
|
+
// Note: we started the question above which will be stopped immediately (never sent on the wire)
|
|
2709
|
+
// before we pick the next search domain below. RetryQuestionWithSearchDomains assumes that the
|
|
2710
|
+
// question has already started.
|
|
2711
|
+
question->AppendLocalSearchDomains = 0;
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
if (q && AddRecord && (question->InterfaceID == mDNSInterface_Unicast) && !answer->rdlength)
|
|
2715
|
+
{
|
|
2716
|
+
// If we get a negative response to the unicast query that we sent above, retry after appending search domains
|
|
2717
|
+
// Note: We could have appended search domains below (where do it for regular unicast questions) instead of doing it here.
|
|
2718
|
+
// As we ignore negative unicast answers below, we would never reach the code where the search domains are appended.
|
|
2719
|
+
// To keep things simple, we handle unicast ".local" separately here.
|
|
2720
|
+
LogInfo("queryrecord_result_callback: Retrying .local question %##s (%s) as unicast after appending search domains", question->qname.c, DNSTypeName(question->qtype));
|
|
2721
|
+
if (RetryQuestionWithSearchDomains(m, question, req))
|
|
2722
|
+
return;
|
|
2723
|
+
if (question->AppendSearchDomains && !question->AppendLocalSearchDomains && IsLocalDomain(&question->qname))
|
|
2724
|
+
{
|
|
2725
|
+
// If "local" is the last search domain, we need to stop the question so that we don't send the "local"
|
|
2726
|
+
// question on the wire as we got a negative response for the local SOA. But, we can't stop the question
|
|
2727
|
+
// yet as we may have to timeout the question (done by the "core") for which we need to leave the question
|
|
2728
|
+
// in the list. We leave it disabled so that it does not hit the wire.
|
|
2729
|
+
LogInfo("queryrecord_result_callback: Disabling .local question %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
|
|
2730
|
+
question->ThisQInterval = 0;
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
// If we are here it means that either "question" is not "q2" OR we got a positive response for "q2" OR we have no more search
|
|
2734
|
+
// domains to append for "q2". In all cases, fall through and deliver the response
|
|
2735
|
+
}
|
|
2736
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
2737
|
+
|
|
2738
|
+
if (answer->RecordType == kDNSRecordTypePacketNegative)
|
|
2739
|
+
{
|
|
2740
|
+
// If this question needs to be timed out and we have reached the stop time, mark
|
|
2741
|
+
// the error as timeout. It is possible that we might get a negative response from an
|
|
2742
|
+
// external DNS server at the same time when this question reaches its stop time. We
|
|
2743
|
+
// can't tell the difference as there is no indication in the callback. This should
|
|
2744
|
+
// be okay as we will be timing out this query anyway.
|
|
2745
|
+
mDNS_Lock(m);
|
|
2746
|
+
if (question->TimeoutQuestion)
|
|
2747
|
+
{
|
|
2748
|
+
if ((m->timenow - question->StopTime) >= 0)
|
|
2749
|
+
{
|
|
2750
|
+
LogInfo("queryrecord_result_callback:Question %##s (%s) timing out, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
|
|
2751
|
+
error = kDNSServiceErr_Timeout;
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
mDNS_Unlock(m);
|
|
2755
|
+
// When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
|
|
2756
|
+
// Active Directory sites) we need to ignore negative unicast answers. Otherwise we'll generate negative
|
|
2757
|
+
// answers for just about every single multicast name we ever look up, since the Microsoft Active Directory
|
|
2758
|
+
// server is going to assert that pretty much every single multicast name doesn't exist.
|
|
2759
|
+
//
|
|
2760
|
+
// If we are timing out this query, we need to deliver the negative answer to the application
|
|
2761
|
+
if (error != kDNSServiceErr_Timeout)
|
|
2762
|
+
{
|
|
2763
|
+
if (!answer->InterfaceID && IsLocalDomain(answer->name))
|
|
2764
|
+
{
|
|
2765
|
+
LogInfo("queryrecord_result_callback:Question %##s (%s) answering local with unicast", question->qname.c, DNSTypeName(question->qtype));
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
error = kDNSServiceErr_NoSuchRecord;
|
|
2769
|
+
}
|
|
2770
|
+
AddRecord = mDNStrue;
|
|
2771
|
+
}
|
|
2772
|
+
// If we get a negative answer, try appending search domains. Don't append search domains
|
|
2773
|
+
// - if we are timing out this question
|
|
2774
|
+
// - if the negative response was received as a result of a multicast query
|
|
2775
|
+
// - if this is an additional query (q2), we already appended search domains above (indicated by "!q" below)
|
|
2776
|
+
if (error != kDNSServiceErr_Timeout)
|
|
2777
|
+
{
|
|
2778
|
+
if (!q && !answer->InterfaceID && !answer->rdlength && AddRecord)
|
|
2779
|
+
{
|
|
2780
|
+
// If the original question did not end in .local, we did not send an SOA query
|
|
2781
|
+
// to figure out whether we should send an additional unicast query or not. If we just
|
|
2782
|
+
// appended .local, we need to see if we need to send an additional query. This should
|
|
2783
|
+
// normally happen just once because after we append .local, we ignore all negative
|
|
2784
|
+
// responses for .local above.
|
|
2785
|
+
LogInfo("queryrecord_result_callback: Retrying question %##s (%s) after appending search domains", question->qname.c, DNSTypeName(question->qtype));
|
|
2786
|
+
if (RetryQuestionWithSearchDomains(m, question, req))
|
|
2787
|
+
{
|
|
2788
|
+
// Note: We need to call SendAdditionalQuery every time after appending a search domain as .local could
|
|
2789
|
+
// be anywhere in the search domain list.
|
|
2790
|
+
#if APPLE_OSX_mDNSResponder
|
|
2791
|
+
mStatus err = mStatus_NoError;
|
|
2792
|
+
err = SendAdditionalQuery(question, req, err);
|
|
2793
|
+
if (err) LogMsg("queryrecord_result_callback: Sending .local SOA query failed, after appending domains");
|
|
2794
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
2795
|
+
return;
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
ConvertDomainNameToCString(answer->name, name);
|
|
2801
|
+
|
|
2802
|
+
LogOperation("%3d: %s(%##s, %s) %s %s", req->sd,
|
|
2803
|
+
req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
|
|
2804
|
+
question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
|
|
2805
|
+
|
|
2806
|
+
len = sizeof(DNSServiceFlags); // calculate reply data length
|
|
2807
|
+
len += sizeof(mDNSu32); // interface index
|
|
2808
|
+
len += sizeof(DNSServiceErrorType);
|
|
2809
|
+
len += strlen(name) + 1;
|
|
2810
|
+
len += 3 * sizeof(mDNSu16); // type, class, rdlen
|
|
2811
|
+
len += answer->rdlength;
|
|
2812
|
+
len += sizeof(mDNSu32); // TTL
|
|
2813
|
+
|
|
2814
|
+
rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
|
|
2815
|
+
|
|
2816
|
+
rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
|
|
2817
|
+
// Call mDNSPlatformInterfaceIndexfromInterfaceID, but suppressNetworkChange (last argument). Otherwise, if the
|
|
2818
|
+
// InterfaceID is not valid, then it simulates a "NetworkChanged" which in turn makes questions
|
|
2819
|
+
// to be stopped and started including *this* one. Normally the InterfaceID is valid. But when we
|
|
2820
|
+
// are using the /etc/hosts entries to answer a question, the InterfaceID may not be known to the
|
|
2821
|
+
// mDNS core . Eventually, we should remove the calls to "NetworkChanged" in
|
|
2822
|
+
// mDNSPlatformInterfaceIndexfromInterfaceID when it can't find InterfaceID as ResourceRecords
|
|
2823
|
+
// should not have existed to answer this question if the corresponding interface is not valid.
|
|
2824
|
+
rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNStrue));
|
|
2825
|
+
rep->rhdr->error = dnssd_htonl(error);
|
|
2826
|
+
|
|
2827
|
+
data = (char *)&rep->rhdr[1];
|
|
2828
|
+
|
|
2829
|
+
put_string(name, &data);
|
|
2830
|
+
put_uint16(answer->rrtype, &data);
|
|
2831
|
+
put_uint16(answer->rrclass, &data);
|
|
2832
|
+
put_uint16(answer->rdlength, &data);
|
|
2833
|
+
// We need to use putRData here instead of the crude put_rdata function, because the crude put_rdata
|
|
2834
|
+
// function just does a blind memory copy without regard to structures that may have holes in them.
|
|
2835
|
+
if (answer->rdlength)
|
|
2836
|
+
if (!putRData(mDNSNULL, (mDNSu8 *)data, (mDNSu8 *)rep->rhdr + len, answer))
|
|
2837
|
+
LogMsg("queryrecord_result_callback putRData failed %d", (mDNSu8 *)rep->rhdr + len - (mDNSu8 *)data);
|
|
2838
|
+
data += answer->rdlength;
|
|
2839
|
+
put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
|
|
2840
|
+
|
|
2841
|
+
append_reply(req, rep);
|
|
2842
|
+
// Stop the question, if we just timed out
|
|
2843
|
+
if (error == kDNSServiceErr_Timeout)
|
|
2844
|
+
{
|
|
2845
|
+
mDNS_StopQuery(m, question);
|
|
2846
|
+
// Reset the pointers so that we don't call stop on termination
|
|
2847
|
+
question->QuestionContext = mDNSNULL;
|
|
2848
|
+
}
|
|
2849
|
+
#if APPLE_OSX_mDNSResponder
|
|
2850
|
+
#if ! NO_WCF
|
|
2851
|
+
CHECK_WCF_FUNCTION(WCFIsServerRunning)
|
|
2852
|
+
{
|
|
2853
|
+
struct xucred x;
|
|
2854
|
+
socklen_t xucredlen = sizeof(x);
|
|
2855
|
+
|
|
2856
|
+
if (WCFIsServerRunning((WCFConnection *)m->WCF) && answer->rdlength != 0)
|
|
2857
|
+
{
|
|
2858
|
+
if (getsockopt(req->sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 &&
|
|
2859
|
+
(x.cr_version == XUCRED_VERSION))
|
|
2860
|
+
{
|
|
2861
|
+
struct sockaddr_storage addr;
|
|
2862
|
+
const RDataBody2 *const rdb = (RDataBody2 *)answer->rdata->u.data;
|
|
2863
|
+
addr.ss_len = 0;
|
|
2864
|
+
if (answer->rrtype == kDNSType_A || answer->rrtype == kDNSType_AAAA)
|
|
2865
|
+
{
|
|
2866
|
+
if (answer->rrtype == kDNSType_A)
|
|
2867
|
+
{
|
|
2868
|
+
struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
|
|
2869
|
+
sin->sin_port = 0;
|
|
2870
|
+
if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(rdb->ipv4)), answer))
|
|
2871
|
+
LogMsg("queryrecord_result_callback: WCF AF_INET putRData failed");
|
|
2872
|
+
else
|
|
2873
|
+
{
|
|
2874
|
+
addr.ss_len = sizeof (struct sockaddr_in);
|
|
2875
|
+
addr.ss_family = AF_INET;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
else if (answer->rrtype == kDNSType_AAAA)
|
|
2879
|
+
{
|
|
2880
|
+
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
|
|
2881
|
+
sin6->sin6_port = 0;
|
|
2882
|
+
if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(rdb->ipv6)), answer))
|
|
2883
|
+
LogMsg("queryrecord_result_callback: WCF AF_INET6 putRData failed");
|
|
2884
|
+
else
|
|
2885
|
+
{
|
|
2886
|
+
addr.ss_len = sizeof (struct sockaddr_in6);
|
|
2887
|
+
addr.ss_family = AF_INET6;
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
if (addr.ss_len)
|
|
2891
|
+
{
|
|
2892
|
+
debugf("queryrecord_result_callback: Name %s, uid %u, addr length %d", name, x.cr_uid, addr.ss_len);
|
|
2893
|
+
CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
|
|
2894
|
+
{
|
|
2895
|
+
WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, x.cr_uid);
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
else if (answer->rrtype == kDNSType_CNAME)
|
|
2900
|
+
{
|
|
2901
|
+
domainname cname;
|
|
2902
|
+
char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
|
|
2903
|
+
if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), answer))
|
|
2904
|
+
LogMsg("queryrecord_result_callback: WCF CNAME putRData failed");
|
|
2905
|
+
else
|
|
2906
|
+
{
|
|
2907
|
+
ConvertDomainNameToCString(&cname, cname_cstr);
|
|
2908
|
+
CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
|
|
2909
|
+
{
|
|
2910
|
+
WCFNameResolvesToName(m->WCF, name, cname_cstr, x.cr_uid);
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
else my_perror("queryrecord_result_callback: ERROR: getsockopt LOCAL_PEERCRED");
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
#endif
|
|
2919
|
+
#endif
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
mDNSlocal void queryrecord_termination_callback(request_state *request)
|
|
2923
|
+
{
|
|
2924
|
+
LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP",
|
|
2925
|
+
request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype));
|
|
2926
|
+
if (request->u.queryrecord.q.QuestionContext)
|
|
2927
|
+
{
|
|
2928
|
+
mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q); // no need to error check
|
|
2929
|
+
request->u.queryrecord.q.QuestionContext = mDNSNULL;
|
|
2930
|
+
}
|
|
2931
|
+
else
|
|
2932
|
+
{
|
|
2933
|
+
DNSQuestion *question = &request->u.queryrecord.q;
|
|
2934
|
+
LogInfo("queryrecord_termination_callback: question %##s (%s) already stopped, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
if (request->u.queryrecord.q.qnameOrig)
|
|
2938
|
+
{
|
|
2939
|
+
freeL("QueryTermination", request->u.queryrecord.q.qnameOrig);
|
|
2940
|
+
request->u.queryrecord.q.qnameOrig = mDNSNULL;
|
|
2941
|
+
}
|
|
2942
|
+
if (request->u.queryrecord.q.InterfaceID == mDNSInterface_P2P || (!request->u.queryrecord.q.InterfaceID && SameDomainName((const domainname *)LastLabel(&request->u.queryrecord.q.qname), &localdomain) && (request->flags & kDNSServiceFlagsIncludeP2P)))
|
|
2943
|
+
{
|
|
2944
|
+
LogInfo("queryrecord_termination_callback: calling external_stop_browsing_for_service()");
|
|
2945
|
+
external_stop_browsing_for_service(&mDNSStorage, &request->u.queryrecord.q.qname, request->u.queryrecord.q.qtype);
|
|
2946
|
+
}
|
|
2947
|
+
if (request->u.queryrecord.q2)
|
|
2948
|
+
{
|
|
2949
|
+
if (request->u.queryrecord.q2->QuestionContext)
|
|
2950
|
+
{
|
|
2951
|
+
LogInfo("queryrecord_termination_callback: Stopping q2 %##s", request->u.queryrecord.q2->qname.c);
|
|
2952
|
+
mDNS_StopQuery(&mDNSStorage, request->u.queryrecord.q2);
|
|
2953
|
+
}
|
|
2954
|
+
else
|
|
2955
|
+
{
|
|
2956
|
+
DNSQuestion *question = request->u.queryrecord.q2;
|
|
2957
|
+
LogInfo("queryrecord_termination_callback: q2 %##s (%s) already stopped, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
|
|
2958
|
+
}
|
|
2959
|
+
if (request->u.queryrecord.q2->qnameOrig)
|
|
2960
|
+
{
|
|
2961
|
+
LogInfo("queryrecord_termination_callback: freeing q2 qnameOrig %##s", request->u.queryrecord.q2->qnameOrig->c);
|
|
2962
|
+
freeL("QueryTermination q2", request->u.queryrecord.q2->qnameOrig);
|
|
2963
|
+
request->u.queryrecord.q2->qnameOrig = mDNSNULL;
|
|
2964
|
+
}
|
|
2965
|
+
freeL("queryrecord Q2", request->u.queryrecord.q2);
|
|
2966
|
+
request->u.queryrecord.q2 = mDNSNULL;
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
mDNSlocal mStatus handle_queryrecord_request(request_state *request)
|
|
2971
|
+
{
|
|
2972
|
+
DNSQuestion *const q = &request->u.queryrecord.q;
|
|
2973
|
+
char name[256];
|
|
2974
|
+
mDNSu16 rrtype, rrclass;
|
|
2975
|
+
mStatus err;
|
|
2976
|
+
|
|
2977
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
2978
|
+
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
|
|
2979
|
+
mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
|
|
2980
|
+
if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
|
|
2981
|
+
|
|
2982
|
+
if (get_string(&request->msgptr, request->msgend, name, 256) < 0) return(mStatus_BadParamErr);
|
|
2983
|
+
rrtype = get_uint16(&request->msgptr, request->msgend);
|
|
2984
|
+
rrclass = get_uint16(&request->msgptr, request->msgend);
|
|
2985
|
+
|
|
2986
|
+
if (!request->msgptr)
|
|
2987
|
+
{ LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
2988
|
+
|
|
2989
|
+
request->flags = flags;
|
|
2990
|
+
mDNSPlatformMemZero(&request->u.queryrecord, sizeof(request->u.queryrecord));
|
|
2991
|
+
|
|
2992
|
+
q->InterfaceID = InterfaceID;
|
|
2993
|
+
q->Target = zeroAddr;
|
|
2994
|
+
if (!MakeDomainNameFromDNSNameString(&q->qname, name)) return(mStatus_BadParamErr);
|
|
2995
|
+
#if 0
|
|
2996
|
+
if (!AuthorizedDomain(request, &q->qname, AutoBrowseDomains)) return (mStatus_NoError);
|
|
2997
|
+
#endif
|
|
2998
|
+
q->qtype = rrtype;
|
|
2999
|
+
q->qclass = rrclass;
|
|
3000
|
+
q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
|
|
3001
|
+
q->ExpectUnique = mDNSfalse;
|
|
3002
|
+
q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
|
|
3003
|
+
q->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
|
|
3004
|
+
q->SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0;
|
|
3005
|
+
q->TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0;
|
|
3006
|
+
q->WakeOnResolve = 0;
|
|
3007
|
+
q->QuestionCallback = queryrecord_result_callback;
|
|
3008
|
+
q->QuestionContext = request;
|
|
3009
|
+
q->SearchListIndex = 0;
|
|
3010
|
+
|
|
3011
|
+
// Don't append search domains for fully qualified domain names including queries
|
|
3012
|
+
// such as e.g., "abc." that has only one label. We convert all names to FQDNs as internally
|
|
3013
|
+
// we only deal with FQDNs. Hence, we cannot look at qname to figure out whether we should
|
|
3014
|
+
// append search domains or not. So, we record that information in AppendSearchDomains.
|
|
3015
|
+
//
|
|
3016
|
+
// We append search domains only for queries that are a single label. If overriden using
|
|
3017
|
+
// command line argument "AlwaysAppendSearchDomains", then we do it for any query which
|
|
3018
|
+
// is not fully qualified.
|
|
3019
|
+
|
|
3020
|
+
if ((rrtype == kDNSType_A || rrtype == kDNSType_AAAA) && name[strlen(name) - 1] != '.' &&
|
|
3021
|
+
(AlwaysAppendSearchDomains || CountLabels(&q->qname) == 1))
|
|
3022
|
+
{
|
|
3023
|
+
q->AppendSearchDomains = 1;
|
|
3024
|
+
q->AppendLocalSearchDomains = 1;
|
|
3025
|
+
}
|
|
3026
|
+
else
|
|
3027
|
+
{
|
|
3028
|
+
q->AppendSearchDomains = 0;
|
|
3029
|
+
q->AppendLocalSearchDomains = 0;
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
// For single label queries that are not fully qualified, look at /etc/hosts, cache and try
|
|
3033
|
+
// search domains before trying them on the wire as a single label query. RetryWithSearchDomains
|
|
3034
|
+
// tell the core to call back into the UDS layer if there is no valid response in /etc/hosts or
|
|
3035
|
+
// the cache
|
|
3036
|
+
q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0;
|
|
3037
|
+
q->qnameOrig = mDNSNULL;
|
|
3038
|
+
|
|
3039
|
+
LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) START", request->sd, flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype));
|
|
3040
|
+
err = mDNS_StartQuery(&mDNSStorage, q);
|
|
3041
|
+
if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q->qname.c, DNSTypeName(q->qtype), (int)err);
|
|
3042
|
+
else
|
|
3043
|
+
{
|
|
3044
|
+
request->terminate = queryrecord_termination_callback;
|
|
3045
|
+
if (q->InterfaceID == mDNSInterface_P2P || (!q->InterfaceID && SameDomainName((const domainname *)LastLabel(&q->qname), &localdomain) && (flags & kDNSServiceFlagsIncludeP2P)))
|
|
3046
|
+
{
|
|
3047
|
+
LogInfo("handle_queryrecord_request: calling external_start_browsing_for_service()");
|
|
3048
|
+
external_start_browsing_for_service(&mDNSStorage, &q->qname, q->qtype);
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
#if APPLE_OSX_mDNSResponder
|
|
3053
|
+
err = SendAdditionalQuery(q, request, err);
|
|
3054
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
3055
|
+
|
|
3056
|
+
return(err);
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3059
|
+
// ***************************************************************************
|
|
3060
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
3061
|
+
#pragma mark -
|
|
3062
|
+
#pragma mark - DNSServiceEnumerateDomains
|
|
3063
|
+
#endif
|
|
3064
|
+
|
|
3065
|
+
mDNSlocal reply_state *format_enumeration_reply(request_state *request,
|
|
3066
|
+
const char *domain, DNSServiceFlags flags, mDNSu32 ifi, DNSServiceErrorType err)
|
|
3067
|
+
{
|
|
3068
|
+
size_t len;
|
|
3069
|
+
reply_state *reply;
|
|
3070
|
+
char *data;
|
|
3071
|
+
|
|
3072
|
+
len = sizeof(DNSServiceFlags);
|
|
3073
|
+
len += sizeof(mDNSu32);
|
|
3074
|
+
len += sizeof(DNSServiceErrorType);
|
|
3075
|
+
len += strlen(domain) + 1;
|
|
3076
|
+
|
|
3077
|
+
reply = create_reply(enumeration_reply_op, len, request);
|
|
3078
|
+
reply->rhdr->flags = dnssd_htonl(flags);
|
|
3079
|
+
reply->rhdr->ifi = dnssd_htonl(ifi);
|
|
3080
|
+
reply->rhdr->error = dnssd_htonl(err);
|
|
3081
|
+
data = (char *)&reply->rhdr[1];
|
|
3082
|
+
put_string(domain, &data);
|
|
3083
|
+
return reply;
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3086
|
+
mDNSlocal void enum_termination_callback(request_state *request)
|
|
3087
|
+
{
|
|
3088
|
+
mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
|
|
3089
|
+
mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_default);
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
mDNSlocal void enum_result_callback(mDNS *const m,
|
|
3093
|
+
DNSQuestion *const question, const ResourceRecord *const answer, QC_result AddRecord)
|
|
3094
|
+
{
|
|
3095
|
+
char domain[MAX_ESCAPED_DOMAIN_NAME];
|
|
3096
|
+
request_state *request = question->QuestionContext;
|
|
3097
|
+
DNSServiceFlags flags = 0;
|
|
3098
|
+
reply_state *reply;
|
|
3099
|
+
(void)m; // Unused
|
|
3100
|
+
|
|
3101
|
+
if (answer->rrtype != kDNSType_PTR) return;
|
|
3102
|
+
|
|
3103
|
+
#if 0
|
|
3104
|
+
if (!AuthorizedDomain(request, &answer->rdata->u.name, request->u.enumeration.flags ? AutoRegistrationDomains : AutoBrowseDomains)) return;
|
|
3105
|
+
#endif
|
|
3106
|
+
|
|
3107
|
+
// We only return add/remove events for the browse and registration lists
|
|
3108
|
+
// For the default browse and registration answers, we only give an "ADD" event
|
|
3109
|
+
if (question == &request->u.enumeration.q_default && !AddRecord) return;
|
|
3110
|
+
|
|
3111
|
+
if (AddRecord)
|
|
3112
|
+
{
|
|
3113
|
+
flags |= kDNSServiceFlagsAdd;
|
|
3114
|
+
if (question == &request->u.enumeration.q_default) flags |= kDNSServiceFlagsDefault;
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
ConvertDomainNameToCString(&answer->rdata->u.name, domain);
|
|
3118
|
+
// Note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
|
|
3119
|
+
// a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
|
|
3120
|
+
// network, so we just pass kDNSServiceInterfaceIndexAny
|
|
3121
|
+
reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
|
|
3122
|
+
if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; }
|
|
3123
|
+
|
|
3124
|
+
LogOperation("%3d: DNSServiceEnumerateDomains(%#2s) RESULT %s: %s", request->sd, question->qname.c, AddRecord ? "Add" : "Rmv", domain);
|
|
3125
|
+
|
|
3126
|
+
append_reply(request, reply);
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
mDNSlocal mStatus handle_enum_request(request_state *request)
|
|
3130
|
+
{
|
|
3131
|
+
mStatus err;
|
|
3132
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
3133
|
+
DNSServiceFlags reg = flags & kDNSServiceFlagsRegistrationDomains;
|
|
3134
|
+
mDNS_DomainType t_all = reg ? mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
|
|
3135
|
+
mDNS_DomainType t_default = reg ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
|
|
3136
|
+
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
|
|
3137
|
+
mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
|
|
3138
|
+
if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
|
|
3139
|
+
|
|
3140
|
+
if (!request->msgptr)
|
|
3141
|
+
{ LogMsg("%3d: DNSServiceEnumerateDomains(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
3142
|
+
|
|
3143
|
+
// allocate context structures
|
|
3144
|
+
uDNS_SetupSearchDomains(&mDNSStorage, UDNS_START_WAB_QUERY);
|
|
3145
|
+
|
|
3146
|
+
#if 0
|
|
3147
|
+
// mark which kind of enumeration we're doing so we can (de)authorize certain domains
|
|
3148
|
+
request->u.enumeration.flags = reg;
|
|
3149
|
+
#endif
|
|
3150
|
+
|
|
3151
|
+
// enumeration requires multiple questions, so we must link all the context pointers so that
|
|
3152
|
+
// necessary context can be reached from the callbacks
|
|
3153
|
+
request->u.enumeration.q_all .QuestionContext = request;
|
|
3154
|
+
request->u.enumeration.q_default.QuestionContext = request;
|
|
3155
|
+
|
|
3156
|
+
// if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
|
|
3157
|
+
if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
|
|
3158
|
+
|
|
3159
|
+
// make the calls
|
|
3160
|
+
LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", request->sd, flags,
|
|
3161
|
+
(flags & kDNSServiceFlagsBrowseDomains ) ? "kDNSServiceFlagsBrowseDomains" :
|
|
3162
|
+
(flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
|
|
3163
|
+
err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_all, t_all, NULL, InterfaceID, enum_result_callback, request);
|
|
3164
|
+
if (!err)
|
|
3165
|
+
{
|
|
3166
|
+
err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_default, t_default, NULL, InterfaceID, enum_result_callback, request);
|
|
3167
|
+
if (err) mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
|
|
3168
|
+
else request->terminate = enum_termination_callback;
|
|
3169
|
+
}
|
|
3170
|
+
|
|
3171
|
+
return(err);
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
// ***************************************************************************
|
|
3175
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
3176
|
+
#pragma mark -
|
|
3177
|
+
#pragma mark - DNSServiceReconfirmRecord & Misc
|
|
3178
|
+
#endif
|
|
3179
|
+
|
|
3180
|
+
mDNSlocal mStatus handle_reconfirm_request(request_state *request)
|
|
3181
|
+
{
|
|
3182
|
+
mStatus status = mStatus_BadParamErr;
|
|
3183
|
+
AuthRecord *rr = read_rr_from_ipc_msg(request, 0, 0);
|
|
3184
|
+
if (rr)
|
|
3185
|
+
{
|
|
3186
|
+
status = mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
|
|
3187
|
+
LogOperation(
|
|
3188
|
+
(status == mStatus_NoError) ?
|
|
3189
|
+
"%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
|
|
3190
|
+
"%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
|
|
3191
|
+
request->sd, RRDisplayString(&mDNSStorage, &rr->resrec),
|
|
3192
|
+
mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID, mDNSfalse), status);
|
|
3193
|
+
freeL("AuthRecord/handle_reconfirm_request", rr);
|
|
3194
|
+
}
|
|
3195
|
+
return(status);
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3198
|
+
mDNSlocal mStatus handle_setdomain_request(request_state *request)
|
|
3199
|
+
{
|
|
3200
|
+
char domainstr[MAX_ESCAPED_DOMAIN_NAME];
|
|
3201
|
+
domainname domain;
|
|
3202
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
3203
|
+
(void)flags; // Unused
|
|
3204
|
+
if (get_string(&request->msgptr, request->msgend, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
|
|
3205
|
+
!MakeDomainNameFromDNSNameString(&domain, domainstr))
|
|
3206
|
+
{ LogMsg("%3d: DNSServiceSetDefaultDomainForUser(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
3207
|
+
|
|
3208
|
+
LogOperation("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
|
|
3209
|
+
return(mStatus_NoError);
|
|
3210
|
+
}
|
|
3211
|
+
|
|
3212
|
+
typedef packedstruct
|
|
3213
|
+
{
|
|
3214
|
+
mStatus err;
|
|
3215
|
+
mDNSu32 len;
|
|
3216
|
+
mDNSu32 vers;
|
|
3217
|
+
} DaemonVersionReply;
|
|
3218
|
+
|
|
3219
|
+
mDNSlocal void handle_getproperty_request(request_state *request)
|
|
3220
|
+
{
|
|
3221
|
+
const mStatus BadParamErr = dnssd_htonl((mDNSu32)mStatus_BadParamErr);
|
|
3222
|
+
char prop[256];
|
|
3223
|
+
if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
|
|
3224
|
+
{
|
|
3225
|
+
LogOperation("%3d: DNSServiceGetProperty(%s)", request->sd, prop);
|
|
3226
|
+
if (!strcmp(prop, kDNSServiceProperty_DaemonVersion))
|
|
3227
|
+
{
|
|
3228
|
+
DaemonVersionReply x = { 0, dnssd_htonl(4), dnssd_htonl(_DNS_SD_H) };
|
|
3229
|
+
send_all(request->sd, (const char *)&x, sizeof(x));
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
// If we didn't recogize the requested property name, return BadParamErr
|
|
3235
|
+
send_all(request->sd, (const char *)&BadParamErr, sizeof(BadParamErr));
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
// ***************************************************************************
|
|
3239
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
3240
|
+
#pragma mark -
|
|
3241
|
+
#pragma mark - DNSServiceNATPortMappingCreate
|
|
3242
|
+
#endif
|
|
3243
|
+
|
|
3244
|
+
#define DNSServiceProtocol(X) ((X) == NATOp_AddrRequest ? 0 : (X) == NATOp_MapUDP ? kDNSServiceProtocol_UDP : kDNSServiceProtocol_TCP)
|
|
3245
|
+
|
|
3246
|
+
mDNSlocal void port_mapping_termination_callback(request_state *request)
|
|
3247
|
+
{
|
|
3248
|
+
LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP", request->sd,
|
|
3249
|
+
DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
|
|
3250
|
+
mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease);
|
|
3251
|
+
mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
// Called via function pointer when we get a NAT-PMP address request or port mapping response
|
|
3255
|
+
mDNSlocal void port_mapping_create_request_callback(mDNS *m, NATTraversalInfo *n)
|
|
3256
|
+
{
|
|
3257
|
+
request_state *request = (request_state *)n->clientContext;
|
|
3258
|
+
reply_state *rep;
|
|
3259
|
+
int replyLen;
|
|
3260
|
+
char *data;
|
|
3261
|
+
|
|
3262
|
+
if (!request) { LogMsg("port_mapping_create_request_callback called with unknown request_state object"); return; }
|
|
3263
|
+
|
|
3264
|
+
// calculate reply data length
|
|
3265
|
+
replyLen = sizeof(DNSServiceFlags);
|
|
3266
|
+
replyLen += 3 * sizeof(mDNSu32); // if index + addr + ttl
|
|
3267
|
+
replyLen += sizeof(DNSServiceErrorType);
|
|
3268
|
+
replyLen += 2 * sizeof(mDNSu16); // Internal Port + External Port
|
|
3269
|
+
replyLen += sizeof(mDNSu8); // protocol
|
|
3270
|
+
|
|
3271
|
+
rep = create_reply(port_mapping_reply_op, replyLen, request);
|
|
3272
|
+
|
|
3273
|
+
rep->rhdr->flags = dnssd_htonl(0);
|
|
3274
|
+
rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, n->InterfaceID, mDNSfalse));
|
|
3275
|
+
rep->rhdr->error = dnssd_htonl(n->Result);
|
|
3276
|
+
|
|
3277
|
+
data = (char *)&rep->rhdr[1];
|
|
3278
|
+
|
|
3279
|
+
*data++ = request->u.pm.NATinfo.ExternalAddress.b[0];
|
|
3280
|
+
*data++ = request->u.pm.NATinfo.ExternalAddress.b[1];
|
|
3281
|
+
*data++ = request->u.pm.NATinfo.ExternalAddress.b[2];
|
|
3282
|
+
*data++ = request->u.pm.NATinfo.ExternalAddress.b[3];
|
|
3283
|
+
*data++ = DNSServiceProtocol(request->u.pm.NATinfo.Protocol);
|
|
3284
|
+
*data++ = request->u.pm.NATinfo.IntPort.b[0];
|
|
3285
|
+
*data++ = request->u.pm.NATinfo.IntPort.b[1];
|
|
3286
|
+
*data++ = request->u.pm.NATinfo.ExternalPort.b[0];
|
|
3287
|
+
*data++ = request->u.pm.NATinfo.ExternalPort.b[1];
|
|
3288
|
+
put_uint32(request->u.pm.NATinfo.Lifetime, &data);
|
|
3289
|
+
|
|
3290
|
+
LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT %.4a:%u TTL %u", request->sd,
|
|
3291
|
+
DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
|
|
3292
|
+
mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
|
|
3293
|
+
&request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort), request->u.pm.NATinfo.Lifetime);
|
|
3294
|
+
|
|
3295
|
+
append_reply(request, rep);
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
mDNSlocal mStatus handle_port_mapping_request(request_state *request)
|
|
3299
|
+
{
|
|
3300
|
+
mDNSu32 ttl = 0;
|
|
3301
|
+
mStatus err = mStatus_NoError;
|
|
3302
|
+
|
|
3303
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
3304
|
+
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
|
|
3305
|
+
mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
|
|
3306
|
+
mDNSu8 protocol = (mDNSu8)get_uint32(&request->msgptr, request->msgend);
|
|
3307
|
+
(void)flags; // Unused
|
|
3308
|
+
if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
|
|
3309
|
+
if (request->msgptr + 8 > request->msgend) request->msgptr = NULL;
|
|
3310
|
+
else
|
|
3311
|
+
{
|
|
3312
|
+
request->u.pm.NATinfo.IntPort.b[0] = *request->msgptr++;
|
|
3313
|
+
request->u.pm.NATinfo.IntPort.b[1] = *request->msgptr++;
|
|
3314
|
+
request->u.pm.ReqExt.b[0] = *request->msgptr++;
|
|
3315
|
+
request->u.pm.ReqExt.b[1] = *request->msgptr++;
|
|
3316
|
+
ttl = get_uint32(&request->msgptr, request->msgend);
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
if (!request->msgptr)
|
|
3320
|
+
{ LogMsg("%3d: DNSServiceNATPortMappingCreate(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
3321
|
+
|
|
3322
|
+
if (protocol == 0) // If protocol == 0 (i.e. just request public address) then IntPort, ExtPort, ttl must be zero too
|
|
3323
|
+
{
|
|
3324
|
+
if (!mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort) || !mDNSIPPortIsZero(request->u.pm.ReqExt) || ttl) return(mStatus_BadParamErr);
|
|
3325
|
+
}
|
|
3326
|
+
else
|
|
3327
|
+
{
|
|
3328
|
+
if (mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort)) return(mStatus_BadParamErr);
|
|
3329
|
+
if (!(protocol & (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP))) return(mStatus_BadParamErr);
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
request->u.pm.NATinfo.Protocol = !protocol ? NATOp_AddrRequest : (protocol == kDNSServiceProtocol_UDP) ? NATOp_MapUDP : NATOp_MapTCP;
|
|
3333
|
+
// u.pm.NATinfo.IntPort = already set above
|
|
3334
|
+
request->u.pm.NATinfo.RequestedPort = request->u.pm.ReqExt;
|
|
3335
|
+
request->u.pm.NATinfo.NATLease = ttl;
|
|
3336
|
+
request->u.pm.NATinfo.clientCallback = port_mapping_create_request_callback;
|
|
3337
|
+
request->u.pm.NATinfo.clientContext = request;
|
|
3338
|
+
|
|
3339
|
+
LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START", request->sd,
|
|
3340
|
+
protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease);
|
|
3341
|
+
err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
|
|
3342
|
+
if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err);
|
|
3343
|
+
else request->terminate = port_mapping_termination_callback;
|
|
3344
|
+
|
|
3345
|
+
return(err);
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
// ***************************************************************************
|
|
3349
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
3350
|
+
#pragma mark -
|
|
3351
|
+
#pragma mark - DNSServiceGetAddrInfo
|
|
3352
|
+
#endif
|
|
3353
|
+
|
|
3354
|
+
mDNSlocal void addrinfo_termination_callback(request_state *request)
|
|
3355
|
+
{
|
|
3356
|
+
LogOperation("%3d: DNSServiceGetAddrInfo(%##s) STOP", request->sd, request->u.addrinfo.q4.qname.c);
|
|
3357
|
+
|
|
3358
|
+
if (request->u.addrinfo.q4.QuestionContext)
|
|
3359
|
+
{
|
|
3360
|
+
mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
|
|
3361
|
+
request->u.addrinfo.q4.QuestionContext = mDNSNULL;
|
|
3362
|
+
}
|
|
3363
|
+
if (request->u.addrinfo.q4.qnameOrig)
|
|
3364
|
+
{
|
|
3365
|
+
freeL("QueryTermination", request->u.addrinfo.q4.qnameOrig);
|
|
3366
|
+
request->u.addrinfo.q4.qnameOrig = mDNSNULL;
|
|
3367
|
+
}
|
|
3368
|
+
if (request->u.addrinfo.q42)
|
|
3369
|
+
{
|
|
3370
|
+
if (request->u.addrinfo.q42->QuestionContext)
|
|
3371
|
+
{
|
|
3372
|
+
LogInfo("addrinfo_termination_callback: Stopping q42 %##s", request->u.addrinfo.q42->qname.c);
|
|
3373
|
+
mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q42);
|
|
3374
|
+
}
|
|
3375
|
+
if (request->u.addrinfo.q42->qnameOrig)
|
|
3376
|
+
{
|
|
3377
|
+
LogInfo("addrinfo_termination_callback: freeing q42 qnameOrig %##s", request->u.addrinfo.q42->qnameOrig->c);
|
|
3378
|
+
freeL("QueryTermination q42", request->u.addrinfo.q42->qnameOrig);
|
|
3379
|
+
request->u.addrinfo.q42->qnameOrig = mDNSNULL;
|
|
3380
|
+
}
|
|
3381
|
+
freeL("addrinfo Q42", request->u.addrinfo.q42);
|
|
3382
|
+
request->u.addrinfo.q42 = mDNSNULL;
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
if (request->u.addrinfo.q6.QuestionContext)
|
|
3386
|
+
{
|
|
3387
|
+
mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
|
|
3388
|
+
request->u.addrinfo.q6.QuestionContext = mDNSNULL;
|
|
3389
|
+
}
|
|
3390
|
+
if (request->u.addrinfo.q6.qnameOrig)
|
|
3391
|
+
{
|
|
3392
|
+
freeL("QueryTermination", request->u.addrinfo.q6.qnameOrig);
|
|
3393
|
+
request->u.addrinfo.q6.qnameOrig = mDNSNULL;
|
|
3394
|
+
}
|
|
3395
|
+
if (request->u.addrinfo.q62)
|
|
3396
|
+
{
|
|
3397
|
+
if (request->u.addrinfo.q62->QuestionContext)
|
|
3398
|
+
{
|
|
3399
|
+
LogInfo("addrinfo_termination_callback: Stopping q62 %##s", request->u.addrinfo.q62->qname.c);
|
|
3400
|
+
mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q62);
|
|
3401
|
+
}
|
|
3402
|
+
if (request->u.addrinfo.q62->qnameOrig)
|
|
3403
|
+
{
|
|
3404
|
+
LogInfo("addrinfo_termination_callback: freeing q62 qnameOrig %##s", request->u.addrinfo.q62->qnameOrig->c);
|
|
3405
|
+
freeL("QueryTermination q62", request->u.addrinfo.q62->qnameOrig);
|
|
3406
|
+
request->u.addrinfo.q62->qnameOrig = mDNSNULL;
|
|
3407
|
+
}
|
|
3408
|
+
freeL("addrinfo Q62", request->u.addrinfo.q62);
|
|
3409
|
+
request->u.addrinfo.q62 = mDNSNULL;
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3413
|
+
mDNSlocal mStatus handle_addrinfo_request(request_state *request)
|
|
3414
|
+
{
|
|
3415
|
+
char hostname[256];
|
|
3416
|
+
domainname d;
|
|
3417
|
+
mStatus err = 0;
|
|
3418
|
+
|
|
3419
|
+
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
|
|
3420
|
+
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
|
|
3421
|
+
|
|
3422
|
+
mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo));
|
|
3423
|
+
request->u.addrinfo.interface_id = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
|
|
3424
|
+
request->u.addrinfo.flags = flags;
|
|
3425
|
+
request->u.addrinfo.protocol = get_uint32(&request->msgptr, request->msgend);
|
|
3426
|
+
|
|
3427
|
+
if (interfaceIndex && !request->u.addrinfo.interface_id) return(mStatus_BadParamErr);
|
|
3428
|
+
if (request->u.addrinfo.protocol > (kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6)) return(mStatus_BadParamErr);
|
|
3429
|
+
|
|
3430
|
+
if (get_string(&request->msgptr, request->msgend, hostname, 256) < 0) return(mStatus_BadParamErr);
|
|
3431
|
+
|
|
3432
|
+
if (!request->msgptr) { LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
|
|
3433
|
+
|
|
3434
|
+
if (!MakeDomainNameFromDNSNameString(&d, hostname))
|
|
3435
|
+
{ LogMsg("ERROR: handle_addrinfo_request: bad hostname: %s", hostname); return(mStatus_BadParamErr); }
|
|
3436
|
+
|
|
3437
|
+
#if 0
|
|
3438
|
+
if (!AuthorizedDomain(request, &d, AutoBrowseDomains)) return (mStatus_NoError);
|
|
3439
|
+
#endif
|
|
3440
|
+
|
|
3441
|
+
if (!request->u.addrinfo.protocol)
|
|
3442
|
+
{
|
|
3443
|
+
flags |= kDNSServiceFlagsSuppressUnusable;
|
|
3444
|
+
request->u.addrinfo.protocol = (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
|
|
3445
|
+
}
|
|
3446
|
+
|
|
3447
|
+
request->u.addrinfo.q4.InterfaceID = request->u.addrinfo.q6.InterfaceID = request->u.addrinfo.interface_id;
|
|
3448
|
+
request->u.addrinfo.q4.Target = request->u.addrinfo.q6.Target = zeroAddr;
|
|
3449
|
+
request->u.addrinfo.q4.qname = request->u.addrinfo.q6.qname = d;
|
|
3450
|
+
request->u.addrinfo.q4.qclass = request->u.addrinfo.q6.qclass = kDNSServiceClass_IN;
|
|
3451
|
+
request->u.addrinfo.q4.LongLived = request->u.addrinfo.q6.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
|
|
3452
|
+
request->u.addrinfo.q4.ExpectUnique = request->u.addrinfo.q6.ExpectUnique = mDNSfalse;
|
|
3453
|
+
request->u.addrinfo.q4.ForceMCast = request->u.addrinfo.q6.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
|
|
3454
|
+
request->u.addrinfo.q4.ReturnIntermed = request->u.addrinfo.q6.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
|
|
3455
|
+
request->u.addrinfo.q4.SuppressUnusable = request->u.addrinfo.q6.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0;
|
|
3456
|
+
request->u.addrinfo.q4.TimeoutQuestion = request->u.addrinfo.q6.TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0;
|
|
3457
|
+
request->u.addrinfo.q4.WakeOnResolve = request->u.addrinfo.q6.WakeOnResolve = 0;
|
|
3458
|
+
request->u.addrinfo.q4.qnameOrig = request->u.addrinfo.q6.qnameOrig = mDNSNULL;
|
|
3459
|
+
|
|
3460
|
+
if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
|
|
3461
|
+
{
|
|
3462
|
+
request->u.addrinfo.q4.qtype = kDNSServiceType_A;
|
|
3463
|
+
request->u.addrinfo.q4.SearchListIndex = 0;
|
|
3464
|
+
|
|
3465
|
+
// We append search domains only for queries that are a single label. If overriden using
|
|
3466
|
+
// command line argument "AlwaysAppendSearchDomains", then we do it for any query which
|
|
3467
|
+
// is not fully qualified.
|
|
3468
|
+
if (hostname[strlen(hostname) - 1] != '.' && (AlwaysAppendSearchDomains || CountLabels(&d) == 1))
|
|
3469
|
+
{
|
|
3470
|
+
request->u.addrinfo.q4.AppendSearchDomains = 1;
|
|
3471
|
+
request->u.addrinfo.q4.AppendLocalSearchDomains = 1;
|
|
3472
|
+
}
|
|
3473
|
+
else
|
|
3474
|
+
{
|
|
3475
|
+
request->u.addrinfo.q4.AppendSearchDomains = 0;
|
|
3476
|
+
request->u.addrinfo.q4.AppendLocalSearchDomains = 0;
|
|
3477
|
+
}
|
|
3478
|
+
request->u.addrinfo.q4.RetryWithSearchDomains = (ApplySearchDomainsFirst(&request->u.addrinfo.q4) ? 1 : 0);
|
|
3479
|
+
request->u.addrinfo.q4.QuestionCallback = queryrecord_result_callback;
|
|
3480
|
+
request->u.addrinfo.q4.QuestionContext = request;
|
|
3481
|
+
err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q4);
|
|
3482
|
+
if (err != mStatus_NoError)
|
|
3483
|
+
{
|
|
3484
|
+
LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
|
|
3485
|
+
request->u.addrinfo.q4.QuestionContext = mDNSNULL;
|
|
3486
|
+
}
|
|
3487
|
+
#if APPLE_OSX_mDNSResponder
|
|
3488
|
+
err = SendAdditionalQuery(&request->u.addrinfo.q4, request, err);
|
|
3489
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3492
|
+
if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6))
|
|
3493
|
+
{
|
|
3494
|
+
request->u.addrinfo.q6.qtype = kDNSServiceType_AAAA;
|
|
3495
|
+
request->u.addrinfo.q6.SearchListIndex = 0;
|
|
3496
|
+
if (hostname[strlen(hostname) - 1] != '.' && (AlwaysAppendSearchDomains || CountLabels(&d) == 1))
|
|
3497
|
+
{
|
|
3498
|
+
request->u.addrinfo.q6.AppendSearchDomains = 1;
|
|
3499
|
+
request->u.addrinfo.q6.AppendLocalSearchDomains = 1;
|
|
3500
|
+
}
|
|
3501
|
+
else
|
|
3502
|
+
{
|
|
3503
|
+
request->u.addrinfo.q6.AppendSearchDomains = 0;
|
|
3504
|
+
request->u.addrinfo.q6.AppendLocalSearchDomains = 0;
|
|
3505
|
+
}
|
|
3506
|
+
request->u.addrinfo.q6.RetryWithSearchDomains = (ApplySearchDomainsFirst(&request->u.addrinfo.q6) ? 1 : 0);
|
|
3507
|
+
request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
|
|
3508
|
+
request->u.addrinfo.q6.QuestionContext = request;
|
|
3509
|
+
err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
|
|
3510
|
+
if (err != mStatus_NoError)
|
|
3511
|
+
{
|
|
3512
|
+
LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
|
|
3513
|
+
request->u.addrinfo.q6.QuestionContext = mDNSNULL;
|
|
3514
|
+
if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
|
|
3515
|
+
{
|
|
3516
|
+
// If we started a query for IPv4, we need to cancel it
|
|
3517
|
+
mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
|
|
3518
|
+
request->u.addrinfo.q4.QuestionContext = mDNSNULL;
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
#if APPLE_OSX_mDNSResponder
|
|
3522
|
+
err = SendAdditionalQuery(&request->u.addrinfo.q6, request, err);
|
|
3523
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3526
|
+
LogOperation("%3d: DNSServiceGetAddrInfo(%X, %d, %d, %##s) START",
|
|
3527
|
+
request->sd, flags, interfaceIndex, request->u.addrinfo.protocol, d.c);
|
|
3528
|
+
|
|
3529
|
+
if (!err) request->terminate = addrinfo_termination_callback;
|
|
3530
|
+
|
|
3531
|
+
return(err);
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
// ***************************************************************************
|
|
3535
|
+
#if COMPILER_LIKES_PRAGMA_MARK
|
|
3536
|
+
#pragma mark -
|
|
3537
|
+
#pragma mark - Main Request Handler etc.
|
|
3538
|
+
#endif
|
|
3539
|
+
|
|
3540
|
+
mDNSlocal request_state *NewRequest(void)
|
|
3541
|
+
{
|
|
3542
|
+
request_state **p = &all_requests;
|
|
3543
|
+
while (*p) p=&(*p)->next;
|
|
3544
|
+
*p = mallocL("request_state", sizeof(request_state));
|
|
3545
|
+
if (!*p) FatalError("ERROR: malloc");
|
|
3546
|
+
mDNSPlatformMemZero(*p, sizeof(request_state));
|
|
3547
|
+
return(*p);
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
// read_msg may be called any time when the transfer state (req->ts) is t_morecoming.
|
|
3551
|
+
// if there is no data on the socket, the socket will be closed and t_terminated will be returned
|
|
3552
|
+
mDNSlocal void read_msg(request_state *req)
|
|
3553
|
+
{
|
|
3554
|
+
if (req->ts == t_terminated || req->ts == t_error)
|
|
3555
|
+
{ LogMsg("%3d: ERROR: read_msg called with transfer state terminated or error", req->sd); req->ts = t_error; return; }
|
|
3556
|
+
|
|
3557
|
+
if (req->ts == t_complete) // this must be death or something is wrong
|
|
3558
|
+
{
|
|
3559
|
+
char buf[4]; // dummy for death notification
|
|
3560
|
+
int nread = udsSupportReadFD(req->sd, buf, 4, 0, req->platform_data);
|
|
3561
|
+
if (!nread) { req->ts = t_terminated; return; }
|
|
3562
|
+
if (nread < 0) goto rerror;
|
|
3563
|
+
LogMsg("%3d: ERROR: read data from a completed request", req->sd);
|
|
3564
|
+
req->ts = t_error;
|
|
3565
|
+
return;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
if (req->ts != t_morecoming)
|
|
3569
|
+
{ LogMsg("%3d: ERROR: read_msg called with invalid transfer state (%d)", req->sd, req->ts); req->ts = t_error; return; }
|
|
3570
|
+
|
|
3571
|
+
if (req->hdr_bytes < sizeof(ipc_msg_hdr))
|
|
3572
|
+
{
|
|
3573
|
+
mDNSu32 nleft = sizeof(ipc_msg_hdr) - req->hdr_bytes;
|
|
3574
|
+
int nread = udsSupportReadFD(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0, req->platform_data);
|
|
3575
|
+
if (nread == 0) { req->ts = t_terminated; return; }
|
|
3576
|
+
if (nread < 0) goto rerror;
|
|
3577
|
+
req->hdr_bytes += nread;
|
|
3578
|
+
if (req->hdr_bytes > sizeof(ipc_msg_hdr))
|
|
3579
|
+
{ LogMsg("%3d: ERROR: read_msg - read too many header bytes", req->sd); req->ts = t_error; return; }
|
|
3580
|
+
|
|
3581
|
+
// only read data if header is complete
|
|
3582
|
+
if (req->hdr_bytes == sizeof(ipc_msg_hdr))
|
|
3583
|
+
{
|
|
3584
|
+
ConvertHeaderBytes(&req->hdr);
|
|
3585
|
+
if (req->hdr.version != VERSION)
|
|
3586
|
+
{ LogMsg("%3d: ERROR: client version 0x%08X daemon version 0x%08X", req->sd, req->hdr.version, VERSION); req->ts = t_error; return; }
|
|
3587
|
+
|
|
3588
|
+
// Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord()
|
|
3589
|
+
// with 64kB of rdata. Adding 1009 byte for a maximal domain name, plus a safety margin
|
|
3590
|
+
// for other overhead, this means any message above 70kB is definitely bogus.
|
|
3591
|
+
if (req->hdr.datalen > 70000)
|
|
3592
|
+
{ LogMsg("%3d: ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
|
|
3593
|
+
req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
|
|
3594
|
+
if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return; }
|
|
3595
|
+
req->msgptr = req->msgbuf;
|
|
3596
|
+
req->msgend = req->msgbuf + req->hdr.datalen;
|
|
3597
|
+
mDNSPlatformMemZero(req->msgbuf, req->hdr.datalen + MSG_PAD_BYTES);
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
// If our header is complete, but we're still needing more body data, then try to read it now
|
|
3602
|
+
// Note: For cancel_request req->hdr.datalen == 0, but there's no error return socket for cancel_request
|
|
3603
|
+
// Any time we need to get the error return socket we know we'll have at least one data byte
|
|
3604
|
+
// (even if only the one-byte empty C string placeholder for the old ctrl_path parameter)
|
|
3605
|
+
if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes < req->hdr.datalen)
|
|
3606
|
+
{
|
|
3607
|
+
mDNSu32 nleft = req->hdr.datalen - req->data_bytes;
|
|
3608
|
+
int nread;
|
|
3609
|
+
#if !defined(_WIN32)
|
|
3610
|
+
struct iovec vec = { req->msgbuf + req->data_bytes, nleft }; // Tell recvmsg where we want the bytes put
|
|
3611
|
+
struct msghdr msg;
|
|
3612
|
+
struct cmsghdr *cmsg;
|
|
3613
|
+
char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))];
|
|
3614
|
+
msg.msg_name = 0;
|
|
3615
|
+
msg.msg_namelen = 0;
|
|
3616
|
+
msg.msg_iov = &vec;
|
|
3617
|
+
msg.msg_iovlen = 1;
|
|
3618
|
+
msg.msg_control = cbuf;
|
|
3619
|
+
msg.msg_controllen = sizeof(cbuf);
|
|
3620
|
+
msg.msg_flags = 0;
|
|
3621
|
+
nread = recvmsg(req->sd, &msg, 0);
|
|
3622
|
+
#else
|
|
3623
|
+
nread = udsSupportReadFD(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0, req->platform_data);
|
|
3624
|
+
#endif
|
|
3625
|
+
if (nread == 0) { req->ts = t_terminated; return; }
|
|
3626
|
+
if (nread < 0) goto rerror;
|
|
3627
|
+
req->data_bytes += nread;
|
|
3628
|
+
if (req->data_bytes > req->hdr.datalen)
|
|
3629
|
+
{ LogMsg("%3d: ERROR: read_msg - read too many data bytes", req->sd); req->ts = t_error; return; }
|
|
3630
|
+
#if !defined(_WIN32)
|
|
3631
|
+
cmsg = CMSG_FIRSTHDR(&msg);
|
|
3632
|
+
#if DEBUG_64BIT_SCM_RIGHTS
|
|
3633
|
+
LogMsg("%3d: Expecting %d %d %d %d", req->sd, sizeof(cbuf), sizeof(cbuf), SOL_SOCKET, SCM_RIGHTS);
|
|
3634
|
+
LogMsg("%3d: Got %d %d %d %d", req->sd, msg.msg_controllen, cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type);
|
|
3635
|
+
#endif // DEBUG_64BIT_SCM_RIGHTS
|
|
3636
|
+
if (msg.msg_controllen == sizeof(cbuf) &&
|
|
3637
|
+
cmsg->cmsg_len == CMSG_LEN(sizeof(dnssd_sock_t)) &&
|
|
3638
|
+
cmsg->cmsg_level == SOL_SOCKET &&
|
|
3639
|
+
cmsg->cmsg_type == SCM_RIGHTS)
|
|
3640
|
+
{
|
|
3641
|
+
#if APPLE_OSX_mDNSResponder
|
|
3642
|
+
// Strictly speaking BPF_fd belongs solely in the platform support layer, but because
|
|
3643
|
+
// of privilege separation on Mac OS X we need to get BPF_fd from mDNSResponderHelper,
|
|
3644
|
+
// and it's convenient to repurpose the existing fd-passing code here for that task
|
|
3645
|
+
if (req->hdr.op == send_bpf)
|
|
3646
|
+
{
|
|
3647
|
+
dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg);
|
|
3648
|
+
LogOperation("%3d: Got BPF %d", req->sd, x);
|
|
3649
|
+
mDNSPlatformReceiveBPF_fd(&mDNSStorage, x);
|
|
3650
|
+
}
|
|
3651
|
+
else
|
|
3652
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
3653
|
+
req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg);
|
|
3654
|
+
#if DEBUG_64BIT_SCM_RIGHTS
|
|
3655
|
+
LogMsg("%3d: read req->errsd %d", req->sd, req->errsd);
|
|
3656
|
+
#endif // DEBUG_64BIT_SCM_RIGHTS
|
|
3657
|
+
if (req->data_bytes < req->hdr.datalen)
|
|
3658
|
+
{
|
|
3659
|
+
LogMsg("%3d: Client sent error socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
|
|
3660
|
+
req->sd, req->errsd, req->data_bytes, req->hdr.datalen);
|
|
3661
|
+
req->ts = t_error;
|
|
3662
|
+
return;
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
#endif
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
// If our header and data are both complete, see if we need to make our separate error return socket
|
|
3669
|
+
if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes == req->hdr.datalen)
|
|
3670
|
+
{
|
|
3671
|
+
if (req->terminate && req->hdr.op != cancel_request)
|
|
3672
|
+
{
|
|
3673
|
+
dnssd_sockaddr_t cliaddr;
|
|
3674
|
+
#if defined(USE_TCP_LOOPBACK)
|
|
3675
|
+
mDNSOpaque16 port;
|
|
3676
|
+
u_long opt = 1;
|
|
3677
|
+
port.b[0] = req->msgptr[0];
|
|
3678
|
+
port.b[1] = req->msgptr[1];
|
|
3679
|
+
req->msgptr += 2;
|
|
3680
|
+
cliaddr.sin_family = AF_INET;
|
|
3681
|
+
cliaddr.sin_port = port.NotAnInteger;
|
|
3682
|
+
cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
|
|
3683
|
+
#else
|
|
3684
|
+
char ctrl_path[MAX_CTLPATH];
|
|
3685
|
+
get_string(&req->msgptr, req->msgend, ctrl_path, MAX_CTLPATH); // path is first element in message buffer
|
|
3686
|
+
mDNSPlatformMemZero(&cliaddr, sizeof(cliaddr));
|
|
3687
|
+
cliaddr.sun_family = AF_LOCAL;
|
|
3688
|
+
mDNSPlatformStrCopy(cliaddr.sun_path, ctrl_path);
|
|
3689
|
+
// If the error return path UDS name is empty string, that tells us
|
|
3690
|
+
// that this is a new version of the library that's going to pass us
|
|
3691
|
+
// the error return path socket via sendmsg/recvmsg
|
|
3692
|
+
if (ctrl_path[0] == 0)
|
|
3693
|
+
{
|
|
3694
|
+
if (req->errsd == req->sd)
|
|
3695
|
+
{ LogMsg("%3d: read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->sd); req->ts = t_error; return; }
|
|
3696
|
+
goto got_errfd;
|
|
3697
|
+
}
|
|
3698
|
+
#endif
|
|
3699
|
+
|
|
3700
|
+
req->errsd = socket(AF_DNSSD, SOCK_STREAM, 0);
|
|
3701
|
+
if (!dnssd_SocketValid(req->errsd)) { my_perror("ERROR: socket"); req->ts = t_error; return; }
|
|
3702
|
+
|
|
3703
|
+
if (connect(req->errsd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
|
|
3704
|
+
{
|
|
3705
|
+
#if !defined(USE_TCP_LOOPBACK)
|
|
3706
|
+
struct stat sb;
|
|
3707
|
+
LogMsg("%3d: read_msg: Couldn't connect to error return path socket “%s” errno %d (%s)",
|
|
3708
|
+
req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
|
|
3709
|
+
if (stat(cliaddr.sun_path, &sb) < 0)
|
|
3710
|
+
LogMsg("%3d: read_msg: stat failed “%s” errno %d (%s)", req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
|
|
3711
|
+
else
|
|
3712
|
+
LogMsg("%3d: read_msg: file “%s” mode %o (octal) uid %d gid %d", req->sd, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
|
|
3713
|
+
#endif
|
|
3714
|
+
req->ts = t_error;
|
|
3715
|
+
return;
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3718
|
+
#if !defined(USE_TCP_LOOPBACK)
|
|
3719
|
+
got_errfd:
|
|
3720
|
+
#endif
|
|
3721
|
+
LogOperation("%3d: Error socket %d created %08X %08X", req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0]);
|
|
3722
|
+
#if defined(_WIN32)
|
|
3723
|
+
if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0)
|
|
3724
|
+
#else
|
|
3725
|
+
if (fcntl(req->errsd, F_SETFL, fcntl(req->errsd, F_GETFL, 0) | O_NONBLOCK) != 0)
|
|
3726
|
+
#endif
|
|
3727
|
+
{
|
|
3728
|
+
LogMsg("%3d: ERROR: could not set control socket to non-blocking mode errno %d (%s)",
|
|
3729
|
+
req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
|
|
3730
|
+
req->ts = t_error;
|
|
3731
|
+
return;
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
req->ts = t_complete;
|
|
3736
|
+
}
|
|
3737
|
+
|
|
3738
|
+
return;
|
|
3739
|
+
|
|
3740
|
+
rerror:
|
|
3741
|
+
if (dnssd_errno == dnssd_EWOULDBLOCK || dnssd_errno == dnssd_EINTR) return;
|
|
3742
|
+
LogMsg("%3d: ERROR: read_msg errno %d (%s)", req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
|
|
3743
|
+
req->ts = t_error;
|
|
3744
|
+
}
|
|
3745
|
+
|
|
3746
|
+
#define RecordOrientedOp(X) \
|
|
3747
|
+
((X) == reg_record_request || (X) == add_record_request || (X) == update_record_request || (X) == remove_record_request)
|
|
3748
|
+
|
|
3749
|
+
// The lightweight operations are the ones that don't need a dedicated request_state structure allocated for them
|
|
3750
|
+
#define LightweightOp(X) (RecordOrientedOp(X) || (X) == cancel_request)
|
|
3751
|
+
|
|
3752
|
+
mDNSlocal void request_callback(int fd, short filter, void *info)
|
|
3753
|
+
{
|
|
3754
|
+
mStatus err = 0;
|
|
3755
|
+
request_state *req = info;
|
|
3756
|
+
mDNSs32 min_size = sizeof(DNSServiceFlags);
|
|
3757
|
+
(void)fd; // Unused
|
|
3758
|
+
(void)filter; // Unused
|
|
3759
|
+
|
|
3760
|
+
for (;;)
|
|
3761
|
+
{
|
|
3762
|
+
read_msg(req);
|
|
3763
|
+
if (req->ts == t_morecoming) return;
|
|
3764
|
+
if (req->ts == t_terminated || req->ts == t_error) { AbortUnlinkAndFree(req); return; }
|
|
3765
|
+
if (req->ts != t_complete) { LogMsg("req->ts %d != t_complete", req->ts); AbortUnlinkAndFree(req); return; }
|
|
3766
|
+
|
|
3767
|
+
if (req->hdr.version != VERSION)
|
|
3768
|
+
{
|
|
3769
|
+
LogMsg("ERROR: client version %d incompatible with daemon version %d", req->hdr.version, VERSION);
|
|
3770
|
+
AbortUnlinkAndFree(req);
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3773
|
+
|
|
3774
|
+
switch(req->hdr.op) // Interface + other data
|
|
3775
|
+
{
|
|
3776
|
+
case connection_request: min_size = 0; break;
|
|
3777
|
+
case reg_service_request: min_size += sizeof(mDNSu32) + 4 /* name, type, domain, host */ + 4 /* port, textlen */; break;
|
|
3778
|
+
case add_record_request: min_size += 4 /* type, rdlen */ + 4 /* ttl */; break;
|
|
3779
|
+
case update_record_request: min_size += 2 /* rdlen */ + 4 /* ttl */; break;
|
|
3780
|
+
case remove_record_request: break;
|
|
3781
|
+
case browse_request: min_size += sizeof(mDNSu32) + 2 /* type, domain */; break;
|
|
3782
|
+
case resolve_request: min_size += sizeof(mDNSu32) + 3 /* type, type, domain */; break;
|
|
3783
|
+
case query_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 4 /* type, class*/; break;
|
|
3784
|
+
case enumeration_request: min_size += sizeof(mDNSu32); break;
|
|
3785
|
+
case reg_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */ + 4 /* ttl */; break;
|
|
3786
|
+
case reconfirm_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */; break;
|
|
3787
|
+
case setdomain_request: min_size += 1 /* domain */; break;
|
|
3788
|
+
case getproperty_request: min_size = 2; break;
|
|
3789
|
+
case port_mapping_request: min_size += sizeof(mDNSu32) + 4 /* udp/tcp */ + 4 /* int/ext port */ + 4 /* ttl */; break;
|
|
3790
|
+
case addrinfo_request: min_size += sizeof(mDNSu32) + 4 /* v4/v6 */ + 1 /* hostname */; break;
|
|
3791
|
+
case send_bpf: // Same as cancel_request below
|
|
3792
|
+
case cancel_request: min_size = 0; break;
|
|
3793
|
+
case sethost_request: min_size = sizeof(mDNSu32) + 1 /* hostname */; break;
|
|
3794
|
+
default: LogMsg("ERROR: validate_message - unsupported req type: %d", req->hdr.op); min_size = -1; break;
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
if ((mDNSs32)req->data_bytes < min_size)
|
|
3798
|
+
{ LogMsg("Invalid message %d bytes; min for %d is %d", req->data_bytes, req->hdr.op, min_size); AbortUnlinkAndFree(req); return; }
|
|
3799
|
+
|
|
3800
|
+
if (LightweightOp(req->hdr.op) && !req->terminate)
|
|
3801
|
+
{ LogMsg("Reg/Add/Update/Remove %d require existing connection", req->hdr.op); AbortUnlinkAndFree(req); return; }
|
|
3802
|
+
|
|
3803
|
+
// check if client wants silent operation
|
|
3804
|
+
if (req->hdr.ipc_flags & IPC_FLAGS_NOREPLY) req->no_reply = 1;
|
|
3805
|
+
|
|
3806
|
+
// If req->terminate is already set, this means this operation is sharing an existing connection
|
|
3807
|
+
if (req->terminate && !LightweightOp(req->hdr.op))
|
|
3808
|
+
{
|
|
3809
|
+
request_state *newreq = NewRequest();
|
|
3810
|
+
newreq->primary = req;
|
|
3811
|
+
newreq->sd = req->sd;
|
|
3812
|
+
newreq->errsd = req->errsd;
|
|
3813
|
+
newreq->uid = req->uid;
|
|
3814
|
+
newreq->hdr = req->hdr;
|
|
3815
|
+
newreq->msgbuf = req->msgbuf;
|
|
3816
|
+
newreq->msgptr = req->msgptr;
|
|
3817
|
+
newreq->msgend = req->msgend;
|
|
3818
|
+
req = newreq;
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
// If we're shutting down, don't allow new client requests
|
|
3822
|
+
// We do allow "cancel" and "getproperty" during shutdown
|
|
3823
|
+
if (mDNSStorage.ShutdownTime && req->hdr.op != cancel_request && req->hdr.op != getproperty_request)
|
|
3824
|
+
{
|
|
3825
|
+
err = mStatus_ServiceNotRunning;
|
|
3826
|
+
}
|
|
3827
|
+
else switch(req->hdr.op)
|
|
3828
|
+
{
|
|
3829
|
+
// These are all operations that have their own first-class request_state object
|
|
3830
|
+
case connection_request: LogOperation("%3d: DNSServiceCreateConnection START", req->sd);
|
|
3831
|
+
req->terminate = connection_termination; break;
|
|
3832
|
+
case resolve_request: err = handle_resolve_request (req); break;
|
|
3833
|
+
case query_request: err = handle_queryrecord_request (req); break;
|
|
3834
|
+
case browse_request: err = handle_browse_request (req); break;
|
|
3835
|
+
case reg_service_request: err = handle_regservice_request (req); break;
|
|
3836
|
+
case enumeration_request: err = handle_enum_request (req); break;
|
|
3837
|
+
case reconfirm_record_request: err = handle_reconfirm_request (req); break;
|
|
3838
|
+
case setdomain_request: err = handle_setdomain_request (req); break;
|
|
3839
|
+
case getproperty_request: handle_getproperty_request (req); break;
|
|
3840
|
+
case port_mapping_request: err = handle_port_mapping_request(req); break;
|
|
3841
|
+
case addrinfo_request: err = handle_addrinfo_request (req); break;
|
|
3842
|
+
case send_bpf: /* Do nothing for send_bpf */ break;
|
|
3843
|
+
|
|
3844
|
+
// These are all operations that work with an existing request_state object
|
|
3845
|
+
case reg_record_request: err = handle_regrecord_request (req); break;
|
|
3846
|
+
case add_record_request: err = handle_add_request (req); break;
|
|
3847
|
+
case update_record_request: err = handle_update_request (req); break;
|
|
3848
|
+
case remove_record_request: err = handle_removerecord_request(req); break;
|
|
3849
|
+
case cancel_request: handle_cancel_request (req); break;
|
|
3850
|
+
case sethost_request: err = handle_sethost_request (req); break;
|
|
3851
|
+
default: LogMsg("%3d: ERROR: Unsupported UDS req: %d", req->sd, req->hdr.op);
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
// req->msgbuf may be NULL, e.g. for connection_request or remove_record_request
|
|
3855
|
+
if (req->msgbuf) freeL("request_state msgbuf", req->msgbuf);
|
|
3856
|
+
|
|
3857
|
+
// There's no return data for a cancel request (DNSServiceRefDeallocate returns no result)
|
|
3858
|
+
// For a DNSServiceGetProperty call, the handler already generated the response, so no need to do it again here
|
|
3859
|
+
if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request && req->hdr.op != send_bpf)
|
|
3860
|
+
{
|
|
3861
|
+
const mStatus err_netorder = dnssd_htonl(err);
|
|
3862
|
+
send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder));
|
|
3863
|
+
if (req->errsd != req->sd)
|
|
3864
|
+
{
|
|
3865
|
+
LogOperation("%3d: Error socket %d closed %08X %08X (%d)",
|
|
3866
|
+
req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0], err);
|
|
3867
|
+
dnssd_close(req->errsd);
|
|
3868
|
+
req->errsd = req->sd;
|
|
3869
|
+
// Also need to reset the parent's errsd, if this is a subordinate operation
|
|
3870
|
+
if (req->primary) req->primary->errsd = req->primary->sd;
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
|
|
3874
|
+
// Reset ready to accept the next req on this pipe
|
|
3875
|
+
if (req->primary) req = req->primary;
|
|
3876
|
+
req->ts = t_morecoming;
|
|
3877
|
+
req->hdr_bytes = 0;
|
|
3878
|
+
req->data_bytes = 0;
|
|
3879
|
+
req->msgbuf = mDNSNULL;
|
|
3880
|
+
req->msgptr = mDNSNULL;
|
|
3881
|
+
req->msgend = 0;
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
mDNSlocal void connect_callback(int fd, short filter, void *info)
|
|
3886
|
+
{
|
|
3887
|
+
dnssd_sockaddr_t cliaddr;
|
|
3888
|
+
dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
|
|
3889
|
+
dnssd_sock_t sd = accept(fd, (struct sockaddr*) &cliaddr, &len);
|
|
3890
|
+
#if defined(SO_NOSIGPIPE) || defined(_WIN32)
|
|
3891
|
+
unsigned long optval = 1;
|
|
3892
|
+
#endif
|
|
3893
|
+
|
|
3894
|
+
(void)filter; // Unused
|
|
3895
|
+
(void)info; // Unused
|
|
3896
|
+
|
|
3897
|
+
if (!dnssd_SocketValid(sd))
|
|
3898
|
+
{
|
|
3899
|
+
if (dnssd_errno != dnssd_EWOULDBLOCK) my_perror("ERROR: accept");
|
|
3900
|
+
return;
|
|
3901
|
+
}
|
|
3902
|
+
|
|
3903
|
+
#ifdef SO_NOSIGPIPE
|
|
3904
|
+
// Some environments (e.g. OS X) support turning off SIGPIPE for a socket
|
|
3905
|
+
if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
|
|
3906
|
+
LogMsg("%3d: WARNING: setsockopt - SO_NOSIGPIPE %d (%s)", sd, dnssd_errno, dnssd_strerror(dnssd_errno));
|
|
3907
|
+
#endif
|
|
3908
|
+
|
|
3909
|
+
#if defined(_WIN32)
|
|
3910
|
+
if (ioctlsocket(sd, FIONBIO, &optval) != 0)
|
|
3911
|
+
#else
|
|
3912
|
+
if (fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK) != 0)
|
|
3913
|
+
#endif
|
|
3914
|
+
{
|
|
3915
|
+
my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
|
|
3916
|
+
dnssd_close(sd);
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3919
|
+
else
|
|
3920
|
+
{
|
|
3921
|
+
request_state *request = NewRequest();
|
|
3922
|
+
request->ts = t_morecoming;
|
|
3923
|
+
request->sd = sd;
|
|
3924
|
+
request->errsd = sd;
|
|
3925
|
+
#if APPLE_OSX_mDNSResponder
|
|
3926
|
+
struct xucred x;
|
|
3927
|
+
socklen_t xucredlen = sizeof(x);
|
|
3928
|
+
if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid;
|
|
3929
|
+
else my_perror("ERROR: getsockopt, LOCAL_PEERCRED");
|
|
3930
|
+
debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups);
|
|
3931
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
3932
|
+
LogOperation("%3d: Adding FD for uid %u", request->sd, request->uid);
|
|
3933
|
+
udsSupportAddFDToEventLoop(sd, request_callback, request, &request->platform_data);
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
|
|
3937
|
+
mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt)
|
|
3938
|
+
{
|
|
3939
|
+
#if defined(SO_NP_EXTENSIONS)
|
|
3940
|
+
struct so_np_extensions sonpx;
|
|
3941
|
+
socklen_t optlen = sizeof(struct so_np_extensions);
|
|
3942
|
+
sonpx.npx_flags = SONPX_SETOPTSHUT;
|
|
3943
|
+
sonpx.npx_mask = SONPX_SETOPTSHUT;
|
|
3944
|
+
if (setsockopt(skt, SOL_SOCKET, SO_NP_EXTENSIONS, &sonpx, optlen) < 0)
|
|
3945
|
+
my_perror("WARNING: could not set sockopt - SO_NP_EXTENSIONS");
|
|
3946
|
+
#endif
|
|
3947
|
+
#if defined(_WIN32)
|
|
3948
|
+
// SEH: do we even need to do this on windows?
|
|
3949
|
+
// This socket will be given to WSAEventSelect which will automatically set it to non-blocking
|
|
3950
|
+
u_long opt = 1;
|
|
3951
|
+
if (ioctlsocket(skt, FIONBIO, &opt) != 0)
|
|
3952
|
+
#else
|
|
3953
|
+
if (fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK) != 0)
|
|
3954
|
+
#endif
|
|
3955
|
+
{
|
|
3956
|
+
my_perror("ERROR: could not set listen socket to non-blocking mode");
|
|
3957
|
+
return mDNSfalse;
|
|
3958
|
+
}
|
|
3959
|
+
|
|
3960
|
+
if (listen(skt, LISTENQ) != 0)
|
|
3961
|
+
{
|
|
3962
|
+
my_perror("ERROR: could not listen on listen socket");
|
|
3963
|
+
return mDNSfalse;
|
|
3964
|
+
}
|
|
3965
|
+
|
|
3966
|
+
if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL, (void **) NULL))
|
|
3967
|
+
{
|
|
3968
|
+
my_perror("ERROR: could not add listen socket to event loop");
|
|
3969
|
+
return mDNSfalse;
|
|
3970
|
+
}
|
|
3971
|
+
else LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", skt);
|
|
3972
|
+
|
|
3973
|
+
return mDNStrue;
|
|
3974
|
+
}
|
|
3975
|
+
|
|
3976
|
+
mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
|
|
3977
|
+
{
|
|
3978
|
+
dnssd_sockaddr_t laddr;
|
|
3979
|
+
int ret;
|
|
3980
|
+
mDNSu32 i = 0;
|
|
3981
|
+
|
|
3982
|
+
LogInfo("udsserver_init");
|
|
3983
|
+
|
|
3984
|
+
// If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
|
|
3985
|
+
if (PID_FILE[0])
|
|
3986
|
+
{
|
|
3987
|
+
FILE *fp = fopen(PID_FILE, "w");
|
|
3988
|
+
if (fp != NULL)
|
|
3989
|
+
{
|
|
3990
|
+
fprintf(fp, "%d\n", getpid());
|
|
3991
|
+
fclose(fp);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
|
|
3995
|
+
if (skts)
|
|
3996
|
+
{
|
|
3997
|
+
for (i = 0; i < count; i++)
|
|
3998
|
+
if (dnssd_SocketValid(skts[i]) && !uds_socket_setup(skts[i]))
|
|
3999
|
+
goto error;
|
|
4000
|
+
}
|
|
4001
|
+
else
|
|
4002
|
+
{
|
|
4003
|
+
listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
|
|
4004
|
+
if (!dnssd_SocketValid(listenfd))
|
|
4005
|
+
{
|
|
4006
|
+
my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
|
|
4007
|
+
goto error;
|
|
4008
|
+
}
|
|
4009
|
+
|
|
4010
|
+
mDNSPlatformMemZero(&laddr, sizeof(laddr));
|
|
4011
|
+
|
|
4012
|
+
#if defined(USE_TCP_LOOPBACK)
|
|
4013
|
+
{
|
|
4014
|
+
laddr.sin_family = AF_INET;
|
|
4015
|
+
laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
|
|
4016
|
+
laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
|
|
4017
|
+
ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
|
|
4018
|
+
if (ret < 0)
|
|
4019
|
+
{
|
|
4020
|
+
my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
|
|
4021
|
+
goto error;
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
#else
|
|
4025
|
+
{
|
|
4026
|
+
mode_t mask = umask(0);
|
|
4027
|
+
unlink(MDNS_UDS_SERVERPATH); // OK if this fails
|
|
4028
|
+
laddr.sun_family = AF_LOCAL;
|
|
4029
|
+
#ifndef NOT_HAVE_SA_LEN
|
|
4030
|
+
// According to Stevens (section 3.2), there is no portable way to
|
|
4031
|
+
// determine whether sa_len is defined on a particular platform.
|
|
4032
|
+
laddr.sun_len = sizeof(struct sockaddr_un);
|
|
4033
|
+
#endif
|
|
4034
|
+
if (strlen(MDNS_UDS_SERVERPATH) >= sizeof(laddr.sun_path))
|
|
4035
|
+
{
|
|
4036
|
+
LogMsg("ERROR: MDNS_UDS_SERVERPATH must be < %d characters", (int)sizeof(laddr.sun_path));
|
|
4037
|
+
goto error;
|
|
4038
|
+
}
|
|
4039
|
+
mDNSPlatformStrCopy(laddr.sun_path, MDNS_UDS_SERVERPATH);
|
|
4040
|
+
ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
|
|
4041
|
+
umask(mask);
|
|
4042
|
+
if (ret < 0)
|
|
4043
|
+
{
|
|
4044
|
+
my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
|
|
4045
|
+
goto error;
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
#endif
|
|
4049
|
+
|
|
4050
|
+
if (!uds_socket_setup(listenfd)) goto error;
|
|
4051
|
+
}
|
|
4052
|
+
|
|
4053
|
+
#if !defined(PLATFORM_NO_RLIMIT)
|
|
4054
|
+
{
|
|
4055
|
+
// Set maximum number of open file descriptors
|
|
4056
|
+
#define MIN_OPENFILES 10240
|
|
4057
|
+
struct rlimit maxfds, newfds;
|
|
4058
|
+
|
|
4059
|
+
// Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
|
|
4060
|
+
// you have to get and set rlimits once before getrlimit will return sensible values
|
|
4061
|
+
if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
|
|
4062
|
+
if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
|
|
4063
|
+
|
|
4064
|
+
if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
|
|
4065
|
+
newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
|
|
4066
|
+
newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
|
|
4067
|
+
if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
|
|
4068
|
+
if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
|
|
4069
|
+
|
|
4070
|
+
if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
|
|
4071
|
+
debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
|
|
4072
|
+
debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
|
|
4073
|
+
}
|
|
4074
|
+
#endif
|
|
4075
|
+
|
|
4076
|
+
// We start a "LocalOnly" query looking for Automatic Browse Domain records.
|
|
4077
|
+
// When Domain Enumeration in uDNS.c finds an "lb" record from the network, its "FoundDomain" routine
|
|
4078
|
+
// creates a "LocalOnly" record, which results in our AutomaticBrowseDomainChange callback being invoked
|
|
4079
|
+
mDNS_GetDomains(&mDNSStorage, &mDNSStorage.AutomaticBrowseDomainQ, mDNS_DomainTypeBrowseAutomatic,
|
|
4080
|
+
mDNSNULL, mDNSInterface_LocalOnly, AutomaticBrowseDomainChange, mDNSNULL);
|
|
4081
|
+
|
|
4082
|
+
// Add "local" as recommended registration domain ("dns-sd -E"), recommended browsing domain ("dns-sd -F"), and automatic browsing domain
|
|
4083
|
+
RegisterLocalOnlyDomainEnumPTR(&mDNSStorage, &localdomain, mDNS_DomainTypeRegistration);
|
|
4084
|
+
RegisterLocalOnlyDomainEnumPTR(&mDNSStorage, &localdomain, mDNS_DomainTypeBrowse);
|
|
4085
|
+
AddAutoBrowseDomain(0, &localdomain);
|
|
4086
|
+
|
|
4087
|
+
udsserver_handle_configchange(&mDNSStorage);
|
|
4088
|
+
return 0;
|
|
4089
|
+
|
|
4090
|
+
error:
|
|
4091
|
+
|
|
4092
|
+
my_perror("ERROR: udsserver_init");
|
|
4093
|
+
return -1;
|
|
4094
|
+
}
|
|
4095
|
+
|
|
4096
|
+
mDNSexport int udsserver_exit(void)
|
|
4097
|
+
{
|
|
4098
|
+
// Cancel all outstanding client requests
|
|
4099
|
+
while (all_requests) AbortUnlinkAndFree(all_requests);
|
|
4100
|
+
|
|
4101
|
+
// Clean up any special mDNSInterface_LocalOnly records we created, both the entries for "local" we
|
|
4102
|
+
// created in udsserver_init, and others we created as a result of reading local configuration data
|
|
4103
|
+
while (LocalDomainEnumRecords)
|
|
4104
|
+
{
|
|
4105
|
+
ARListElem *rem = LocalDomainEnumRecords;
|
|
4106
|
+
LocalDomainEnumRecords = LocalDomainEnumRecords->next;
|
|
4107
|
+
mDNS_Deregister(&mDNSStorage, &rem->ar);
|
|
4108
|
+
}
|
|
4109
|
+
|
|
4110
|
+
// If the launching environment created no listening socket,
|
|
4111
|
+
// that means we created it ourselves, so we should clean it up on exit
|
|
4112
|
+
if (dnssd_SocketValid(listenfd))
|
|
4113
|
+
{
|
|
4114
|
+
dnssd_close(listenfd);
|
|
4115
|
+
#if !defined(USE_TCP_LOOPBACK)
|
|
4116
|
+
// Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
|
|
4117
|
+
// to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
|
|
4118
|
+
// It would be nice if we could find a solution to this problem
|
|
4119
|
+
if (unlink(MDNS_UDS_SERVERPATH))
|
|
4120
|
+
debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
|
|
4121
|
+
#endif
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
if (PID_FILE[0]) unlink(PID_FILE);
|
|
4125
|
+
|
|
4126
|
+
return 0;
|
|
4127
|
+
}
|
|
4128
|
+
|
|
4129
|
+
mDNSlocal void LogClientInfo(mDNS *const m, const request_state *req)
|
|
4130
|
+
{
|
|
4131
|
+
char prefix[16];
|
|
4132
|
+
if (req->primary) mDNS_snprintf(prefix, sizeof(prefix), " -> ");
|
|
4133
|
+
else mDNS_snprintf(prefix, sizeof(prefix), "%3d:", req->sd);
|
|
4134
|
+
|
|
4135
|
+
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
|
|
4136
|
+
|
|
4137
|
+
if (!req->terminate)
|
|
4138
|
+
LogMsgNoIdent("%s No operation yet on this socket", prefix);
|
|
4139
|
+
else if (req->terminate == connection_termination)
|
|
4140
|
+
{
|
|
4141
|
+
int num_records = 0, num_ops = 0;
|
|
4142
|
+
const registered_record_entry *p;
|
|
4143
|
+
const request_state *r;
|
|
4144
|
+
for (p = req->u.reg_recs; p; p=p->next) num_records++;
|
|
4145
|
+
for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
|
|
4146
|
+
LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s", prefix,
|
|
4147
|
+
num_records, num_records != 1 ? "s" : "",
|
|
4148
|
+
num_ops, num_ops != 1 ? "s" : "");
|
|
4149
|
+
for (p = req->u.reg_recs; p; p=p->next)
|
|
4150
|
+
LogMsgNoIdent(" -> DNSServiceRegisterRecord %3d %s", p->key, ARDisplayString(m, p->rr));
|
|
4151
|
+
for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(m, r);
|
|
4152
|
+
}
|
|
4153
|
+
else if (req->terminate == regservice_termination_callback)
|
|
4154
|
+
{
|
|
4155
|
+
service_instance *ptr;
|
|
4156
|
+
for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
|
|
4157
|
+
LogMsgNoIdent("%s DNSServiceRegister %##s %u/%u",
|
|
4158
|
+
(ptr == req->u.servicereg.instances) ? prefix : " ",
|
|
4159
|
+
ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), SRS_PORT(&ptr->srs));
|
|
4160
|
+
}
|
|
4161
|
+
else if (req->terminate == browse_termination_callback)
|
|
4162
|
+
{
|
|
4163
|
+
browser_t *blist;
|
|
4164
|
+
for (blist = req->u.browser.browsers; blist; blist = blist->next)
|
|
4165
|
+
LogMsgNoIdent("%s DNSServiceBrowse %##s", (blist == req->u.browser.browsers) ? prefix : " ", blist->q.qname.c);
|
|
4166
|
+
}
|
|
4167
|
+
else if (req->terminate == resolve_termination_callback)
|
|
4168
|
+
LogMsgNoIdent("%s DNSServiceResolve %##s", prefix, req->u.resolve.qsrv.qname.c);
|
|
4169
|
+
else if (req->terminate == queryrecord_termination_callback)
|
|
4170
|
+
LogMsgNoIdent("%s DNSServiceQueryRecord %##s (%s)", prefix, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype));
|
|
4171
|
+
else if (req->terminate == enum_termination_callback)
|
|
4172
|
+
LogMsgNoIdent("%s DNSServiceEnumerateDomains %##s", prefix, req->u.enumeration.q_all.qname.c);
|
|
4173
|
+
else if (req->terminate == port_mapping_termination_callback)
|
|
4174
|
+
LogMsgNoIdent("%s DNSServiceNATPortMapping %.4a %s%s Int %d Req %d Ext %d Req TTL %d Granted TTL %d",
|
|
4175
|
+
prefix,
|
|
4176
|
+
&req->u.pm.NATinfo.ExternalAddress,
|
|
4177
|
+
req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
|
|
4178
|
+
req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
|
|
4179
|
+
mDNSVal16(req->u.pm.NATinfo.IntPort),
|
|
4180
|
+
mDNSVal16(req->u.pm.ReqExt),
|
|
4181
|
+
mDNSVal16(req->u.pm.NATinfo.ExternalPort),
|
|
4182
|
+
req->u.pm.NATinfo.NATLease,
|
|
4183
|
+
req->u.pm.NATinfo.Lifetime);
|
|
4184
|
+
else if (req->terminate == addrinfo_termination_callback)
|
|
4185
|
+
LogMsgNoIdent("%s DNSServiceGetAddrInfo %s%s %##s", prefix,
|
|
4186
|
+
req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : " ",
|
|
4187
|
+
req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : " ",
|
|
4188
|
+
req->u.addrinfo.q4.qname.c);
|
|
4189
|
+
else
|
|
4190
|
+
LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
mDNSlocal char *RecordTypeName(mDNSu8 rtype)
|
|
4194
|
+
{
|
|
4195
|
+
switch (rtype)
|
|
4196
|
+
{
|
|
4197
|
+
case kDNSRecordTypeUnregistered: return ("Unregistered ");
|
|
4198
|
+
case kDNSRecordTypeDeregistering: return ("Deregistering");
|
|
4199
|
+
case kDNSRecordTypeUnique: return ("Unique ");
|
|
4200
|
+
case kDNSRecordTypeAdvisory: return ("Advisory ");
|
|
4201
|
+
case kDNSRecordTypeShared: return ("Shared ");
|
|
4202
|
+
case kDNSRecordTypeVerified: return ("Verified ");
|
|
4203
|
+
case kDNSRecordTypeKnownUnique: return ("KnownUnique ");
|
|
4204
|
+
default: return("Unknown");
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
|
|
4208
|
+
mDNSlocal void LogEtcHosts(mDNS *const m)
|
|
4209
|
+
{
|
|
4210
|
+
mDNSBool showheader = mDNStrue;
|
|
4211
|
+
const AuthRecord *ar;
|
|
4212
|
+
mDNSu32 slot;
|
|
4213
|
+
AuthGroup *ag;
|
|
4214
|
+
int count = 0;
|
|
4215
|
+
int authslot = 0;
|
|
4216
|
+
mDNSBool truncated = 0;
|
|
4217
|
+
|
|
4218
|
+
for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
|
|
4219
|
+
{
|
|
4220
|
+
if (m->rrauth.rrauth_hash[slot]) authslot++;
|
|
4221
|
+
for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
|
|
4222
|
+
for (ar = ag->members; ar; ar = ar->next)
|
|
4223
|
+
{
|
|
4224
|
+
if (ar->RecordCallback != FreeEtcHosts) continue;
|
|
4225
|
+
if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" State Interface"); }
|
|
4226
|
+
|
|
4227
|
+
// Print a maximum of 50 records
|
|
4228
|
+
if (count++ >= 50) { truncated = mDNStrue; continue; }
|
|
4229
|
+
if (ar->ARType == AuthRecordLocalOnly)
|
|
4230
|
+
{
|
|
4231
|
+
if (ar->resrec.InterfaceID == mDNSInterface_LocalOnly)
|
|
4232
|
+
LogMsgNoIdent(" %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
|
|
4233
|
+
else
|
|
4234
|
+
{
|
|
4235
|
+
mDNSu32 scopeid = (mDNSu32)(uintptr_t)ar->resrec.InterfaceID;
|
|
4236
|
+
LogMsgNoIdent(" %s %u %s", RecordTypeName(ar->resrec.RecordType), scopeid, ARDisplayString(m, ar));
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
|
|
4243
|
+
if (showheader) LogMsgNoIdent("<None>");
|
|
4244
|
+
else if (truncated) LogMsgNoIdent("<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4247
|
+
mDNSlocal void LogLocalOnlyAuthRecords(mDNS *const m)
|
|
4248
|
+
{
|
|
4249
|
+
mDNSBool showheader = mDNStrue;
|
|
4250
|
+
const AuthRecord *ar;
|
|
4251
|
+
mDNSu32 slot;
|
|
4252
|
+
AuthGroup *ag;
|
|
4253
|
+
|
|
4254
|
+
for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
|
|
4255
|
+
{
|
|
4256
|
+
for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
|
|
4257
|
+
for (ar = ag->members; ar; ar = ar->next)
|
|
4258
|
+
{
|
|
4259
|
+
if (ar->RecordCallback == FreeEtcHosts) continue;
|
|
4260
|
+
if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" State Interface"); }
|
|
4261
|
+
|
|
4262
|
+
// Print a maximum of 400 records
|
|
4263
|
+
if (ar->ARType == AuthRecordLocalOnly)
|
|
4264
|
+
LogMsgNoIdent(" %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
|
|
4265
|
+
else if (ar->ARType == AuthRecordP2P)
|
|
4266
|
+
LogMsgNoIdent(" %s PP %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
|
|
4267
|
+
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
if (showheader) LogMsgNoIdent("<None>");
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4274
|
+
mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
|
|
4275
|
+
{
|
|
4276
|
+
mDNSBool showheader = mDNStrue;
|
|
4277
|
+
const AuthRecord *ar;
|
|
4278
|
+
OwnerOptData owner = zeroOwner;
|
|
4279
|
+
for (ar = ResourceRecords; ar; ar=ar->next)
|
|
4280
|
+
{
|
|
4281
|
+
const char *const ifname = InterfaceNameForID(m, ar->resrec.InterfaceID);
|
|
4282
|
+
if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL))
|
|
4283
|
+
{
|
|
4284
|
+
if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" Int Next Expire State"); }
|
|
4285
|
+
if (proxy) (*proxy)++;
|
|
4286
|
+
if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)))
|
|
4287
|
+
{
|
|
4288
|
+
owner = ar->WakeUp;
|
|
4289
|
+
if (owner.password.l[0])
|
|
4290
|
+
LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
|
|
4291
|
+
else if (!mDNSSameEthAddress(&owner.HMAC, &owner.IMAC))
|
|
4292
|
+
LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d", &owner.HMAC, &owner.IMAC, owner.seq);
|
|
4293
|
+
else
|
|
4294
|
+
LogMsgNoIdent("Proxying for %.6a seq %d", &owner.HMAC, owner.seq);
|
|
4295
|
+
}
|
|
4296
|
+
if (AuthRecord_uDNS(ar))
|
|
4297
|
+
LogMsgNoIdent("%7d %7d %7d %7d %s",
|
|
4298
|
+
ar->ThisAPInterval / mDNSPlatformOneSecond,
|
|
4299
|
+
(ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
|
|
4300
|
+
ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
|
|
4301
|
+
ar->state, ARDisplayString(m, ar));
|
|
4302
|
+
else if (ar->ARType == AuthRecordLocalOnly)
|
|
4303
|
+
LogMsgNoIdent(" LO %s", ARDisplayString(m, ar));
|
|
4304
|
+
else if (ar->ARType == AuthRecordP2P)
|
|
4305
|
+
LogMsgNoIdent(" PP %s", ARDisplayString(m, ar));
|
|
4306
|
+
else
|
|
4307
|
+
LogMsgNoIdent("%7d %7d %7d %7s %s",
|
|
4308
|
+
ar->ThisAPInterval / mDNSPlatformOneSecond,
|
|
4309
|
+
ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
|
|
4310
|
+
ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0,
|
|
4311
|
+
ifname ? ifname : "ALL",
|
|
4312
|
+
ARDisplayString(m, ar));
|
|
4313
|
+
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
|
|
4314
|
+
}
|
|
4315
|
+
}
|
|
4316
|
+
if (showheader) LogMsgNoIdent("<None>");
|
|
4317
|
+
}
|
|
4318
|
+
|
|
4319
|
+
mDNSexport void udsserver_info(mDNS *const m)
|
|
4320
|
+
{
|
|
4321
|
+
const mDNSs32 now = mDNS_TimeNow(m);
|
|
4322
|
+
mDNSu32 CacheUsed = 0, CacheActive = 0, slot;
|
|
4323
|
+
int ProxyA = 0, ProxyD = 0;
|
|
4324
|
+
const CacheGroup *cg;
|
|
4325
|
+
const CacheRecord *cr;
|
|
4326
|
+
const DNSQuestion *q;
|
|
4327
|
+
const DNameListElem *d;
|
|
4328
|
+
const SearchListElem *s;
|
|
4329
|
+
|
|
4330
|
+
LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
|
|
4331
|
+
|
|
4332
|
+
LogMsgNoIdent("------------ Cache -------------");
|
|
4333
|
+
LogMsgNoIdent("Slt Q TTL if U Type rdlen");
|
|
4334
|
+
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
|
|
4335
|
+
for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
|
|
4336
|
+
{
|
|
4337
|
+
CacheUsed++; // Count one cache entity for the CacheGroup object
|
|
4338
|
+
for (cr = cg->members; cr; cr=cr->next)
|
|
4339
|
+
{
|
|
4340
|
+
const mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
|
|
4341
|
+
const char *ifname;
|
|
4342
|
+
mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
|
|
4343
|
+
if (!InterfaceID && cr->resrec.rDNSServer)
|
|
4344
|
+
InterfaceID = cr->resrec.rDNSServer->interface;
|
|
4345
|
+
ifname = InterfaceNameForID(m, InterfaceID);
|
|
4346
|
+
CacheUsed++;
|
|
4347
|
+
if (cr->CRActiveQuestion) CacheActive++;
|
|
4348
|
+
LogMsgNoIdent("%3d %s%8ld %-7s%s %-6s%s",
|
|
4349
|
+
slot,
|
|
4350
|
+
cr->CRActiveQuestion ? "*" : " ",
|
|
4351
|
+
remain,
|
|
4352
|
+
ifname ? ifname : "-U-",
|
|
4353
|
+
(cr->resrec.RecordType == kDNSRecordTypePacketNegative) ? "-" :
|
|
4354
|
+
(cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
|
|
4355
|
+
DNSTypeName(cr->resrec.rrtype),
|
|
4356
|
+
CRDisplayString(m, cr));
|
|
4357
|
+
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4361
|
+
if (m->rrcache_totalused != CacheUsed)
|
|
4362
|
+
LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
|
|
4363
|
+
if (m->rrcache_active != CacheActive)
|
|
4364
|
+
LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
|
|
4365
|
+
LogMsgNoIdent("Cache currently contains %lu entities; %lu referenced by active questions", CacheUsed, CacheActive);
|
|
4366
|
+
|
|
4367
|
+
LogMsgNoIdent("--------- Auth Records ---------");
|
|
4368
|
+
LogAuthRecords(m, now, m->ResourceRecords, mDNSNULL);
|
|
4369
|
+
|
|
4370
|
+
LogMsgNoIdent("--------- LocalOnly, P2P Auth Records ---------");
|
|
4371
|
+
LogLocalOnlyAuthRecords(m);
|
|
4372
|
+
|
|
4373
|
+
LogMsgNoIdent("--------- /etc/hosts ---------");
|
|
4374
|
+
LogEtcHosts(m);
|
|
4375
|
+
|
|
4376
|
+
LogMsgNoIdent("------ Duplicate Records -------");
|
|
4377
|
+
LogAuthRecords(m, now, m->DuplicateRecords, mDNSNULL);
|
|
4378
|
+
|
|
4379
|
+
LogMsgNoIdent("----- Auth Records Proxied -----");
|
|
4380
|
+
LogAuthRecords(m, now, m->ResourceRecords, &ProxyA);
|
|
4381
|
+
|
|
4382
|
+
LogMsgNoIdent("-- Duplicate Records Proxied ---");
|
|
4383
|
+
LogAuthRecords(m, now, m->DuplicateRecords, &ProxyD);
|
|
4384
|
+
|
|
4385
|
+
LogMsgNoIdent("---------- Questions -----------");
|
|
4386
|
+
if (!m->Questions) LogMsgNoIdent("<None>");
|
|
4387
|
+
else
|
|
4388
|
+
{
|
|
4389
|
+
CacheUsed = 0;
|
|
4390
|
+
CacheActive = 0;
|
|
4391
|
+
LogMsgNoIdent(" Int Next if T NumAns VDNS Qptr DupOf SU SQ Type Name");
|
|
4392
|
+
for (q = m->Questions; q; q=q->next)
|
|
4393
|
+
{
|
|
4394
|
+
mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
|
|
4395
|
+
mDNSs32 n = (NextQSendTime(q) - now) / mDNSPlatformOneSecond;
|
|
4396
|
+
char *ifname = InterfaceNameForID(m, q->InterfaceID);
|
|
4397
|
+
CacheUsed++;
|
|
4398
|
+
if (q->ThisQInterval) CacheActive++;
|
|
4399
|
+
LogMsgNoIdent("%6d%6d %-7s%s%s %5d 0x%x%x 0x%p 0x%p %1d %2d %-5s%##s%s",
|
|
4400
|
+
i, n,
|
|
4401
|
+
ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
|
|
4402
|
+
mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
|
|
4403
|
+
PrivateQuery(q) ? "P" : " ",
|
|
4404
|
+
q->CurrentAnswers, q->validDNSServers.l[1], q->validDNSServers.l[0], q, q->DuplicateOf,
|
|
4405
|
+
q->SuppressUnusable, q->SuppressQuery, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
|
|
4406
|
+
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
|
|
4407
|
+
}
|
|
4408
|
+
LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
|
|
4409
|
+
}
|
|
4410
|
+
|
|
4411
|
+
LogMsgNoIdent("----- Local-Only Questions -----");
|
|
4412
|
+
if (!m->LocalOnlyQuestions) LogMsgNoIdent("<None>");
|
|
4413
|
+
else for (q = m->LocalOnlyQuestions; q; q=q->next)
|
|
4414
|
+
LogMsgNoIdent(" %5d %-6s%##s%s",
|
|
4415
|
+
q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
|
|
4416
|
+
|
|
4417
|
+
LogMsgNoIdent("---- Active Client Requests ----");
|
|
4418
|
+
if (!all_requests) LogMsgNoIdent("<None>");
|
|
4419
|
+
else
|
|
4420
|
+
{
|
|
4421
|
+
const request_state *req, *r;
|
|
4422
|
+
for (req = all_requests; req; req=req->next)
|
|
4423
|
+
{
|
|
4424
|
+
if (req->primary) // If this is a subbordinate operation, check that the parent is in the list
|
|
4425
|
+
{
|
|
4426
|
+
for (r = all_requests; r && r != req; r=r->next) if (r == req->primary) goto foundparent;
|
|
4427
|
+
LogMsgNoIdent("%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
|
|
4428
|
+
}
|
|
4429
|
+
// For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
|
|
4430
|
+
LogClientInfo(m, req);
|
|
4431
|
+
foundparent:;
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
|
|
4435
|
+
LogMsgNoIdent("-------- NAT Traversals --------");
|
|
4436
|
+
if (!m->NATTraversals) LogMsgNoIdent("<None>");
|
|
4437
|
+
else
|
|
4438
|
+
{
|
|
4439
|
+
const NATTraversalInfo *nat;
|
|
4440
|
+
for (nat = m->NATTraversals; nat; nat=nat->next)
|
|
4441
|
+
{
|
|
4442
|
+
if (nat->Protocol)
|
|
4443
|
+
LogMsgNoIdent("%p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d",
|
|
4444
|
+
nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP",
|
|
4445
|
+
mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result,
|
|
4446
|
+
nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
|
|
4447
|
+
nat->retryInterval / mDNSPlatformOneSecond,
|
|
4448
|
+
nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0);
|
|
4449
|
+
else
|
|
4450
|
+
LogMsgNoIdent("%p Address Request Retry %5d Interval %5d", nat,
|
|
4451
|
+
(m->retryGetAddr - now) / mDNSPlatformOneSecond,
|
|
4452
|
+
m->retryIntervalGetAddr / mDNSPlatformOneSecond);
|
|
4453
|
+
usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
|
|
4457
|
+
LogMsgNoIdent("--------- AuthInfoList ---------");
|
|
4458
|
+
if (!m->AuthInfoList) LogMsgNoIdent("<None>");
|
|
4459
|
+
else
|
|
4460
|
+
{
|
|
4461
|
+
const DomainAuthInfo *a;
|
|
4462
|
+
for (a = m->AuthInfoList; a; a = a->next)
|
|
4463
|
+
LogMsgNoIdent("%##s %##s %##s %d %s", a->domain.c, a->keyname.c, a->hostname.c, (a->port.b[0] << 8 | a->port.b[1]), a->AutoTunnel ? a->AutoTunnel : "");
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4466
|
+
#if APPLE_OSX_mDNSResponder
|
|
4467
|
+
LogMsgNoIdent("--------- TunnelClients --------");
|
|
4468
|
+
if (!m->TunnelClients) LogMsgNoIdent("<None>");
|
|
4469
|
+
else
|
|
4470
|
+
{
|
|
4471
|
+
const ClientTunnel *c;
|
|
4472
|
+
for (c = m->TunnelClients; c; c = c->next)
|
|
4473
|
+
LogMsgNoIdent("%s %##s local %.16a %.4a %.16a remote %.16a %.4a %5d %.16a interval %d",
|
|
4474
|
+
c->prefix, c->dstname.c, &c->loc_inner, &c->loc_outer, &c->loc_outer6, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), &c->rmt_outer6, c->q.ThisQInterval);
|
|
4475
|
+
}
|
|
4476
|
+
#endif // APPLE_OSX_mDNSResponder
|
|
4477
|
+
|
|
4478
|
+
LogMsgNoIdent("---------- Misc State ----------");
|
|
4479
|
+
|
|
4480
|
+
LogMsgNoIdent("PrimaryMAC: %.6a", &m->PrimaryMAC);
|
|
4481
|
+
|
|
4482
|
+
LogMsgNoIdent("m->SleepState %d (%s) seq %d",
|
|
4483
|
+
m->SleepState,
|
|
4484
|
+
m->SleepState == SleepState_Awake ? "Awake" :
|
|
4485
|
+
m->SleepState == SleepState_Transferring ? "Transferring" :
|
|
4486
|
+
m->SleepState == SleepState_Sleeping ? "Sleeping" : "?",
|
|
4487
|
+
m->SleepSeqNum);
|
|
4488
|
+
|
|
4489
|
+
if (!m->SPSSocket) LogMsgNoIdent("Not offering Sleep Proxy Service");
|
|
4490
|
+
else LogMsgNoIdent("Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
|
|
4491
|
+
|
|
4492
|
+
if (m->ProxyRecords == ProxyA + ProxyD) LogMsgNoIdent("ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD);
|
|
4493
|
+
else LogMsgNoIdent("ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords);
|
|
4494
|
+
|
|
4495
|
+
LogMsgNoIdent("------ Auto Browse Domains -----");
|
|
4496
|
+
if (!AutoBrowseDomains) LogMsgNoIdent("<None>");
|
|
4497
|
+
else for (d=AutoBrowseDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
|
|
4498
|
+
|
|
4499
|
+
LogMsgNoIdent("--- Auto Registration Domains --");
|
|
4500
|
+
if (!AutoRegistrationDomains) LogMsgNoIdent("<None>");
|
|
4501
|
+
else for (d=AutoRegistrationDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
|
|
4502
|
+
|
|
4503
|
+
LogMsgNoIdent("--- Search Domains --");
|
|
4504
|
+
if (!SearchList) LogMsgNoIdent("<None>");
|
|
4505
|
+
else
|
|
4506
|
+
{
|
|
4507
|
+
for (s=SearchList; s; s=s->next)
|
|
4508
|
+
{
|
|
4509
|
+
char *ifname = InterfaceNameForID(m, s->InterfaceID);
|
|
4510
|
+
LogMsgNoIdent("%##s %s", s->domain.c, ifname ? ifname : "");
|
|
4511
|
+
}
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4514
|
+
LogMsgNoIdent("---- Task Scheduling Timers ----");
|
|
4515
|
+
|
|
4516
|
+
if (!m->NewQuestions)
|
|
4517
|
+
LogMsgNoIdent("NewQuestion <NONE>");
|
|
4518
|
+
else
|
|
4519
|
+
LogMsgNoIdent("NewQuestion DelayAnswering %d %d %##s (%s)",
|
|
4520
|
+
m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
|
|
4521
|
+
m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
|
|
4522
|
+
|
|
4523
|
+
if (!m->NewLocalOnlyQuestions)
|
|
4524
|
+
LogMsgNoIdent("NewLocalOnlyQuestions <NONE>");
|
|
4525
|
+
else
|
|
4526
|
+
LogMsgNoIdent("NewLocalOnlyQuestions %##s (%s)",
|
|
4527
|
+
m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
|
|
4528
|
+
|
|
4529
|
+
if (!m->NewLocalRecords)
|
|
4530
|
+
LogMsgNoIdent("NewLocalRecords <NONE>");
|
|
4531
|
+
else
|
|
4532
|
+
LogMsgNoIdent("NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
|
|
4533
|
+
|
|
4534
|
+
LogMsgNoIdent("SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
|
|
4535
|
+
LogMsgNoIdent("LocalRemoveEvents%s", m->LocalRemoveEvents ? "" : " <NONE>");
|
|
4536
|
+
LogMsgNoIdent("m->RegisterAutoTunnel6 %08X", m->RegisterAutoTunnel6);
|
|
4537
|
+
LogMsgNoIdent("m->AutoTunnelRelayAddrIn %.16a", &m->AutoTunnelRelayAddrIn);
|
|
4538
|
+
LogMsgNoIdent("m->AutoTunnelRelayAddrOut %.16a", &m->AutoTunnelRelayAddrOut);
|
|
4539
|
+
|
|
4540
|
+
#define LogTimer(MSG,T) LogMsgNoIdent( MSG " %08X %11d %08X %11d", (T), (T), (T)-now, (T)-now)
|
|
4541
|
+
|
|
4542
|
+
LogMsgNoIdent(" ABS (hex) ABS (dec) REL (hex) REL (dec)");
|
|
4543
|
+
LogMsgNoIdent("m->timenow %08X %11d", now, now);
|
|
4544
|
+
LogMsgNoIdent("m->timenow_adjust %08X %11d", m->timenow_adjust, m->timenow_adjust);
|
|
4545
|
+
LogTimer("m->NextScheduledEvent ", m->NextScheduledEvent);
|
|
4546
|
+
|
|
4547
|
+
#ifndef UNICAST_DISABLED
|
|
4548
|
+
LogTimer("m->NextuDNSEvent ", m->NextuDNSEvent);
|
|
4549
|
+
LogTimer("m->NextSRVUpdate ", m->NextSRVUpdate);
|
|
4550
|
+
LogTimer("m->NextScheduledNATOp ", m->NextScheduledNATOp);
|
|
4551
|
+
LogTimer("m->retryGetAddr ", m->retryGetAddr);
|
|
4552
|
+
#endif
|
|
4553
|
+
|
|
4554
|
+
LogTimer("m->NextCacheCheck ", m->NextCacheCheck);
|
|
4555
|
+
LogTimer("m->NextScheduledSPS ", m->NextScheduledSPS);
|
|
4556
|
+
LogTimer("m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
|
|
4557
|
+
LogTimer("m->DelaySleep ", m->DelaySleep);
|
|
4558
|
+
|
|
4559
|
+
LogTimer("m->NextScheduledQuery ", m->NextScheduledQuery);
|
|
4560
|
+
LogTimer("m->NextScheduledProbe ", m->NextScheduledProbe);
|
|
4561
|
+
LogTimer("m->NextScheduledResponse", m->NextScheduledResponse);
|
|
4562
|
+
|
|
4563
|
+
LogTimer("m->SuppressSending ", m->SuppressSending);
|
|
4564
|
+
LogTimer("m->SuppressProbes ", m->SuppressProbes);
|
|
4565
|
+
LogTimer("m->ProbeFailTime ", m->ProbeFailTime);
|
|
4566
|
+
LogTimer("m->DelaySleep ", m->DelaySleep);
|
|
4567
|
+
LogTimer("m->SleepLimit ", m->SleepLimit);
|
|
4568
|
+
LogTimer("m->NextScheduledStopTime ", m->NextScheduledStopTime);
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4571
|
+
#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
|
|
4572
|
+
mDNSexport void uds_validatelists(void)
|
|
4573
|
+
{
|
|
4574
|
+
const request_state *req, *p;
|
|
4575
|
+
for (req = all_requests; req; req=req->next)
|
|
4576
|
+
{
|
|
4577
|
+
if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2))
|
|
4578
|
+
LogMemCorruption("UDS request list: %p is garbage (%d)", req, req->sd);
|
|
4579
|
+
|
|
4580
|
+
if (req->primary == req)
|
|
4581
|
+
LogMemCorruption("UDS request list: req->primary should not point to self %p/%d", req, req->sd);
|
|
4582
|
+
|
|
4583
|
+
if (req->primary && req->replies)
|
|
4584
|
+
LogMemCorruption("UDS request list: Subordinate request %p/%d/%p should not have replies (%p)",
|
|
4585
|
+
req, req->sd, req->primary && req->replies);
|
|
4586
|
+
|
|
4587
|
+
p = req->primary;
|
|
4588
|
+
if ((long)p & 3)
|
|
4589
|
+
LogMemCorruption("UDS request list: req %p primary %p is misaligned (%d)", req, p, req->sd);
|
|
4590
|
+
else if (p && (p->next == (request_state *)~0 || (p->sd < 0 && p->sd != -2)))
|
|
4591
|
+
LogMemCorruption("UDS request list: req %p primary %p is garbage (%d)", req, p, p->sd);
|
|
4592
|
+
|
|
4593
|
+
reply_state *rep;
|
|
4594
|
+
for (rep = req->replies; rep; rep=rep->next)
|
|
4595
|
+
if (rep->next == (reply_state *)~0)
|
|
4596
|
+
LogMemCorruption("UDS req->replies: %p is garbage", rep);
|
|
4597
|
+
|
|
4598
|
+
if (req->terminate == connection_termination)
|
|
4599
|
+
{
|
|
4600
|
+
registered_record_entry *r;
|
|
4601
|
+
for (r = req->u.reg_recs; r; r=r->next)
|
|
4602
|
+
if (r->next == (registered_record_entry *)~0)
|
|
4603
|
+
LogMemCorruption("UDS req->u.reg_recs: %p is garbage", r);
|
|
4604
|
+
}
|
|
4605
|
+
else if (req->terminate == regservice_termination_callback)
|
|
4606
|
+
{
|
|
4607
|
+
service_instance *s;
|
|
4608
|
+
for (s = req->u.servicereg.instances; s; s=s->next)
|
|
4609
|
+
if (s->next == (service_instance *)~0)
|
|
4610
|
+
LogMemCorruption("UDS req->u.servicereg.instances: %p is garbage", s);
|
|
4611
|
+
}
|
|
4612
|
+
else if (req->terminate == browse_termination_callback)
|
|
4613
|
+
{
|
|
4614
|
+
browser_t *b;
|
|
4615
|
+
for (b = req->u.browser.browsers; b; b=b->next)
|
|
4616
|
+
if (b->next == (browser_t *)~0)
|
|
4617
|
+
LogMemCorruption("UDS req->u.browser.browsers: %p is garbage", b);
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
|
|
4621
|
+
DNameListElem *d;
|
|
4622
|
+
for (d = SCPrefBrowseDomains; d; d=d->next)
|
|
4623
|
+
if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
|
|
4624
|
+
LogMemCorruption("SCPrefBrowseDomains: %p is garbage (%d)", d, d->name.c[0]);
|
|
4625
|
+
|
|
4626
|
+
ARListElem *b;
|
|
4627
|
+
for (b = LocalDomainEnumRecords; b; b=b->next)
|
|
4628
|
+
if (b->next == (ARListElem *)~0 || b->ar.resrec.name->c[0] > 63)
|
|
4629
|
+
LogMemCorruption("LocalDomainEnumRecords: %p is garbage (%d)", b, b->ar.resrec.name->c[0]);
|
|
4630
|
+
|
|
4631
|
+
for (d = AutoBrowseDomains; d; d=d->next)
|
|
4632
|
+
if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
|
|
4633
|
+
LogMemCorruption("AutoBrowseDomains: %p is garbage (%d)", d, d->name.c[0]);
|
|
4634
|
+
|
|
4635
|
+
for (d = AutoRegistrationDomains; d; d=d->next)
|
|
4636
|
+
if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
|
|
4637
|
+
LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]);
|
|
4638
|
+
}
|
|
4639
|
+
#endif // APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
|
|
4640
|
+
|
|
4641
|
+
mDNSlocal int send_msg(request_state *const req)
|
|
4642
|
+
{
|
|
4643
|
+
reply_state *const rep = req->replies; // Send the first waiting reply
|
|
4644
|
+
ssize_t nwriten;
|
|
4645
|
+
if (req->no_reply) return(t_complete);
|
|
4646
|
+
|
|
4647
|
+
ConvertHeaderBytes(rep->mhdr);
|
|
4648
|
+
nwriten = send(req->sd, (char *)&rep->mhdr + rep->nwriten, rep->totallen - rep->nwriten, 0);
|
|
4649
|
+
ConvertHeaderBytes(rep->mhdr);
|
|
4650
|
+
|
|
4651
|
+
if (nwriten < 0)
|
|
4652
|
+
{
|
|
4653
|
+
if (dnssd_errno == dnssd_EINTR || dnssd_errno == dnssd_EWOULDBLOCK) nwriten = 0;
|
|
4654
|
+
else
|
|
4655
|
+
{
|
|
4656
|
+
#if !defined(PLATFORM_NO_EPIPE)
|
|
4657
|
+
if (dnssd_errno == EPIPE)
|
|
4658
|
+
return(req->ts = t_terminated);
|
|
4659
|
+
else
|
|
4660
|
+
#endif
|
|
4661
|
+
{
|
|
4662
|
+
LogMsg("send_msg ERROR: failed to write %d of %d bytes to fd %d errno %d (%s)",
|
|
4663
|
+
rep->totallen - rep->nwriten, rep->totallen, req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
|
|
4664
|
+
return(t_error);
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
rep->nwriten += nwriten;
|
|
4669
|
+
return (rep->nwriten == rep->totallen) ? t_complete : t_morecoming;
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4672
|
+
mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
|
|
4673
|
+
{
|
|
4674
|
+
mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
|
|
4675
|
+
request_state **req = &all_requests;
|
|
4676
|
+
|
|
4677
|
+
while (*req)
|
|
4678
|
+
{
|
|
4679
|
+
request_state *const r = *req;
|
|
4680
|
+
|
|
4681
|
+
if (r->terminate == resolve_termination_callback)
|
|
4682
|
+
if (r->u.resolve.ReportTime && now - r->u.resolve.ReportTime >= 0)
|
|
4683
|
+
{
|
|
4684
|
+
r->u.resolve.ReportTime = 0;
|
|
4685
|
+
LogMsgNoIdent("Client application bug: DNSServiceResolve(%##s) active for over two minutes. "
|
|
4686
|
+
"This places considerable burden on the network.", r->u.resolve.qsrv.qname.c);
|
|
4687
|
+
}
|
|
4688
|
+
|
|
4689
|
+
// Note: Only primary req's have reply lists, not subordinate req's.
|
|
4690
|
+
while (r->replies) // Send queued replies
|
|
4691
|
+
{
|
|
4692
|
+
transfer_state result;
|
|
4693
|
+
if (r->replies->next) r->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
|
|
4694
|
+
result = send_msg(r); // Returns t_morecoming if buffer full because client is not reading
|
|
4695
|
+
if (result == t_complete)
|
|
4696
|
+
{
|
|
4697
|
+
reply_state *fptr = r->replies;
|
|
4698
|
+
r->replies = r->replies->next;
|
|
4699
|
+
freeL("reply_state/udsserver_idle", fptr);
|
|
4700
|
+
r->time_blocked = 0; // reset failure counter after successful send
|
|
4701
|
+
r->unresponsiveness_reports = 0;
|
|
4702
|
+
continue;
|
|
4703
|
+
}
|
|
4704
|
+
else if (result == t_terminated || result == t_error)
|
|
4705
|
+
{
|
|
4706
|
+
LogMsg("%3d: Could not write data to client because of error - aborting connection", r->sd);
|
|
4707
|
+
LogClientInfo(&mDNSStorage, r);
|
|
4708
|
+
abort_request(r);
|
|
4709
|
+
}
|
|
4710
|
+
break;
|
|
4711
|
+
}
|
|
4712
|
+
|
|
4713
|
+
if (r->replies) // If we failed to send everything, check our time_blocked timer
|
|
4714
|
+
{
|
|
4715
|
+
if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;
|
|
4716
|
+
|
|
4717
|
+
if (mDNSStorage.SleepState != SleepState_Awake) r->time_blocked = 0;
|
|
4718
|
+
else if (!r->time_blocked) r->time_blocked = NonZeroTime(now);
|
|
4719
|
+
else if (now - r->time_blocked >= 10 * mDNSPlatformOneSecond * (r->unresponsiveness_reports+1))
|
|
4720
|
+
{
|
|
4721
|
+
int num = 0;
|
|
4722
|
+
struct reply_state *x = r->replies;
|
|
4723
|
+
while (x) { num++; x=x->next; }
|
|
4724
|
+
LogMsg("%3d: Could not write data to client after %ld seconds, %d repl%s waiting",
|
|
4725
|
+
r->sd, (now - r->time_blocked) / mDNSPlatformOneSecond, num, num == 1 ? "y" : "ies");
|
|
4726
|
+
if (++r->unresponsiveness_reports >= 60)
|
|
4727
|
+
{
|
|
4728
|
+
LogMsg("%3d: Client unresponsive; aborting connection", r->sd);
|
|
4729
|
+
LogClientInfo(&mDNSStorage, r);
|
|
4730
|
+
abort_request(r);
|
|
4731
|
+
}
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
if (!dnssd_SocketValid(r->sd)) // If this request is finished, unlink it from the list and free the memory
|
|
4736
|
+
{
|
|
4737
|
+
// Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
|
|
4738
|
+
*req = r->next;
|
|
4739
|
+
freeL("request_state/udsserver_idle", r);
|
|
4740
|
+
}
|
|
4741
|
+
else
|
|
4742
|
+
req = &r->next;
|
|
4743
|
+
}
|
|
4744
|
+
return nextevent;
|
|
4745
|
+
}
|
|
4746
|
+
|
|
4747
|
+
struct CompileTimeAssertionChecks_uds_daemon
|
|
4748
|
+
{
|
|
4749
|
+
// Check our structures are reasonable sizes. Including overly-large buffers, or embedding
|
|
4750
|
+
// other overly-large structures instead of having a pointer to them, can inadvertently
|
|
4751
|
+
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
|
|
4752
|
+
char sizecheck_request_state [(sizeof(request_state) <= 1784) ? 1 : -1];
|
|
4753
|
+
char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 60) ? 1 : -1];
|
|
4754
|
+
char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1];
|
|
4755
|
+
char sizecheck_browser_t [(sizeof(browser_t) <= 1050) ? 1 : -1];
|
|
4756
|
+
char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 12) ? 1 : -1];
|
|
4757
|
+
char sizecheck_reply_state [(sizeof(reply_state) <= 64) ? 1 : -1];
|
|
4758
|
+
};
|