/* Module Name: btest.c Abstract: This module sends sample BINL packets to the BINL server of your choice. -b Use broadcast rather than directed datagram to -s To specify a BINL server of your choice. Default is COLINW2 Author: Colin Watson Apr 29 1997 Revision History: */ #include #pragma hdrstop #include #include #include #include #include #include #include #include #define MAX_MSGLEN 80 #define MAX_ADDLEN 80 #define MAX_MSLOTNAME 80 typedef struct _OPTION2 { BYTE OptionType; BYTE OptionLength; BYTE OptionValue[]; } OPTION2, *POPTION2, *LPOPTION2; BOOL __stdcall CtrlCHandler ( DWORD dwEvent ); void __stdcall Udp ( ); void __stdcall Usage ( CHAR *pszProgramName ); void __stdcall PrintError ( LPSTR lpszRoutine, LPSTR lpszCallName, DWORD dwError ); void __stdcall DoStartup ( void ); void __stdcall DoCleanup ( void ); VOID GetHardwareAddress( PUCHAR Address ); VOID DumpMessage( LPDHCP_MESSAGE BinlMessage ); // // Global Variables // // If Startup was successful, fStarted is used to keep track. BOOL fStarted = FALSE; BOOL fBroadcast = FALSE; // Global socket descriptor SOCKET sock = INVALID_SOCKET; LPSTR ServerName = "COLINW2"; ULONG ServerAddress; ULONG ClientAddress; void __cdecl main ( INT argc, CHAR **argv ) { int i; // // Install the CTRL+BREAK Handler // if ( FALSE == SetConsoleCtrlHandler ( (PHANDLER_ROUTINE) CtrlCHandler, TRUE ) ){ PrintError ( "main", "SetConsoleCtrlHandler", GetLastError ( ) ); } // // allow the user to override settings with command line switches // for ( i = 1; i < argc; i++ ) { if ( ( *argv[i] == '-' ) || ( *argv[i] == '/' ) ) { switch ( tolower ( *( argv[i]+1 ) ) ) { // // Broadcast // case 'b': fBroadcast = TRUE; break; // // ServerName. // case 's': ServerName = argv[++i]; break; // // Help. // case 'h': case '?': default: Usage ( argv[0] ); } } else // // Help. // Usage ( argv[0] ); } // // Print a Summary of the switches specfied // Helpful for debugging // fprintf ( stdout, "SUMMARY:\n" ); if (fBroadcast) { fprintf ( stdout, "Broadcast test\n" ); } else { fprintf ( stdout, "Unicast to BINL server %s\n", ServerName ); } DoStartup ( ); Udp(); return; } // // CtrlCHandler () intercepts the CTRL+BREAK or CTRL+C events and calls the // cleanup routines. // BOOL __stdcall CtrlCHandler ( DWORD dwEvent ) { if ( ( CTRL_C_EVENT == dwEvent ) || ( CTRL_BREAK_EVENT == dwEvent ) ) { DoCleanup ( ); } return FALSE; } void __stdcall Discover( ) { // IP address structures needed to fill the source and destination // addresses. SOCKADDR_IN saUdpServ, saUdpCli; INT err; DWORD nSize; UCHAR MessageBuffer[DHCP_MESSAGE_SIZE]; PDHCP_MESSAGE Message = (PDHCP_MESSAGE)&MessageBuffer[0]; // Data used for building Messages LPOPTION Option; UCHAR MagicCookie[] = {DHCP_MAGIC_COOKIE_BYTE1, DHCP_MAGIC_COOKIE_BYTE2, DHCP_MAGIC_COOKIE_BYTE3, DHCP_MAGIC_COOKIE_BYTE4}; #define COOKIESIZE (4) OPTION2 DiscoverOption = {OPTION_MESSAGE_TYPE, 1, DHCP_DISCOVER_MESSAGE}; #define DISCOVEROPTIONSIZE (DiscoverOption.OptionLength + 2) OPTION2 ClientOption = {OPTION_CLIENT_CLASS_INFO,9,"PXEClient"}; // Size must ignore null at end of the string. #define CLIENTOPTIONSIZE (ClientOption.OptionLength + 2) OPTION2 NITOption = {OPTION_NETWORK_INTERFACE_TYPE,3,1,2,0}; // Size must ignore null at end of the string. #define NITOPTIONSIZE (NITOption.OptionLength + 2) OPTION2 SAOption = {OPTION_SYSTEM_ARCHITECTURE,1,0}; // Size must ignore null at end of the string. #define SAOPTIONSIZE (SAOption.OptionLength + 2) OPTION2 EndOption = {OPTION_END,0}; // Size must ignore null at end of the string. #define ENDOPTIONSIZE (1) do { sendagain: // // Fill an IP address structure, to send an IP broadcast. // saUdpServ.sin_family = AF_INET; if (fBroadcast) { saUdpServ.sin_addr.s_addr = htonl ( INADDR_BROADCAST ); } else { saUdpServ.sin_addr.s_addr = ServerAddress; } saUdpServ.sin_port = htons ( DHCP_SERVR_PORT ); // Practice with a dummy BINL Discover packet ZeroMemory(MessageBuffer, sizeof(MessageBuffer)); Message->Operation = BOOT_REQUEST; Option = &Message->Option; GetHardwareAddress(Message->HardwareAddress); Message->HardwareAddressType = 1; Message->HardwareAddressLength = 6; Message->TransactionID = 0x12345678; memcpy(Option, &MagicCookie, COOKIESIZE); Option = (LPOPTION)((PUCHAR)Option + COOKIESIZE); memcpy(Option, &DiscoverOption, DISCOVEROPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + DISCOVEROPTIONSIZE); memcpy(Option, &ClientOption, CLIENTOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + CLIENTOPTIONSIZE); memcpy(Option, &NITOption, NITOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + NITOPTIONSIZE); memcpy(Option, &SAOption, SAOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + SAOPTIONSIZE); memcpy(Option, &EndOption, ENDOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + ENDOPTIONSIZE); err = sendto ( sock, (PUCHAR)Message, (PUCHAR)Option - (PUCHAR)Message, 0, (SOCKADDR *) &saUdpServ, sizeof ( SOCKADDR_IN ) ); if ( SOCKET_ERROR == err ) { PrintError ( "Udp", "sendto", WSAGetLastError ( ) ); } fprintf ( stdout, "%d bytes of data sent\n", err ); Sleep(1000); // Give server a few seconds to respond. do { err = ioctlsocket( sock, FIONREAD, &nSize); if ( SOCKET_ERROR == err ) { PrintError ( "Udp", "recvfrom", WSAGetLastError ( ) ); } if (!nSize) { goto sendagain; // we have processed all the DHCP/BINL responses } // // receive a datagram on the bound port number. // nSize = sizeof ( SOCKADDR_IN ); err = recvfrom ( sock, (PUCHAR)Message, DHCP_MESSAGE_SIZE, 0, (SOCKADDR FAR *) &saUdpCli, &nSize ); if ( SOCKET_ERROR == err ) { PrintError ( "Udp", "recvfrom", WSAGetLastError ( ) ); } if (Message->TransactionID == 0x12345678) { goto processit; } } while ( 1 ); // while there are datagrams queued } while (1); processit: // // print the sender's information. // fprintf ( stdout, "A Udp Datagram of length %d bytes received from ", err ); fprintf ( stdout, "\n\tIP Adress->%s ", inet_ntoa ( saUdpCli.sin_addr ) ); fprintf ( stdout, "\n\tPort Number->%d\n", ntohs ( saUdpCli.sin_port ) ); DumpMessage(Message); } void __stdcall Request( ) { // IP address structures needed to fill the source and destination // addresses. SOCKADDR_IN saUdpServ, saUdpCli; INT err; DWORD nSize; UCHAR MessageBuffer[DHCP_MESSAGE_SIZE]; PDHCP_MESSAGE Message = (PDHCP_MESSAGE)&MessageBuffer[0]; // Data used for building Messages LPOPTION Option; UCHAR MagicCookie[] = {DHCP_MAGIC_COOKIE_BYTE1, DHCP_MAGIC_COOKIE_BYTE2, DHCP_MAGIC_COOKIE_BYTE3, DHCP_MAGIC_COOKIE_BYTE4}; #define COOKIESIZE (4) OPTION2 RequestOption = {OPTION_MESSAGE_TYPE, 1, DHCP_REQUEST_MESSAGE}; #define REQUESTOPTIONSIZE (RequestOption.OptionLength + 2) OPTION2 ClientOption = {OPTION_CLIENT_CLASS_INFO,9,"PXEClient"}; // Size must ignore null at end of the string. #define CLIENTOPTIONSIZE (ClientOption.OptionLength + 2) OPTION2 NITOption = {OPTION_NETWORK_INTERFACE_TYPE,3,1,2,0}; // Size must ignore null at end of the string. #define NITOPTIONSIZE (NITOption.OptionLength + 2) OPTION2 SAOption = {OPTION_SYSTEM_ARCHITECTURE,1,0}; // Size must ignore null at end of the string. #define SAOPTIONSIZE (SAOption.OptionLength + 2) OPTION2 EndOption = {OPTION_END,0}; // Size must ignore null at end of the string. #define ENDOPTIONSIZE (1) do { sendagain: // // Fill an IP address structure, to send an IP broadcast. // saUdpServ.sin_family = AF_INET; if (fBroadcast) { saUdpServ.sin_addr.s_addr = htonl ( INADDR_BROADCAST ); } else { saUdpServ.sin_addr.s_addr = ServerAddress; } //saUdpServ.sin_port = htons ( BINL_DEFAULT_PORT ); saUdpServ.sin_port = htons ( 0xaee8 ); // Practice with a dummy BINL Request packet ZeroMemory(MessageBuffer, sizeof(MessageBuffer)); Message->Operation = BOOT_REQUEST; Option = &Message->Option; GetHardwareAddress(Message->HardwareAddress); Message->HardwareAddressType = 1; Message->HardwareAddressLength = 6; Message->TransactionID = 0x56781234; Message->YourIpAddress = ClientAddress; memcpy(Option, &MagicCookie, COOKIESIZE); Option = (LPOPTION)((PUCHAR)Option + COOKIESIZE); memcpy(Option, &RequestOption, REQUESTOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + REQUESTOPTIONSIZE); memcpy(Option, &ClientOption, CLIENTOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + CLIENTOPTIONSIZE); memcpy(Option, &NITOption, NITOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + NITOPTIONSIZE); memcpy(Option, &SAOption, SAOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + SAOPTIONSIZE); memcpy(Option, &EndOption, ENDOPTIONSIZE); Option = (LPOPTION)((PUCHAR)Option + ENDOPTIONSIZE); err = sendto ( sock, (PUCHAR)Message, (PUCHAR)Option - (PUCHAR)Message, 0, (SOCKADDR *) &saUdpServ, sizeof ( SOCKADDR_IN ) ); if ( SOCKET_ERROR == err ) { PrintError ( "Udp", "sendto", WSAGetLastError ( ) ); } fprintf ( stdout, "%d bytes of data sent\n", err ); Sleep(1000); // Give server a few seconds to respond. do { err = ioctlsocket( sock, FIONREAD, &nSize); if ( SOCKET_ERROR == err ) { PrintError ( "Udp", "recvfrom", WSAGetLastError ( ) ); } if (!nSize) { goto sendagain; // we have processed all the DHCP/BINL responses } // // receive a datagram on the bound port number. // nSize = sizeof ( SOCKADDR_IN ); err = recvfrom ( sock, (PUCHAR)Message, DHCP_MESSAGE_SIZE, 0, (SOCKADDR FAR *) &saUdpCli, &nSize ); if ( SOCKET_ERROR == err ) { PrintError ( "Udp", "recvfrom", WSAGetLastError ( ) ); } if (Message->TransactionID == 0x56781234) { goto processit; } } while ( 1 ); // while there are datagrams queued } while (1); processit: // // print the sender's information. // fprintf ( stdout, "A Udp Datagram of length %d bytes received from ", err ); fprintf ( stdout, "\n\tIP Adress->%s ", inet_ntoa ( saUdpCli.sin_addr ) ); fprintf ( stdout, "\n\tPort Number->%d\n", ntohs ( saUdpCli.sin_port ) ); DumpMessage(Message); } void __stdcall Udp( ) { INT err; LPHOSTENT pServerHostEntry; char MyName[80]; // IP address structures needed to fill the source and destination // addresses. SOCKADDR_IN saUdpServ, saUdpCli; // // Initialize the global socket descriptor. // sock = socket ( AF_INET, SOCK_DGRAM, 0 ); if ( INVALID_SOCKET == sock) { PrintError ( "Udp", "socket", WSAGetLastError() ); } if (fBroadcast) { err = setsockopt ( sock, SOL_SOCKET, SO_BROADCAST, (CHAR *) &fBroadcast, sizeof ( BOOL ) ); if ( SOCKET_ERROR == err ) { PrintError ( "Udp", "setsockopt", WSAGetLastError ( ) ); } } else { // Convert ServerName to an IP address ServerAddress = inet_addr(ServerName); // Dotted form of address if ((ServerAddress == INADDR_NONE) && (memcmp(ServerName, "255.255.255.255", sizeof("255.255.255.255")))) { // must be a servername pServerHostEntry = gethostbyname(ServerName); if (pServerHostEntry) { ServerAddress = *((PULONG)(pServerHostEntry->h_addr)); } else { PrintError ( "Udp", "gethostbyname", WSAGetLastError ( ) ); return; } } } // // bind to a local socket and an interface. // saUdpCli.sin_family = AF_INET; saUdpCli.sin_addr.s_addr = htonl ( INADDR_ANY ); saUdpCli.sin_port = htons ( DHCP_CLIENT_PORT ); err = bind ( sock, (SOCKADDR *) &saUdpCli, sizeof (SOCKADDR_IN) ); if ( SOCKET_ERROR == err ) { PrintError ( "Udp", "bind", WSAGetLastError ( ) ); } // Find my (clients) IP address. if (gethostname(MyName, sizeof(MyName)) != SOCKET_ERROR ){ PHOSTENT Host; Host = gethostbyname(MyName); if (Host) { ClientAddress = *(PDHCP_IP_ADDRESS)Host->h_addr; } } Discover(); Request(); // // Call the cleanup routine. // DoCleanup ( ); return; } // // Usage () lists the available command line options. // void __stdcall Usage ( CHAR *pszProgramName ) { fprintf ( stderr, "Usage: %s\n", pszProgramName ); fprintf ( stderr, "\t-b Use broadcast to DHCP/BINL socket\n" ); fprintf ( stderr, "\t-s , Use directed datagram to ServerName default - COLINW2)\n" ); exit ( 1 ); } // // PrintError () is a function available globally for printing the error and // doing the cleanup. // void __stdcall PrintError ( LPSTR lpszRoutine, LPSTR lpszCallName, DWORD dwError ) { fprintf ( stderr, "The Call to %s() in routine() %s failed with error %d\n", lpszCallName, lpszRoutine, dwError ); DoCleanup ( ); exit ( 1 ); } // // DoStartup () initializes the Winsock DLL with Winsock version 1.1 // void __stdcall DoStartup ( void ) { WSADATA wsaData; INT iRetVal; iRetVal = WSAStartup ( MAKEWORD ( 1,1 ), &wsaData ); if ( 0 != iRetVal) { PrintError ( "DoStartup", "WSAStartup", iRetVal ); } // // Set the global flag. // fStarted = TRUE; return; } // // DoCleanup () will close the global socket which was opened successfully by // a call to socket (). Additionally, it will call WSACleanup (), if a call // to WSAStartup () was made successfully. // void __stdcall DoCleanup ( void ) { if ( INVALID_SOCKET != sock ) { closesocket ( sock ); } if ( TRUE == fStarted ) { WSACleanup ( ); } fprintf ( stdout, "DONE\n" ); return; } #define ClearNcb( PNCB ) { \ ZeroMemory( PNCB , sizeof (NCB) ); \ MoveMemory( (PNCB)->ncb_name, SPACES, sizeof(SPACES)-1 );\ MoveMemory( (PNCB)->ncb_callname, SPACES, sizeof(SPACES)-1 );\ } #define SPACES " " VOID GetHardwareAddress( PUCHAR Address ) { NCB myncb; ADAPTER_STATUS adapterstatus; UCHAR lanNumber; LANA_ENUM Enum; ClearNcb( &myncb ); myncb.ncb_command = NCBENUM; myncb.ncb_lana_num = 0; myncb.ncb_length = sizeof(Enum); myncb.ncb_buffer = (PUCHAR)&Enum; Netbios( &myncb ); if (( myncb.ncb_retcode != NRC_GOODRET ) || ( !Enum.length )) { return; } lanNumber = Enum.lana[0]; ClearNcb( &myncb ); myncb.ncb_command = NCBRESET; myncb.ncb_lsn = 0; // Request resources myncb.ncb_lana_num = lanNumber; myncb.ncb_callname[0] = 0; // 16 sessions myncb.ncb_callname[1] = 0; // 16 commands myncb.ncb_callname[2] = 0; // 8 names Netbios( &myncb ); if ( myncb.ncb_retcode != NRC_GOODRET ) return; ClearNcb( &myncb ); myncb.ncb_command = NCBASTAT; myncb.ncb_lana_num = lanNumber; myncb.ncb_buffer = (PUCHAR)&adapterstatus; myncb.ncb_length = sizeof(adapterstatus); myncb.ncb_callname[0] = '*'; Netbios( &myncb ); if ( myncb.ncb_retcode != NRC_GOODRET ) return; CopyMemory(Address, &adapterstatus.adapter_address[0], 6); } VOID DumpMessage( LPDHCP_MESSAGE BinlMessage ) /*++ Routine Description: This function dumps a DHCP packet in human readable form. Arguments: BinlMessage - A pointer to a DHCP message. Return Value: None. --*/ { LPOPTION option; BYTE i; fprintf ( stdout,"Binl message: \n\n"); fprintf ( stdout,"Operation :"); if ( BinlMessage->Operation == BOOT_REQUEST ) { fprintf ( stdout, "BootRequest\n"); } else if ( BinlMessage->Operation == BOOT_REPLY ) { fprintf ( stdout, "BootReply\n"); } else { fprintf ( stdout, "Unknown\n"); } fprintf ( stdout,"Hardware Address type : %d\n", BinlMessage->HardwareAddressType); fprintf ( stdout,"Hardware Address Length: %d\n", BinlMessage->HardwareAddressLength); fprintf ( stdout,"Hop Count : %d\n", BinlMessage->HopCount ); fprintf ( stdout,"Transaction ID : %lx\n", BinlMessage->TransactionID ); fprintf ( stdout,"Seconds Since Boot : %d\n", BinlMessage->SecondsSinceBoot ); fprintf ( stdout,"Client IP Address : " ); fprintf ( stdout,"%s\n", inet_ntoa(*(struct in_addr *)&BinlMessage->ClientIpAddress ) ); fprintf ( stdout,"Your IP Address : " ); fprintf ( stdout,"%s\n", inet_ntoa(*(struct in_addr *)&BinlMessage->YourIpAddress ) ); fprintf ( stdout,"Server IP Address : " ); fprintf ( stdout,"%s\n", inet_ntoa(*(struct in_addr *)&BinlMessage->BootstrapServerAddress ) ); fprintf ( stdout,"Relay Agent IP Address : " ); fprintf ( stdout,"%s\n", inet_ntoa(*(struct in_addr *)&BinlMessage->RelayAgentIpAddress ) ); fprintf ( stdout,"Hardware Address : "); for ( i = 0; i < BinlMessage->HardwareAddressLength; i++ ) { fprintf ( stdout,"%2.2x", BinlMessage->HardwareAddress[i] ); } if (BinlMessage->HostName[0]) { fprintf( stdout, "\nHostName \"%s\"\n", BinlMessage->HostName); } if (BinlMessage->BootFileName[0]) { fprintf( stdout, "BootFileName \"%s\"\n", BinlMessage->BootFileName); } option = &BinlMessage->Option; fprintf ( stdout,"\nMagic Cookie: "); for ( i = 0; i < 4; i++ ) { fprintf ( stdout,"%d ", *((LPBYTE)option)++ ); } fprintf ( stdout,"\n\n"); fprintf ( stdout,"Options:\n"); while ( option->OptionType != 255 ) { fprintf ( stdout,"\tType = %d ", option->OptionType ); for ( i = 0; i < option->OptionLength; i++ ) { fprintf ( stdout,"%2.2x", option->OptionValue[i] ); } fprintf ( stdout,"\n"); if ( option->OptionType == OPTION_PAD || option->OptionType == OPTION_END ) { option = (LPOPTION)( (LPBYTE)(option) + 1); } else { option = (LPOPTION)( (LPBYTE)(option) + option->OptionLength + 2); } if ( (LPBYTE)option - (LPBYTE)BinlMessage > DHCP_MESSAGE_SIZE ) { fprintf ( stdout,"End of message, but no trailer found!\n"); break; } } }