Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

554 lines
14 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Abstract:
  4. Routines implementing Dynamic DNS registration of IPv6 addresses.
  5. --*/
  6. #include "precomp.h"
  7. #pragma hdrstop
  8. #include <windns.h>
  9. //
  10. // DHCP IPv4 addresses inside Microsoft have a TTL of 900.
  11. // But since IPv6 is in testing/development mode currently,
  12. // we use a smaller TTL.
  13. //
  14. #define MAX_AAAA_TTL 60 // Seconds.
  15. //
  16. // We must update the DNS records occasionally,
  17. // or the DNS server might garbage-collect them.
  18. // MSDN recommends a one-day interval.
  19. //
  20. #define MIN_UPDATE_INTERVAL (1*DAYS*1000) // Milliseconds.
  21. __inline ULONG
  22. MIN(ULONG a, ULONG b)
  23. {
  24. if (a < b)
  25. return a;
  26. else
  27. return b;
  28. }
  29. SOCKET g_hIpv6Socket = INVALID_SOCKET;
  30. WSAEVENT g_hIpv6AddressChangeEvent = NULL;
  31. HANDLE g_hIpv6AddressChangeWait = NULL;
  32. WSAOVERLAPPED g_hIpv6AddressChangeOverlapped;
  33. //
  34. // Our caller uses StopIpv6AddressChangeNotification
  35. // if we fail, so we don't need to cleanup.
  36. //
  37. DWORD
  38. StartIpv6AddressChangeNotification()
  39. {
  40. ASSERT(g_hIpv6Socket == INVALID_SOCKET);
  41. g_hIpv6Socket = WSASocket(AF_INET6, 0, 0,
  42. NULL, 0,
  43. WSA_FLAG_OVERLAPPED);
  44. if (g_hIpv6Socket == INVALID_SOCKET)
  45. return WSAGetLastError();
  46. //
  47. // We create an auto-reset event in the signalled state.
  48. // So OnIpv6AddressChange will be executed initially.
  49. //
  50. ASSERT(g_hIpv6AddressChangeEvent == NULL);
  51. g_hIpv6AddressChangeEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
  52. if (g_hIpv6AddressChangeEvent == NULL)
  53. return GetLastError();
  54. //
  55. // We specify a timeout, so that we update DNS
  56. // at least that often. Otherwise the DNS server might
  57. // garbage-collect our records.
  58. //
  59. IncEventCount("AC:StartIpv6AddressChangeNotification");
  60. if (! RegisterWaitForSingleObject(&g_hIpv6AddressChangeWait,
  61. g_hIpv6AddressChangeEvent,
  62. OnIpv6AddressChange,
  63. NULL,
  64. MIN_UPDATE_INTERVAL,
  65. WT_EXECUTELONGFUNCTION)) {
  66. DecEventCount("AC:StartIpv6AddressChangeNotification");
  67. return GetLastError();
  68. }
  69. return NO_ERROR;
  70. }
  71. //
  72. // Assume that if the primary DNS server is the same, then that's
  73. // good enough to combine the records.
  74. //
  75. BOOL
  76. IsSameDNSServer(
  77. PIP_ADAPTER_ADDRESSES pIf1,
  78. PIP_ADAPTER_ADDRESSES pIf2
  79. )
  80. {
  81. PIP_ADAPTER_DNS_SERVER_ADDRESS pDns1, pDns2;
  82. pDns1 = pIf1->FirstDnsServerAddress;
  83. pDns2 = pIf2->FirstDnsServerAddress;
  84. if ((pDns1 == NULL) || (pDns2 == NULL)) {
  85. return FALSE;
  86. }
  87. return !memcmp(pDns1->Address.lpSockaddr,
  88. pDns2->Address.lpSockaddr,
  89. pDns1->Address.iSockaddrLength);
  90. }
  91. DNS_RECORD *
  92. BuildRecordSetW(
  93. WCHAR *hostname,
  94. PIP_ADAPTER_ADDRESSES pFirstIf,
  95. PIP4_ARRAY *ppServerList
  96. )
  97. {
  98. DNS_RECORD *RSet, *pNext;
  99. int i, iAddressCount = 0;
  100. PIP_ADAPTER_UNICAST_ADDRESS Address;
  101. PIP_ADAPTER_ADDRESSES pIf;
  102. int ServerCount = 0;
  103. PIP_ADAPTER_DNS_SERVER_ADDRESS DnsServer;
  104. LPSOCKADDR_IN sin;
  105. //
  106. // Count DNS servers
  107. //
  108. for (DnsServer = pFirstIf->FirstDnsServerAddress;
  109. DnsServer;
  110. DnsServer = DnsServer->Next)
  111. {
  112. if (DnsServer->Address.lpSockaddr->sa_family != AF_INET) {
  113. //
  114. // DNS api currently only supports IPv4 addresses of servers
  115. //
  116. continue;
  117. }
  118. ServerCount++;
  119. }
  120. if (ServerCount == 0) {
  121. *ppServerList = NULL;
  122. return NULL;
  123. }
  124. //
  125. // Fill in DNS server array
  126. //
  127. *ppServerList = MALLOC(FIELD_OFFSET(IP4_ARRAY, AddrArray[ServerCount]));
  128. if (*ppServerList == NULL) {
  129. return NULL;
  130. }
  131. (*ppServerList)->AddrCount = ServerCount;
  132. for (i = 0, DnsServer = pFirstIf->FirstDnsServerAddress;
  133. DnsServer;
  134. DnsServer = DnsServer->Next)
  135. {
  136. sin = (LPSOCKADDR_IN)DnsServer->Address.lpSockaddr;
  137. if (sin->sin_family == AF_INET) {
  138. (*ppServerList)->AddrArray[i++] = sin->sin_addr.s_addr;
  139. }
  140. }
  141. ASSERT(i == ServerCount);
  142. //
  143. // Count eligible addresses
  144. //
  145. for (pIf=pFirstIf; pIf; pIf=pIf->Next) {
  146. if (!(pIf->Flags & IP_ADAPTER_DDNS_ENABLED))
  147. continue;
  148. //
  149. // Make sure interface has same DNS server
  150. //
  151. if ((pIf != pFirstIf) && !IsSameDNSServer(pFirstIf, pIf)) {
  152. continue;
  153. }
  154. for (Address=pIf->FirstUnicastAddress; Address; Address=Address->Next) {
  155. if ((Address->Address.lpSockaddr->sa_family == AF_INET6) &&
  156. (Address->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE)) {
  157. iAddressCount++;
  158. }
  159. }
  160. }
  161. Trace1(FSM, _T("DDNS building record set of %u addresses"), iAddressCount);
  162. if (iAddressCount == 0) {
  163. //
  164. // Build a record set that specifies deletion.
  165. //
  166. RSet = MALLOC(sizeof *RSet);
  167. if (RSet == NULL) {
  168. return NULL;
  169. }
  170. memset(RSet, 0, sizeof *RSet);
  171. RSet->pName = (LPTSTR)hostname;
  172. RSet->wType = DNS_TYPE_AAAA;
  173. return RSet;
  174. }
  175. RSet = MALLOC(sizeof *RSet * iAddressCount);
  176. if (RSet == NULL) {
  177. return NULL;
  178. }
  179. memset(RSet, 0, sizeof *RSet * iAddressCount);
  180. pNext = NULL;
  181. i = iAddressCount;
  182. while (--i >= 0) {
  183. RSet[i].pNext = pNext;
  184. pNext = &RSet[i];
  185. }
  186. i=0;
  187. for (pIf=pFirstIf; pIf; pIf=pIf->Next) {
  188. if (!(pIf->Flags & IP_ADAPTER_DDNS_ENABLED))
  189. continue;
  190. if ((pIf != pFirstIf) && !IsSameDNSServer(pFirstIf, pIf)) {
  191. continue;
  192. }
  193. for (Address=pIf->FirstUnicastAddress;
  194. Address;
  195. Address=Address->Next) {
  196. if ((Address->Address.lpSockaddr->sa_family == AF_INET6) &&
  197. (Address->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE)) {
  198. SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)
  199. Address->Address.lpSockaddr;
  200. RSet[i].pName = (LPTSTR)hostname;
  201. //
  202. // Using a large TTL is not good because it means
  203. // any changes (adding a new address, removing an address)
  204. // might not be visible for a long time.
  205. //
  206. RSet[i].dwTtl = MIN(MAX_AAAA_TTL,
  207. MIN(Address->PreferredLifetime,
  208. Address->LeaseLifetime));
  209. RSet[i].wType = DNS_TYPE_AAAA;
  210. RSet[i].wDataLength = sizeof RSet[i].Data.AAAA;
  211. RSet[i].Data.AAAA.Ip6Address =
  212. * (IP6_ADDRESS *) &sin6->sin6_addr;
  213. i++;
  214. }
  215. }
  216. }
  217. ASSERT(i == iAddressCount);
  218. return RSet;
  219. }
  220. VOID
  221. ReportDnsUpdateStatusW(
  222. IN DNS_STATUS Status,
  223. IN WCHAR *hostname,
  224. IN DNS_RECORD *RSet
  225. )
  226. {
  227. Trace3(ERR, _T("6to4svc: DnsReplaceRecordSet(%ls) %s: status %d"),
  228. hostname,
  229. RSet->wDataLength == 0 ? "delete" : "replace",
  230. Status);
  231. }
  232. //
  233. // This function adapted from net\tcpip\commands\ipconfig\info.c
  234. //
  235. VOID
  236. GetInterfaceDeviceName(
  237. IN ULONG Ipv4IfIndex,
  238. IN PIP_INTERFACE_INFO InterfaceInfo,
  239. OUT LPWSTR *IfDeviceName
  240. )
  241. {
  242. DWORD i;
  243. //
  244. // search the InterfaceInfo to get the devicename for this interface.
  245. //
  246. (*IfDeviceName) = NULL;
  247. for( i = 0; i < (DWORD)InterfaceInfo->NumAdapters; i ++ ) {
  248. if( InterfaceInfo->Adapter[i].Index != Ipv4IfIndex ) continue;
  249. (*IfDeviceName) = InterfaceInfo->Adapter[i].Name + strlen(
  250. "\\Device\\Tcpip_" );
  251. break;
  252. }
  253. }
  254. VOID
  255. RegisterNameOnInterface(
  256. PIP_ADAPTER_ADDRESSES pIf,
  257. PWCHAR hostname,
  258. DWORD namelen)
  259. {
  260. DNS_RECORD *RSet = NULL;
  261. PIP4_ARRAY pServerList = NULL;
  262. DWORD Status;
  263. //
  264. // Convert to a DNS record set.
  265. //
  266. RSet = BuildRecordSetW(hostname, pIf, &pServerList);
  267. if ((RSet == NULL) || (pServerList == NULL)) {
  268. goto Cleanup;
  269. }
  270. Trace2(ERR, _T("DDNS registering %ls to server %d.%d.%d.%d"),
  271. hostname, PRINT_IPADDR(pServerList->AddrArray[0]));
  272. //
  273. // REVIEW: We could (should?) compare the current record set
  274. // to the previous record set, and only update DNS
  275. // if there has been a change or if there was a timeout.
  276. //
  277. Status = DnsReplaceRecordSetW(
  278. RSet,
  279. DNS_UPDATE_CACHE_SECURITY_CONTEXT,
  280. NULL,
  281. pServerList,
  282. NULL);
  283. if (Status != NO_ERROR) {
  284. Trace1(ERR, _T("Error: DnsReplaceRecordSet returned %d"), Status);
  285. }
  286. ReportDnsUpdateStatusW(Status, hostname, RSet);
  287. Cleanup:
  288. if (pServerList) {
  289. FREE(pServerList);
  290. }
  291. if (RSet) {
  292. FREE(RSet);
  293. }
  294. }
  295. VOID
  296. DoDdnsOnInterface(
  297. PIP_ADAPTER_ADDRESSES pIf)
  298. {
  299. // Leave room to add a trailing "."
  300. WCHAR hostname[NI_MAXHOST+1];
  301. DWORD namelen = NI_MAXHOST;
  302. //
  303. // Get the fully-qualified DNS name for this machine
  304. // and append a trailing dot.
  305. //
  306. if (! GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified,
  307. hostname, &namelen)) {
  308. return;
  309. }
  310. namelen = (DWORD)wcslen(hostname);
  311. hostname[namelen] = L'.';
  312. hostname[namelen+1] = L'\0';
  313. RegisterNameOnInterface(pIf, hostname, namelen);
  314. //
  315. // Also register the connection-specific name if configured to do so.
  316. //
  317. if (pIf->Flags & IP_ADAPTER_REGISTER_ADAPTER_SUFFIX) {
  318. if (! GetComputerNameExW(ComputerNamePhysicalDnsHostname,
  319. hostname, &namelen)) {
  320. return;
  321. }
  322. wcscat(hostname, L".");
  323. wcscat(hostname, pIf->DnsSuffix);
  324. namelen = (DWORD)wcslen(hostname);
  325. hostname[namelen] = L'.';
  326. hostname[namelen+1] = L'\0';
  327. RegisterNameOnInterface(pIf, hostname, namelen);
  328. }
  329. }
  330. VOID CALLBACK
  331. OnIpv6AddressChange(
  332. IN PVOID lpParameter,
  333. IN BOOLEAN TimerOrWaitFired)
  334. {
  335. PIP_ADAPTER_ADDRESSES pAdapterAddresses = NULL;
  336. PIP_ADAPTER_ADDRESSES pIf, pIf2;
  337. ULONG BytesNeeded = 0;
  338. DWORD dwErr;
  339. DWORD BytesReturned;
  340. //
  341. // Sleep for one second.
  342. // Often there will be multiple address changes in a small time period,
  343. // and we prefer to update DNS once.
  344. //
  345. Sleep(1000);
  346. ENTER_API();
  347. TraceEnter("OnIpv6AddressChange");
  348. if (g_stService == DISABLED) {
  349. Trace0(FSM, L"Service disabled");
  350. goto Done;
  351. }
  352. //
  353. // First request another async notification.
  354. // We must do this *before* getting the address list,
  355. // to avoid missing an address change.
  356. //
  357. if (TimerOrWaitFired == FALSE) {
  358. for (;;) {
  359. ZeroMemory(&g_hIpv6AddressChangeOverlapped, sizeof(WSAOVERLAPPED));
  360. g_hIpv6AddressChangeOverlapped.hEvent = g_hIpv6AddressChangeEvent;
  361. dwErr = WSAIoctl(g_hIpv6Socket, SIO_ADDRESS_LIST_CHANGE,
  362. NULL, 0,
  363. NULL, 0, &BytesReturned,
  364. &g_hIpv6AddressChangeOverlapped,
  365. NULL);
  366. if (dwErr != 0) {
  367. dwErr = WSAGetLastError();
  368. if (dwErr != WSA_IO_PENDING) {
  369. goto Done;
  370. }
  371. //
  372. // The overlapped operation was initiated.
  373. //
  374. break;
  375. }
  376. //
  377. // The overlapped operation completed immediately.
  378. // Just try it again.
  379. //
  380. }
  381. }
  382. //
  383. // Get the address list.
  384. //
  385. for (;;) {
  386. //
  387. // GetAdaptersAddresses only returns addresses of the specified address
  388. // family. To obtain both IPv4 DNS server addresses and IPv6 unicast
  389. // addresses in the same call we need to pass AF_UNSPEC.
  390. //
  391. dwErr = GetAdaptersAddresses(
  392. AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
  393. GAA_FLAG_SKIP_FRIENDLY_NAME,
  394. NULL, pAdapterAddresses, &BytesNeeded);
  395. if (dwErr == NO_ERROR) {
  396. break;
  397. }
  398. if (dwErr != ERROR_BUFFER_OVERFLOW) {
  399. Trace1(ERR, _T("Error: GetAdaptersAddresses returned %d"), dwErr);
  400. goto Cleanup;
  401. }
  402. if (pAdapterAddresses == NULL)
  403. pAdapterAddresses = MALLOC(BytesNeeded);
  404. else {
  405. PVOID Mem;
  406. Mem = REALLOC(pAdapterAddresses, BytesNeeded);
  407. if (Mem == NULL) {
  408. FREE(pAdapterAddresses);
  409. }
  410. pAdapterAddresses = Mem;
  411. }
  412. if (pAdapterAddresses == NULL) {
  413. Trace0(ERR, _T("Error: malloc failed"));
  414. goto Cleanup;
  415. }
  416. }
  417. for (pIf=pAdapterAddresses; pIf; pIf=pIf->Next) {
  418. if (pIf->Flags & IP_ADAPTER_DDNS_ENABLED) {
  419. //
  420. // See if we've already done this interface because it
  421. // had the same DNS server as a previous one.
  422. //
  423. for (pIf2=pAdapterAddresses; pIf2 != pIf; pIf2 = pIf2->Next) {
  424. if (!(pIf2->Flags & IP_ADAPTER_DDNS_ENABLED))
  425. continue;
  426. if (IsSameDNSServer(pIf2, pIf)) {
  427. break;
  428. }
  429. }
  430. //
  431. // If not, go ahead and do DDNS.
  432. //
  433. if (pIf2 == pIf) {
  434. DoDdnsOnInterface(pIf);
  435. }
  436. }
  437. }
  438. Cleanup:
  439. if (pAdapterAddresses) {
  440. FREE(pAdapterAddresses);
  441. }
  442. Done:
  443. TraceLeave("OnIpv6AddressChange");
  444. LEAVE_API();
  445. }
  446. VOID
  447. StopIpv6AddressChangeNotification()
  448. {
  449. if (g_hIpv6AddressChangeWait != NULL) {
  450. //
  451. // Block until we're sure that the address change callback isn't
  452. // still running.
  453. //
  454. LEAVE_API();
  455. UnregisterWaitEx(g_hIpv6AddressChangeWait, INVALID_HANDLE_VALUE);
  456. ENTER_API();
  457. //
  458. // Release the event we counted for RegisterWaitForSingleObject
  459. //
  460. DecEventCount("AC:StopIpv6AddressChangeNotification");
  461. g_hIpv6AddressChangeWait = NULL;
  462. }
  463. if (g_hIpv6AddressChangeEvent != NULL) {
  464. CloseHandle(g_hIpv6AddressChangeEvent);
  465. g_hIpv6AddressChangeEvent = NULL;
  466. }
  467. if (g_hIpv6Socket != INVALID_SOCKET) {
  468. closesocket(g_hIpv6Socket);
  469. g_hIpv6Socket = INVALID_SOCKET;
  470. }
  471. }