windows-nt/Source/XPSP1/NT/net/dhcp/server/binl/binlt.c

818 lines
21 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
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 <ServerName>
-s <Servername> To specify a BINL server of your choice. Default is COLINW2
Author:
Colin Watson Apr 29 1997
Revision History:
*/
#include <binl.h>
#pragma hdrstop
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <tdiinfo.h>
#include <wsipx.h>
#include <wsnwlink.h>
#include <nb30.h>
#include <binldef.h>
#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 <ServerName>, 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;
}
}
}