1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-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 Change History (most recent first): 18 19 $Log: uDNS.c,v $ 20 Revision 1.230.2.1 2006/08/29 06:24:23 cheshire 21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 22 23 Revision 1.230 2006/06/29 03:02:44 cheshire 24 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support 25 26 Revision 1.229 2006/03/02 22:03:41 cheshire 27 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" 28 Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end 29 30 Revision 1.228 2006/02/26 00:54:42 cheshire 31 Fixes to avoid code generation warning/error on FreeBSD 7 32 33 Revision 1.227 2006/01/09 20:47:05 cheshire 34 <rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" 35 36 Revision 1.226 2005/12/20 02:46:33 cheshire 37 <rdar://problem/4175520> mDNSPosix wide-area registration broken 38 Check too strict -- we can still do wide-area registration (without NAT-PMP) 39 without having to know our gateway address 40 41 Revision 1.225 2005/10/21 22:51:17 cheshire 42 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code 43 Refinement: Shorten "check-for-broken-dns-relay" to just "dnsbugtest" 44 to avoid crashing NAT gateways that have a different DNS relay bug 45 46 Revision 1.224 2005/10/20 00:10:33 cheshire 47 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code 48 49 Revision 1.223 2005/10/17 18:52:42 cheshire 50 <rdar://problem/4271183> mDNSResponder crashed in CheckRecordRegistrations 51 Move code to unregister the service's extra records from uDNS_DeregisterService() to unlinkSRS(). 52 53 Revision 1.222 2005/10/05 23:04:10 cheshire 54 Add more information to unlinkAR and startLLQHandshakeCallback error messages 55 56 Revision 1.221 2005/10/05 17:27:48 herscher 57 <rdar://problem/4272516> Change 200ms delay to 10ms 58 59 Revision 1.220 2005/09/24 01:10:09 cheshire 60 Fix comment typos 61 62 Revision 1.219 2005/09/22 07:28:25 herscher 63 Double the delay to 200000 usec after sending out a DNS query 64 65 Revision 1.218 2005/09/13 01:06:14 herscher 66 <rdar://problem/4248878> Add 100ms delay in sendQuery. 67 68 Revision 1.217 2005/08/04 18:08:24 cheshire 69 Update comments 70 71 Revision 1.216 2005/07/29 23:05:22 ksekar 72 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update 73 Services should point to IPv6 address if IPv4 NAT mapping fails 74 75 Revision 1.215 2005/07/29 21:01:51 ksekar 76 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update 77 correction to original checkin - misplaced return in HostnameCallback and logic error determining v6 changes 78 79 Revision 1.214 2005/07/29 19:46:10 ksekar 80 <rdar://problem/4191860> reduce polling period on failed LLQs to 15 minutes 81 82 Revision 1.213 2005/07/29 18:04:22 ksekar 83 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update 84 85 Revision 1.212 2005/07/22 19:35:50 ksekar 86 <rdar://problem/4188821> SUTiger: LLQ event acknowledgments are not formated correctly 87 88 Revision 1.211 2005/07/21 18:51:04 ksekar 89 <rdar://problem/4103136> mDNSResponder times out when mapping ports after sleep 90 91 Revision 1.210 2005/07/21 18:47:31 ksekar 92 <rdar://problem/4137283> NAT-PMP refresh Requested Public Port should contain actual mapped port 93 94 Revision 1.209 2005/07/04 21:16:37 cheshire 95 Minor code tidying -- initialize variables where they are declared 96 97 Revision 1.208 2005/06/28 00:24:28 ksekar 98 <rdar://problem/4157823> memory smasher in conQueryCallback 99 100 Revision 1.207 2005/05/13 20:45:10 ksekar 101 <rdar://problem/4074400> Rapid wide-area txt record updates don't work 102 103 Revision 1.206 2005/03/31 02:19:55 cheshire 104 <rdar://problem/4021486> Fix build warnings 105 Reviewed by: Scott Herscher 106 107 Revision 1.205 2005/03/21 00:33:51 shersche 108 <rdar://problem/4021486> Fix build warnings on Win32 platform 109 110 Revision 1.204 2005/03/16 00:42:32 ksekar 111 <rdar://problem/4012279> Long-lived queries not working on Windows 112 113 Revision 1.203 2005/03/04 03:00:03 ksekar 114 <rdar://problem/4026546> Retransmissions happen too early, causing registrations to conflict with themselves 115 116 Revision 1.202 2005/03/01 19:29:17 ksekar 117 changed LogMsgs to debugfs 118 119 Revision 1.201 2005/02/26 03:04:13 cheshire 120 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection 121 Don't try to do updates to root name server. This ensures status dot turns red if user 122 enters a bad host name such as just "fred" instead of a properly fully-qualified name. 123 124 Revision 1.200 2005/02/25 17:47:45 ksekar 125 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep 126 127 Revision 1.199 2005/02/25 04:21:00 cheshire 128 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing 129 130 Revision 1.198 2005/02/25 02:35:22 cheshire 131 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection 132 If we get NXDomain error looking for the _dns-update._udp record, 133 update status from 1 (in progress) to mStatus_NoSuchNameErr (failed) 134 135 Revision 1.197 2005/02/24 21:56:59 ksekar 136 Change LogMsgs to debugfs 137 138 Revision 1.196 2005/02/24 21:52:28 ksekar 139 <rdar://problem/3922768> Remove "deferred deregistration" logic for hostnames 140 141 Revision 1.195 2005/02/22 17:53:08 ksekar 142 Changed successful NAT Traversals from LogMsg to LogOperation 143 144 Revision 1.194 2005/02/15 18:38:03 ksekar 145 <rdar://problem/3967876> change expected/redundant log messages to debugfs. 146 147 Revision 1.193 2005/02/15 01:17:48 ksekar 148 Fixed build failure. 149 150 Revision 1.192 2005/02/14 23:01:28 ksekar 151 Refinement to previous checkin - don't log bad LLQ opcode if we had to send the request more than once. 152 153 Revision 1.191 2005/02/14 18:26:51 ksekar 154 <rdar://problem/4005569> mDNSResponder complains about bad LLQ Opcode 2 155 156 Revision 1.190 2005/02/11 19:44:06 shersche 157 Remove extra semicolon at end of line 158 159 Revision 1.189 2005/02/10 21:07:02 ksekar 160 Don't goto error in ReceiveNATAddrResponse if we receive a malformatted response 161 162 Revision 1.188 2005/02/10 02:02:44 ksekar 163 Remove double semi-colon 164 165 Revision 1.187 2005/02/09 23:28:01 ksekar 166 <rdar://problem/3984374> NAT-PMP response callback should return a 167 boolean indicating if the packet matched the request 168 169 Revision 1.186 2005/02/04 21:56:29 ksekar 170 <rdar://problem/3984374> Simultaneous port map requests sometimes fail 171 - Refinement to previous checkin. 172 173 Revision 1.185 2005/02/03 23:48:22 ksekar 174 <rdar://problem/3984374> Simultaneous port map requests sometimes fail 175 176 Revision 1.184 2005/02/01 19:33:29 ksekar 177 <rdar://problem/3985239> Keychain format too restrictive 178 179 Revision 1.183 2005/01/27 22:57:55 cheshire 180 Fix compile errors on gcc4 181 182 Revision 1.182 2005/01/25 18:55:05 ksekar 183 Shortened log message 184 185 Revision 1.181 2005/01/25 02:17:32 cheshire 186 <rdar://problem/3971263> Don't use query ID zero in uDNS queries 187 188 Revision 1.180 2005/01/19 21:01:54 ksekar 189 <rdar://problem/3955355> uDNS needs to support subtype registration and browsing 190 191 Revision 1.179 2005/01/19 19:15:35 ksekar 192 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer 193 194 Revision 1.178 2005/01/17 23:47:58 cheshire 195 <rdar://problem/3904954> Wide-area services not found on little-endian 196 197 Revision 1.177 2005/01/17 23:41:26 cheshire 198 Fix compile errors 199 200 Revision 1.176 2005/01/17 21:03:04 cheshire 201 <rdar://problem/3904954> Wide-area services not found on little-endian 202 203 Revision 1.175 2005/01/15 00:56:41 ksekar 204 <rdar://problem/3954575> Unicast services don't disappear when logging 205 out of VPN 206 207 Revision 1.174 2005/01/14 18:44:28 ksekar 208 <rdar://problem/3954609> mDNSResponder is crashing when changing domains 209 210 Revision 1.173 2005/01/14 18:34:22 ksekar 211 <rdar://problem/3954571> Services registered outside of firewall don't succeed after location change 212 213 Revision 1.172 2005/01/11 22:50:52 ksekar 214 Fixed constant naming (was using kLLQ_DefLease for update leases) 215 216 Revision 1.171 2005/01/10 04:52:49 ksekar 217 Changed LogMsg to debugf 218 219 Revision 1.170 2005/01/08 00:50:05 ksekar 220 Fixed spelling mistake in log msg 221 222 Revision 1.169 2005/01/08 00:42:18 ksekar 223 <rdar://problem/3922758> Clean up syslog messages 224 225 Revision 1.168 2004/12/23 23:22:47 ksekar 226 <rdar://problem/3933606> Unicast known answers "name" pointers point to garbage stack memory 227 228 Revision 1.167 2004/12/22 22:25:47 ksekar 229 <rdar://problem/3734265> NATPMP: handle location changes 230 231 Revision 1.166 2004/12/22 00:04:12 ksekar 232 <rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply 233 234 Revision 1.165 2004/12/18 03:14:22 cheshire 235 DblNAT -> DoubleNAT 236 237 Revision 1.164 2004/12/17 03:55:40 ksekar 238 Don't use -1 as special meaning for expiration timer (it is a valid 239 value, and is redundant with our state variables) 240 241 Revision 1.163 2004/12/17 03:51:53 ksekar 242 <rdar://problem/3920991> Don't update TXT record if service registration fails 243 244 Revision 1.162 2004/12/17 01:29:11 ksekar 245 <rdar://problem/3920598> Questions can go deaf on location changes 246 247 Revision 1.161 2004/12/16 20:42:02 cheshire 248 Fix compiler warnings 249 250 Revision 1.160 2004/12/16 20:13:00 cheshire 251 <rdar://problem/3324626> Cache memory management improvements 252 253 Revision 1.159 2004/12/15 02:11:22 ksekar 254 <rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness 255 256 Revision 1.158 2004/12/15 02:04:28 ksekar 257 Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails 258 259 Revision 1.157 2004/12/15 01:39:21 ksekar 260 Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails 261 262 Revision 1.156 2004/12/15 01:18:57 ksekar 263 <rdar://problem/3825979> Call DeregisterService on nat port map failure 264 265 Revision 1.155 2004/12/14 21:21:20 ksekar 266 <rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot" 267 268 Revision 1.154 2004/12/14 20:52:27 cheshire 269 Add question->qnamehash and cr->resrec.namehash to log message 270 271 Revision 1.153 2004/12/14 20:45:02 cheshire 272 Improved error logging in "unexpected answer" message 273 274 Revision 1.152 2004/12/14 03:02:10 ksekar 275 <rdar://problem/3919016> Rare race condition can cause crash 276 277 Revision 1.151 2004/12/13 21:45:08 ksekar 278 uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer) 279 280 Revision 1.150 2004/12/13 20:42:41 ksekar 281 Fixed LogMsg 282 283 Revision 1.149 2004/12/13 18:10:03 ksekar 284 Fixed LogMsg 285 286 Revision 1.148 2004/12/13 01:18:04 ksekar 287 Fixed unused variable warning for non-debug builds 288 289 Revision 1.147 2004/12/12 23:51:42 ksekar 290 <rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target 291 292 Revision 1.146 2004/12/12 23:30:40 ksekar 293 <rdar://problem/3916987> Extra RRs not properly unlinked when parent service registration fails 294 295 Revision 1.145 2004/12/12 22:56:29 ksekar 296 <rdar://problem/3668508> Need to properly handle duplicate long-lived queries 297 298 Revision 1.144 2004/12/11 20:55:29 ksekar 299 <rdar://problem/3916479> Clean up registration state machines 300 301 Revision 1.143 2004/12/10 01:21:27 cheshire 302 <rdar://problem/3914089> Get rid of "LLQ Responses over TCP not currently supported" message 303 304 Revision 1.142 2004/12/08 02:03:31 ksekar 305 <rdar://problem/3865124> Looping on NAT Traversal error - check for 306 NULL RR on error 307 308 Revision 1.141 2004/12/07 01:39:28 cheshire 309 Don't fail if the same server is responsible for more than one domain 310 (e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.) 311 312 Revision 1.140 2004/12/06 21:15:22 ksekar 313 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations 314 315 Revision 1.139 2004/12/06 19:08:03 cheshire 316 Add clarifying comment -- CountLabels() excludes the final root label. 317 318 Revision 1.138 2004/12/06 01:45:54 ksekar 319 Correct wording in LogMsg 320 321 Revision 1.137 2004/12/03 20:40:35 ksekar 322 <rdar://problem/3865124> Looping on NAT Traversal error 323 324 Revision 1.136 2004/12/03 07:20:50 ksekar 325 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails 326 327 Revision 1.135 2004/12/03 05:18:33 ksekar 328 <rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors 329 330 Revision 1.134 2004/12/02 20:03:49 ksekar 331 <rdar://problem/3889647> Still publishes wide-area domains even after switching to a local subnet 332 333 Revision 1.133 2004/12/02 18:37:52 ksekar 334 <rdar://problem/3758233> Registering with port number zero should not create a port mapping 335 336 Revision 1.132 2004/12/01 20:57:19 ksekar 337 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware 338 339 Revision 1.131 2004/12/01 19:59:27 cheshire 340 <rdar://problem/3882643> Crash in mDNSPlatformTCPConnect 341 If a TCP response has the TC bit set, don't respond by just trying another TCP connection 342 343 Revision 1.130 2004/12/01 02:43:23 cheshire 344 Don't call StatusCallback if function pointer is null 345 346 Revision 1.129 2004/11/30 23:51:06 cheshire 347 Remove double semicolons 348 349 Revision 1.128 2004/11/25 01:48:30 ksekar 350 <rdar://problem/3878991> Logging into VPN does not trigger registration of address record 351 352 Revision 1.127 2004/11/25 01:41:36 ksekar 353 Changed unnecessary LogMsgs to debugfs 354 355 Revision 1.126 2004/11/23 23:54:17 ksekar 356 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures 357 can crash mDNSResponder 358 359 Revision 1.125 2004/11/23 04:16:48 cheshire 360 Removed receiveMsg() routine. 361 362 Revision 1.124 2004/11/23 04:06:51 cheshire 363 Get rid of floating point constant -- in a small embedded device, bringing in all 364 the floating point libraries just to halve an integer value is a bit too heavyweight. 365 366 Revision 1.123 2004/11/22 17:16:20 ksekar 367 <rdar://problem/3854298> Unicast services don't disappear when you disable all networking 368 369 Revision 1.122 2004/11/19 18:00:34 ksekar 370 <rdar://problem/3682646> Security: use random ID for one-shot unicast queries 371 372 Revision 1.121 2004/11/19 04:24:08 ksekar 373 <rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries 374 375 Revision 1.120 2004/11/19 02:32:43 ksekar 376 <rdar://problem/3682608> Wide-Area Security: Add LLQ-ID to events 377 378 Revision 1.119 2004/11/18 23:21:24 ksekar 379 <rdar://problem/3764544> LLQ Security: Need to verify src port/address for LLQ handshake 380 381 Revision 1.118 2004/11/18 22:58:37 ksekar 382 Removed old comment. 383 384 Revision 1.117 2004/11/18 18:04:21 ksekar 385 Restore checkins lost due to repository disk failure: Update comments & <rdar://problem/3880688> 386 387 Revision 1.xxx 2004/11/17 06:17:57 cheshire 388 Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>. 389 390 Revision 1.xxx 2004/11/17 00:45:28 ksekar 391 <rdar://problem/3880688> Result of putUpdateLease not error-checked 392 393 Revision 1.116 2004/11/16 01:41:47 ksekar 394 Fixed typo in debugf 395 396 Revision 1.115 2004/11/15 20:09:24 ksekar 397 <rdar://problem/3719050> Wide Area support for Add/Remove record 398 399 Revision 1.114 2004/11/13 02:32:47 ksekar 400 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface 401 - fixed incorrect state comparison in CheckQueries 402 403 Revision 1.113 2004/11/13 02:29:52 ksekar 404 <rdar://problem/3878386> LLQ refreshes not reliable 405 406 Revision 1.112 2004/11/11 20:45:14 ksekar 407 <rdar://problem/3876052> self-conflict test not compatible with some BIND servers 408 409 Revision 1.111 2004/11/11 20:14:55 ksekar 410 <rdar://problem/3719574> Wide-Area registrations not deregistered on sleep 411 412 Revision 1.110 2004/11/10 23:53:53 ksekar 413 Remove no longer relevant comment 414 415 Revision 1.109 2004/11/10 20:40:53 ksekar 416 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface 417 418 Revision 1.108 2004/11/01 20:36:16 ksekar 419 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications 420 421 Revision 1.107 2004/10/26 06:11:41 cheshire 422 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed 423 424 Revision 1.106 2004/10/26 03:52:03 cheshire 425 Update checkin comments 426 427 Revision 1.105 2004/10/26 01:15:06 cheshire 428 Use "#if 0" instead of commenting out code 429 430 Revision 1.104 2004/10/25 21:41:38 ksekar 431 <rdar://problem/3852958> wide-area name conflicts can cause crash 432 433 Revision 1.103 2004/10/25 19:30:52 ksekar 434 <rdar://problem/3827956> Simplify dynamic host name structures 435 436 Revision 1.102 2004/10/23 01:16:00 cheshire 437 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts 438 439 Revision 1.101 2004/10/22 20:52:07 ksekar 440 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries 441 442 Revision 1.100 2004/10/20 02:16:41 cheshire 443 Improve "could not confirm existence of NS record" error message 444 Don't call newRR->RecordCallback if it is NULL 445 446 Revision 1.99 2004/10/19 21:33:18 cheshire 447 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API 448 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name 449 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want 450 451 Revision 1.98 2004/10/16 00:16:59 cheshire 452 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check 453 454 Revision 1.97 2004/10/15 23:00:18 ksekar 455 <rdar://problem/3799242> Need to update LLQs on location changes 456 457 Revision 1.96 2004/10/12 23:30:44 ksekar 458 <rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals 459 460 Revision 1.95 2004/10/12 03:15:09 ksekar 461 <rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error 462 463 Revision 1.94 2004/10/12 02:49:20 ksekar 464 <rdar://problem/3831228> Clean up LLQ sleep/wake, error handling 465 466 Revision 1.93 2004/10/08 04:17:25 ksekar 467 <rdar://problem/3831819> Don't use DNS extensions if the server does not advertise required SRV record 468 469 Revision 1.92 2004/10/08 03:54:35 ksekar 470 <rdar://problem/3831802> Refine unicast polling intervals 471 472 Revision 1.91 2004/09/30 17:45:34 ksekar 473 <rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged 474 475 Revision 1.90 2004/09/25 00:22:13 ksekar 476 <rdar://problem/3815534> Crash in uDNS_RegisterService 477 478 Revision 1.89 2004/09/24 19:14:53 cheshire 479 Remove unused "extern mDNS mDNSStorage" 480 481 Revision 1.88 2004/09/23 20:48:15 ksekar 482 Clarify retransmission debugf messages. 483 484 Revision 1.87 2004/09/22 00:41:59 cheshire 485 Move tcp connection status codes into the legal range allocated for mDNS use 486 487 Revision 1.86 2004/09/21 23:40:11 ksekar 488 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure 489 490 Revision 1.85 2004/09/21 22:38:27 ksekar 491 <rdar://problem/3810286> PrimaryIP type uninitialized 492 493 Revision 1.84 2004/09/18 00:30:39 cheshire 494 <rdar://problem/3806643> Infinite loop in CheckServiceRegistrations 495 496 Revision 1.83 2004/09/17 00:31:51 cheshire 497 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' 498 499 Revision 1.82 2004/09/16 21:36:36 cheshire 500 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow() 501 Changes to add necessary locking calls around unicast DNS operations 502 503 Revision 1.81 2004/09/16 02:29:39 cheshire 504 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around 505 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService 506 507 Revision 1.80 2004/09/16 01:58:21 cheshire 508 Fix compiler warnings 509 510 Revision 1.79 2004/09/16 00:24:48 cheshire 511 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow() 512 513 Revision 1.78 2004/09/15 01:16:57 ksekar 514 <rdar://problem/3797598> mDNSResponder printing too many messages 515 516 Revision 1.77 2004/09/14 23:27:47 cheshire 517 Fix compile errors 518 519 Revision 1.76 2004/09/14 22:22:00 ksekar 520 <rdar://problem/3800920> Legacy browses broken against some BIND versions 521 522 Revision 1.75 2004/09/03 19:23:05 ksekar 523 <rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations 524 525 Revision 1.74 2004/09/02 17:49:04 ksekar 526 <rdar://problem/3785135>: 8A246: mDNSResponder crash while logging on restart 527 Fixed incorrect conversions, changed %s to %##s for all domain names. 528 529 Revision 1.73 2004/09/02 01:39:40 cheshire 530 For better readability, follow consistent convention that QR bit comes first, followed by OP bits 531 532 Revision 1.72 2004/09/01 03:59:29 ksekar 533 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows 534 535 Revision 1.71 2004/08/27 17:51:53 ksekar 536 Replaced unnecessary LogMsg with debugf. 537 538 Revision 1.70 2004/08/25 00:37:27 ksekar 539 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code 540 541 Revision 1.69 2004/08/18 17:35:41 ksekar 542 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways 543 544 Revision 1.68 2004/08/14 03:22:41 cheshire 545 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue 546 Add GetUserSpecifiedDDNSName() routine 547 Convert ServiceRegDomain to domainname instead of C string 548 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs 549 550 Revision 1.67 2004/08/13 23:46:58 cheshire 551 "asyncronous" -> "asynchronous" 552 553 Revision 1.66 2004/08/13 23:37:02 cheshire 554 Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with 555 "uDNS_info.UnicastHostname" for clarity 556 557 Revision 1.65 2004/08/13 23:12:32 cheshire 558 Don't use strcpy() and strlen() on "struct domainname" objects; 559 use AssignDomainName() and DomainNameLength() instead 560 (A "struct domainname" is a collection of packed pascal strings, not a C string.) 561 562 Revision 1.64 2004/08/13 23:01:05 cheshire 563 Use platform-independent mDNSNULL instead of NULL 564 565 Revision 1.63 2004/08/12 00:32:36 ksekar 566 <rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered 567 568 Revision 1.62 2004/08/10 23:19:14 ksekar 569 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery 570 Moved routines/constants to allow extern access for garbage collection daemon 571 572 Revision 1.61 2004/07/30 17:40:06 ksekar 573 <rdar://problem/3739115>: TXT Record updates not available for wide-area services 574 575 Revision 1.60 2004/07/29 19:40:05 ksekar 576 NATPMP Support - minor fixes and cleanup 577 578 Revision 1.59 2004/07/29 19:27:15 ksekar 579 NATPMP Support - minor fixes and cleanup 580 581 Revision 1.58 2004/07/27 07:35:38 shersche 582 fix syntax error, variables declared in the middle of a block 583 584 Revision 1.57 2004/07/26 22:49:30 ksekar 585 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client 586 587 Revision 1.56 2004/07/26 19:14:44 ksekar 588 <rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback 589 590 Revision 1.55 2004/07/15 19:01:33 ksekar 591 <rdar://problem/3681029>: Check for incorrect time comparisons 592 593 Revision 1.54 2004/06/22 02:10:53 ksekar 594 <rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS 595 596 Revision 1.53 2004/06/17 20:49:09 ksekar 597 <rdar://problem/3690436>: mDNSResponder crash while location cycling 598 599 Revision 1.52 2004/06/17 01:13:11 ksekar 600 <rdar://problem/3696616>: polling interval too short 601 602 Revision 1.51 2004/06/10 04:36:44 cheshire 603 Fix compiler warning 604 605 Revision 1.50 2004/06/10 00:55:13 ksekar 606 <rdar://problem/3686213>: crash on network reconnect 607 608 Revision 1.49 2004/06/10 00:10:50 ksekar 609 <rdar://problem/3686174>: Infinite Loop in uDNS_Execute() 610 611 Revision 1.48 2004/06/09 20:03:37 ksekar 612 <rdar://problem/3686163>: Incorrect copying of resource record in deregistration 613 614 Revision 1.47 2004/06/09 03:48:28 ksekar 615 <rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server 616 617 Revision 1.46 2004/06/09 01:44:30 ksekar 618 <rdar://problem/3681378> reworked Cache Record copy code 619 620 Revision 1.45 2004/06/08 18:54:47 ksekar 621 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility 622 623 Revision 1.44 2004/06/05 00:33:51 cheshire 624 <rdar://problem/3681029>: Check for incorrect time comparisons 625 626 Revision 1.43 2004/06/05 00:14:44 cheshire 627 Fix signed/unsigned and other compiler warnings 628 629 Revision 1.42 2004/06/04 22:36:16 ksekar 630 Properly set u->nextevent in uDNS_Execute 631 632 Revision 1.41 2004/06/04 08:58:29 ksekar 633 <rdar://problem/3668624>: Keychain integration for secure dynamic update 634 635 Revision 1.40 2004/06/03 03:09:58 ksekar 636 <rdar://problem/3668626>: Garbage Collection for Dynamic Updates 637 638 Revision 1.39 2004/06/01 23:46:50 ksekar 639 <rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports 640 641 Revision 1.38 2004/05/31 22:19:44 ksekar 642 <rdar://problem/3258021>: Feature: DNS server->client notification on 643 record changes (#7805) - revert to polling mode on setup errors 644 645 Revision 1.37 2004/05/28 23:42:37 ksekar 646 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805) 647 648 Revision 1.36 2004/05/18 23:51:25 cheshire 649 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers 650 651 Revision 1.35 2004/05/07 23:01:04 ksekar 652 Cleaned up list traversal in deriveGoodbyes - removed unnecessary 653 conditional assignment. 654 655 Revision 1.34 2004/05/05 18:26:12 ksekar 656 Periodically re-transmit questions if the send() fails. Include 657 internal questions in retransmission. 658 659 Revision 1.33 2004/05/05 17:40:06 ksekar 660 Removed prerequisite from deregistration update - it does not work for 661 shared records, and is unnecessary until we have more sophisticated 662 name conflict management. 663 664 Revision 1.32 2004/05/05 17:32:18 ksekar 665 Prevent registration of loopback interface caused by removal of 666 Multicast flag in interface structure. 667 668 Revision 1.31 2004/05/05 17:05:02 ksekar 669 Use LargeCacheRecord structs when pulling records off packets 670 671 Revision 1.30 2004/04/16 21:33:27 ksekar 672 Fixed bug in processing GetZoneData responses that do not use BIND formatting. 673 674 Revision 1.29 2004/04/15 20:03:13 ksekar 675 Clarified log message when pulling bad resource records off packet. 676 677 Revision 1.28 2004/04/15 00:51:28 bradley 678 Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers. 679 Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers. 680 681 Revision 1.27 2004/04/14 23:09:28 ksekar 682 Support for TSIG signed dynamic updates. 683 684 Revision 1.26 2004/04/14 19:36:05 ksekar 685 Fixed memory corruption error in deriveGoodbyes. 686 687 Revision 1.25 2004/04/14 04:07:11 ksekar 688 Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine. 689 690 Revision 1.24 2004/04/08 09:41:40 bradley 691 Added const to AuthRecord in deadvertiseIfCallback to match callback typedef. 692 693 Revision 1.23 2004/03/24 00:29:45 ksekar 694 Make it safe to call StopQuery in a unicast question callback 695 696 Revision 1.22 2004/03/19 10:11:09 bradley 697 Added AuthRecord * cast from umalloc for C++ builds. 698 699 Revision 1.21 2004/03/15 02:03:45 bradley 700 Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead 701 of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++. 702 703 Revision 1.20 2004/03/13 02:07:26 ksekar 704 <rdar://problem/3192546>: DynDNS: Dynamic update of service records 705 706 Revision 1.19 2004/03/13 01:57:33 ksekar 707 <rdar://problem/3192546>: DynDNS: Dynamic update of service records 708 709 Revision 1.18 2004/02/21 08:34:15 bradley 710 Added casts from void * to specific type for C++ builds. Changed void * l-value cast 711 r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error. 712 713 Revision 1.17 2004/02/21 02:06:24 cheshire 714 Can't use anonymous unions -- they're non-standard and don't work on all compilers 715 716 Revision 1.16 2004/02/12 01:51:45 cheshire 717 Don't try to send uDNS queries unless we have at least one uDNS server available 718 719 Revision 1.15 2004/02/10 03:02:46 cheshire 720 Fix compiler warning 721 722 Revision 1.14 2004/02/06 23:04:19 ksekar 723 Basic Dynamic Update support via mDNS_Register (dissabled via 724 UNICAST_REGISTRATION #define) 725 726 Revision 1.13 2004/02/03 22:15:01 ksekar 727 Fixed nameToAddr error check: don't abort state machine on nxdomain error. 728 729 Revision 1.12 2004/02/03 19:47:36 ksekar 730 Added an asynchronous state machine mechanism to uDNS.c, including 731 calls to find the parent zone for a domain name. Changes include code 732 in repository previously dissabled via "#if 0 incomplete". Codepath 733 is currently unused, and will be called to create update records, etc. 734 735 Revision 1.11 2004/01/30 02:12:30 ksekar 736 Changed uDNS_ReceiveMsg() to correctly return void. 737 738 Revision 1.10 2004/01/29 02:59:17 ksekar 739 Unicast DNS: Changed from a resource record oriented question/response 740 matching to packet based matching. New callback architecture allows 741 collections of records in a response to be processed differently 742 depending on the nature of the request, and allows the same structure 743 to be used for internal and client-driven queries with different processing needs. 744 745 Revision 1.9 2004/01/28 20:20:45 ksekar 746 Unified ActiveQueries and ActiveInternalQueries lists, using a flag to 747 demux them. Check-in includes work-in-progress code, #ifdef'd out. 748 749 Revision 1.8 2004/01/28 02:30:07 ksekar 750 Added default Search Domains to unicast browsing, controlled via 751 Networking sharing prefs pane. Stopped sending unicast messages on 752 every interface. Fixed unicast resolving via mach-port API. 753 754 Revision 1.7 2004/01/27 20:15:22 cheshire 755 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53 756 757 Revision 1.6 2004/01/24 23:47:17 cheshire 758 Use mDNSOpaque16fromIntVal() instead of shifting and masking 759 760 Revision 1.5 2004/01/24 04:59:15 cheshire 761 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again 762 763 Revision 1.4 2004/01/24 04:19:26 cheshire 764 Restore overwritten checkin 1.2 765 766 Revision 1.3 2004/01/23 23:23:15 ksekar 767 Added TCP support for truncated unicast messages. 768 769 Revision 1.2 2004/01/22 03:48:41 cheshire 770 Make sure uDNS client doesn't accidentally use query ID zero 771 772 Revision 1.1 2003/12/13 03:05:27 ksekar 773 <rdar://problem/3192548>: DynDNS: Unicast query of service records 774 775 */ 776 777 #pragma ident "%Z%%M% %I% %E% SMI" 778 779 #include "uDNS.h" 780 781 #if(defined(_MSC_VER)) 782 // Disable "assignment within conditional expression". 783 // Other compilers understand the convention that if you place the assignment expression within an extra pair 784 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary. 785 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal 786 // to the compiler that the assignment is intentional, we have to just turn this warning off completely. 787 #pragma warning(disable:4706) 788 #endif 789 790 #define umalloc(x) mDNSPlatformMemAllocate(x) // short hands for common routines 791 #define ufree(x) mDNSPlatformMemFree(x) 792 #define ubzero(x,y) mDNSPlatformMemZero(x,y) 793 #define umemcpy(x, y, l) mDNSPlatformMemCopy(y, x, l) // uses memcpy(2) arg ordering 794 795 // Asynchronous operation types 796 797 typedef enum 798 { 799 zoneDataResult 800 // other async. operation names go here 801 } AsyncOpResultType; 802 803 typedef struct 804 { 805 domainname zoneName; 806 mDNSAddr primaryAddr; 807 mDNSu16 zoneClass; 808 mDNSIPPort llqPort; 809 mDNSIPPort updatePort; 810 } zoneData_t; 811 812 // other async. result struct defs go here 813 814 typedef struct 815 { 816 AsyncOpResultType type; 817 zoneData_t zoneData; 818 // other async result structs go here 819 } AsyncOpResult; 820 821 typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result); 822 823 824 // Private Function Prototypes 825 // Note: In general, functions are ordered such that they do not require forward declarations. 826 // However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls 827 // foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier 828 // read top-to-bottom.) 829 830 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n); 831 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m); 832 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo); 833 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID); 834 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr); 835 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs); 836 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs); 837 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result); 838 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive); 839 mDNSlocal void RestartQueries(mDNS *m); 840 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer); 841 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context); 842 843 // *************************************************************************** 844 #if COMPILER_LIKES_PRAGMA_MARK 845 #pragma mark - Temporary workaround 846 #endif 847 848 // 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe 849 // The platform function is now called mDNSPlatformRawTime(), and 850 // mDNSPlatformTimeNow() is defined here as a temporary workaround. 851 // This is a gross hack, and after this change has been tested for a while, 852 // all these calls should be replaced by simple references to m->timenow 853 854 mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m) 855 { 856 if (m->mDNS_busy && m->timenow) return(m->timenow); 857 LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock"); 858 859 // To get a quick and easy stack trace to find out *how* this routine 860 // is being called without holding main mDNS lock, uncomment the line below: 861 // *(long*)0=0; 862 863 return(mDNS_TimeNow(m)); 864 } 865 866 // *************************************************************************** 867 #if COMPILER_LIKES_PRAGMA_MARK 868 #pragma mark - General Utility Functions 869 #endif 870 871 // CountLabels() returns number of labels in name, excluding final root label 872 // (e.g. for "apple.com." CountLabels returns 2.) 873 mDNSlocal int CountLabels(const domainname *d) 874 { 875 int count = 0; 876 const mDNSu8 *ptr; 877 878 for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++; 879 return count; 880 } 881 882 mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u) 883 { 884 static mDNSBool randomized = mDNSfalse; 885 886 if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; } 887 if (u->NextMessageID == 0) u->NextMessageID++; 888 return mDNSOpaque16fromIntVal(u->NextMessageID++); 889 } 890 891 // unlink an AuthRecord from a linked list 892 mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr) 893 { 894 while (*list && *list != rr) list = &(*list)->next; 895 if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); } 896 LogMsg("ERROR: unlinkAR - no such active record %##s", rr->resrec.name->c); 897 return(mStatus_NoSuchRecord); 898 } 899 900 mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs) 901 { 902 uDNS_GlobalInfo *u = &m->uDNS_info; 903 ServiceRecordSet **p; 904 NATTraversalInfo *n = u->NATTraversals; 905 906 // verify that no NAT objects reference this service 907 while (n) 908 { 909 if (n->reg.ServiceRegistration == srs) 910 { 911 NATTraversalInfo *tmp = n; 912 n = n->next; 913 LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c); 914 FreeNATInfo(m, tmp); 915 } 916 else n = n->next; 917 } 918 919 for (p = &u->ServiceRegistrations; *p; p = &(*p)->next) 920 if (*p == srs) 921 { 922 ExtraResourceRecord *e; 923 *p = srs->next; 924 srs->next = mDNSNULL; 925 for (e=srs->Extras; e; e=e->next) 926 if (unlinkAR(&u->RecordRegistrations, &e->r)) 927 LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c); 928 return; 929 } 930 LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c); 931 } 932 933 mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q) 934 { 935 if (uDNS_IsActiveQuery(q, u)) 936 { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; } 937 938 q->next = u->ActiveQueries; 939 u->ActiveQueries = q; 940 } 941 942 // set retry timestamp for record with exponential backoff 943 // (for service record sets, use RR_SRV as representative for time checks 944 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) 945 { 946 rr->LastAPTime = mDNSPlatformTimeNow(m); 947 if (SendErr == mStatus_TransientErr || rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL) rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; 948 else if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL) rr->ThisAPInterval *= 2; 949 else if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL) rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL; 950 } 951 952 953 // *************************************************************************** 954 #if COMPILER_LIKES_PRAGMA_MARK 955 #pragma mark - Name Server List Management 956 #endif 957 958 mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d) 959 { 960 uDNS_GlobalInfo *u = &m->uDNS_info; 961 DNSServer *s, **p = &u->Servers; 962 963 mDNS_Lock(m); 964 if (!d) d = (domainname *)""; 965 966 while (*p) // Check if we already have this {server,domain} pair registered 967 { 968 if (mDNSSameAddress(&(*p)->addr, addr) && SameDomainName(&(*p)->domain, d)) 969 LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c); 970 p=&(*p)->next; 971 } 972 973 // allocate, add to list 974 s = umalloc(sizeof(*s)); 975 if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; } 976 s->addr = *addr; 977 s->del = mDNSfalse; 978 s->teststate = DNSServer_Untested; 979 AssignDomainName(&s->domain, d); 980 s->next = mDNSNULL; 981 *p = s; 982 983 end: 984 mDNS_Unlock(m); 985 } 986 987 mDNSexport void mDNS_DeleteDNSServers(mDNS *const m) 988 { 989 DNSServer *s; 990 mDNS_Lock(m); 991 992 s = m->uDNS_info.Servers; 993 m->uDNS_info.Servers = mDNSNULL; 994 while (s) 995 { 996 DNSServer *tmp = s; 997 s = s->next; 998 ufree(tmp); 999 } 1000 1001 mDNS_Unlock(m); 1002 } 1003 1004 // *************************************************************************** 1005 #if COMPILER_LIKES_PRAGMA_MARK 1006 #pragma mark - authorization management 1007 #endif 1008 1009 mDNSlocal uDNS_AuthInfo *GetAuthInfoForName(const uDNS_GlobalInfo *u, const domainname *name) 1010 { 1011 uDNS_AuthInfo *ptr; 1012 while (name->c[0]) 1013 { 1014 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next) 1015 if (SameDomainName(&ptr->zone, name)) return(ptr); 1016 name = (const domainname *)(name->c + 1 + name->c[0]); 1017 } 1018 return mDNSNULL; 1019 } 1020 1021 mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone) 1022 { 1023 uDNS_AuthInfo *ptr, *prev = mDNSNULL; 1024 1025 for (ptr = u->AuthInfoList; ptr; ptr = ptr->next) 1026 { 1027 if (SameDomainName(&ptr->zone, zone)) 1028 { 1029 if (prev) prev->next = ptr->next; 1030 else u->AuthInfoList = ptr->next; 1031 ufree(ptr); 1032 return; 1033 } 1034 prev = ptr; 1035 } 1036 } 1037 1038 mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret) 1039 { 1040 uDNS_AuthInfo *info; 1041 mDNSu8 keybuf[1024]; 1042 mDNSs32 keylen; 1043 uDNS_GlobalInfo *u = &m->uDNS_info; 1044 mStatus status = mStatus_NoError; 1045 1046 mDNS_Lock(m); 1047 1048 if (GetAuthInfoForName(u, zone)) DeleteAuthInfoForZone(u, zone); 1049 if (!key) goto exit; 1050 1051 info = (uDNS_AuthInfo*)umalloc(sizeof(*info)); 1052 if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; } 1053 ubzero(info, sizeof(*info)); 1054 AssignDomainName(&info->zone, zone); 1055 AssignDomainName(&info->keyname, key); 1056 1057 keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024); 1058 if (keylen < 0) 1059 { 1060 LogMsg("ERROR: mDNS_SetSecretForZone - could not convert shared secret %s from base64", sharedSecret); 1061 ufree(info); 1062 status = mStatus_UnknownErr; 1063 goto exit; 1064 } 1065 DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen); 1066 1067 // link into list 1068 info->next = m->uDNS_info.AuthInfoList; 1069 m->uDNS_info.AuthInfoList = info; 1070 exit: 1071 mDNS_Unlock(m); 1072 return status; 1073 } 1074 1075 // *************************************************************************** 1076 #if COMPILER_LIKES_PRAGMA_MARK 1077 #pragma mark - NAT Traversal 1078 #endif 1079 1080 mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str) 1081 { 1082 const domainlabel *l; 1083 domainlabel buf; 1084 1085 if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse; 1086 1087 for (l = (const domainlabel *)d; l->c[0]; l = (const domainlabel *)(l->c + l->c[0]+1)) 1088 if (SameDomainLabel(l->c, buf.c)) return mDNStrue; 1089 return mDNSfalse; 1090 } 1091 1092 // allocate struct, link into global list, initialize 1093 mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback) 1094 { 1095 uDNS_GlobalInfo *u = &m->uDNS_info; 1096 NATTraversalInfo *info = umalloc(sizeof(NATTraversalInfo)); 1097 if (!info) { LogMsg("ERROR: malloc"); return mDNSNULL; } 1098 ubzero(info, sizeof(NATTraversalInfo)); 1099 info->next = u->NATTraversals; 1100 u->NATTraversals = info; 1101 info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY; 1102 info->op = op; 1103 info->state = NATState_Init; 1104 info->ReceiveResponse = callback; 1105 info->PublicPort.NotAnInteger = 0; 1106 info->Router = u->Router; 1107 return info; 1108 } 1109 1110 // unlink from list, deallocate 1111 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n) 1112 { 1113 NATTraversalInfo *ptr, *prev = mDNSNULL; 1114 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations; 1115 1116 // Verify that object is not referenced by any services 1117 while (s) 1118 { 1119 if (s->uDNS_info.NATinfo == n) 1120 { 1121 LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s->RR_SRV.resrec.name->c); 1122 s->uDNS_info.NATinfo = mDNSNULL; 1123 } 1124 s = s->next; 1125 } 1126 1127 if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL; 1128 ptr = m->uDNS_info.NATTraversals; 1129 while (ptr) 1130 { 1131 if (ptr == n) 1132 { 1133 if (prev) prev->next = ptr->next; 1134 else m->uDNS_info.NATTraversals = ptr->next; 1135 ufree(n); 1136 return mDNStrue; 1137 } 1138 prev = ptr; 1139 ptr = ptr->next; 1140 } 1141 LogMsg("FreeNATInfo: NATTraversalInfo not found in list"); 1142 return mDNSfalse; 1143 } 1144 1145 mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m) 1146 { 1147 mStatus err; 1148 uDNS_GlobalInfo *u = &m->uDNS_info; 1149 1150 if (info->state != NATState_Request && info->state != NATState_Refresh) 1151 { LogMsg("SendNATMsg: Bad state %d", info->state); return; } 1152 1153 if (u->Router.ip.v4.NotAnInteger) 1154 { 1155 // send msg if we have a router 1156 const mDNSu8 *end = (mDNSu8 *)&info->request; 1157 if (info->op == NATOp_AddrRequest) end += sizeof(NATAddrRequest); 1158 else end += sizeof(NATPortMapRequest); 1159 1160 err = mDNSPlatformSendUDP(m, &info->request, end, 0, &u->Router, NATPMPPort); 1161 if (!err) (info->ntries++); // don't increment attempt counter if the send failed 1162 } 1163 1164 // set retry 1165 if (info->RetryInterval < NATMAP_INIT_RETRY) info->RetryInterval = NATMAP_INIT_RETRY; 1166 else if (info->RetryInterval * 2 > NATMAP_MAX_RETRY) info->RetryInterval = NATMAP_MAX_RETRY; 1167 else info->RetryInterval *= 2; 1168 info->retry = mDNSPlatformTimeNow(m) + info->RetryInterval; 1169 } 1170 1171 mDNSlocal mDNSBool ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len) 1172 { 1173 mStatus err = mStatus_NoError; 1174 AuthRecord *rr = mDNSNULL; 1175 NATAddrReply *response = (NATAddrReply *)pkt; 1176 mDNSAddr addr; 1177 1178 if (n->state != NATState_Request) 1179 { 1180 LogMsg("ReceiveNATAddrResponse: bad state %d", n->state); 1181 return mDNSfalse; 1182 } 1183 1184 rr = n->reg.RecordRegistration; 1185 if (!rr) 1186 { 1187 LogMsg("ReceiveNATAddrResponse: registration cancelled"); 1188 return mDNSfalse; 1189 } 1190 1191 addr.type = mDNSAddrType_IPv4; 1192 addr.ip.v4 = rr->resrec.rdata->u.ipv4; 1193 1194 if (!pkt) // timeout 1195 { 1196 #ifdef _LEGACY_NAT_TRAVERSAL_ 1197 err = LNT_GetPublicIP(&addr.ip.v4); 1198 if (err) goto end; 1199 else n->state = NATState_Legacy; 1200 #else 1201 debugf("ReceiveNATAddrResponse: timeout"); 1202 err = mStatus_NATTraversal; 1203 goto end; 1204 #endif // _LEGACY_NAT_TRAVERSAL_ 1205 } 1206 else 1207 { 1208 if (len < sizeof(*response)) 1209 { 1210 LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len); 1211 return mDNSfalse; 1212 } 1213 if (response->vers != NATMAP_VERS) 1214 { 1215 LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt[0], NATMAP_VERS); 1216 return mDNSfalse; 1217 } 1218 if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK)) 1219 { 1220 LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode); 1221 return mDNSfalse; 1222 } 1223 if (response->err.NotAnInteger) 1224 { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; } 1225 1226 addr.ip.v4 = response->PubAddr; 1227 n->state = NATState_Established; 1228 } 1229 1230 if (IsPrivateV4Addr(&addr)) 1231 { 1232 LogMsg("ReceiveNATAddrResponse: Double NAT"); 1233 err = mStatus_DoubleNAT; 1234 goto end; 1235 } 1236 1237 end: 1238 if (err) 1239 { 1240 FreeNATInfo(m, n); 1241 if (rr) 1242 { 1243 rr->uDNS_info.NATinfo = mDNSNULL; 1244 rr->uDNS_info.state = regState_Unregistered; // note that rr is not yet in global list 1245 rr->RecordCallback(m, rr, mStatus_NATTraversal); 1246 // note - unsafe to touch rr after callback 1247 } 1248 return mDNStrue; 1249 } 1250 else LogOperation("Received public IP address %d.%d.%d.%d from NAT.", addr.ip.v4.b[0], addr.ip.v4.b[1], addr.ip.v4.b[2], addr.ip.v4.b[3]); 1251 rr->resrec.rdata->u.ipv4 = addr.ip.v4; // replace rdata w/ public address 1252 uDNS_RegisterRecord(m, rr); 1253 return mDNStrue; 1254 } 1255 1256 1257 mDNSlocal void StartGetPublicAddr(mDNS *m, AuthRecord *AddressRec) 1258 { 1259 NATAddrRequest *req; 1260 uDNS_GlobalInfo *u = &m->uDNS_info; 1261 1262 NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse); 1263 if (!info) { uDNS_RegisterRecord(m, AddressRec); return; } 1264 AddressRec->uDNS_info.NATinfo = info; 1265 info->reg.RecordRegistration = AddressRec; 1266 info->state = NATState_Request; 1267 1268 // format message 1269 req = &info->request.AddrReq; 1270 req->vers = NATMAP_VERS; 1271 req->opcode = NATOp_AddrRequest; 1272 1273 if (!u->Router.ip.v4.NotAnInteger) 1274 { 1275 debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY); 1276 return; 1277 } 1278 1279 SendNATMsg(info, m); 1280 } 1281 1282 1283 mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m) 1284 { 1285 n->state = NATState_Refresh; 1286 n->RetryInterval = NATMAP_INIT_RETRY; 1287 n->ntries = 0; 1288 SendNATMsg(n, m); 1289 } 1290 1291 mDNSlocal void LLQNatMapComplete(mDNS *m) 1292 { 1293 uDNS_GlobalInfo *u = &m->uDNS_info; 1294 LLQ_Info *llqInfo; 1295 NATTraversalInfo *n = u->LLQNatInfo; 1296 1297 if (!n) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; } 1298 if (n->state != NATState_Established && n->state != NATState_Legacy && n->state != NATState_Error) 1299 { LogMsg("LLQNatMapComplete - bad nat state %d", n->state); return; } 1300 1301 u->CurrentQuery = u->ActiveQueries; 1302 while (u->CurrentQuery) 1303 { 1304 DNSQuestion *q = u->CurrentQuery; 1305 u->CurrentQuery = u->CurrentQuery->next; 1306 llqInfo = q->uDNS_info.llq; 1307 if (q->LongLived && llqInfo->state == LLQ_NatMapWait) 1308 { 1309 if (n->state == NATState_Error) 1310 { 1311 llqInfo->NATMap = mDNSfalse; 1312 llqInfo->question->uDNS_info.responseCallback = llqResponseHndlr; 1313 llqInfo->state = LLQ_Poll; 1314 llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll 1315 llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL; 1316 } 1317 else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); } 1318 } 1319 } 1320 } 1321 1322 mDNSlocal mDNSBool ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len) 1323 { 1324 ServiceRecordSet *srs = n->reg.ServiceRegistration; 1325 mDNSIPPort priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4; 1326 mDNSu32 lease; 1327 mDNSBool deletion = !n->request.PortReq.lease.NotAnInteger; 1328 NATPortMapReply *reply = (NATPortMapReply *)pkt; 1329 mDNSu8 *service = srs ? srs->RR_SRV.resrec.name->c : (mDNSu8 *)"\016LLQ event port"; 1330 1331 if (n->state != NATState_Request && n->state != NATState_Refresh) 1332 { LogMsg("ReceivePortMapReply (%##s): bad state %d", service, n->state); return mDNSfalse; } 1333 1334 if (!pkt && !deletion) // timeout 1335 { 1336 #ifdef _LEGACY_NAT_TRAVERSAL_ 1337 mDNSIPPort pub; 1338 int ntries = 0; 1339 mStatus err; 1340 mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")); 1341 1342 pub = priv; // initially request priv == pub 1343 while (1) 1344 { 1345 err = LNT_MapPort(priv, pub, tcp); 1346 if (!err) 1347 { 1348 n->PublicPort = pub; 1349 n->state = NATState_Legacy; 1350 goto end; 1351 } 1352 else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES) 1353 { 1354 n->state = NATState_Error; 1355 goto end; 1356 } 1357 else 1358 { 1359 // the mapping we want is taken - try a random port 1360 mDNSu16 RandPort = mDNSRandom(DYN_PORT_MAX - DYN_PORT_MIN) + DYN_PORT_MIN; 1361 pub = mDNSOpaque16fromIntVal(RandPort); 1362 } 1363 } 1364 #else 1365 goto end; 1366 #endif // _LEGACY_NAT_TRAVERSAL_ 1367 } 1368 1369 if (len < sizeof(*reply)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); return mDNSfalse; } 1370 if (reply->vers != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received version %d (expect version %d)", pkt[0], NATMAP_VERS); return mDNSfalse; } 1371 if (reply->opcode != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); return mDNSfalse; } 1372 if (reply->err.NotAnInteger) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply->err)); return mDNSfalse; } 1373 if (priv.NotAnInteger != reply->priv.NotAnInteger) return mDNSfalse; // packet does not match this request 1374 1375 if (!srs && n != m->uDNS_info.LLQNatInfo) 1376 { 1377 LogMsg("ReceivePortMapReply: registration cancelled"); //!!!KRS change to debugf before checkin 1378 FreeNATInfo(m, n); 1379 return mDNStrue; 1380 } 1381 1382 if (deletion) { n->state = NATState_Deleted; return mDNStrue; } 1383 1384 lease = (mDNSu32)mDNSVal32(reply->lease); 1385 if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond; 1386 1387 if (n->state == NATState_Refresh && reply->pub.NotAnInteger != n->PublicPort.NotAnInteger) 1388 LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(reply->pub)); 1389 // this should never happen 1390 // !!!KRS to be defensive, use SRVChanged flag on service and deregister here 1391 1392 n->PublicPort = reply->pub; 1393 if (reply->pub.NotAnInteger != n->request.PortReq.pub.NotAnInteger) n->request.PortReq.pub = reply->pub; // set message buffer for refreshes 1394 1395 n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2); // retry half way to expiration 1396 1397 if (n->state == NATState_Refresh) { n->state = NATState_Established; return mDNStrue; } 1398 n->state = NATState_Established; 1399 1400 end: 1401 if (n->state != NATState_Established && n->state != NATState_Legacy) 1402 { 1403 LogMsg("NAT Port Mapping (%##s): timeout", service); 1404 if (pkt) LogMsg("!!! timeout with non-null packet"); 1405 n->state = NATState_Error; 1406 if (srs) 1407 { 1408 uDNS_HostnameInfo *hi = m->uDNS_info.Hostnames; 1409 while (hi) 1410 { 1411 if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) break; 1412 else hi = hi->next; 1413 } 1414 1415 if (hi) 1416 { 1417 debugf("Port map failed for service %##s - using IPv6 service target", service); 1418 srs->uDNS_info.NATinfo = mDNSNULL; 1419 FreeNATInfo(m, n); 1420 goto register_service; 1421 } 1422 else srs->uDNS_info.state = regState_NATError; 1423 } 1424 else LLQNatMapComplete(m); 1425 return mDNStrue; 1426 } 1427 else LogOperation("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort)); 1428 1429 if (!srs) { LLQNatMapComplete(m); return mDNStrue; } 1430 1431 register_service: 1432 if (srs->uDNS_info.ns.ip.v4.NotAnInteger) SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update 1433 else 1434 { 1435 srs->uDNS_info.state = regState_FetchingZoneData; 1436 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs); 1437 } 1438 return mDNStrue; 1439 } 1440 1441 mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port) 1442 { 1443 NATPortMapRequest *req = &info->request.PortReq; 1444 1445 req->vers = NATMAP_VERS; 1446 req->opcode = info->op; 1447 req->unused.NotAnInteger = 0; 1448 req->priv = port; 1449 req->pub = port; 1450 req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE); 1451 } 1452 1453 mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info) 1454 { 1455 if (!m->uDNS_info.Router.ip.v4.NotAnInteger) 1456 { 1457 debugf("No router. Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY); 1458 info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY; 1459 info->RetryInterval = NATMAP_INIT_RETRY; 1460 return; 1461 } 1462 SendNATMsg(info, m); 1463 return; 1464 } 1465 1466 mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs) 1467 { 1468 NATOp_t op; 1469 NATTraversalInfo *info; 1470 1471 if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP; 1472 else if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP; 1473 else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; } 1474 1475 if (srs->uDNS_info.NATinfo) { LogMsg("Error: StartNATPortMap - NAT info already initialized!"); FreeNATInfo(m, srs->uDNS_info.NATinfo); } 1476 info = AllocNATInfo(m, op, ReceivePortMapReply); 1477 srs->uDNS_info.NATinfo = info; 1478 info->reg.ServiceRegistration = srs; 1479 info->state = NATState_Request; 1480 1481 FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port); 1482 SendInitialPMapReq(m, info); 1483 return; 1484 1485 error: 1486 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs); 1487 } 1488 1489 mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs) 1490 { 1491 if (nat->state == NATState_Established) // let other edge-case states expire for simplicity 1492 { 1493 // zero lease 1494 nat->request.PortReq.lease.NotAnInteger = 0; 1495 nat->state = NATState_Request; 1496 SendNATMsg(nat, m); 1497 } 1498 #ifdef _LEGACY_NAT_TRAVERSAL_ 1499 else if (nat->state == NATState_Legacy) 1500 { 1501 mStatus err = mStatus_NoError; 1502 mDNSBool tcp = srs ? DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse; 1503 err = LNT_UnmapPort(nat->PublicPort, tcp); 1504 if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err); 1505 } 1506 #else 1507 (void)srs; // unused 1508 #endif // _LEGACY_NAT_TRAVERSAL_ 1509 } 1510 1511 mDNSlocal void StartLLQNatMap(mDNS *m) 1512 { 1513 NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply); 1514 uDNS_GlobalInfo *u = &m->uDNS_info; 1515 1516 u->LLQNatInfo = info; 1517 1518 info->reg.RecordRegistration = mDNSNULL; 1519 info->reg.ServiceRegistration = mDNSNULL; 1520 info->state = NATState_Request; 1521 FormatPortMaprequest(info, m->UnicastPort4); 1522 SendInitialPMapReq(m, info); 1523 return; 1524 } 1525 1526 // if LLQ NAT context unreferenced, delete the mapping 1527 mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m) 1528 { 1529 NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo; 1530 DNSQuestion *q; 1531 1532 if (!nat) return; 1533 1534 for (q = m->uDNS_info.ActiveQueries; q; q = q->next) 1535 if (q->LongLived && q->uDNS_info.llq->NATMap) return; 1536 1537 //to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration 1538 if (nat->state == NATState_Established || nat->state == NATState_Legacy) 1539 DeleteNATPortMapping(m, nat, mDNSNULL); // for simplicity we allow other states to expire 1540 FreeNATInfo(m, nat); // note: this clears the global LLQNatInfo pointer 1541 } 1542 1543 // *************************************************************************** 1544 #if COMPILER_LIKES_PRAGMA_MARK 1545 #pragma mark - host name and interface management 1546 #endif 1547 1548 // if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname 1549 // for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query 1550 mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainname *dst) 1551 { 1552 uDNS_HostnameInfo *hi = u->Hostnames; 1553 (void)srv; // unused 1554 1555 dst->c[0] = 0; 1556 while (hi) 1557 { 1558 if (hi->arv4 && (hi->arv4->uDNS_info.state == regState_Registered || hi->arv4->uDNS_info.state == regState_Refresh)) 1559 { 1560 AssignDomainName(dst, hi->arv4->resrec.name); 1561 return mDNStrue; 1562 } 1563 if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) 1564 { 1565 AssignDomainName(dst, hi->arv4->resrec.name); 1566 return mDNStrue; 1567 } 1568 hi = hi->next; 1569 } 1570 1571 if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; } 1572 return mDNSfalse; 1573 } 1574 1575 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) 1576 { 1577 uDNS_GlobalInfo *u = &m->uDNS_info; 1578 ExtraResourceRecord *e; 1579 1580 // Target change if: 1581 // We have a target and were previously waiting for one, or 1582 // We had a target and no longer do, or 1583 // The target has changed 1584 1585 domainname newtarget; 1586 domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target; 1587 mDNSBool HaveTarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget); 1588 mDNSBool TargetChanged = (HaveTarget && srs->uDNS_info.state == regState_NoTarget) || (curtarget->c[0] && !HaveTarget) || !SameDomainName(curtarget, &newtarget); 1589 mDNSBool HaveZoneData = srs->uDNS_info.ns.ip.v4.NotAnInteger ? mDNStrue : mDNSfalse; 1590 1591 // Nat state change if: 1592 // We were behind a NAT, and now we are behind a new NAT, or 1593 // We're not behind a NAT but our port was previously mapped to a different public port 1594 // We were not behind a NAT and now we are 1595 1596 NATTraversalInfo *nat = srs->uDNS_info.NATinfo; 1597 mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port; 1598 mDNSBool NATChanged = mDNSfalse; 1599 mDNSBool NowBehindNAT = port.NotAnInteger && IsPrivateV4Addr(&u->AdvertisedV4); 1600 mDNSBool WereBehindNAT = nat != mDNSNULL; 1601 mDNSBool NATRouterChanged = nat && nat->Router.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger; 1602 mDNSBool PortWasMapped = nat && (nat->state == NATState_Established || nat->state == NATState_Legacy) && nat->PublicPort.NotAnInteger != port.NotAnInteger; 1603 1604 if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue; 1605 else if (!NowBehindNAT && PortWasMapped) NATChanged = mDNStrue; 1606 else if (!WereBehindNAT && NowBehindNAT) NATChanged = mDNStrue; 1607 1608 if (!TargetChanged && !NATChanged) return; 1609 1610 debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d", 1611 srs->RR_SRV.resrec.name->c, HaveZoneData, TargetChanged, HaveTarget, NowBehindNAT, WereBehindNAT, NATRouterChanged, PortWasMapped); 1612 1613 switch(srs->uDNS_info.state) 1614 { 1615 case regState_FetchingZoneData: 1616 case regState_Cancelled: 1617 case regState_DeregPending: 1618 case regState_DeregDeferred: 1619 case regState_Unregistered: 1620 case regState_NATMap: 1621 case regState_ExtraQueued: 1622 // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is) 1623 // or is in the process of, or has already been, deregistered 1624 return; 1625 1626 case regState_Pending: 1627 case regState_Refresh: 1628 case regState_UpdatePending: 1629 // let the in-flight operation complete before updating 1630 srs->uDNS_info.SRVUpdateDeferred = mDNStrue; 1631 return; 1632 1633 case regState_NATError: 1634 if (!NATChanged) return; 1635 // if nat changed, register if we have a target (below) 1636 1637 case regState_NoTarget: 1638 if (HaveTarget) 1639 { 1640 debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c); 1641 if (!HaveZoneData) 1642 { 1643 srs->uDNS_info.state = regState_FetchingZoneData; 1644 startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs); 1645 } 1646 else 1647 { 1648 if (nat && (NATChanged || !NowBehindNAT)) { srs->uDNS_info.NATinfo = mDNSNULL; FreeNATInfo(m, nat); } 1649 if (NATChanged && NowBehindNAT) { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); } 1650 else SendServiceRegistration(m, srs); 1651 } 1652 } 1653 return; 1654 1655 case regState_Registered: 1656 // target or nat changed. deregister service. upon completion, we'll look for a new target 1657 debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c); 1658 for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered 1659 srs->uDNS_info.SRVChanged = mDNStrue; 1660 SendServiceDeregistration(m, srs); 1661 return; 1662 } 1663 } 1664 1665 mDNSlocal void UpdateSRVRecords(mDNS *m) 1666 { 1667 ServiceRecordSet *srs; 1668 1669 for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs); 1670 } 1671 1672 mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 1673 { 1674 uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext; 1675 1676 if (result == mStatus_MemFree) 1677 { 1678 if (hi) 1679 { 1680 if (hi->arv4 == rr) hi->arv4 = mDNSNULL; 1681 else if (hi->arv4 == rr) hi->arv6 = mDNSNULL; 1682 rr->RecordContext = mDNSNULL; 1683 if (!hi->arv4 && !hi->arv6) ufree(hi); // free hi when both v4 and v6 AuthRecs deallocated 1684 } 1685 ufree(rr); 1686 return; 1687 } 1688 1689 if (result) 1690 { 1691 // don't unlink or free - we can retry when we get a new address/router 1692 if (rr->resrec.rrtype == kDNSType_A) 1693 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); 1694 else 1695 LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); 1696 if (!hi) { ufree(rr); return; } 1697 if (rr->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!"); 1698 1699 if ((!hi->arv4 || hi->arv4->uDNS_info.state == regState_Unregistered) && 1700 (!hi->arv6 || hi->arv6->uDNS_info.state == regState_Unregistered)) 1701 { 1702 // only deliver status if both v4 and v6 fail 1703 rr->RecordContext = (void *)hi->StatusContext; 1704 if (hi->StatusCallback) 1705 hi->StatusCallback(m, rr, result); // client may NOT make API calls here 1706 rr->RecordContext = (void *)hi; 1707 } 1708 return; 1709 } 1710 // register any pending services that require a target 1711 UpdateSRVRecords(m); 1712 1713 // Deliver success to client 1714 if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; } 1715 if (rr->resrec.rrtype == kDNSType_A) 1716 LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); 1717 else 1718 LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); 1719 1720 rr->RecordContext = (void *)hi->StatusContext; 1721 if (hi->StatusCallback) 1722 hi->StatusCallback(m, rr, result); // client may NOT make API calls here 1723 rr->RecordContext = (void *)hi; 1724 } 1725 1726 // register record or begin NAT traversal 1727 mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h) 1728 { 1729 uDNS_GlobalInfo *u = &m->uDNS_info; 1730 1731 if (u->AdvertisedV4.ip.v4.NotAnInteger && h->arv4->uDNS_info.state == regState_Unregistered) 1732 { 1733 if (IsPrivateV4Addr(&u->AdvertisedV4)) 1734 StartGetPublicAddr(m, h->arv4); 1735 else 1736 { 1737 LogMsg("Advertising %##s IP %.4a", h->arv4->resrec.name->c, &u->AdvertisedV4.ip.v4); 1738 uDNS_RegisterRecord(m, h->arv4); 1739 } 1740 } 1741 if (u->AdvertisedV6.ip.v6.b[0] && h->arv6->uDNS_info.state == regState_Unregistered) 1742 { 1743 LogMsg("Advertising %##s IP %.16a", h->arv4->resrec.name->c, &u->AdvertisedV6.ip.v6); 1744 uDNS_RegisterRecord(m, h->arv6); 1745 } 1746 } 1747 1748 mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) 1749 { 1750 const domainname *pktname = &answer->rdata->u.name; 1751 domainname *storedname = &m->uDNS_info.StaticHostname; 1752 uDNS_HostnameInfo *h = m->uDNS_info.Hostnames; 1753 1754 (void)question; 1755 1756 debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed"); 1757 if (AddRecord && !SameDomainName(pktname, storedname)) 1758 { 1759 AssignDomainName(storedname, pktname); 1760 while (h) 1761 { 1762 if ((h->arv4 && (h->arv4->uDNS_info.state == regState_FetchingZoneData || h->arv4->uDNS_info.state == regState_Pending || h->arv4->uDNS_info.state == regState_NATMap)) || 1763 (h->arv6 && (h->arv6->uDNS_info.state == regState_FetchingZoneData || h->arv6->uDNS_info.state == regState_Pending))) 1764 { 1765 // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds 1766 m->uDNS_info.DelaySRVUpdate = mDNStrue; 1767 m->uDNS_info.NextSRVUpdate = mDNSPlatformTimeNow(m) + (5 * mDNSPlatformOneSecond); 1768 return; 1769 } 1770 h = h->next; 1771 } 1772 UpdateSRVRecords(m); 1773 } 1774 else if (!AddRecord && SameDomainName(pktname, storedname)) 1775 { 1776 storedname->c[0] = 0; 1777 UpdateSRVRecords(m); 1778 } 1779 } 1780 1781 mDNSlocal void GetStaticHostname(mDNS *m) 1782 { 1783 char buf[MAX_ESCAPED_DOMAIN_NAME]; 1784 DNSQuestion *q = &m->uDNS_info.ReverseMap; 1785 mDNSu8 *ip = m->uDNS_info.AdvertisedV4.ip.v4.b; 1786 mStatus err; 1787 1788 if (m->uDNS_info.ReverseMapActive) 1789 { 1790 uDNS_StopQuery(m, q); 1791 m->uDNS_info.ReverseMapActive = mDNSfalse; 1792 } 1793 1794 m->uDNS_info.StaticHostname.c[0] = 0; 1795 if (!m->uDNS_info.AdvertisedV4.ip.v4.NotAnInteger) return; 1796 ubzero(q, sizeof(*q)); 1797 mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]); 1798 if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; } 1799 1800 q->InterfaceID = mDNSInterface_Any; 1801 q->Target = zeroAddr; 1802 q->qtype = kDNSType_PTR; 1803 q->qclass = kDNSClass_IN; 1804 q->LongLived = mDNSfalse; 1805 q->ExpectUnique = mDNSfalse; 1806 q->ForceMCast = mDNSfalse; 1807 q->QuestionCallback = FoundStaticHostname; 1808 q->QuestionContext = mDNSNULL; 1809 1810 err = uDNS_StartQuery(m, q); 1811 if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err); 1812 else m->uDNS_info.ReverseMapActive = mDNStrue; 1813 } 1814 1815 mDNSlocal void AssignHostnameInfoAuthRecord(mDNS *m, uDNS_HostnameInfo *hi, int type) 1816 { 1817 AuthRecord **dst = (type == mDNSAddrType_IPv4 ? &hi->arv4 : &hi->arv6); 1818 AuthRecord *ar = umalloc(sizeof(*ar)); 1819 uDNS_GlobalInfo *u = &m->uDNS_info; 1820 1821 if (type != mDNSAddrType_IPv4 && type != mDNSAddrType_IPv6) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - bad type %d", type); return; } 1822 if (!ar) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - malloc"); return; } 1823 1824 mDNS_SetupResourceRecord(ar, mDNSNULL, 0, type == mDNSAddrType_IPv4 ? kDNSType_A : kDNSType_AAAA, 1, kDNSRecordTypeKnownUnique, HostnameCallback, hi); 1825 AssignDomainName(ar->resrec.name, &hi->fqdn); 1826 1827 // only set RData if we have a valid IP 1828 if (type == mDNSAddrType_IPv4 && u->AdvertisedV4.ip.v4.NotAnInteger) 1829 { 1830 if (u->MappedV4.ip.v4.NotAnInteger) ar->resrec.rdata->u.ipv4 = u->MappedV4.ip.v4; 1831 else ar->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4; 1832 } 1833 else if (type == mDNSAddrType_IPv6 && u->AdvertisedV6.ip.v6.b[0]) 1834 { 1835 ar->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6; 1836 } 1837 1838 ar->uDNS_info.state = regState_Unregistered; 1839 1840 if (*dst) 1841 { 1842 LogMsg("ERROR: AssignHostnameInfoAuthRecord - overwriting %s AuthRec", type == mDNSAddrType_IPv4 ? "IPv4" : "IPv6"); 1843 unlinkAR(&u->RecordRegistrations, *dst); 1844 (*dst)->RecordContext = mDNSNULL; // defensively clear backpointer to avoid doubly-referenced context 1845 } 1846 1847 *dst = ar; 1848 } 1849 1850 1851 // Deregister hostnames and register new names for each host domain with the current global 1852 // values for the hostlabel and primary IP address 1853 mDNSlocal void UpdateHostnameRegistrations(mDNS *m) 1854 { 1855 uDNS_GlobalInfo *u = &m->uDNS_info; 1856 uDNS_HostnameInfo *i; 1857 1858 for (i = u->Hostnames; i; i = i->next) 1859 { 1860 if (i->arv4 && i->arv4->uDNS_info.state != regState_Unregistered && 1861 i->arv4->resrec.rdata->u.ipv4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger && 1862 i->arv4->resrec.rdata->u.ipv4.NotAnInteger !=u->MappedV4.ip.v4.NotAnInteger) 1863 { 1864 uDNS_DeregisterRecord(m, i->arv4); 1865 i->arv4 = mDNSNULL; 1866 } 1867 if (i->arv6 && !mDNSPlatformMemSame(i->arv6->resrec.rdata->u.ipv6.b, u->AdvertisedV6.ip.v6.b, 16) && i->arv6->uDNS_info.state != regState_Unregistered) 1868 { 1869 uDNS_DeregisterRecord(m, i->arv6); 1870 i->arv6 = mDNSNULL; 1871 } 1872 1873 if (!i->arv4 && u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv4); 1874 else if (i->arv4 && i->arv4->uDNS_info.state == regState_Unregistered) i->arv4->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4; // simply overwrite unregistered 1875 if (!i->arv6 && u->AdvertisedV6.ip.v6.b[0]) AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv6); 1876 else if (i->arv6 &&i->arv6->uDNS_info.state == regState_Unregistered) i->arv6->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6; 1877 1878 AdvertiseHostname(m, i); 1879 } 1880 } 1881 1882 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext) 1883 { 1884 uDNS_GlobalInfo *u = &m->uDNS_info; 1885 uDNS_HostnameInfo *ptr, *new; 1886 1887 mDNS_Lock(m); 1888 1889 // check if domain already registered 1890 for (ptr = u->Hostnames; ptr; ptr = ptr->next) 1891 { 1892 if (SameDomainName(fqdn, &ptr->fqdn)) 1893 { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; } 1894 } 1895 1896 // allocate and format new address record 1897 new = umalloc(sizeof(*new)); 1898 if (!new) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; } 1899 ubzero(new, sizeof(*new)); 1900 new->next = u->Hostnames; 1901 u->Hostnames = new; 1902 1903 AssignDomainName(&new->fqdn, fqdn); 1904 new->StatusCallback = StatusCallback; 1905 new->StatusContext = StatusContext; 1906 1907 if (u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv4); 1908 else new->arv4 = mDNSNULL; 1909 if (u->AdvertisedV6.ip.v6.b[0]) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv6); 1910 else new->arv6 = mDNSNULL; 1911 1912 if (u->AdvertisedV6.ip.v6.b[0] || u->AdvertisedV4.ip.v4.NotAnInteger) AdvertiseHostname(m, new); 1913 1914 exit: 1915 mDNS_Unlock(m); 1916 } 1917 1918 mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) 1919 { 1920 uDNS_GlobalInfo *u = &m->uDNS_info; 1921 uDNS_HostnameInfo **ptr = &u->Hostnames; 1922 1923 mDNS_Lock(m); 1924 1925 while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next; 1926 if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c); 1927 else 1928 { 1929 uDNS_HostnameInfo *hi = *ptr; 1930 *ptr = (*ptr)->next; // unlink 1931 if (hi->arv4) 1932 { 1933 hi->arv4->RecordContext = mDNSNULL; // about to free wrapper struct 1934 if (hi->arv4->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv4); 1935 else { ufree(hi->arv4); hi->arv4 = mDNSNULL; } 1936 } 1937 if (hi->arv6) 1938 { 1939 hi->arv6->RecordContext = mDNSNULL; // about to free wrapper struct 1940 if (hi->arv6->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv6); 1941 else { ufree(hi->arv6); hi->arv6 = mDNSNULL; } 1942 } 1943 ufree(hi); 1944 } 1945 UpdateSRVRecords(m); 1946 mDNS_Unlock(m); 1947 } 1948 1949 mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router) 1950 { 1951 uDNS_GlobalInfo *u = &m->uDNS_info; 1952 mDNSBool v4Changed, v6Changed, RouterChanged; 1953 1954 if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo V4 address - incorrect type. Discarding."); return; } 1955 if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo V6 address - incorrect type. Discarding."); return; } 1956 if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 router. Discarding."); return; } 1957 1958 mDNS_Lock(m); 1959 1960 v4Changed = (v4addr ? v4addr->ip.v4.NotAnInteger : 0) != u->AdvertisedV4.ip.v4.NotAnInteger; 1961 v6Changed = v6addr ? !mDNSPlatformMemSame(v6addr, &u->AdvertisedV6, sizeof(*v6addr)) : (u->AdvertisedV6.ip.v6.b[0] != 0); 1962 RouterChanged = (router ? router->ip.v4.NotAnInteger : 0) != u->Router.ip.v4.NotAnInteger; 1963 1964 #if MDNS_DEBUGMSGS 1965 if (v4addr && (v4Changed || RouterChanged)) 1966 LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d", 1967 u->AdvertisedV4.ip.v4.b[0], u->AdvertisedV4.ip.v4.b[1], u->AdvertisedV4.ip.v4.b[2], u->AdvertisedV4.ip.v4.b[3], 1968 v4addr->ip.v4.b[0], v4addr->ip.v4.b[1], v4addr->ip.v4.b[2], v4addr->ip.v4.b[3]); 1969 #endif // MDNS_DEBUGMSGS 1970 1971 if ((v4Changed || RouterChanged) && u->MappedV4.ip.v4.NotAnInteger) u->MappedV4.ip.v4.NotAnInteger = 0; 1972 if (v4addr) u->AdvertisedV4 = *v4addr; else u->AdvertisedV4.ip.v4.NotAnInteger = 0; 1973 if (v6addr) u->AdvertisedV6 = *v6addr; else ubzero(u->AdvertisedV6.ip.v6.b, 16); 1974 if (router) u->Router = *router; else u->Router.ip.v4.NotAnInteger = 0; 1975 // setting router to zero indicates that nat mappings must be reestablished when router is reset 1976 1977 if ((v4Changed || RouterChanged || v6Changed) && v4addr) 1978 { 1979 // don't update these unless we've got V4 1980 UpdateHostnameRegistrations(m); 1981 UpdateSRVRecords(m); 1982 GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address 1983 } 1984 1985 mDNS_Unlock(m); 1986 } 1987 1988 // *************************************************************************** 1989 #if COMPILER_LIKES_PRAGMA_MARK 1990 #pragma mark - Incoming Message Processing 1991 #endif 1992 1993 mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr) 1994 { 1995 CacheRecord *ptr; 1996 1997 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next) 1998 if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue; 1999 2000 return mDNSfalse; 2001 } 2002 2003 2004 mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr) 2005 { 2006 CacheRecord *ptr, *prev = mDNSNULL; 2007 2008 for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next) 2009 { 2010 if (SameResourceRecord(&ptr->resrec, &rr->resrec)) 2011 { 2012 if (prev) prev->next = ptr->next; 2013 else question->uDNS_info.knownAnswers = ptr->next; 2014 ufree(ptr); 2015 return; 2016 } 2017 prev = ptr; 2018 } 2019 LogMsg("removeKnownAnswer() called for record not in KA list"); 2020 } 2021 2022 2023 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr) 2024 { 2025 CacheRecord *newCR = mDNSNULL; 2026 mDNSu32 size; 2027 2028 size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize; 2029 newCR = (CacheRecord *)umalloc(size); 2030 if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; } 2031 umemcpy(newCR, rr, size); 2032 newCR->resrec.rdata = (RData*)&newCR->rdatastorage; 2033 newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength; 2034 newCR->resrec.name = &question->qname; 2035 newCR->next = question->uDNS_info.knownAnswers; 2036 question->uDNS_info.knownAnswers = newCR; 2037 } 2038 2039 mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question) 2040 { 2041 const mDNSu8 *ptr; 2042 int i; 2043 CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL; 2044 LargeCacheRecord *lcr; 2045 2046 if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; } 2047 2048 ptr = LocateAnswers(msg, end); 2049 if (!ptr) goto pkt_error; 2050 2051 if (!msg->h.numAnswers) 2052 { 2053 // delete the whole KA list 2054 ka = question->uDNS_info.knownAnswers; 2055 while (ka) 2056 { 2057 debugf("deriving goodbye for %##s", ka->resrec.name->c); 2058 2059 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2060 question->QuestionCallback(m, question, &ka->resrec, mDNSfalse); 2061 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2062 // CAUTION: Need to be careful after calling question->QuestionCallback(), 2063 // because the client's callback function is allowed to do anything, 2064 // including starting/stopping queries, registering/deregistering records, etc. 2065 if (question != m->uDNS_info.CurrentQuery) 2066 { 2067 debugf("deriveGoodbyes - question removed via callback. returning."); 2068 return; 2069 } 2070 fptr = ka; 2071 ka = ka->next; 2072 ufree(fptr); 2073 } 2074 question->uDNS_info.knownAnswers = mDNSNULL; 2075 return; 2076 } 2077 2078 // make a list of all the new answers 2079 for (i = 0; i < msg->h.numAnswers; i++) 2080 { 2081 lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord)); 2082 if (!lcr) goto malloc_error; 2083 ubzero(lcr, sizeof(LargeCacheRecord)); 2084 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr); 2085 if (!ptr) goto pkt_error; 2086 cr = &lcr->r; 2087 if (ResourceRecordAnswersQuestion(&cr->resrec, question)) 2088 { 2089 cr->next = answers; 2090 answers = cr; 2091 } 2092 else ufree(cr); 2093 } 2094 2095 // make sure every known answer is in the answer list 2096 ka = question->uDNS_info.knownAnswers; 2097 while (ka) 2098 { 2099 for (cr = answers; cr; cr = cr->next) 2100 { if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; } 2101 if (!cr) 2102 { 2103 // record is in KA list but not answer list - remove from KA list 2104 if (prev) prev->next = ka->next; 2105 else question->uDNS_info.knownAnswers = ka->next; 2106 debugf("deriving goodbye for %##s", ka->resrec.name->c); 2107 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2108 question->QuestionCallback(m, question, &ka->resrec, mDNSfalse); 2109 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2110 // CAUTION: Need to be careful after calling question->QuestionCallback(), 2111 // because the client's callback function is allowed to do anything, 2112 // including starting/stopping queries, registering/deregistering records, etc. 2113 if (question != m->uDNS_info.CurrentQuery) 2114 { 2115 debugf("deriveGoodbyes - question removed via callback. returning."); 2116 return; 2117 } 2118 fptr = ka; 2119 ka = ka->next; 2120 ufree(fptr); 2121 } 2122 else 2123 { 2124 prev = ka; 2125 ka = ka->next; 2126 } 2127 } 2128 2129 // free temp answers list 2130 cr = answers; 2131 while (cr) { fptr = cr; cr = cr->next; ufree(fptr); } 2132 2133 return; 2134 2135 pkt_error: 2136 LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)", 2137 question->qname.c, question->qtype); 2138 return; 2139 2140 malloc_error: 2141 LogMsg("ERROR: Malloc"); 2142 } 2143 2144 mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, mDNSBool llq) 2145 { 2146 const mDNSu8 *ptr; 2147 int i; 2148 CacheRecord *cr = &m->rec.r; 2149 mDNSBool goodbye, inKAList; 2150 int followedCNames = 0; 2151 static const int maxCNames = 5; 2152 LLQ_Info *llqInfo = question->uDNS_info.llq; 2153 domainname origname; 2154 origname.c[0] = 0; 2155 2156 if (question != m->uDNS_info.CurrentQuery) 2157 { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; } 2158 2159 if (question->uDNS_info.Answered == 0 && msg->h.numAnswers == 0 && !llq) 2160 { 2161 /* NXDOMAIN error or empty RR set - notify client */ 2162 question->uDNS_info.Answered = mDNStrue; 2163 2164 /* Create empty resource record */ 2165 cr->resrec.RecordType = kDNSRecordTypeUnregistered; 2166 cr->resrec.InterfaceID = mDNSNULL; 2167 cr->resrec.name = &question->qname; 2168 cr->resrec.rrtype = question->qtype; 2169 cr->resrec.rrclass = question->qclass; 2170 cr->resrec.rroriginalttl = 1; /* What should we use for the TTL? TTL from SOA for domain? */ 2171 cr->resrec.rdlength = 0; 2172 cr->resrec.rdestimate = 0; 2173 cr->resrec.namehash = 0; 2174 cr->resrec.namehash = 0; 2175 cr->resrec.rdata = (RData*)&cr->rdatastorage; 2176 cr->resrec.rdata->MaxRDLength = cr->resrec.rdlength; 2177 2178 /* Pass empty answer to callback */ 2179 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2180 question->QuestionCallback(m, question, &cr->resrec, 0); 2181 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2182 // CAUTION: Need to be careful after calling question->QuestionCallback(), 2183 // because the client's callback function is allowed to do anything, 2184 // including starting/stopping queries, registering/deregistering records, etc. 2185 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 2186 if (question != m->uDNS_info.CurrentQuery) 2187 { 2188 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning."); 2189 return; 2190 } 2191 } 2192 2193 question->uDNS_info.Answered = mDNStrue; 2194 2195 ptr = LocateAnswers(msg, end); 2196 if (!ptr) goto pkt_error; 2197 2198 for (i = 0; i < msg->h.numAnswers; i++) 2199 { 2200 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &m->rec); 2201 if (!ptr) goto pkt_error; 2202 if (ResourceRecordAnswersQuestion(&cr->resrec, question)) 2203 { 2204 goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse; 2205 if (cr->resrec.rrtype == kDNSType_CNAME) 2206 { 2207 if (followedCNames > (maxCNames - 1)) LogMsg("Error: too many CNAME referals for question %##s", &origname); 2208 else 2209 { 2210 debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c); 2211 if (question->ReturnCNAME) 2212 { 2213 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2214 question->QuestionCallback(m, question, &cr->resrec, !goodbye); 2215 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2216 // CAUTION: Need to be careful after calling question->QuestionCallback(), 2217 // because the client's callback function is allowed to do anything, 2218 // including starting/stopping queries, registering/deregistering records, etc. 2219 if (question != m->uDNS_info.CurrentQuery) 2220 { 2221 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 2222 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning."); 2223 return; 2224 } 2225 } 2226 AssignDomainName(&origname, &question->qname); 2227 AssignDomainName(&question->qname, &cr->resrec.rdata->u.name); 2228 question->qnamehash = DomainNameHashValue(&question->qname); 2229 followedCNames++; 2230 i = -1; // restart packet answer matching 2231 ptr = LocateAnswers(msg, end); 2232 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 2233 continue; 2234 } 2235 } 2236 2237 inKAList = kaListContainsAnswer(question, cr); 2238 2239 if ((goodbye && !inKAList) || (!goodbye && inKAList)) 2240 { 2241 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 2242 continue; // list up to date 2243 } 2244 if (!inKAList) addKnownAnswer(question, cr); 2245 if (goodbye) removeKnownAnswer(question, cr); 2246 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2247 question->QuestionCallback(m, question, &cr->resrec, !goodbye); 2248 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2249 if (question != m->uDNS_info.CurrentQuery) 2250 { 2251 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 2252 debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning"); 2253 return; 2254 } 2255 } 2256 2257 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 2258 } 2259 2260 if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume) 2261 { 2262 deriveGoodbyes(m, msg, end,question); 2263 if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse; 2264 } 2265 2266 // Our interval may be set lower to recover from failures -- now that we have an answer, fully back off retry. 2267 // If the server advertised an LLQ-specific port number then that implies that this zone 2268 // *wants* to support LLQs, so if the setup fails (e.g. because we are behind a NAT) 2269 // then we use a slightly faster polling rate to give slightly better user experience. 2270 if (llq && llqInfo->state == LLQ_Poll && llqInfo->servPort.NotAnInteger) question->ThisQInterval = LLQ_POLL_INTERVAL; 2271 else if (question->ThisQInterval < MAX_UCAST_POLL_INTERVAL) question->ThisQInterval = MAX_UCAST_POLL_INTERVAL; 2272 return; 2273 2274 pkt_error: 2275 LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)", 2276 question->qname.c, question->qtype); 2277 return; 2278 } 2279 2280 mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context) 2281 { 2282 (void)context; // unused 2283 pktResponseHndlr(m, msg, end, question, mDNSfalse); 2284 } 2285 2286 mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context) 2287 { 2288 (void)context; // unused 2289 pktResponseHndlr(m, msg, end, question, mDNStrue); 2290 } 2291 2292 mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname) 2293 { 2294 LargeCacheRecord lcr; 2295 const mDNSu8 *ptr; 2296 mStatus err = mStatus_NoError; 2297 int i; 2298 2299 ptr = LocateAdditionals(msg, end); 2300 if (!ptr) goto finish; 2301 2302 for (i = 0; i < msg->h.numAdditionals; i++) 2303 { 2304 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); 2305 if (!ptr) goto finish; 2306 if (lcr.r.resrec.rrtype == kDNSType_TSIG) 2307 { 2308 mDNSu32 macsize; 2309 mDNSu8 *rd = lcr.r.resrec.rdata->u.data; 2310 mDNSu8 *rdend = rd + MaximumRDSize; 2311 int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name); 2312 2313 if (rd + alglen > rdend) goto finish; 2314 rd += alglen; // algorithm name 2315 if (rd + 6 > rdend) goto finish; 2316 rd += 6; // 48-bit timestamp 2317 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; 2318 rd += sizeof(mDNSOpaque16); // fudge 2319 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; 2320 macsize = mDNSVal16(*(mDNSOpaque16 *)rd); 2321 rd += sizeof(mDNSOpaque16); // MAC size 2322 if (rd + macsize > rdend) goto finish; 2323 rd += macsize; 2324 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; 2325 rd += sizeof(mDNSOpaque16); // orig id 2326 if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; 2327 err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code 2328 2329 if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; } 2330 else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; } 2331 else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; } 2332 else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; } 2333 goto finish; 2334 } 2335 } 2336 2337 finish: 2338 return err; 2339 } 2340 2341 mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end) 2342 { 2343 (void)msg; // currently unused, needed for TSIG errors 2344 if (!rcode) return mStatus_NoError; 2345 else if (rcode == kDNSFlag1_RC_YXDomain) 2346 { 2347 debugf("name in use: %##s", displayname->c); 2348 return mStatus_NameConflict; 2349 } 2350 else if (rcode == kDNSFlag1_RC_Refused) 2351 { 2352 LogMsg("Update %##s refused", displayname->c); 2353 return mStatus_Refused; 2354 } 2355 else if (rcode == kDNSFlag1_RC_NXRRSet) 2356 { 2357 LogMsg("Reregister refused (NXRRSET): %##s", displayname->c); 2358 return mStatus_NoSuchRecord; 2359 } 2360 else if (rcode == kDNSFlag1_RC_NotAuth) 2361 { 2362 // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too 2363 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname); 2364 if (!tsigerr) 2365 { 2366 LogMsg("Permission denied (NOAUTH): %##s", displayname->c); 2367 return mStatus_UnknownErr; 2368 } 2369 else return tsigerr; 2370 } 2371 else if (rcode == kDNSFlag1_RC_FmtErr) 2372 { 2373 mStatus tsigerr = ParseTSIGError(m, msg, end, displayname); 2374 if (!tsigerr) 2375 { 2376 LogMsg("Format Error: %##s", displayname->c); 2377 return mStatus_UnknownErr; 2378 } 2379 else return tsigerr; 2380 } 2381 else 2382 { 2383 LogMsg("Update %##s failed with rcode %d", displayname->c, rcode); 2384 return mStatus_UnknownErr; 2385 } 2386 } 2387 2388 mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs, mStatus err) 2389 { 2390 mDNSBool InvokeCallback = mDNSfalse; 2391 uDNS_RegInfo *info = &srs->uDNS_info; 2392 NATTraversalInfo *nat = srs->uDNS_info.NATinfo; 2393 ExtraResourceRecord **e = &srs->Extras; 2394 AuthRecord *txt = &srs->RR_TXT; 2395 uDNS_RegInfo *txtInfo = &txt->uDNS_info; 2396 switch (info->state) 2397 { 2398 case regState_Pending: 2399 if (err == mStatus_NameConflict && !info->TestForSelfConflict) 2400 { 2401 info->TestForSelfConflict = mDNStrue; 2402 debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c); 2403 SendServiceRegistration(m, srs); 2404 return; 2405 } 2406 else if (info->TestForSelfConflict) 2407 { 2408 info->TestForSelfConflict = mDNSfalse; 2409 if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict 2410 if (err) info->state = regState_Unregistered; 2411 else info->state = regState_Registered; 2412 InvokeCallback = mDNStrue; 2413 break; 2414 } 2415 else if (err == mStatus_UnknownErr && info->lease) 2416 { 2417 LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c); 2418 info->lease = mDNSfalse; 2419 SendServiceRegistration(m, srs); 2420 return; 2421 } 2422 else 2423 { 2424 if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); info->state = regState_Unregistered; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state 2425 else info->state = regState_Registered; 2426 InvokeCallback = mDNStrue; 2427 break; 2428 } 2429 case regState_Refresh: 2430 if (err) 2431 { 2432 LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c); 2433 InvokeCallback = mDNStrue; 2434 info->state = regState_Unregistered; 2435 } 2436 else info->state = regState_Registered; 2437 break; 2438 case regState_DeregPending: 2439 if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c); 2440 if (info->SRVChanged) 2441 { 2442 info->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state 2443 break; 2444 } 2445 err = mStatus_MemFree; 2446 InvokeCallback = mDNStrue; 2447 if (nat) 2448 { 2449 if (nat->state == NATState_Deleted) { info->NATinfo = mDNSNULL; FreeNATInfo(m, nat); } // deletion copmleted 2450 else nat->reg.ServiceRegistration = mDNSNULL; // allow mapping deletion to continue 2451 } 2452 info->state = regState_Unregistered; 2453 break; 2454 case regState_DeregDeferred: 2455 if (err) 2456 { 2457 debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c); 2458 err = mStatus_MemFree; 2459 InvokeCallback = mDNStrue; 2460 info->state = regState_Unregistered; 2461 break; 2462 } 2463 else 2464 { 2465 debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c); 2466 info->state = regState_Registered; 2467 SendServiceDeregistration(m, srs); 2468 return; 2469 } 2470 case regState_UpdatePending: 2471 if (err) 2472 { 2473 LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c); 2474 info->state = regState_Unregistered; 2475 InvokeCallback = mDNStrue; 2476 } 2477 else 2478 { 2479 info->state = regState_Registered; 2480 // deallocate old RData 2481 if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData); 2482 SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen); 2483 txtInfo->OrigRData = mDNSNULL; 2484 txtInfo->InFlightRData = mDNSNULL; 2485 } 2486 break; 2487 case regState_FetchingZoneData: 2488 case regState_Registered: 2489 case regState_Cancelled: 2490 case regState_Unregistered: 2491 case regState_NATMap: 2492 case regState_NoTarget: 2493 case regState_ExtraQueued: 2494 case regState_NATError: 2495 LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.", 2496 srs->RR_SRV.resrec.name->c, info->state, err); 2497 err = mStatus_UnknownErr; 2498 } 2499 2500 if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered)) 2501 { 2502 if (InvokeCallback) 2503 { 2504 info->ClientCallbackDeferred = mDNStrue; 2505 info->DeferredStatus = err; 2506 } 2507 info->SRVChanged = mDNSfalse; 2508 UpdateSRV(m, srs); 2509 return; 2510 } 2511 2512 while (*e) 2513 { 2514 uDNS_RegInfo *einfo = &(*e)->r.uDNS_info; 2515 if (einfo->state == regState_ExtraQueued) 2516 { 2517 if (info->state == regState_Registered && !err) 2518 { 2519 // extra resource record queued for this service - copy zone info and register 2520 AssignDomainName(&einfo->zone, &info->zone); 2521 einfo->ns = info->ns; 2522 einfo->port = info->port; 2523 einfo->lease = info->lease; 2524 sendRecordRegistration(m, &(*e)->r); 2525 e = &(*e)->next; 2526 } 2527 else if (err && einfo->state != regState_Unregistered) 2528 { 2529 // unlink extra from list 2530 einfo->state = regState_Unregistered; 2531 *e = (*e)->next; 2532 } 2533 else e = &(*e)->next; 2534 } 2535 else e = &(*e)->next; 2536 } 2537 2538 srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc. 2539 if (info->state == regState_Unregistered) unlinkSRS(m, srs); 2540 else if (txtInfo->QueuedRData && info->state == regState_Registered) 2541 { 2542 if (InvokeCallback) 2543 { 2544 // if we were supposed to give a client callback, we'll do it after we update the primary txt record 2545 info->ClientCallbackDeferred = mDNStrue; 2546 info->DeferredStatus = err; 2547 } 2548 info->state = regState_UpdatePending; 2549 txtInfo->InFlightRData = txtInfo->QueuedRData; 2550 txtInfo->InFlightRDLen = txtInfo->QueuedRDLen; 2551 info->OrigRData = txt->resrec.rdata; 2552 info->OrigRDLen = txt->resrec.rdlength; 2553 txtInfo->QueuedRData = mDNSNULL; 2554 SendServiceRegistration(m, srs); 2555 return; 2556 } 2557 2558 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2559 if (InvokeCallback) srs->ServiceCallback(m, srs, err); 2560 else if (info->ClientCallbackDeferred) 2561 { 2562 info->ClientCallbackDeferred = mDNSfalse; 2563 srs->ServiceCallback(m, srs, info->DeferredStatus); 2564 } 2565 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2566 // NOTE: do not touch structures after calling ServiceCallback 2567 } 2568 2569 mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) 2570 { 2571 uDNS_RegInfo *info = &rr->uDNS_info; 2572 mDNSBool InvokeCallback = mDNStrue; 2573 2574 if (info->state == regState_UpdatePending) 2575 { 2576 if (err) 2577 { 2578 LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err); 2579 info->state = regState_Unregistered; 2580 } 2581 else 2582 { 2583 debugf("Update record %##s - success", rr->resrec.name->c); 2584 info->state = regState_Registered; 2585 // deallocate old RData 2586 if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, info->OrigRData); 2587 SetNewRData(&rr->resrec, info->InFlightRData, info->InFlightRDLen); 2588 info->OrigRData = mDNSNULL; 2589 info->InFlightRData = mDNSNULL; 2590 } 2591 } 2592 2593 if (info->state == regState_DeregPending) 2594 { 2595 debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); 2596 if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld", 2597 rr->resrec.name->c, rr->resrec.rrtype, err); 2598 err = mStatus_MemFree; 2599 info->state = regState_Unregistered; 2600 } 2601 2602 if (info->state == regState_DeregDeferred) 2603 { 2604 if (err) 2605 { 2606 LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld", 2607 rr->resrec.name->c, rr->resrec.rrtype, err); 2608 info->state = regState_Unregistered; 2609 } 2610 debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); 2611 info->state = regState_Registered; 2612 uDNS_DeregisterRecord(m, rr); 2613 return; 2614 } 2615 2616 if (info->state == regState_Pending || info->state == regState_Refresh) 2617 { 2618 if (!err) 2619 { 2620 info->state = regState_Registered; 2621 if (info->state == regState_Refresh) InvokeCallback = mDNSfalse; 2622 } 2623 else 2624 { 2625 if (info->lease && err == mStatus_UnknownErr) 2626 { 2627 LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c); 2628 info->lease = mDNSfalse; 2629 sendRecordRegistration(m, rr); 2630 return; 2631 } 2632 LogMsg("Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err); 2633 info->state = regState_Unregistered; 2634 } 2635 } 2636 2637 if (info->state == regState_Unregistered) unlinkAR(&m->uDNS_info.RecordRegistrations, rr); 2638 else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc. 2639 2640 if (info->QueuedRData && info->state == regState_Registered) 2641 { 2642 info->state = regState_UpdatePending; 2643 info->InFlightRData = info->QueuedRData; 2644 info->InFlightRDLen = info->QueuedRDLen; 2645 info->OrigRData = rr->resrec.rdata; 2646 info->OrigRDLen = rr->resrec.rdlength; 2647 info->QueuedRData = mDNSNULL; 2648 sendRecordRegistration(m, rr); 2649 return; 2650 } 2651 2652 if (InvokeCallback) 2653 { 2654 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2655 if (rr->RecordCallback) rr->RecordCallback(m, rr, err); 2656 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2657 } 2658 } 2659 2660 2661 mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info) 2662 { 2663 LargeCacheRecord lcr; 2664 const mDNSu8 *ptr; 2665 int i; 2666 mDNSu32 lease = 0; 2667 mDNSs32 expire; 2668 2669 ptr = LocateAdditionals(msg, end); 2670 2671 if (info->lease && (ptr = LocateAdditionals(msg, end))) 2672 { 2673 for (i = 0; i < msg->h.numAdditionals; i++) 2674 { 2675 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); 2676 if (!ptr) break; 2677 if (lcr.r.resrec.rrtype == kDNSType_OPT) 2678 { 2679 if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue; 2680 if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue; 2681 lease = lcr.r.resrec.rdata->u.opt.OptData.lease; 2682 break; 2683 } 2684 } 2685 } 2686 2687 if (lease > 0) 2688 { 2689 expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4); 2690 if (info->state == regState_UpdatePending) 2691 // if updating individual record, the service record set may expire sooner 2692 { if (expire - info->expire < 0) info->expire = expire; } 2693 else info->expire = expire; 2694 } 2695 else info->lease = mDNSfalse; 2696 } 2697 2698 mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len) 2699 { 2700 uDNS_GlobalInfo *u = &m->uDNS_info; 2701 NATTraversalInfo *ptr = u->NATTraversals; 2702 NATOp_t op; 2703 2704 // check length, version, opcode 2705 if (len < sizeof(NATPortMapReply) && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; } 2706 if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; } 2707 op = pkt[1]; 2708 if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; } 2709 2710 while (ptr) 2711 { 2712 if ((ptr->state == NATState_Request || ptr->state == NATState_Refresh) && (ptr->op | NATMAP_RESPONSE_MASK) == op) 2713 if (ptr->ReceiveResponse(ptr, m, pkt, len)) break; // note callback may invalidate ptr if it return value is non-zero 2714 ptr = ptr->next; 2715 } 2716 } 2717 2718 mDNSlocal const domainname *DNSRelayTestQuestion = (domainname*) 2719 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest" 2720 "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa"; 2721 2722 // Returns mDNStrue if response was handled 2723 mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, 2724 const mDNSAddr *const srcaddr, const mDNSInterfaceID InterfaceID) 2725 { 2726 const mDNSu8 *ptr = msg->data; 2727 DNSQuestion q; 2728 DNSServer *s; 2729 mDNSu32 result = 0; 2730 mDNSBool found = mDNSfalse; 2731 2732 // 1. Find out if this is an answer to one of our test questions 2733 if (msg->h.numQuestions != 1) return(mDNSfalse); 2734 ptr = getQuestion(msg, ptr, end, InterfaceID, &q); 2735 if (!ptr) return(mDNSfalse); 2736 if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse); 2737 if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse); 2738 2739 // 2. If the DNS relay gave us a positive response, then it's got buggy firmware 2740 // else, if the DNS relay gave us an error or no-answer response, it passed our test 2741 if ((msg->h.flags.b[1] & kDNSFlag1_RC) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0) 2742 result = DNSServer_Failed; 2743 else 2744 result = DNSServer_Passed; 2745 2746 // 3. Find occurrences of this server in our list, and mark them appropriately 2747 for (s = m->uDNS_info.Servers; s; s = s->next) 2748 if (mDNSSameAddress(srcaddr, &s->addr) && s->teststate != result) 2749 { s->teststate = result; found = mDNStrue; } 2750 2751 // 4. Assuming we found the server in question in our list (don't want to risk being victim of a deliberate DOS attack here) 2752 // log a message to let the user know why Wide-Area Service Discovery isn't working 2753 if (found && result == DNSServer_Failed) 2754 LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a.", srcaddr); 2755 2756 return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doens't need to process this packet further 2757 } 2758 2759 mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, 2760 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, 2761 const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID) 2762 { 2763 DNSQuestion *qptr; 2764 AuthRecord *rptr; 2765 ServiceRecordSet *sptr; 2766 mStatus err = mStatus_NoError; 2767 uDNS_GlobalInfo *u = &m->uDNS_info; 2768 2769 mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; 2770 mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; 2771 mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); 2772 mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC); 2773 2774 mDNSs32 timenow = mDNSPlatformTimeNow(m); 2775 2776 // unused 2777 (void)dstaddr; 2778 (void)dstport; 2779 (void)InterfaceID; 2780 2781 if (QR_OP == StdR) 2782 { 2783 // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot 2784 // LLQ Responses over TCP not currently supported 2785 if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return; 2786 2787 if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, InterfaceID)) return; 2788 2789 for (qptr = u->ActiveQueries; qptr; qptr = qptr->next) 2790 { 2791 //!!!KRS we should have a hashtable, hashed on message id 2792 if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger) 2793 { 2794 if (timenow - (qptr->LastQTime + RESPONSE_WINDOW) > 0) 2795 { debugf("uDNS_ReceiveMsg - response received after maximum allowed window. Discarding"); return; } 2796 if (msg->h.flags.b[0] & kDNSFlag0_TC) 2797 { hndlTruncatedAnswer(qptr, srcaddr, m); return; } 2798 else 2799 { 2800 u->CurrentQuery = qptr; 2801 qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context); 2802 u->CurrentQuery = mDNSNULL; 2803 // Note: responseCallback can invalidate qptr 2804 return; 2805 } 2806 } 2807 } 2808 } 2809 if (QR_OP == UpdateR) 2810 { 2811 for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next) 2812 { 2813 if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger) 2814 { 2815 err = checkUpdateResult(sptr->RR_SRV.resrec.name, rcode, m, msg, end); 2816 if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info); 2817 hndlServiceUpdateReply(m, sptr, err); 2818 return; 2819 } 2820 } 2821 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next) 2822 { 2823 if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger) 2824 { 2825 err = checkUpdateResult(rptr->resrec.name, rcode, m, msg, end); 2826 if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info); 2827 hndlRecordUpdateReply(m, rptr, err); 2828 return; 2829 } 2830 } 2831 } 2832 debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id)); 2833 } 2834 2835 // lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful 2836 mDNSlocal DNSServer *GetServerForName(uDNS_GlobalInfo *u, const domainname *name) 2837 { 2838 DNSServer *curmatch = mDNSNULL, *p = u->Servers; 2839 int i, curmatchlen = -1; 2840 int ncount = name ? CountLabels(name) : 0; 2841 2842 while (p) 2843 { 2844 int scount = CountLabels(&p->domain); 2845 if (scount <= ncount && scount > curmatchlen) 2846 { 2847 // only inspect if server's domain is longer than current best match and shorter than the name itself 2848 const domainname *tail = name; 2849 for (i = 0; i < ncount - scount; i++) 2850 tail = (domainname *)(tail->c + 1 + tail->c[0]); // find "tail" (scount labels) of name 2851 if (SameDomainName(tail, &p->domain)) { curmatch = p; curmatchlen = scount; } 2852 } 2853 p = p->next; 2854 } 2855 return(curmatch); 2856 } 2857 2858 // *************************************************************************** 2859 #if COMPILER_LIKES_PRAGMA_MARK 2860 #pragma mark - Query Routines 2861 #endif 2862 2863 #define sameID(x,y) mDNSPlatformMemSame(x,y,8) 2864 2865 mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question) 2866 { 2867 ubzero(msg, sizeof(msg)); 2868 InitializeDNSMessage(&msg->h, question->uDNS_info.id, uQueryFlags); 2869 } 2870 2871 mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question) 2872 { 2873 initializeQuery(msg, question); 2874 2875 *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass); 2876 if (!*endPtr) 2877 { 2878 LogMsg("ERROR: Unicast query out of space in packet"); 2879 return mStatus_UnknownErr; 2880 } 2881 return mStatus_NoError; 2882 } 2883 2884 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion) 2885 { 2886 AuthRecord rr; 2887 ResourceRecord *opt = &rr.resrec; 2888 rdataOpt *optRD; 2889 2890 //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section 2891 if (includeQuestion) 2892 { 2893 ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass); 2894 if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; } 2895 } 2896 // locate OptRR if it exists, set pointer to end 2897 // !!!KRS implement me 2898 2899 2900 // format opt rr (fields not specified are zero-valued) 2901 ubzero(&rr, sizeof(AuthRecord)); 2902 mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); 2903 opt->rdlength = LLQ_OPT_RDLEN; 2904 opt->rdestimate = LLQ_OPT_RDLEN; 2905 2906 optRD = &rr.resrec.rdata->u.opt; 2907 optRD->opt = kDNSOpt_LLQ; 2908 optRD->optlen = LLQ_OPTLEN; 2909 umemcpy(&optRD->OptData.llq, data, sizeof(*data)); 2910 ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0); 2911 if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; } 2912 2913 return ptr; 2914 } 2915 2916 2917 mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index) 2918 { 2919 LargeCacheRecord lcr; 2920 int i; 2921 const mDNSu8 *ptr; 2922 2923 ubzero(&lcr, sizeof(lcr)); 2924 2925 ptr = LocateAdditionals(msg, end); 2926 if (!ptr) return mDNSfalse; 2927 2928 // find the last additional 2929 for (i = 0; i < msg->h.numAdditionals; i++) 2930 // { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; } 2931 //!!!KRS workaround for LH server bug, which puts OPT as first additional 2932 { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; } 2933 if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse; 2934 if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_RDLEN) return mDNSfalse; // rdata too small 2935 umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(*llq)), sizeof(*llq)); 2936 return mDNStrue; 2937 } 2938 2939 mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q) 2940 { 2941 LLQ_Info *qInfo; 2942 LLQOptData pktData; 2943 2944 qInfo = q->uDNS_info.llq; 2945 if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; } 2946 if (pktData.llqOp != kLLQOp_Refresh) return; 2947 if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch. Discarding"); return; } 2948 if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; } 2949 2950 qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond); 2951 qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2); 2952 2953 qInfo->origLease = pktData.lease; 2954 qInfo->state = LLQ_Established; 2955 } 2956 2957 mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease) 2958 { 2959 DNSMessage msg; 2960 mDNSu8 *end; 2961 LLQOptData llq; 2962 LLQ_Info *info = q->uDNS_info.llq; 2963 mStatus err; 2964 mDNSs32 timenow; 2965 2966 timenow = mDNSPlatformTimeNow(m); 2967 if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) || 2968 info->expire - timenow < 0) 2969 { 2970 LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q->qname.c, kLLQ_DEF_RETRY/60); 2971 info->state = LLQ_Retry; 2972 info->retry = mDNSPlatformTimeNow(m) + kLLQ_DEF_RETRY * mDNSPlatformOneSecond; 2973 info->deriveRemovesOnResume = mDNStrue; 2974 return; 2975 //!!!KRS handle this - periodically try to re-establish 2976 } 2977 2978 llq.vers = kLLQ_Vers; 2979 llq.llqOp = kLLQOp_Refresh; 2980 llq.err = LLQErr_NoError; 2981 umemcpy(llq.id, info->id, 8); 2982 llq.lease = lease; 2983 2984 initializeQuery(&msg, q); 2985 end = putLLQ(&msg, msg.data, q, &llq, mDNStrue); 2986 if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; } 2987 2988 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL); 2989 if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err); 2990 2991 if (info->state == LLQ_Established) info->ntries = 1; 2992 else info->ntries++; 2993 info->state = LLQ_Refresh; 2994 q->LastQTime = timenow; 2995 info->retry = (info->expire - q->LastQTime) / 2; 2996 } 2997 2998 mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID) 2999 { 3000 DNSMessage ack; 3001 mDNSu8 *ackEnd = ack.data; 3002 mStatus err; 3003 LLQOptData opt; 3004 3005 (void)InterfaceID; // unused 3006 3007 // find Opt RR, verify correct ID 3008 if (!getLLQAtIndex(m, msg, end, &opt, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse; } 3009 if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata"); return mDNSfalse; } 3010 if (!sameID(opt.id, q->uDNS_info.llq->id)) { return mDNSfalse; } 3011 if (opt.llqOp != kLLQOp_Event) { if (!q->uDNS_info.llq->ntries) LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; } 3012 3013 // invoke response handler 3014 m->uDNS_info.CurrentQuery = q; 3015 q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); 3016 if (m->uDNS_info.CurrentQuery != q) return mDNStrue; 3017 3018 // format and send ack 3019 InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags); 3020 ackEnd = putLLQ(&ack, ack.data, mDNSNULL, &opt, mDNSfalse); 3021 if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putLLQ"); return mDNSfalse; } 3022 err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL); 3023 if (err) debugf("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err); 3024 return mDNStrue; 3025 } 3026 3027 3028 3029 mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q) 3030 { 3031 LLQ_Info *info = q->uDNS_info.llq; 3032 3033 if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; } 3034 if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering) 3035 info->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)llq->lease * mDNSPlatformOneSecond); 3036 info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2); 3037 3038 info->origLease = llq->lease; 3039 info->state = LLQ_Established; 3040 3041 q->uDNS_info.responseCallback = llqResponseHndlr; 3042 llqResponseHndlr(m, pktMsg, end, q, mDNSNULL); 3043 return; 3044 3045 error: 3046 info->state = LLQ_Error; 3047 } 3048 3049 mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq) 3050 { 3051 LLQ_Info *info = q->uDNS_info.llq; 3052 DNSMessage response; 3053 mDNSu8 *responsePtr = response.data; 3054 mStatus err; 3055 LLQOptData llqBuf; 3056 mDNSs32 timenow = mDNSPlatformTimeNow(m); 3057 3058 if (info->ntries++ == kLLQ_MAX_TRIES) 3059 { 3060 LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes", 3061 kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60); 3062 info->state = LLQ_Retry; 3063 info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond); 3064 // !!!KRS give a callback error in these cases? 3065 return; 3066 } 3067 3068 if (!llq) 3069 { 3070 llq = &llqBuf; 3071 llq->vers = kLLQ_Vers; 3072 llq->llqOp = kLLQOp_Setup; 3073 llq->err = LLQErr_NoError; 3074 umemcpy(llq->id, info->id, 8); 3075 llq->lease = info->origLease; 3076 } 3077 3078 q->LastQTime = timenow; 3079 info->retry = timenow + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond); 3080 3081 if (constructQueryMsg(&response, &responsePtr, q)) goto error; 3082 responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse); 3083 if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; } 3084 3085 err = mDNSSendDNSMessage(m, &response, responsePtr, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL); 3086 if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err); 3087 // on error, we procede as normal and retry after the appropriate interval 3088 3089 return; 3090 3091 error: 3092 info->state = LLQ_Error; 3093 } 3094 3095 3096 3097 mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q) 3098 { 3099 LLQ_Info *info = q->uDNS_info.llq; 3100 mDNSs32 timenow = mDNSPlatformTimeNow(m); 3101 switch(llq->err) 3102 { 3103 case LLQErr_NoError: break; 3104 case LLQErr_ServFull: 3105 LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s. Retry in %lu sec", q->qname.c, llq->lease); 3106 info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond); 3107 info->state = LLQ_Retry; 3108 simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL); // get available answers 3109 info->deriveRemovesOnResume = mDNStrue; 3110 case LLQErr_Static: 3111 info->state = LLQ_Static; 3112 LogMsg("LLQ %##s: static", q->qname.c); 3113 simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL); 3114 return; 3115 case LLQErr_FormErr: 3116 LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c); 3117 goto error; 3118 case LLQErr_BadVers: 3119 LogMsg("ERROR: hndlRequestChallenge - received BadVers from server"); 3120 goto error; 3121 case LLQErr_UnknownErr: 3122 LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c); 3123 goto error; 3124 default: 3125 LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c); 3126 goto error; 3127 } 3128 3129 if (info->origLease != llq->lease) 3130 debugf("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease); 3131 3132 // cache expiration in case we go to sleep before finishing setup 3133 info->origLease = llq->lease; 3134 info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond); 3135 3136 // update state 3137 info->state = LLQ_SecondaryRequest; 3138 umemcpy(info->id, llq->id, 8); 3139 info->ntries = 0; // first attempt to send response 3140 3141 sendChallengeResponse(m, q, llq); 3142 return; 3143 3144 3145 error: 3146 info->state = LLQ_Error; 3147 } 3148 3149 3150 // response handler for initial and secondary setup responses 3151 mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext) 3152 { 3153 DNSQuestion pktQuestion; 3154 LLQOptData llq; 3155 const mDNSu8 *ptr = pktMsg->data; 3156 LLQ_Info *info = q->uDNS_info.llq; 3157 mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC); 3158 3159 (void)clientContext; // unused 3160 3161 if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll; 3162 3163 ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion); 3164 if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll; } 3165 if (!SameDomainName(&q->qname, &pktQuestion.qname)) 3166 { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c); goto poll; } 3167 3168 if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; } 3169 if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; } 3170 if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers); goto poll; } 3171 3172 if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; } 3173 if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; } 3174 LogMsg("recvSetupResponse - bad state %d", info->state); 3175 3176 poll: 3177 info->state = LLQ_Poll; 3178 q->uDNS_info.responseCallback = llqResponseHndlr; 3179 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll 3180 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL; 3181 } 3182 3183 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer) 3184 { 3185 DNSMessage msg; 3186 mDNSu8 *end; 3187 LLQOptData llqData; 3188 DNSQuestion *q = info->question; 3189 mStatus err = mStatus_NoError; 3190 mDNSs32 timenow = mDNSPlatformTimeNow(m); 3191 uDNS_GlobalInfo *u = &m->uDNS_info; 3192 3193 if (IsPrivateV4Addr(&u->AdvertisedV4)) 3194 { 3195 if (!u->LLQNatInfo) 3196 { 3197 info->state = LLQ_NatMapWait; 3198 StartLLQNatMap(m); 3199 return; 3200 } 3201 if (u->LLQNatInfo->state == NATState_Error) goto poll; 3202 if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy) 3203 { info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; } 3204 info->NATMap = mDNStrue; // this llq references the global llq nat mapping 3205 } 3206 3207 if (info->ntries++ >= kLLQ_MAX_TRIES) 3208 { 3209 debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60); 3210 goto poll; 3211 } 3212 3213 // set llq rdata 3214 llqData.vers = kLLQ_Vers; 3215 llqData.llqOp = kLLQOp_Setup; 3216 llqData.err = LLQErr_NoError; 3217 ubzero(llqData.id, 8); 3218 llqData.lease = kLLQ_DefLease; 3219 3220 initializeQuery(&msg, q); 3221 end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue); 3222 if (!end) 3223 { 3224 LogMsg("ERROR: startLLQHandshake - putLLQ"); 3225 info->state = LLQ_Error; 3226 return; 3227 } 3228 3229 if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future 3230 { 3231 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL); 3232 if (err) debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err); 3233 // on error, we procede as normal and retry after the appropriate interval 3234 } 3235 3236 // update question/info state 3237 info->state = LLQ_InitialRequest; 3238 info->origLease = kLLQ_DefLease; 3239 info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond); 3240 q->LastQTime = timenow; 3241 q->uDNS_info.responseCallback = recvSetupResponse; 3242 q->uDNS_info.internal = mDNStrue; 3243 return; 3244 3245 poll: 3246 info->question->uDNS_info.responseCallback = llqResponseHndlr; 3247 info->state = LLQ_Poll; 3248 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll 3249 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL; 3250 } 3251 3252 // wrapper for startLLQHandshake, invoked by async op callback 3253 mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result) 3254 { 3255 LLQ_Info *info = (LLQ_Info *)llqInfo; 3256 const zoneData_t *zoneInfo = mDNSNULL; 3257 3258 // check state first to make sure it is OK to touch question object 3259 if (info->state == LLQ_Cancelled) 3260 { 3261 // StopQuery was called while we were getting the zone info 3262 debugf("startLLQHandshake - LLQ Cancelled."); 3263 info->question = mDNSNULL; // question may be deallocated 3264 ufree(info); 3265 return; 3266 } 3267 3268 if (!info->question) 3269 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; } 3270 3271 if (info->state != LLQ_GetZoneInfo) 3272 { LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; } 3273 3274 if (err) 3275 { LogMsg("ERROR: startLLQHandshakeCallback %##s invoked with error code %ld", info->question->qname.c, err); goto poll; } 3276 3277 if (!result) 3278 { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; } 3279 3280 zoneInfo = &result->zoneData; 3281 3282 if (!zoneInfo->llqPort.NotAnInteger) 3283 { debugf("LLQ port lookup failed - reverting to polling"); info->servPort.NotAnInteger = 0; goto poll; } 3284 3285 // cache necessary zone data 3286 info->servAddr = zoneInfo->primaryAddr; 3287 info->servPort = zoneInfo->llqPort; 3288 info->ntries = 0; 3289 3290 if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended; 3291 else startLLQHandshake(m, info, mDNSfalse); 3292 return; 3293 3294 poll: 3295 info->question->uDNS_info.responseCallback = llqResponseHndlr; 3296 info->state = LLQ_Poll; 3297 info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll 3298 info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL; 3299 return; 3300 3301 error: 3302 info->state = LLQ_Error; 3303 } 3304 3305 mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question) 3306 { 3307 LLQ_Info *info; 3308 mStatus err = mStatus_NoError; 3309 3310 // allocate / init info struct 3311 info = umalloc(sizeof(LLQ_Info)); 3312 if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; } 3313 ubzero(info, sizeof(LLQ_Info)); 3314 info->state = LLQ_GetZoneInfo; 3315 3316 // link info/question 3317 info->question = question; 3318 question->uDNS_info.llq = info; 3319 3320 question->uDNS_info.responseCallback = llqResponseHndlr; 3321 3322 err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info); 3323 if (err) 3324 { 3325 LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err); 3326 info->question = mDNSNULL; 3327 ufree(info); 3328 question->uDNS_info.llq = mDNSNULL; 3329 return err; 3330 } 3331 3332 LinkActiveQuestion(&m->uDNS_info, question); 3333 return err; 3334 } 3335 3336 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID) 3337 { 3338 DNSQuestion pktQ, *q; 3339 uDNS_GlobalInfo *u = &m->uDNS_info; 3340 const mDNSu8 *ptr = msg->data; 3341 LLQ_Info *llqInfo; 3342 3343 if (!msg->h.numQuestions) return mDNSfalse; 3344 3345 ptr = getQuestion(msg, ptr, end, 0, &pktQ); 3346 if (!ptr) return mDNSfalse; 3347 pktQ.uDNS_info.id = msg->h.id; 3348 3349 q = u->ActiveQueries; 3350 while (q) 3351 { 3352 llqInfo = q->uDNS_info.llq; 3353 if (q->LongLived && 3354 llqInfo && 3355 q->qnamehash == pktQ.qnamehash && 3356 q->qtype == pktQ.qtype && 3357 SameDomainName(&q->qname, &pktQ.qname)) 3358 { 3359 u->CurrentQuery = q; 3360 if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers)) 3361 { if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; } 3362 else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger) 3363 { 3364 if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers) 3365 { recvRefreshReply(m, msg, end, q); return mDNStrue; } 3366 if (llqInfo->state < LLQ_Static) 3367 { 3368 if ((llqInfo->state != LLQ_InitialRequest && llqInfo->state != LLQ_SecondaryRequest) || mDNSSameAddress(srcaddr, &llqInfo->servAddr)) 3369 { q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; } 3370 } 3371 } 3372 } 3373 q = q->next; 3374 } 3375 return mDNSfalse; 3376 } 3377 3378 mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u) 3379 { 3380 DNSQuestion *q; 3381 3382 for (q = u->ActiveQueries; q; q = q->next) 3383 { 3384 if (q == question) 3385 { 3386 if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&question->qname)) 3387 LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p", 3388 question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID); 3389 return mDNStrue; 3390 } 3391 } 3392 return mDNSfalse; 3393 } 3394 3395 // stopLLQ happens IN ADDITION to stopQuery 3396 mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question) 3397 { 3398 LLQ_Info *info = question->uDNS_info.llq; 3399 (void)m; // unused 3400 3401 if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; } 3402 if (!info) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; } 3403 3404 switch (info->state) 3405 { 3406 case LLQ_UnInit: 3407 LogMsg("ERROR: stopLLQ - state LLQ_UnInit"); 3408 //!!!KRS should we unlink info<->question here? 3409 return; 3410 case LLQ_GetZoneInfo: 3411 case LLQ_SuspendDeferred: 3412 info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op 3413 info->state = LLQ_Cancelled; 3414 return; 3415 case LLQ_Established: 3416 case LLQ_Refresh: 3417 // refresh w/ lease 0 3418 sendLLQRefresh(m, question, 0); 3419 goto end; 3420 default: 3421 debugf("stopLLQ - silently discarding LLQ in state %d", info->state); 3422 goto end; 3423 } 3424 3425 end: 3426 if (info->NATMap) info->NATMap = mDNSfalse; 3427 CheckForUnreferencedLLQMapping(m); 3428 info->question = mDNSNULL; 3429 ufree(info); 3430 question->uDNS_info.llq = mDNSNULL; 3431 question->LongLived = mDNSfalse; 3432 } 3433 3434 mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question) 3435 { 3436 uDNS_GlobalInfo *u = &m->uDNS_info; 3437 DNSQuestion *qptr, *prev = mDNSNULL; 3438 CacheRecord *ka; 3439 3440 qptr = u->ActiveQueries; 3441 while (qptr) 3442 { 3443 if (qptr == question) 3444 { 3445 if (question->LongLived && question->uDNS_info.llq) 3446 stopLLQ(m, question); 3447 if (m->uDNS_info.CurrentQuery == question) 3448 m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next; 3449 while (question->uDNS_info.knownAnswers) 3450 { 3451 ka = question->uDNS_info.knownAnswers; 3452 question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next; 3453 ufree(ka); 3454 } 3455 if (prev) prev->next = question->next; 3456 else u->ActiveQueries = question->next; 3457 return mStatus_NoError; 3458 } 3459 prev = qptr; 3460 qptr = qptr->next; 3461 } 3462 LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c); 3463 return mStatus_UnknownErr; 3464 } 3465 3466 mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal) 3467 { 3468 uDNS_GlobalInfo *u = &m->uDNS_info; 3469 //!!!KRS we should check if the question is already in our activequestion list 3470 if (!ValidateDomainName(&question->qname)) 3471 { 3472 LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 3473 return mStatus_Invalid; 3474 } 3475 3476 question->next = mDNSNULL; 3477 question->qnamehash = DomainNameHashValue(&question->qname); // to do quick domain name comparisons 3478 question->uDNS_info.id = newMessageID(u); 3479 question->uDNS_info.Answered = mDNSfalse; 3480 3481 // break here if its and LLQ 3482 if (question->LongLived) return startLLQ(m, question); 3483 3484 question->ThisQInterval = INIT_UCAST_POLL_INTERVAL / 2; 3485 question->LastQTime = mDNSPlatformTimeNow(m) - question->ThisQInterval; 3486 // store the question/id in active question list 3487 question->uDNS_info.internal = internal; 3488 LinkActiveQuestion(u, question); 3489 question->uDNS_info.knownAnswers = mDNSNULL; 3490 LogOperation("uDNS startQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 3491 3492 return mStatus_NoError; 3493 } 3494 3495 mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question) 3496 { 3497 ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo)); 3498 question->uDNS_info.responseCallback = simpleResponseHndlr; 3499 question->uDNS_info.context = mDNSNULL; 3500 //LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 3501 return startQuery(m, question, 0); 3502 } 3503 3504 // explicitly set response handler 3505 mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext) 3506 { 3507 ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo)); 3508 q->QuestionContext = hndlrContext; 3509 q->uDNS_info.responseCallback = callback; 3510 q->uDNS_info.context = hndlrContext; 3511 return startQuery(m, q, 1); 3512 } 3513 3514 3515 3516 // *************************************************************************** 3517 #if COMPILER_LIKES_PRAGMA_MARK 3518 #pragma mark - Domain -> Name Server Conversion 3519 #endif 3520 3521 3522 /* startGetZoneData 3523 * 3524 * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name, 3525 * i.e. the server to which update and LLQ requests will be sent for a given name. Once the address is 3526 * derived, it will be passed to the callback, along with a context pointer. If the zone cannot 3527 * be determined or if an error occurs, an all-zeros address will be passed and a message will be 3528 * written to the syslog. 3529 * 3530 * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined 3531 * by querying for the _dns-update._udp.<zone>. SRV record. Likewise, if the FindLLQPort arg is set, 3532 * the port on which the server accepts long lived queries is determined by querying for 3533 * _dns-llq._udp.<zone>. record. If either of these queries fail, or flags are not specified, 3534 * the llqPort and updatePort fields in the result structure are set to zero. 3535 * 3536 * Steps for deriving the zone name are as follows: 3537 * 3538 * Query for an SOA record for the required domain. If we don't get an answer (or an SOA in the Authority 3539 * section), we strip the leading label from the name and repeat, until we get an answer. 3540 * 3541 * The name of the SOA record is our enclosing zone. The mname field in the SOA rdata is the domain 3542 * name of the primary NS. 3543 * 3544 * We verify that there is an NS record with this zone for a name and the mname for its rdata. 3545 * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since 3546 * the NS query will get us address records in the additionals section, which we'd otherwise have to 3547 * explicitly query for.) 3548 * 3549 * We then query for the address record for this nameserver (if it is not in the addionals section of 3550 * the NS record response.) 3551 */ 3552 3553 3554 // state machine types and structs 3555 // 3556 3557 // state machine states 3558 typedef enum 3559 { 3560 init, 3561 lookupSOA, 3562 foundZone, 3563 lookupNS, 3564 foundNS, 3565 lookupA, 3566 foundA, 3567 lookupPort, 3568 foundPort, 3569 complete 3570 } ntaState; 3571 3572 // state machine actions 3573 typedef enum 3574 { 3575 smContinue, // continue immediately to next state 3576 smBreak, // break until next packet/timeout 3577 smError // terminal error - cleanup and abort 3578 } smAction; 3579 3580 typedef struct 3581 { 3582 domainname origName; // name we originally try to convert 3583 domainname *curSOA; // name we have an outstanding SOA query for 3584 ntaState state; // determines what we do upon receiving a packet 3585 mDNS *m; 3586 domainname zone; // left-hand-side of SOA record 3587 mDNSu16 zoneClass; 3588 domainname ns; // mname in SOA rdata, verified in confirmNS state 3589 mDNSv4Addr addr; // address of nameserver 3590 DNSQuestion question; // storage for any active question 3591 DNSQuestion extraQuestion; // additional storage 3592 mDNSBool questionActive; // if true, StopQuery() can be called on the question field 3593 mDNSBool findUpdatePort; 3594 mDNSBool findLLQPort; 3595 mDNSIPPort updatePort; 3596 mDNSIPPort llqPort; 3597 AsyncOpCallback *callback; // caller specified function to be called upon completion 3598 void *callbackInfo; 3599 } ntaContext; 3600 3601 3602 // function prototypes (for routines that must be used as fn pointers prior to their definitions, 3603 // and allows states to be read top-to-bottom in logical order) 3604 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr); 3605 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context); 3606 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr); 3607 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context); 3608 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context); 3609 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context); 3610 3611 // initialization 3612 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, 3613 AsyncOpCallback callback, void *callbackInfo) 3614 { 3615 ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext)); 3616 if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed"); return mStatus_NoMemoryErr; } 3617 ubzero(context, sizeof(ntaContext)); 3618 AssignDomainName(&context->origName, name); 3619 context->state = init; 3620 context->m = m; 3621 context->callback = callback; 3622 context->callbackInfo = callbackInfo; 3623 context->findUpdatePort = findUpdatePort; 3624 context->findLLQPort = findLLQPort; 3625 getZoneData(m, mDNSNULL, mDNSNULL, mDNSNULL, context); 3626 return mStatus_NoError; 3627 } 3628 3629 // state machine entry routine 3630 mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr) 3631 { 3632 AsyncOpResult result; 3633 ntaContext *context = (ntaContext*)contextPtr; 3634 smAction action; 3635 3636 // unused 3637 (void)m; 3638 (void)question; 3639 3640 // stop any active question 3641 if (context->questionActive) 3642 { 3643 uDNS_StopQuery(context->m, &context->question); 3644 context->questionActive = mDNSfalse; 3645 } 3646 3647 if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain) 3648 { 3649 // rcode non-zero, non-nxdomain 3650 LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4); 3651 goto error; 3652 } 3653 3654 switch (context->state) 3655 { 3656 case init: 3657 case lookupSOA: 3658 action = hndlLookupSOA(msg, end, context); 3659 if (action == smError) goto error; 3660 if (action == smBreak) return; 3661 case foundZone: 3662 case lookupNS: 3663 action = confirmNS(msg, end, context); 3664 if (action == smError) goto error; 3665 if (action == smBreak) return; 3666 case foundNS: 3667 case lookupA: 3668 action = lookupNSAddr(msg, end, context); 3669 if (action == smError) goto error; 3670 if (action == smBreak) return; 3671 case foundA: 3672 if (!context->findUpdatePort && !context->findLLQPort) 3673 { 3674 context->state = complete; 3675 break; 3676 } 3677 case lookupPort: 3678 action = hndlLookupPorts(msg, end, context); 3679 if (action == smError) goto error; 3680 if (action == smBreak) return; 3681 if (action == smContinue) context->state = complete; 3682 case foundPort: 3683 case complete: break; 3684 } 3685 3686 if (context->state != complete) 3687 { 3688 LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state); 3689 goto error; 3690 } 3691 3692 result.type = zoneDataResult; 3693 result.zoneData.primaryAddr.ip.v4 = context->addr; 3694 result.zoneData.primaryAddr.type = mDNSAddrType_IPv4; 3695 AssignDomainName(&result.zoneData.zoneName, &context->zone); 3696 result.zoneData.zoneClass = context->zoneClass; 3697 3698 if (context->findLLQPort) 3699 result.zoneData.llqPort = context->llqPort; 3700 else 3701 result.zoneData.llqPort = zeroIPPort; 3702 3703 if (context->findUpdatePort) 3704 result.zoneData.updatePort = context->updatePort; 3705 else 3706 result.zoneData.updatePort = zeroIPPort; 3707 3708 context->callback(mStatus_NoError, context->m, context->callbackInfo, &result); 3709 goto cleanup; 3710 3711 error: 3712 if (context && context->callback) 3713 context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL); 3714 cleanup: 3715 if (context && context->questionActive) 3716 { 3717 uDNS_StopQuery(context->m, &context->question); 3718 context->questionActive = mDNSfalse; 3719 } 3720 if (context) ufree(context); 3721 } 3722 3723 mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context) 3724 { 3725 mStatus err; 3726 LargeCacheRecord lcr; 3727 ResourceRecord *rr = &lcr.r.resrec; 3728 DNSQuestion *query = &context->question; 3729 const mDNSu8 *ptr; 3730 3731 if (msg) 3732 { 3733 // if msg contains SOA record in answer or authority sections, update context/state and return 3734 int i; 3735 ptr = LocateAnswers(msg, end); 3736 for (i = 0; i < msg->h.numAnswers; i++) 3737 { 3738 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); 3739 if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL"); return smError; } 3740 if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, rr->name)) 3741 { 3742 processSOA(context, rr); 3743 return smContinue; 3744 } 3745 } 3746 ptr = LocateAuthorities(msg, end); 3747 // SOA not in answers, check in authority 3748 for (i = 0; i < msg->h.numAuthorities; i++) 3749 { 3750 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth 3751 if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL"); return smError; } 3752 if (rr->rrtype == kDNSType_SOA) 3753 { 3754 processSOA(context, rr); 3755 return smContinue; 3756 } 3757 } 3758 } 3759 3760 if (context->state != init && !context->curSOA->c[0]) 3761 { 3762 // we've gone down to the root and have not found an SOA 3763 LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA", 3764 context->origName.c); 3765 return smError; 3766 } 3767 3768 ubzero(query, sizeof(DNSQuestion)); 3769 // chop off leading label unless this is our first try 3770 if (context->state == init) context->curSOA = &context->origName; 3771 else context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1); 3772 3773 context->state = lookupSOA; 3774 AssignDomainName(&query->qname, context->curSOA); 3775 query->qtype = kDNSType_SOA; 3776 query->qclass = kDNSClass_IN; 3777 err = startInternalQuery(query, context->m, getZoneData, context); 3778 context->questionActive = mDNStrue; 3779 if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err); 3780 3781 return smBreak; // break from state machine until we receive another packet 3782 } 3783 3784 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr) 3785 { 3786 AssignDomainName(&context->zone, rr->name); 3787 context->zoneClass = rr->rrclass; 3788 AssignDomainName(&context->ns, &rr->rdata->u.soa.mname); 3789 context->state = foundZone; 3790 } 3791 3792 3793 mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context) 3794 { 3795 DNSQuestion *query = &context->question; 3796 mStatus err; 3797 LargeCacheRecord lcr; 3798 const ResourceRecord *const rr = &lcr.r.resrec; 3799 const mDNSu8 *ptr; 3800 int i; 3801 3802 if (context->state == foundZone) 3803 { 3804 // we've just learned the zone. confirm that an NS record exists 3805 AssignDomainName(&query->qname, &context->zone); 3806 query->qtype = kDNSType_NS; 3807 query->qclass = kDNSClass_IN; 3808 err = startInternalQuery(query, context->m, getZoneData, context); 3809 context->questionActive = mDNStrue; 3810 if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err); 3811 context->state = lookupNS; 3812 return smBreak; // break from SM until we receive another packet 3813 } 3814 else if (context->state == lookupNS) 3815 { 3816 ptr = LocateAnswers(msg, end); 3817 for (i = 0; i < msg->h.numAnswers; i++) 3818 { 3819 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); 3820 if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL"); return smError; } 3821 if (rr->rrtype == kDNSType_NS && 3822 SameDomainName(&context->zone, rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name)) 3823 { 3824 context->state = foundNS; 3825 return smContinue; // next routine will examine additionals section of A record 3826 } 3827 } 3828 debugf("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c); 3829 return smError; 3830 } 3831 else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; } 3832 } 3833 3834 mDNSlocal smAction queryNSAddr(ntaContext *context) 3835 { 3836 mStatus err; 3837 DNSQuestion *query = &context->question; 3838 3839 AssignDomainName(&query->qname, &context->ns); 3840 query->qtype = kDNSType_A; 3841 query->qclass = kDNSClass_IN; 3842 err = startInternalQuery(query, context->m, getZoneData, context); 3843 context->questionActive = mDNStrue; 3844 if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err); 3845 context->state = lookupA; 3846 return smBreak; 3847 } 3848 3849 mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context) 3850 { 3851 const mDNSu8 *ptr; 3852 int i; 3853 LargeCacheRecord lcr; 3854 ResourceRecord *rr = &lcr.r.resrec; 3855 3856 if (context->state == foundNS) 3857 { 3858 // we just found the NS record - look for the corresponding A record in the Additionals section 3859 if (!msg->h.numAdditionals) return queryNSAddr(context); 3860 ptr = LocateAdditionals(msg, end); 3861 if (!ptr) 3862 { 3863 LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals); 3864 return queryNSAddr(context); 3865 } 3866 else 3867 { 3868 for (i = 0; i < msg->h.numAdditionals; i++) 3869 { 3870 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); 3871 if (!ptr) 3872 { 3873 LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL"); 3874 return queryNSAddr(context); 3875 } 3876 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name)) 3877 { 3878 context->addr = rr->rdata->u.ipv4; 3879 context->state = foundA; 3880 return smContinue; 3881 } 3882 } 3883 } 3884 // no A record in Additionals - query the server 3885 return queryNSAddr(context); 3886 } 3887 else if (context->state == lookupA) 3888 { 3889 ptr = LocateAnswers(msg, end); 3890 if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL"); return smError; } 3891 for (i = 0; i < msg->h.numAnswers; i++) 3892 { 3893 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); 3894 if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; } 3895 if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name)) 3896 { 3897 context->addr = rr->rdata->u.ipv4; 3898 context->state = foundA; 3899 return smContinue; 3900 } 3901 } 3902 LogMsg("ERROR: lookupNSAddr: Address record not found in answer section"); 3903 return smError; 3904 } 3905 else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; } 3906 } 3907 3908 mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port) 3909 { 3910 int i; 3911 LargeCacheRecord lcr; 3912 const mDNSu8 *ptr; 3913 DNSQuestion *q; 3914 mStatus err; 3915 3916 if (context->state == lookupPort) // we've already issued the query 3917 { 3918 if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; } 3919 ptr = LocateAnswers(msg, end); 3920 for (i = 0; i < msg->h.numAnswers; i++) 3921 { 3922 ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); 3923 if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL"); return smError; } 3924 if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question)) 3925 { 3926 *port = lcr.r.resrec.rdata->u.srv.port; 3927 context->state = foundPort; 3928 return smContinue; 3929 } 3930 } 3931 debugf("hndlLookupUpdatePort - no answer for type %s", portName); 3932 port->NotAnInteger = 0; 3933 context->state = foundPort; 3934 return smContinue; 3935 } 3936 3937 // query the server for the update port for the zone 3938 context->state = lookupPort; 3939 q = &context->question; 3940 MakeDomainNameFromDNSNameString(&q->qname, portName); 3941 AppendDomainName(&q->qname, &context->zone); 3942 q->qtype = kDNSType_SRV; 3943 q->qclass = kDNSClass_IN; 3944 err = startInternalQuery(q, context->m, getZoneData, context); 3945 context->questionActive = mDNStrue; 3946 if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err); 3947 return smBreak; // break from state machine until we receive another packet 3948 } 3949 3950 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context) 3951 { 3952 smAction action; 3953 3954 if (context->findUpdatePort && !context->updatePort.NotAnInteger) 3955 { 3956 action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort); 3957 if (action != smContinue) return action; 3958 } 3959 if (context->findLLQPort && !context->llqPort.NotAnInteger) 3960 return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort); 3961 3962 return smContinue; 3963 } 3964 3965 3966 // *************************************************************************** 3967 #if COMPILER_LIKES_PRAGMA_MARK 3968 #pragma mark - Truncation Handling 3969 #endif 3970 3971 typedef struct 3972 { 3973 DNSQuestion *question; 3974 DNSMessage *reply; 3975 mDNSu16 replylen; 3976 int nread; 3977 mDNS *m; 3978 } tcpInfo_t; 3979 3980 // issue queries over a conected socket 3981 mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished) 3982 { 3983 mStatus err = 0; 3984 char msgbuf[356]; // 96 (hdr) + 256 (domain) + 4 (class/type) 3985 DNSMessage *msg; 3986 mDNSu8 *end; 3987 tcpInfo_t *info = (tcpInfo_t *)context; 3988 DNSQuestion *question = info->question; 3989 int n; 3990 mDNS *m = info->m; 3991 3992 mDNS_Lock(m); 3993 3994 if (ConnectionEstablished) 3995 { 3996 // connection is established - send the message 3997 msg = (DNSMessage *)&msgbuf; 3998 err = constructQueryMsg(msg, &end, question); 3999 if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err); goto error; } 4000 err = mDNSSendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL); 4001 question->LastQTime = mDNSPlatformTimeNow(m); 4002 if (err) { debugf("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err); goto error; } 4003 } 4004 else 4005 { 4006 if (!info->nread) 4007 { 4008 // read msg len 4009 mDNSu8 lenbuf[2]; 4010 n = mDNSPlatformReadTCP(sd, lenbuf, 2); 4011 if (n != 2) 4012 { 4013 LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n); 4014 goto error; 4015 } 4016 info->replylen = (mDNSu16)((mDNSu16)lenbuf[0] << 8 | lenbuf[1]); 4017 if (info->replylen < sizeof(DNSMessageHeader)) 4018 { LogMsg("ERROR: conQueryCallback - length too short (%d bytes)", info->replylen); goto error; } 4019 info->reply = umalloc(info->replylen); 4020 if (!info->reply) { LogMsg("ERROR: conQueryCallback - malloc failed"); goto error; } 4021 } 4022 n = mDNSPlatformReadTCP(sd, ((char *)info->reply) + info->nread, info->replylen - info->nread); 4023 if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; } 4024 info->nread += n; 4025 if (info->nread == info->replylen) 4026 { 4027 // Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second) 4028 DNSMessage *msg = info->reply; 4029 mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions; 4030 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 4031 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 4032 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); 4033 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); 4034 uDNS_ReceiveMsg(m, msg, (mDNSu8 *)msg + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID); 4035 mDNSPlatformTCPCloseConnection(sd); 4036 ufree(info->reply); 4037 ufree(info); 4038 } 4039 } 4040 4041 mDNS_Unlock(m); 4042 return; 4043 4044 error: 4045 mDNSPlatformTCPCloseConnection(sd); 4046 if (info->reply) ufree(info->reply); 4047 ufree(info); 4048 mDNS_Unlock(m); 4049 } 4050 4051 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m) 4052 { 4053 mStatus connectionStatus; 4054 uDNS_QuestionInfo *info = &question->uDNS_info; 4055 int sd; 4056 tcpInfo_t *context; 4057 4058 if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; } 4059 4060 context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t)); 4061 if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; } 4062 ubzero(context, sizeof(tcpInfo_t)); 4063 context->question = question; 4064 context->m = m; 4065 info->id = newMessageID(&m->uDNS_info); 4066 4067 connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd); 4068 if (connectionStatus == mStatus_ConnEstablished) // manually invoke callback if connection completes 4069 { 4070 conQueryCallback(sd, context, mDNStrue); 4071 return; 4072 } 4073 if (connectionStatus == mStatus_ConnPending) return; // callback will be automatically invoked when connection completes 4074 LogMsg("hndlTruncatedAnswer: connection failed"); 4075 uDNS_StopQuery(m, question); //!!!KRS can we really call this here? 4076 } 4077 4078 4079 // *************************************************************************** 4080 #if COMPILER_LIKES_PRAGMA_MARK 4081 #pragma mark - Dynamic Updates 4082 #endif 4083 4084 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr) 4085 { 4086 DNSMessage msg; 4087 mDNSu8 *ptr = msg.data; 4088 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage); 4089 uDNS_GlobalInfo *u = &m->uDNS_info; 4090 mDNSOpaque16 id; 4091 uDNS_RegInfo *regInfo = &rr->uDNS_info; 4092 mStatus err = mStatus_UnknownErr; 4093 4094 id = newMessageID(u); 4095 InitializeDNSMessage(&msg.h, id, UpdateReqFlags); 4096 rr->uDNS_info.id = id; 4097 4098 // set zone 4099 ptr = putZone(&msg, ptr, end, ®Info->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); 4100 if (!ptr) goto error; 4101 4102 if (regInfo->state == regState_UpdatePending) 4103 { 4104 // delete old RData 4105 SetNewRData(&rr->resrec, regInfo->OrigRData, regInfo->OrigRDLen); 4106 if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error; // delete old rdata 4107 4108 // add new RData 4109 SetNewRData(&rr->resrec, regInfo->InFlightRData, regInfo->InFlightRDLen); 4110 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) goto error; 4111 } 4112 4113 else 4114 { 4115 if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) 4116 { 4117 // KnownUnique: Delete any previous value 4118 ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype); 4119 if (!ptr) goto error; 4120 } 4121 4122 else if (rr->resrec.RecordType != kDNSRecordTypeShared) 4123 { 4124 ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end); 4125 if (!ptr) goto error; 4126 } 4127 4128 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl); 4129 if (!ptr) goto error; 4130 } 4131 4132 if (rr->uDNS_info.lease) 4133 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; } 4134 4135 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, ®Info->ns, regInfo->port, -1, GetAuthInfoForName(u, rr->resrec.name)); 4136 if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err); 4137 4138 SetRecordRetry(m, rr, err); 4139 4140 if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred && regInfo->state != regState_UpdatePending) 4141 regInfo->state = regState_Pending; 4142 4143 return; 4144 4145 error: 4146 LogMsg("sendRecordRegistration: Error formatting message"); 4147 if (rr->uDNS_info.state != regState_Unregistered) 4148 { 4149 unlinkAR(&u->RecordRegistrations, rr); 4150 rr->uDNS_info.state = regState_Unregistered; 4151 } 4152 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4153 if (rr->RecordCallback) rr->RecordCallback(m, rr, err); 4154 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4155 // NOTE: not safe to touch any client structures here 4156 } 4157 4158 mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result) 4159 { 4160 AuthRecord *newRR = (AuthRecord*)authPtr; 4161 const zoneData_t *zoneData = mDNSNULL; 4162 uDNS_GlobalInfo *u = &m->uDNS_info; 4163 AuthRecord *ptr; 4164 4165 // make sure record is still in list 4166 for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next) 4167 if (ptr == newRR) break; 4168 if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; } 4169 4170 // check error/result 4171 if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; } 4172 if (!result) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error; } 4173 else zoneData = &result->zoneData; 4174 4175 if (newRR->uDNS_info.state == regState_Cancelled) 4176 { 4177 //!!!KRS we should send a memfree callback here! 4178 debugf("Registration of %##s type %d cancelled prior to update", 4179 newRR->resrec.name->c, newRR->resrec.rrtype); 4180 newRR->uDNS_info.state = regState_Unregistered; 4181 unlinkAR(&u->RecordRegistrations, newRR); 4182 return; 4183 } 4184 4185 if (result->type != zoneDataResult) 4186 { 4187 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type); 4188 goto error; 4189 } 4190 4191 if (newRR->resrec.rrclass != zoneData->zoneClass) 4192 { 4193 LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", 4194 newRR->resrec.rrclass, zoneData->zoneClass); 4195 goto error; 4196 } 4197 4198 // Don't try to do updates to the root name server. 4199 // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some 4200 // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that. 4201 if (zoneData->zoneName.c[0] == 0) 4202 { 4203 LogMsg("ERROR: Only name server claiming responsibility for \"%##s\" is \"%##s\"!", 4204 newRR->resrec.name->c, zoneData->zoneName.c); 4205 err = mStatus_NoSuchNameErr; 4206 goto error; 4207 } 4208 4209 // cache zone data 4210 AssignDomainName(&newRR->uDNS_info.zone, &zoneData->zoneName); 4211 newRR->uDNS_info.ns = zoneData->primaryAddr; 4212 if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort; 4213 else 4214 { 4215 debugf("Update port not advertised via SRV - guessing port 53, no lease option"); 4216 newRR->uDNS_info.port = UnicastDNSPort; 4217 newRR->uDNS_info.lease = mDNSfalse; 4218 } 4219 4220 sendRecordRegistration(m, newRR); 4221 return; 4222 4223 error: 4224 if (newRR->uDNS_info.state != regState_Unregistered) 4225 { 4226 unlinkAR(&u->RecordRegistrations, newRR); 4227 newRR->uDNS_info.state = regState_Unregistered; 4228 } 4229 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4230 if (newRR->RecordCallback) 4231 newRR->RecordCallback(m, newRR, err); 4232 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4233 // NOTE: not safe to touch any client structures here 4234 } 4235 4236 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs) 4237 { 4238 DNSMessage msg; 4239 mDNSu8 *ptr = msg.data; 4240 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage); 4241 uDNS_GlobalInfo *u = &m->uDNS_info; 4242 mDNSOpaque16 id; 4243 uDNS_RegInfo *rInfo = &srs->uDNS_info; 4244 mStatus err = mStatus_UnknownErr; 4245 mDNSIPPort privport; 4246 NATTraversalInfo *nat = srs->uDNS_info.NATinfo; 4247 mDNSBool mapped = mDNSfalse; 4248 domainname target; 4249 AuthRecord *srv = &srs->RR_SRV; 4250 mDNSu32 i; 4251 4252 privport = zeroIPPort; 4253 4254 if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; } 4255 4256 id = newMessageID(u); 4257 InitializeDNSMessage(&msg.h, id, UpdateReqFlags); 4258 4259 // setup resource records 4260 SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0); 4261 SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0); 4262 4263 // replace port w/ NAT mapping if necessary 4264 if (nat && nat->PublicPort.NotAnInteger && 4265 (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)) 4266 { 4267 privport = srv->resrec.rdata->u.srv.port; 4268 srv->resrec.rdata->u.srv.port = nat->PublicPort; 4269 mapped = mDNStrue; 4270 } 4271 4272 // construct update packet 4273 // set zone 4274 ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass)); 4275 if (!ptr) goto error; 4276 4277 if (srs->uDNS_info.TestForSelfConflict) 4278 { 4279 // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records 4280 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error; 4281 if (!(ptr = putDeleteRRSet(&msg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) goto error; 4282 } 4283 4284 else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending) 4285 { 4286 // use SRV name for prereq 4287 ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end); 4288 if (!ptr) goto error; 4289 } 4290 4291 //!!!KRS Need to do bounds checking and use TCP if it won't fit!!! 4292 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error; 4293 4294 for (i = 0; i < srs->NumSubTypes; i++) 4295 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) goto error; 4296 4297 if (rInfo->state == regState_UpdatePending) // we're updating the txt record 4298 { 4299 AuthRecord *txt = &srs->RR_TXT; 4300 uDNS_RegInfo *txtInfo = &txt->uDNS_info; 4301 // delete old RData 4302 SetNewRData(&txt->resrec, txtInfo->OrigRData, txtInfo->OrigRDLen); 4303 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error; // delete old rdata 4304 4305 // add new RData 4306 SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen); 4307 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error; 4308 } 4309 else 4310 if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error; 4311 4312 if (!GetServiceTarget(u, srv, &target)) 4313 { 4314 debugf("Couldn't get target for service %##s", srv->resrec.name->c); 4315 rInfo->state = regState_NoTarget; 4316 return; 4317 } 4318 4319 if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target)) 4320 { 4321 AssignDomainName(&srv->resrec.rdata->u.srv.target, &target); 4322 SetNewRData(&srv->resrec, mDNSNULL, 0); 4323 } 4324 4325 ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl); 4326 if (!ptr) goto error; 4327 4328 if (srs->uDNS_info.lease) 4329 { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; } 4330 4331 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name)); 4332 if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err); 4333 4334 if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending) 4335 rInfo->state = regState_Pending; 4336 4337 SetRecordRetry(m, &srs->RR_SRV, err); 4338 rInfo->id = id; 4339 if (mapped) srv->resrec.rdata->u.srv.port = privport; 4340 return; 4341 4342 error: 4343 LogMsg("SendServiceRegistration - Error formatting message"); 4344 if (mapped) srv->resrec.rdata->u.srv.port = privport; 4345 unlinkSRS(m, srs); 4346 rInfo->state = regState_Unregistered; 4347 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4348 srs->ServiceCallback(m, srs, err); 4349 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4350 //!!!KRS will mem still be free'd on error? 4351 // NOTE: not safe to touch any client structures here 4352 } 4353 4354 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result) 4355 { 4356 ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr; 4357 const zoneData_t *zoneData = mDNSNULL; 4358 4359 if (err) goto error; 4360 if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error"); goto error; } 4361 else zoneData = &result->zoneData; 4362 4363 if (result->type != zoneDataResult) 4364 { 4365 LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type); 4366 goto error; 4367 } 4368 4369 if (srs->uDNS_info.state == regState_Cancelled) 4370 { 4371 // client cancelled registration while fetching zone data 4372 srs->uDNS_info.state = regState_Unregistered; 4373 unlinkSRS(m, srs); 4374 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4375 srs->ServiceCallback(m, srs, mStatus_MemFree); 4376 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4377 return; 4378 } 4379 4380 if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass) 4381 { 4382 LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c); 4383 goto error; 4384 } 4385 4386 // cache zone data 4387 AssignDomainName(&srs->uDNS_info.zone, &zoneData->zoneName); 4388 srs->uDNS_info.ns.type = mDNSAddrType_IPv4; 4389 srs->uDNS_info.ns = zoneData->primaryAddr; 4390 if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort; 4391 else 4392 { 4393 debugf("Update port not advertised via SRV - guessing port 53, no lease option"); 4394 srs->uDNS_info.port = UnicastDNSPort; 4395 srs->uDNS_info.lease = mDNSfalse; 4396 } 4397 4398 if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && IsPrivateV4Addr(&m->uDNS_info.AdvertisedV4)) 4399 { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); } 4400 else SendServiceRegistration(m, srs); 4401 return; 4402 4403 error: 4404 unlinkSRS(m, srs); 4405 srs->uDNS_info.state = regState_Unregistered; 4406 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4407 srs->ServiceCallback(m, srs, err); 4408 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4409 // NOTE: not safe to touch any client structures here 4410 } 4411 4412 mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr) 4413 { 4414 domainname *target = GetRRDomainNameTarget(&rr->resrec); 4415 AuthRecord *ptr = m->uDNS_info.RecordRegistrations; 4416 4417 while (ptr && ptr != rr) ptr = ptr->next; 4418 if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name->c); return mStatus_AlreadyRegistered; } 4419 4420 if (rr->uDNS_info.state == regState_FetchingZoneData || 4421 rr->uDNS_info.state == regState_Pending || 4422 rr->uDNS_info.state == regState_Registered) 4423 { 4424 LogMsg("Requested double-registration of physical record %##s type %d", 4425 rr->resrec.name->c, rr->resrec.rrtype); 4426 return mStatus_AlreadyRegistered; 4427 } 4428 4429 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse); 4430 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue); 4431 4432 if (!ValidateDomainName(rr->resrec.name)) 4433 { 4434 LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); 4435 return mStatus_Invalid; 4436 } 4437 4438 // Don't do this until *after* we've set rr->resrec.rdlength 4439 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata)) 4440 { 4441 LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); 4442 return mStatus_Invalid; 4443 } 4444 4445 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 4446 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u); 4447 4448 rr->uDNS_info.state = regState_FetchingZoneData; 4449 rr->next = m->uDNS_info.RecordRegistrations; 4450 m->uDNS_info.RecordRegistrations = rr; 4451 rr->uDNS_info.lease = mDNStrue; 4452 4453 return mStatus_NoError; 4454 } 4455 4456 mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr) 4457 { 4458 mStatus err = SetupRecordRegistration(m, rr); 4459 if (err) return err; 4460 else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr); 4461 } 4462 4463 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) 4464 { 4465 uDNS_GlobalInfo *u = &m->uDNS_info; 4466 DNSMessage msg; 4467 mDNSu8 *ptr = msg.data; 4468 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage); 4469 mStatus err; 4470 4471 InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags); 4472 4473 ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); 4474 if (!ptr) goto error; 4475 if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error; 4476 4477 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(u, rr->resrec.name)); 4478 if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err); 4479 4480 SetRecordRetry(m, rr, err); 4481 rr->uDNS_info.state = regState_DeregPending; 4482 return; 4483 4484 error: 4485 LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet"); 4486 unlinkAR(&u->RecordRegistrations, rr); 4487 rr->uDNS_info.state = regState_Unregistered; 4488 } 4489 4490 4491 4492 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr) 4493 { 4494 uDNS_GlobalInfo *u = &m->uDNS_info; 4495 NATTraversalInfo *n = rr->uDNS_info.NATinfo; 4496 4497 switch (rr->uDNS_info.state) 4498 { 4499 case regState_NATMap: 4500 // we're in the middle of a NAT traversal operation 4501 rr->uDNS_info.NATinfo = mDNSNULL; 4502 if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context"); 4503 else FreeNATInfo(m, n); // cause response to outstanding request to be ignored. 4504 // Note: normally here we're trying to determine our public address, 4505 //in which case there is not state to be torn down. For simplicity, 4506 //we allow other operations to expire. 4507 rr->uDNS_info.state = regState_Unregistered; 4508 break; 4509 case regState_ExtraQueued: 4510 rr->uDNS_info.state = regState_Unregistered; 4511 break; 4512 case regState_FetchingZoneData: 4513 rr->uDNS_info.state = regState_Cancelled; 4514 return mStatus_NoError; 4515 case regState_Refresh: 4516 case regState_Pending: 4517 case regState_UpdatePending: 4518 rr->uDNS_info.state = regState_DeregDeferred; 4519 LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c); 4520 return mStatus_NoError; 4521 case regState_Registered: 4522 case regState_DeregPending: 4523 break; 4524 case regState_DeregDeferred: 4525 case regState_Cancelled: 4526 LogMsg("Double deregistration of record %##s type %d", 4527 rr->resrec.name->c, rr->resrec.rrtype); 4528 return mStatus_UnknownErr; 4529 case regState_Unregistered: 4530 LogMsg("Requested deregistration of unregistered record %##s type %d", 4531 rr->resrec.name->c, rr->resrec.rrtype); 4532 return mStatus_UnknownErr; 4533 case regState_NATError: 4534 case regState_NoTarget: 4535 LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError"); 4536 return mStatus_UnknownErr; 4537 } 4538 4539 if (rr->uDNS_info.state == regState_Unregistered) 4540 { 4541 // unlink and deliver memfree 4542 4543 unlinkAR(&u->RecordRegistrations, rr); 4544 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4545 if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree); 4546 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4547 return mStatus_NoError; 4548 } 4549 4550 rr->uDNS_info.NATinfo = mDNSNULL; 4551 if (n) FreeNATInfo(m, n); 4552 4553 SendRecordDeregistration(m, rr); 4554 return mStatus_NoError; 4555 } 4556 4557 mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs) 4558 { 4559 mDNSu32 i; 4560 domainname target; 4561 uDNS_RegInfo *info = &srs->uDNS_info; 4562 ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations; 4563 while (*p && *p != srs) p=&(*p)->next; 4564 if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); } 4565 ubzero(info, sizeof(*info)); 4566 *p = srs; 4567 srs->next = mDNSNULL; 4568 4569 srs->RR_SRV.resrec.rroriginalttl = kWideAreaTTL; 4570 srs->RR_TXT.resrec.rroriginalttl = kWideAreaTTL; 4571 srs->RR_PTR.resrec.rroriginalttl = kWideAreaTTL; 4572 for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kWideAreaTTL; 4573 4574 info->lease = mDNStrue; 4575 4576 srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0; 4577 if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target)) 4578 { 4579 // defer registration until we've got a target 4580 debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c); 4581 info->state = regState_NoTarget; 4582 return mStatus_NoError; 4583 } 4584 4585 info->state = regState_FetchingZoneData; 4586 return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs); 4587 } 4588 4589 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs) 4590 { 4591 uDNS_RegInfo *info = &srs->uDNS_info; 4592 uDNS_GlobalInfo *u = &m->uDNS_info; 4593 DNSMessage msg; 4594 mDNSOpaque16 id; 4595 mDNSu8 *ptr = msg.data; 4596 mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage); 4597 mStatus err = mStatus_UnknownErr; 4598 mDNSu32 i; 4599 4600 id = newMessageID(u); 4601 InitializeDNSMessage(&msg.h, id, UpdateReqFlags); 4602 4603 // put zone 4604 ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass)); 4605 if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; } 4606 4607 if (!(ptr = putDeleteAllRRSets(&msg, ptr, srs->RR_SRV.resrec.name))) goto error; // this deletes SRV, TXT, and Extras 4608 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error; 4609 for (i = 0; i < srs->NumSubTypes; i++) 4610 if (!(ptr = putDeletionRecord(&msg, ptr, &srs->SubTypes[i].resrec))) goto error; 4611 4612 4613 err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name)); 4614 if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; } 4615 4616 SetRecordRetry(m, &srs->RR_SRV, err); 4617 info->id = id; 4618 info->state = regState_DeregPending; 4619 4620 return; 4621 4622 error: 4623 unlinkSRS(m, srs); 4624 info->state = regState_Unregistered; 4625 } 4626 4627 mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs) 4628 { 4629 NATTraversalInfo *nat = srs->uDNS_info.NATinfo; 4630 char *errmsg = "Unknown State"; 4631 4632 // don't re-register with a new target following deregistration 4633 srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse; 4634 4635 if (nat) 4636 { 4637 if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy) 4638 DeleteNATPortMapping(m, nat, srs); 4639 nat->reg.ServiceRegistration = mDNSNULL; 4640 srs->uDNS_info.NATinfo = mDNSNULL; 4641 FreeNATInfo(m, nat); 4642 } 4643 4644 switch (srs->uDNS_info.state) 4645 { 4646 case regState_Unregistered: 4647 debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c); 4648 return mStatus_BadReferenceErr; 4649 case regState_FetchingZoneData: 4650 // let the async op complete, then terminate 4651 srs->uDNS_info.state = regState_Cancelled; 4652 return mStatus_NoError; // deliver memfree upon completion of async op 4653 case regState_Pending: 4654 case regState_Refresh: 4655 case regState_UpdatePending: 4656 // deregister following completion of in-flight operation 4657 srs->uDNS_info.state = regState_DeregDeferred; 4658 return mStatus_NoError; 4659 case regState_DeregPending: 4660 case regState_DeregDeferred: 4661 case regState_Cancelled: 4662 debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c); 4663 return mStatus_NoError; 4664 case regState_NATError: // not registered 4665 case regState_NATMap: // not registered 4666 case regState_NoTarget: // not registered 4667 unlinkSRS(m, srs); 4668 srs->uDNS_info.state = regState_Unregistered; 4669 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4670 srs->ServiceCallback(m, srs, mStatus_MemFree); 4671 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4672 return mStatus_NoError; 4673 case regState_Registered: 4674 srs->uDNS_info.state = regState_DeregPending; 4675 SendServiceDeregistration(m, srs); 4676 return mStatus_NoError; 4677 case regState_ExtraQueued: // only for record registrations 4678 errmsg = "bad state (regState_ExtraQueued)"; 4679 goto error; 4680 } 4681 4682 error: 4683 LogMsg("Error, uDNS_DeregisterService: %s", errmsg); 4684 return mStatus_BadReferenceErr; 4685 } 4686 4687 mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra) 4688 { 4689 mStatus err = mStatus_UnknownErr; 4690 4691 extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name 4692 extra->r.RecordCallback = mDNSNULL; // don't generate callbacks for extra RRs 4693 4694 if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh) 4695 err = uDNS_RegisterRecord(m, &extra->r); 4696 else 4697 { 4698 err = SetupRecordRegistration(m, &extra->r); 4699 extra->r.uDNS_info.state = regState_ExtraQueued; // %%% Is it okay to overwrite the previous uDNS_info.state? 4700 } 4701 4702 if (!err) 4703 { 4704 extra->next = sr->Extras; 4705 sr->Extras = extra; 4706 } 4707 return err; 4708 } 4709 4710 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr) 4711 { 4712 uDNS_GlobalInfo *u = &m->uDNS_info; 4713 ServiceRecordSet *parent = mDNSNULL; 4714 AuthRecord *rptr; 4715 uDNS_RegInfo *info = &rr->uDNS_info; 4716 regState_t *stateptr = mDNSNULL; 4717 4718 // find the record in registered service list 4719 for (parent = u->ServiceRegistrations; parent; parent = parent->next) 4720 if (&parent->RR_TXT == rr) { stateptr = &parent->uDNS_info.state; break; } 4721 4722 if (!parent) 4723 { 4724 // record not part of a service - check individual record registrations 4725 for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next) 4726 if (rptr == rr) { stateptr = &rr->uDNS_info.state; break; } 4727 if (!rptr) goto unreg_error; 4728 } 4729 4730 switch(*stateptr) 4731 { 4732 case regState_DeregPending: 4733 case regState_DeregDeferred: 4734 case regState_Cancelled: 4735 case regState_Unregistered: 4736 // not actively registered 4737 goto unreg_error; 4738 4739 case regState_FetchingZoneData: 4740 case regState_NATMap: 4741 case regState_ExtraQueued: 4742 case regState_NoTarget: 4743 // change rdata directly since it hasn't been sent yet 4744 if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, rr->resrec.rdata); 4745 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); 4746 rr->NewRData = mDNSNULL; 4747 return mStatus_NoError; 4748 4749 case regState_Pending: 4750 case regState_Refresh: 4751 case regState_UpdatePending: 4752 // registration in-flight. queue rdata and return 4753 if (info->QueuedRData && info->UpdateRDCallback) 4754 // if unsent rdata is already queued, free it before we replace it 4755 info->UpdateRDCallback(m, rr, info->QueuedRData); 4756 info->QueuedRData = rr->NewRData; 4757 info->QueuedRDLen = rr->newrdlength; 4758 rr->NewRData = mDNSNULL; 4759 return mStatus_NoError; 4760 4761 case regState_Registered: 4762 info->OrigRData = rr->resrec.rdata; 4763 info->OrigRDLen = rr->resrec.rdlength; 4764 info->InFlightRData = rr->NewRData; 4765 info->InFlightRDLen = rr->newrdlength; 4766 rr->NewRData = mDNSNULL; 4767 *stateptr = regState_UpdatePending; 4768 if (parent) SendServiceRegistration(m, parent); 4769 else sendRecordRegistration(m, rr); 4770 return mStatus_NoError; 4771 4772 case regState_NATError: 4773 LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c); 4774 return mStatus_UnknownErr; // states for service records only 4775 } 4776 4777 unreg_error: 4778 LogMsg("Requested update of record %##s type %d, part of service not currently registered", 4779 rr->resrec.name->c, rr->resrec.rrtype); 4780 return mStatus_Invalid; 4781 } 4782 4783 4784 // *************************************************************************** 4785 #if COMPILER_LIKES_PRAGMA_MARK 4786 #pragma mark - Periodic Execution Routines 4787 #endif 4788 4789 4790 mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow) 4791 { 4792 NATTraversalInfo *ptr = m->uDNS_info.NATTraversals; 4793 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; 4794 4795 while (ptr) 4796 { 4797 NATTraversalInfo *cur = ptr; 4798 ptr = ptr->next; 4799 if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established) // no refresh necessary for established Add requests 4800 { 4801 if (cur->retry - timenow < 0) 4802 { 4803 if (cur->state == NATState_Established) RefreshNATMapping(cur, m); 4804 else if (cur->state == NATState_Request || cur->state == NATState_Refresh) 4805 { 4806 if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur" 4807 else SendNATMsg(cur, m); 4808 } 4809 } 4810 else if (cur->retry - nextevent < 0) nextevent = cur->retry; 4811 } 4812 } 4813 return nextevent; 4814 } 4815 4816 mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow) 4817 { 4818 DNSQuestion *q; 4819 uDNS_GlobalInfo *u = &m->uDNS_info; 4820 LLQ_Info *llq; 4821 mDNSs32 sendtime; 4822 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; 4823 DNSMessage msg; 4824 mStatus err = mStatus_NoError; 4825 mDNSu8 *end; 4826 uDNS_QuestionInfo *info; 4827 4828 u->CurrentQuery = u->ActiveQueries; 4829 while (u->CurrentQuery) 4830 { 4831 q = u->CurrentQuery; 4832 info = &q->uDNS_info; 4833 llq = info->llq; 4834 4835 if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) && 4836 info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0) 4837 { 4838 // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later) 4839 while (info->knownAnswers) 4840 { 4841 CacheRecord *cr = info->knownAnswers; 4842 info->knownAnswers = info->knownAnswers->next; 4843 4844 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4845 q->QuestionCallback(m, q, &cr->resrec, mDNSfalse); 4846 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4847 ufree(cr); 4848 if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; } 4849 } 4850 } 4851 if (q != u->CurrentQuery) continue; 4852 4853 if (q->LongLived && llq->state != LLQ_Poll) 4854 { 4855 if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established) 4856 { 4857 if (llq->retry - timenow < 0) 4858 { 4859 // sanity check to avoid packet flood bugs 4860 if (!llq->retry) 4861 LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state); 4862 else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh) 4863 sendLLQRefresh(m, q, llq->origLease); 4864 else if (llq->state == LLQ_InitialRequest) 4865 startLLQHandshake(m, llq, mDNSfalse); 4866 else if (llq->state == LLQ_SecondaryRequest) 4867 sendChallengeResponse(m, q, mDNSNULL); 4868 else if (llq->state == LLQ_Retry) 4869 { llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); } 4870 } 4871 else if (llq->retry - nextevent < 0) nextevent = llq->retry; 4872 } 4873 } 4874 else 4875 { 4876 sendtime = q->LastQTime + q->ThisQInterval; 4877 if (m->SuppressStdPort53Queries && 4878 sendtime - m->SuppressStdPort53Queries < 0) // Don't allow sendtime to be earlier than SuppressStdPort53Queries 4879 sendtime = m->SuppressStdPort53Queries; 4880 if (sendtime - timenow < 0) 4881 { 4882 DNSServer *server = GetServerForName(&m->uDNS_info, &q->qname); 4883 if (server) 4884 { 4885 if (server->teststate == DNSServer_Untested) 4886 { 4887 InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), uQueryFlags); 4888 end = putQuestion(&msg, msg.data, msg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN); 4889 } 4890 else 4891 err = constructQueryMsg(&msg, &end, q); 4892 if (err) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q->qname.c); 4893 else 4894 { 4895 if (server->teststate != DNSServer_Failed) 4896 err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &server->addr, UnicastDNSPort, -1, mDNSNULL); 4897 m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100); 4898 q->LastQTime = timenow; 4899 if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network 4900 else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2; // don't increase interval if send failed 4901 } 4902 } 4903 } 4904 else if (sendtime - nextevent < 0) nextevent = sendtime; 4905 } 4906 u->CurrentQuery = u->CurrentQuery->next; 4907 } 4908 return nextevent; 4909 } 4910 4911 mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow) 4912 { 4913 AuthRecord *rr; 4914 uDNS_RegInfo *rInfo; 4915 uDNS_GlobalInfo *u = &m->uDNS_info; 4916 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; 4917 4918 //!!!KRS list should be pre-sorted by expiration 4919 for (rr = u->RecordRegistrations; rr; rr = rr->next) 4920 { 4921 rInfo = &rr->uDNS_info; 4922 if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh) 4923 { 4924 if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0) 4925 { 4926 #if MDNS_DEBUGMSGS 4927 char *op = "(unknown operation)"; 4928 if (rInfo->state == regState_Pending) op = "registration"; 4929 else if (rInfo->state == regState_DeregPending) op = "deregistration"; 4930 else if (rInfo->state == regState_Refresh) op = "refresh"; 4931 debugf("Retransmit record %s %##s", op, rr->resrec.name->c); 4932 #endif 4933 //LogMsg("Retransmit record %##s", rr->resrec.name->c); 4934 if (rInfo->state == regState_DeregPending) SendRecordDeregistration(m, rr); 4935 else sendRecordRegistration(m, rr); 4936 } 4937 if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval; 4938 } 4939 if (rInfo->lease && rInfo->state == regState_Registered) 4940 { 4941 if (rInfo->expire - timenow < 0) 4942 { 4943 debugf("refreshing record %##s", rr->resrec.name->c); 4944 rInfo->state = regState_Refresh; 4945 sendRecordRegistration(m, rr); 4946 } 4947 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire; 4948 } 4949 } 4950 return nextevent; 4951 } 4952 4953 mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow) 4954 { 4955 ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations; 4956 uDNS_RegInfo *rInfo; 4957 mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; 4958 4959 // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery 4960 while (s) 4961 { 4962 ServiceRecordSet *srs = s; 4963 // NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at, 4964 // and then if we tried to do srs = srs->next at the end we'd be referencing a dead object 4965 s = s->next; 4966 4967 rInfo = &srs->uDNS_info; 4968 if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh || rInfo->state == regState_UpdatePending) 4969 { 4970 if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0) 4971 { 4972 #if MDNS_DEBUGMSGS 4973 char *op = "unknown"; 4974 if (rInfo->state == regState_Pending) op = "registration"; 4975 else if (rInfo->state == regState_DeregPending) op = "deregistration"; 4976 else if (rInfo->state == regState_Refresh) op = "refresh"; 4977 else if (rInfo->state == regState_UpdatePending) op = "txt record update"; 4978 debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name->c); 4979 #endif 4980 if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; } 4981 else SendServiceRegistration (m, srs); 4982 } 4983 if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0) 4984 nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval; 4985 } 4986 4987 if (rInfo->lease && rInfo->state == regState_Registered) 4988 { 4989 if (rInfo->expire - timenow < 0) 4990 { 4991 debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c); 4992 rInfo->state = regState_Refresh; 4993 SendServiceRegistration(m, srs); 4994 } 4995 if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire; 4996 } 4997 } 4998 return nextevent; 4999 } 5000 5001 mDNSexport void uDNS_Execute(mDNS *const m) 5002 { 5003 uDNS_GlobalInfo *u = &m->uDNS_info; 5004 mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m); 5005 5006 u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; 5007 5008 if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0) 5009 { 5010 u->DelaySRVUpdate = mDNSfalse; 5011 UpdateSRVRecords(m); 5012 } 5013 5014 nexte = CheckNATMappings(m, timenow); 5015 if (nexte - u->nextevent < 0) u->nextevent = nexte; 5016 5017 if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0) 5018 m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it 5019 5020 nexte = CheckQueries(m, timenow); 5021 if (nexte - u->nextevent < 0) u->nextevent = nexte; 5022 5023 nexte = CheckRecordRegistrations(m, timenow); 5024 if (nexte - u->nextevent < 0) u->nextevent = nexte; 5025 5026 nexte = CheckServiceRegistrations(m, timenow); 5027 if (nexte - u->nextevent < 0) u->nextevent = nexte; 5028 5029 } 5030 5031 // *************************************************************************** 5032 #if COMPILER_LIKES_PRAGMA_MARK 5033 #pragma mark - Startup, Shutdown, and Sleep 5034 #endif 5035 5036 // DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false 5037 // following a location change, as the server will reject deletions from a source address different 5038 // from the address on which the LLQ was created. 5039 5040 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive) 5041 { 5042 DNSQuestion *q; 5043 LLQ_Info *llq; 5044 for (q = m->uDNS_info.ActiveQueries; q; q = q->next) 5045 { 5046 llq = q->uDNS_info.llq; 5047 if (q->LongLived && llq) 5048 { 5049 if (llq->state == LLQ_GetZoneInfo) 5050 { 5051 debugf("Marking %##s suspend-deferred", q->qname.c); 5052 llq->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info 5053 } 5054 else if (llq->state < LLQ_Suspended) 5055 { 5056 if (DeregisterActive && (llq->state == LLQ_Established || llq->state == LLQ_Refresh)) 5057 { debugf("Deleting LLQ %##s", q->qname.c); sendLLQRefresh(m, q, 0); } 5058 debugf("Marking %##s suspended", q->qname.c); 5059 llq->state = LLQ_Suspended; 5060 ubzero(llq->id, 8); 5061 } 5062 else if (llq->state == LLQ_Poll) { debugf("Marking %##s suspended-poll", q->qname.c); llq->state = LLQ_SuspendedPoll; } 5063 if (llq->NATMap) llq->NATMap = mDNSfalse; // may not need nat mapping if we restart with new route 5064 } 5065 } 5066 CheckForUnreferencedLLQMapping(m); 5067 } 5068 5069 mDNSlocal void RestartQueries(mDNS *m) 5070 { 5071 uDNS_GlobalInfo *u = &m->uDNS_info; 5072 DNSQuestion *q; 5073 LLQ_Info *llqInfo; 5074 mDNSs32 timenow = mDNSPlatformTimeNow(m); 5075 5076 u->CurrentQuery = u->ActiveQueries; 5077 while (u->CurrentQuery) 5078 { 5079 q = u->CurrentQuery; 5080 u->CurrentQuery = u->CurrentQuery->next; 5081 llqInfo = q->uDNS_info.llq; 5082 q->uDNS_info.RestartTime = timenow; 5083 q->uDNS_info.Answered = mDNSfalse; 5084 if (q->LongLived) 5085 { 5086 if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; } 5087 if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait) 5088 { 5089 llqInfo->ntries = -1; 5090 llqInfo->deriveRemovesOnResume = mDNStrue; 5091 startLLQHandshake(m, llqInfo, mDNStrue); // we set defer to true since several events that may generate restarts often arrive in rapid succession, and this cuts unnecessary packets 5092 } 5093 else if (llqInfo->state == LLQ_SuspendDeferred) 5094 llqInfo->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual 5095 else if (llqInfo->state == LLQ_SuspendedPoll) 5096 { 5097 // if we were polling, we may have had bad zone data due to firewall, etc. - refetch 5098 llqInfo->ntries = 0; 5099 llqInfo->deriveRemovesOnResume = mDNStrue; 5100 llqInfo->state = LLQ_GetZoneInfo; 5101 startGetZoneData(&q->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, llqInfo); 5102 } 5103 } 5104 else { q->LastQTime = timenow; q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; } // trigger poll in 1 second (to reduce packet rate when restarts come in rapid succession) 5105 } 5106 } 5107 5108 mDNSexport void mDNS_UpdateLLQs(mDNS *m) 5109 { 5110 uDNS_GlobalInfo *u = &m->uDNS_info; 5111 5112 mDNS_Lock(m); 5113 if (u->LLQNatInfo) 5114 { 5115 DeleteNATPortMapping(m, u->LLQNatInfo, mDNSNULL); 5116 FreeNATInfo(m, u->LLQNatInfo); // routine clears u->LLQNatInfo ptr 5117 } 5118 SuspendLLQs(m, mDNStrue); 5119 RestartQueries(m); 5120 mDNS_Unlock(m); 5121 } 5122 5123 // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of 5124 // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough 5125 // in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake, 5126 // we just move up the timers. 5127 5128 5129 5130 mDNSlocal void SleepRecordRegistrations(mDNS *m) 5131 { 5132 DNSMessage msg; 5133 AuthRecord *rr = m->uDNS_info.RecordRegistrations; 5134 mDNSs32 timenow = mDNSPlatformTimeNow(m); 5135 5136 while (rr) 5137 { 5138 if (rr->uDNS_info.state == regState_Registered || 5139 rr->uDNS_info.state == regState_Refresh) 5140 { 5141 mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage); 5142 InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags); 5143 5144 // construct deletion update 5145 ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); 5146 if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; } 5147 ptr = putDeletionRecord(&msg, ptr, &rr->resrec); 5148 if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; } 5149 5150 mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(&m->uDNS_info, rr->resrec.name)); 5151 rr->uDNS_info.state = regState_Refresh; 5152 rr->LastAPTime = timenow; 5153 rr->ThisAPInterval = 300 * mDNSPlatformOneSecond; 5154 } 5155 rr = rr->next; 5156 } 5157 } 5158 5159 mDNSlocal void WakeRecordRegistrations(mDNS *m) 5160 { 5161 mDNSs32 timenow = mDNSPlatformTimeNow(m); 5162 AuthRecord *rr = m->uDNS_info.RecordRegistrations; 5163 5164 while (rr) 5165 { 5166 if (rr->uDNS_info.state == regState_Refresh) 5167 { 5168 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets) 5169 rr->LastAPTime = timenow; 5170 rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; 5171 } 5172 rr = rr->next; 5173 } 5174 } 5175 5176 mDNSlocal void SleepServiceRegistrations(mDNS *m) 5177 { 5178 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations; 5179 while(srs) 5180 { 5181 uDNS_RegInfo *info = &srs->uDNS_info; 5182 NATTraversalInfo *nat = info->NATinfo; 5183 5184 if (nat) 5185 { 5186 if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy) 5187 DeleteNATPortMapping(m, nat, srs); 5188 nat->reg.ServiceRegistration = mDNSNULL; 5189 srs->uDNS_info.NATinfo = mDNSNULL; 5190 FreeNATInfo(m, nat); 5191 } 5192 5193 if (info->state == regState_UpdatePending) 5194 { 5195 // act as if the update succeeded, since we're about to delete the name anyway 5196 AuthRecord *txt = &srs->RR_TXT; 5197 uDNS_RegInfo *txtInfo = &txt->uDNS_info; 5198 info->state = regState_Registered; 5199 // deallocate old RData 5200 if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData); 5201 SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen); 5202 txtInfo->OrigRData = mDNSNULL; 5203 txtInfo->InFlightRData = mDNSNULL; 5204 } 5205 5206 if (info->state == regState_Registered || info->state == regState_Refresh) 5207 { 5208 mDNSOpaque16 origid = srs->uDNS_info.id; 5209 info->state = regState_DeregPending; // state expected by SendDereg() 5210 SendServiceDeregistration(m, srs); 5211 info->id = origid; 5212 info->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes 5213 srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0; 5214 } 5215 srs = srs->next; 5216 } 5217 } 5218 5219 mDNSlocal void WakeServiceRegistrations(mDNS *m) 5220 { 5221 mDNSs32 timenow = mDNSPlatformTimeNow(m); 5222 ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations; 5223 while(srs) 5224 { 5225 if (srs->uDNS_info.state == regState_Refresh) 5226 { 5227 // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets) 5228 srs->RR_SRV.LastAPTime = timenow; 5229 srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL; 5230 } 5231 srs = srs->next; 5232 } 5233 } 5234 5235 mDNSexport void uDNS_Init(mDNS *const m) 5236 { 5237 mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo)); 5238 m->uDNS_info.nextevent = m->timenow_last + 0x78000000; 5239 } 5240 5241 mDNSexport void uDNS_Sleep(mDNS *const m) 5242 { 5243 SuspendLLQs(m, mDNStrue); 5244 SleepServiceRegistrations(m); 5245 SleepRecordRegistrations(m); 5246 } 5247 5248 mDNSexport void uDNS_Wake(mDNS *const m) 5249 { 5250 RestartQueries(m); 5251 WakeServiceRegistrations(m); 5252 WakeRecordRegistrations(m); 5253 } 5254