Leaked source code of windows server 2003
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.

708 lines
22 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. network.c
  5. Abstract:
  6. This module contains the network interface for the BINL server.
  7. Author:
  8. Colin Watson (colinw) 2-May-1997
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include "binl.h"
  14. #pragma hdrstop
  15. DWORD
  16. BinlWaitForMessage(
  17. BINL_REQUEST_CONTEXT *pRequestContext
  18. )
  19. /*++
  20. Routine Description:
  21. This function waits for a request on the BINL port on any of the
  22. configured interfaces.
  23. Arguments:
  24. RequestContext - A pointer to a request context block for
  25. this request.
  26. Return Value:
  27. The status of the operation.
  28. --*/
  29. {
  30. DWORD length;
  31. DWORD error;
  32. fd_set readSocketSet;
  33. DWORD i;
  34. int readySockets;
  35. struct timeval timeout = { 0x7FFFFFFF, 0 }; // forever.
  36. LPOPTION Option;
  37. LPBYTE EndOfScan;
  38. LPBYTE MagicCookie;
  39. BOOLEAN FoundDesirablePacket;
  40. #define CLIENTOPTIONSTRING "PXEClient"
  41. #define CLIENTOPTIONSIZE (sizeof(CLIENTOPTIONSTRING) - 1)
  42. //
  43. // Loop until we get an extended DHCP request or an error
  44. //
  45. while (1) {
  46. //
  47. // Setup the file descriptor set for select.
  48. //
  49. FD_ZERO( &readSocketSet );
  50. for ( i = 0; i < BinlGlobalNumberOfNets ; i++ ) {
  51. if (BinlGlobalEndpointList[i].Socket) {
  52. FD_SET(
  53. BinlGlobalEndpointList[i].Socket,
  54. &readSocketSet
  55. );
  56. }
  57. }
  58. readySockets = select( 0, &readSocketSet, NULL, NULL, &timeout );
  59. //
  60. // return to caller when the service is shutting down or select()
  61. // times out.
  62. //
  63. if( (readySockets == 0) ||
  64. (WaitForSingleObject( BinlGlobalProcessTerminationEvent, 0 ) == 0) ) {
  65. return( ERROR_SEM_TIMEOUT );
  66. }
  67. if( readySockets == SOCKET_ERROR) {
  68. continue; // Closed the DHCP socket?
  69. }
  70. //
  71. // Time to play 20 question with winsock. Which socket is ready?
  72. //
  73. pRequestContext->ActiveEndpoint = NULL;
  74. for ( i = 0; i < BinlGlobalNumberOfNets ; i++ ) {
  75. if ( FD_ISSET( BinlGlobalEndpointList[i].Socket, &readSocketSet ) ) {
  76. pRequestContext->ActiveEndpoint = &BinlGlobalEndpointList[i];
  77. break;
  78. }
  79. }
  80. //BinlAssert(pRequestContext->ActiveEndpoint != NULL );
  81. if ( pRequestContext->ActiveEndpoint == NULL ) {
  82. return ERROR_SEM_TIMEOUT;
  83. }
  84. //
  85. // Read data from the net. If multiple sockets have data, just
  86. // process the first available socket.
  87. //
  88. pRequestContext->SourceNameLength = sizeof( struct sockaddr );
  89. //
  90. // clean the receive buffer before receiving data in it. We clear
  91. // out one more byte than we actually hand to recvfrom, so we can
  92. // be sure the message has a NULL after it (in case we do a
  93. // wcslen etc. into the received packet).
  94. //
  95. RtlZeroMemory( pRequestContext->ReceiveBuffer, BINL_MESSAGE_SIZE + 1 );
  96. pRequestContext->ReceiveMessageSize = BINL_MESSAGE_SIZE;
  97. length = recvfrom(
  98. pRequestContext->ActiveEndpoint->Socket,
  99. (char *)pRequestContext->ReceiveBuffer,
  100. pRequestContext->ReceiveMessageSize,
  101. 0,
  102. &pRequestContext->SourceName,
  103. (int *)&pRequestContext->SourceNameLength
  104. );
  105. if ( length == SOCKET_ERROR ) {
  106. error = WSAGetLastError();
  107. BinlPrintDbg(( DEBUG_ERRORS, "Recv failed, error = %ld\n", error ));
  108. }
  109. else if (length == 0) {
  110. //
  111. // the connection closed under us.
  112. // lets hope the connection opens again.
  113. //
  114. continue;
  115. }
  116. //
  117. // we received a message!!
  118. // we are expecting to receive a message whose first byte tells us
  119. // the purpose of the message. Since we have received a message (it
  120. // must be of positive length), we can look at the first byte (Operation)
  121. // to tell us what to do with the message. but we still need to be
  122. // careful, as the rest of the data may be bad.
  123. //
  124. else {
  125. //
  126. // Ignore all messages that do not look like DHCP or doesn't have the
  127. // option "PXEClient", OR that is not an oschooser message (they
  128. // all start with 0x81).
  129. //
  130. if ( ((LPDHCP_MESSAGE)pRequestContext->ReceiveBuffer)->Operation == OSC_REQUEST) {
  131. //
  132. // All OSC request packets have a 4-byte signature (first byte
  133. // is OSC_REQUEST) followed by a DWORD length (that does not
  134. // include the signature/length). Make sure the length matches
  135. // what we got from recvfrom (we allow padding at the end). We
  136. // use SIGNED_PACKET but any of the XXX_PACKET structures in
  137. // oscpkt.h would work.
  138. //
  139. if (length < FIELD_OFFSET(SIGNED_PACKET, SequenceNumber)) {
  140. BinlPrintDbg(( DEBUG_OSC_ERROR, "Discarding runt packet %d bytes\n", length ));
  141. continue;
  142. }
  143. if ((length - FIELD_OFFSET(SIGNED_PACKET, SequenceNumber)) <
  144. ((SIGNED_PACKET UNALIGNED *)pRequestContext->ReceiveBuffer)->Length) {
  145. BinlPrintDbg(( DEBUG_OSC_ERROR, "Discarding invalid length message %d bytes (header said %d)\n",
  146. length, ((SIGNED_PACKET UNALIGNED *)pRequestContext->ReceiveBuffer)->Length));
  147. continue;
  148. }
  149. BinlPrintDbg(( DEBUG_MESSAGE, "Received OSC message\n", 0 ));
  150. error = ERROR_SUCCESS;
  151. } else {
  152. //
  153. // check to see if this is a BOOTP message.
  154. // do so by checking to make sure it is at least the minimum
  155. // size for a DHCP message. if so, check to see if it has
  156. // the appriopriate magic cookie '99' '130' '83' '99'.
  157. //
  158. // once we verified that this is a BOOTP message,
  159. // we will be looking for two options. either an option
  160. // indicating this is a inform packet or
  161. // an option indicating this Vendor Class as "PXEClient"
  162. //
  163. // ignore all others.
  164. //
  165. if ( length < DHCP_MESSAGE_FIXED_PART_SIZE + 4 ) {
  166. //
  167. // Message isn't long enough to include the
  168. // DHCP message header and the BOOTP magic cookie,
  169. // ignore it.
  170. //
  171. continue;
  172. }
  173. if ( ((LPDHCP_MESSAGE)pRequestContext->ReceiveBuffer)->Operation != BOOT_REQUEST) {
  174. //
  175. // Doesn't look like an interesting DHCP frame
  176. //
  177. continue;
  178. }
  179. //
  180. // check the BOOTP magic cookie.
  181. //
  182. MagicCookie = (LPBYTE)&((LPDHCP_MESSAGE)pRequestContext->ReceiveBuffer)->Option;
  183. if( (*MagicCookie != (BYTE)DHCP_MAGIC_COOKIE_BYTE1) ||
  184. (*(MagicCookie+1) != (BYTE)DHCP_MAGIC_COOKIE_BYTE2) ||
  185. (*(MagicCookie+2) != (BYTE)DHCP_MAGIC_COOKIE_BYTE3) ||
  186. (*(MagicCookie+3) != (BYTE)DHCP_MAGIC_COOKIE_BYTE4))
  187. {
  188. //
  189. // this is a vendor specific magic cookie.
  190. // ignore the message
  191. //
  192. continue;
  193. }
  194. //
  195. // At this point, we have something that looks like a DHCP/BOOTP
  196. // packet. we will now carefully look for two particular option
  197. // types that are interest to us.
  198. // 1. An inform packet which is indicated by the option type
  199. // OPTION_MESSAGE_TYPE(53) with the message type of
  200. // DHCP_INFORM_MESSAGE(8)
  201. // 2. A vendor class indentifier "PXEClient" indicated by
  202. // the option type OPTION_CLIENT_CLASS_INFO(60) with the
  203. // value CLIENTOPTIONSTRING("PXEClient")
  204. // Stop scanning after we have found either one of these options
  205. // or we run off the packet. if we do not find either option,
  206. // continue in the while loop looking for a packet with either
  207. // of these options
  208. //
  209. // EndOfScan indicates the last byte we received in the packet
  210. //
  211. EndOfScan = pRequestContext->ReceiveBuffer + length - 1;
  212. Option = (LPOPTION) (MagicCookie + 4);
  213. FoundDesirablePacket = FALSE;
  214. while ( ((LPBYTE)Option <= EndOfScan) &&
  215. (Option->OptionType != OPTION_END) &&
  216. (FoundDesirablePacket == FALSE) ) {
  217. if ( Option->OptionType == OPTION_PAD ) {
  218. //
  219. // found an OPTION_PAD. this is a 1 byte option ('0').
  220. // just walk past this.
  221. //
  222. Option = (LPOPTION)((LPBYTE)(Option) + 1);
  223. }
  224. else {
  225. //
  226. // OPTION_PAD and OPTION_END are the only two options
  227. // that do not have a length field and a Value field.
  228. // we know we do not have either, so we have to make
  229. // sure we do not step past the EndOfScan by
  230. // looking at the option length or the option value
  231. //
  232. // Note. Option type and Option length take up two bytes
  233. // but we only add one when seeing if the length brings us
  234. // past EndOfScan, because when we step past the last
  235. // option, it will bring us 1 byte past EndOfScan.
  236. // we want to see if this is an invalid option
  237. // that will somehow overstep the standard case
  238. //
  239. if ( (((LPBYTE)(Option) + 1) > EndOfScan) ||
  240. (((LPBYTE)(Option) + Option->OptionLength + 1) > EndOfScan) ) {
  241. //
  242. // invalid option
  243. //
  244. break;
  245. }
  246. //
  247. // look for the two option types of interest.
  248. // OPTION_CLIENT_CLASS_INFO and OPTION_MESSAGE_TYPE
  249. //
  250. switch ( Option->OptionType ) {
  251. case OPTION_MESSAGE_TYPE:
  252. //
  253. // check to see if we got an inform packet
  254. //
  255. if ( (Option->OptionLength == 1) &&
  256. (Option->OptionValue[0] == DHCP_INFORM_MESSAGE) ) {
  257. FoundDesirablePacket = TRUE;
  258. }
  259. break;
  260. case OPTION_CLIENT_CLASS_INFO:
  261. //
  262. // check to see if the Client class identifier is "PXEClient"
  263. //
  264. if (memcmp(Option->OptionValue,
  265. CLIENTOPTIONSTRING,
  266. CLIENTOPTIONSIZE) == 0) {
  267. FoundDesirablePacket = TRUE;
  268. }
  269. break;
  270. default:
  271. break;
  272. }
  273. //
  274. // walk past this option to check the next one
  275. //
  276. Option = (LPOPTION)((LPBYTE)(Option) + Option->OptionLength + 2);
  277. }
  278. }
  279. if ( FoundDesirablePacket == FALSE ) {
  280. //
  281. // Message was not an extended DHCP packet
  282. // with the desired option ("PXEClient")
  283. // or an inform packet.
  284. // ignore the message
  285. //
  286. continue;
  287. }
  288. BinlPrintDbg(( DEBUG_MESSAGE, "Received message\n", 0 ));
  289. error = ERROR_SUCCESS;
  290. }
  291. }
  292. pRequestContext->ReceiveMessageSize = length;
  293. return( error );
  294. }
  295. }
  296. DWORD
  297. BinlSendMessage(
  298. LPBINL_REQUEST_CONTEXT RequestContext
  299. )
  300. /*++
  301. Routine Description:
  302. This function send a response to a BINL client.
  303. Arguments:
  304. RequestContext - A pointer to the BinlRequestContext block for
  305. this request.
  306. Return Value:
  307. The status of the operation.
  308. --*/
  309. {
  310. DWORD error;
  311. struct sockaddr_in *source;
  312. LPDHCP_MESSAGE binlMessage;
  313. LPDHCP_MESSAGE binlReceivedMessage;
  314. DWORD MessageLength;
  315. BOOL ArpCacheUpdated = FALSE;
  316. binlMessage = (LPDHCP_MESSAGE) RequestContext->SendBuffer;
  317. binlReceivedMessage = (LPDHCP_MESSAGE) RequestContext->ReceiveBuffer;
  318. //
  319. // if the request arrived from a relay agent, then send the reply
  320. // on server port otherwise leave it as the client's source port.
  321. //
  322. source = (struct sockaddr_in *)&RequestContext->SourceName;
  323. if ( binlReceivedMessage->RelayAgentIpAddress != 0 ) {
  324. source->sin_port = htons( DHCP_SERVR_PORT );
  325. }
  326. //
  327. // if this request arrived from relay agent then send the
  328. // response to the address the relay agent says.
  329. //
  330. if ( binlReceivedMessage->RelayAgentIpAddress != 0 ) {
  331. source->sin_addr.s_addr = binlReceivedMessage->RelayAgentIpAddress;
  332. }
  333. else {
  334. //
  335. // if the client didnt specify broadcast bit and if
  336. // we know the ipaddress of the client then send unicast.
  337. //
  338. //
  339. // But if IgnoreBroadcastFlag is set in the registry and
  340. // if the client requested to broadcast or the server is
  341. // nacking or If the client doesn't have an address yet,
  342. // respond via broadcast.
  343. // Note that IgnoreBroadcastFlag is off by default. But it
  344. // can be set as a workaround for the clients that are not
  345. // capable of receiving unicast
  346. // and they also dont set the broadcast bit.
  347. //
  348. if ( (RequestContext->MessageType == DHCP_INFORM_MESSAGE) &&
  349. (ntohs(binlMessage->Reserved) & DHCP_BROADCAST) ) {
  350. source->sin_addr.s_addr = (DWORD)-1;
  351. } else if ( BinlGlobalIgnoreBroadcastFlag ) {
  352. if ((ntohs(binlReceivedMessage->Reserved) & DHCP_BROADCAST) ||
  353. (binlReceivedMessage->ClientIpAddress == 0) ||
  354. (source->sin_addr.s_addr == 0) ) {
  355. source->sin_addr.s_addr = (DWORD)-1;
  356. binlMessage->Reserved = 0;
  357. // this flag should be zero in the local response.
  358. }
  359. } else {
  360. if( (ntohs(binlReceivedMessage->Reserved) & DHCP_BROADCAST) ||
  361. (!source->sin_addr.s_addr ) ){
  362. source->sin_addr.s_addr = (DWORD)-1;
  363. binlMessage->Reserved = 0;
  364. // this flag should be zero in the local response.
  365. } else {
  366. //
  367. // Send back to the same IP address that the request came in on (
  368. // i.e. source->sin_addr.s_addr)
  369. //
  370. }
  371. }
  372. }
  373. BinlPrint(( DEBUG_STOC, "Sending response to = %s, XID = %lx.\n",
  374. inet_ntoa(source->sin_addr), binlMessage->TransactionID));
  375. //
  376. // send minimum DHCP_MIN_SEND_RECV_PK_SIZE (300) bytes, otherwise
  377. // bootp relay agents don't like the packet.
  378. //
  379. MessageLength = (RequestContext->SendMessageSize >
  380. DHCP_MIN_SEND_RECV_PK_SIZE) ?
  381. RequestContext->SendMessageSize :
  382. DHCP_MIN_SEND_RECV_PK_SIZE;
  383. error = sendto(
  384. RequestContext->ActiveEndpoint->Socket,
  385. (char *)RequestContext->SendBuffer,
  386. MessageLength,
  387. 0,
  388. &RequestContext->SourceName,
  389. RequestContext->SourceNameLength
  390. );
  391. if ( error == SOCKET_ERROR ) {
  392. error = WSAGetLastError();
  393. BinlPrintDbg(( DEBUG_ERRORS, "Send failed, error = %ld\n", error ));
  394. } else {
  395. error = ERROR_SUCCESS;
  396. }
  397. return( error );
  398. }
  399. NTSTATUS
  400. GetIpAddressInfo (
  401. ULONG Delay
  402. )
  403. {
  404. ULONG count;
  405. DWORD Size;
  406. PIP_ADAPTER_INFO pAddressInfo = NULL;
  407. //
  408. // We can get out ahead of the dns cached info here... let's delay a bit
  409. // if the pnp logic told us there was a change.
  410. //
  411. if (Delay) {
  412. Sleep( Delay );
  413. }
  414. Size = 0;
  415. if ( (GetAdaptersInfo(pAddressInfo,&Size) == ERROR_BUFFER_OVERFLOW) &&
  416. (pAddressInfo = BinlAllocateMemory(Size)) &&
  417. (GetAdaptersInfo(pAddressInfo,&Size) == ERROR_SUCCESS)) {
  418. PIP_ADAPTER_INFO pNext = pAddressInfo;
  419. count = 0;
  420. while (pNext) {
  421. count += 1;
  422. pNext = pNext->Next;
  423. }
  424. } else {
  425. count = 0;
  426. }
  427. if (count == 0) {
  428. //
  429. // we don't know what went wrong, we'll fall back to old APIs.
  430. //
  431. DHCP_IP_ADDRESS ipaddr = 0;
  432. PHOSTENT Host = gethostbyname( NULL );
  433. if (Host) {
  434. ipaddr = *(PDHCP_IP_ADDRESS)Host->h_addr;
  435. if ((Host->h_addr_list[0] != NULL) &&
  436. (Host->h_addr_list[1] != NULL)) {
  437. BinlIsMultihomed = TRUE;
  438. } else {
  439. BinlIsMultihomed = FALSE;
  440. }
  441. BinlGlobalMyIpAddress = ipaddr;
  442. } else {
  443. //
  444. // what's with the ip stack? we can't get any type of address
  445. // info out of it... for now, we won't answer any if we don't
  446. // already have the info we need.
  447. //
  448. if (BinlIpAddressInfo == NULL) {
  449. BinlIsMultihomed = TRUE;
  450. }
  451. }
  452. return STATUS_SUCCESS;
  453. }
  454. EnterCriticalSection(&gcsParameters);
  455. if (BinlIpAddressInfo) {
  456. BinlFreeMemory( BinlIpAddressInfo );
  457. }
  458. BinlIpAddressInfo = pAddressInfo;
  459. BinlIpAddressInfoCount = count;
  460. BinlIsMultihomed = (count != 1);
  461. if (!BinlIsMultihomed) {
  462. BinlGlobalMyIpAddress = inet_addr(pAddressInfo->IpAddressList.IpAddress.String);
  463. }
  464. LeaveCriticalSection(&gcsParameters);
  465. return STATUS_SUCCESS;
  466. }
  467. DHCP_IP_ADDRESS
  468. BinlGetMyNetworkAddress (
  469. LPBINL_REQUEST_CONTEXT RequestContext
  470. )
  471. /*++
  472. Routine Description:
  473. This function returns our (the server's) IP address.
  474. if multihomed, the function will walk through
  475. each of the server's ip addresses looking for an
  476. address with the same subnet mask as the sender.
  477. Arguments:
  478. RequestContext - The RequestContext from the packet
  479. sent to us by the client.
  480. Return Value:
  481. The Ip Address of the server. in the multihome
  482. situation, the ip address on the same subnet
  483. as the client. In case of failure to find an
  484. IP address on the same subnet or if we were
  485. somehow unable to get the client's address, 0 is
  486. returned
  487. --*/
  488. {
  489. ULONG RemoteIp;
  490. DHCP_IP_ADDRESS ipaddr;
  491. ULONG i;
  492. ULONG subnetMask;
  493. ULONG localAddr;
  494. PIP_ADAPTER_INFO pNext;
  495. BinlAssert( RequestContext != NULL);
  496. //
  497. // If we're not multihomed, then we know the address since there's just one.
  498. //
  499. if (!BinlIsMultihomed) {
  500. return BinlGlobalMyIpAddress;
  501. }
  502. RemoteIp = ((struct sockaddr_in *)&RequestContext->SourceName)->sin_addr.s_addr;
  503. //
  504. // in attempt to be consistent with the previous case where we only
  505. // have 1 ip address, we should at least return an IP address.
  506. // Return the first ip address in the list.
  507. //
  508. ipaddr = (BinlIpAddressInfo) ? inet_addr(BinlIpAddressInfo->IpAddressList.IpAddress.String) : 0;
  509. if (RemoteIp == 0) {
  510. return ipaddr;
  511. }
  512. EnterCriticalSection(&gcsParameters);
  513. if (BinlIpAddressInfo == NULL) {
  514. LeaveCriticalSection(&gcsParameters);
  515. return (BinlIsMultihomed ? 0 : BinlGlobalMyIpAddress);
  516. }
  517. pNext = BinlIpAddressInfo;
  518. while (pNext) {
  519. localAddr = inet_addr(pNext->IpAddressList.IpAddress.String);
  520. subnetMask = inet_addr(pNext->IpAddressList.IpMask.String);
  521. pNext = pNext->Next;
  522. //
  523. // check that the remote ip address may have come from this subnet.
  524. // note that the address could be the address of a dhcp relay agent,
  525. // which is fine since we're just looking for the address of the
  526. // local subnet to broadcast the response on.
  527. //
  528. //
  529. // guard against bad ip address
  530. //
  531. if (!localAddr || !subnetMask) {
  532. continue;
  533. }
  534. if ((RemoteIp & subnetMask) == (localAddr & subnetMask)) {
  535. ipaddr = localAddr;
  536. break;
  537. }
  538. }
  539. LeaveCriticalSection(&gcsParameters);
  540. return ipaddr;
  541. }
  542. VOID
  543. FreeIpAddressInfo (
  544. VOID
  545. )
  546. {
  547. EnterCriticalSection(&gcsParameters);
  548. if (BinlIpAddressInfo != NULL) {
  549. BinlFreeMemory( BinlIpAddressInfo );
  550. }
  551. BinlIpAddressInfo = NULL;
  552. BinlIpAddressInfoCount = 0;
  553. LeaveCriticalSection(&gcsParameters);
  554. return;
  555. }