#include <stdio.h> #include <errno.h> #include <stdarg.h> #include <stdlib.h> #include <sys/poll.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> /* NBT Session Service Packet Type Codes */ #define SESS_MSG 0x00 #define SESS_REQ 0x81 #define SESS_POS_RESP 0x82 #define SESS_NEG_RESP 0x83 #define SESS_RETARGET 0x84 #define SESS_KEEPALIVE 0x85 /* NBT Session Service Error Codes */ #define ErrNLCalled 0x80 #define ErrNLCalling 0x81 #define ErrCalledNotPrsnt 0x82 #define ErrInsResources 0x83 #define ErrUnspecified 0x8F ushort nbt_GetShort( uchar *src, int offset ) /* ---------------------------------------------------- ** * Read two bytes from an NBT message and convert them * to an unsigned short int. * * Note that we read the bytes in NBT byte order, which * is the opposite of SMB byte order. * ---------------------------------------------------- ** */ { ushort tmp; tmp = src[offset]; tmp = (tmp << 8) | src[offset+1]; return( tmp ); } /* nbt_GetShort */ void Fail( char *fmt, ... ) /* ---------------------------------------------------- ** * This function formats and prints an error to stdout, * then exits the program. * A nice quick way to abandon ship. * ---------------------------------------------------- ** */ { va_list ap; va_start( ap, fmt ); (void)fprintf( stdout, "Error: " ); (void)vfprintf( stdout, fmt, ap ); exit( EXIT_FAILURE ); } /* Fail */ void NegResponse( uchar *bufr, int len ) /* ---------------------------------------------------- ** * Negative Session Response error reporting. * * The Negative Session Response message should always * be five bytes in length. The final byte (bufr[4]) * contains the error code. * ---------------------------------------------------- ** */ { if( len < 5 ) Fail( "Truncated Negative Session Response.\n" ); printf( "Negative Session Response: " ); switch( bufr[4] ) { case ErrNLCalled: printf( "Not listening on Called Name.\n" ); break; case ErrNLCalling: printf( "Not listening *for* Calling Name.\n" ); break; case ErrCalledNotPrsnt: printf( "Called Name not present.\n" ); break; case ErrInsResources: printf( "Insufficient resources on server.\n" ); break; case ErrUnspecified: printf( "Unspecified error.\n" ); break; default: printf( "Unknown error.\n" ); break; } } /* NegResponse */ void Retarget( uchar *bufr, int result ) /* ---------------------------------------------------- ** * This function is called if we receive a RETARGET * SESSION RESPONSE from the server. The correct thing * to do would be to retry the connection, using the * returned information. This function simply reports * the retarget response so that the user can manually * retry. * ---------------------------------------------------- ** */ { if( result < 10 ) Fail( "Truncated Retarget Session Response.\n" ); printf( "Retarget Session Response: " ); printf( "IP = %d.%d.%d.%d, ", bufr[4], bufr[5], bufr[6], bufr[7] ); printf( "Port = %d\n", nbt_GetShort( bufr, 8 ) ); } /* Retarget */ int MakeSessReq( uchar *bufr, uchar *Called, uchar *Calling ) /* ---------------------------------------------------- ** * Create an NBT SESSION REQUEST message. * ---------------------------------------------------- ** */ { /* Write the header. */ bufr[0] = SESS_REQ; bufr[1] = 0; bufr[2] = 0; bufr[3] = 68; /* 2x34 bytes in length. */ /* Copy the Called and Calling names into the buffer. */ (void)memcpy( &bufr[4], Called, 34 ); (void)memcpy( &bufr[38], Calling, 34 ); /* Return the total message length. */ return( 72 ); } /* MakeSessReq */ int RecvTimeout( int sock, uchar *bufr, int bsize, int timeout ) /* ---------------------------------------------------- ** * Attempt to receive a TCP packet within a specified * period of time. * ---------------------------------------------------- ** */ { int result; struct pollfd pollfd[1]; /* Wait timeout/1000 seconds for a message to arrive. */ pollfd->fd = sock; pollfd->events = POLLIN; pollfd->revents = 0; result = poll( pollfd, 1, timeout ); /* A result less than zero is an error. */ if( result < 0 ) Fail( "Poll() error: %s\n", strerror( errno ) ); /* A result of zero is a timeout. */ if( result == 0 ) return( 0 ); /* A result greater than zero means a message arrived, * so we attempt to read the message. */ result = recv( sock, bufr, bsize, 0 ); if( result < 0 ) Fail( "Recv() error: %s\n", strerror( errno ) ); /* Return the number of bytes received. * (Zero or more.) */ return( result ); } /* RecvTimeout */ void RequestNBTSession( int sock, uchar *Called, uchar *Calling ) /* ---------------------------------------------------- ** * Send an NBT SESSION REQUEST over the TCP connection, * then wait for a reply. * ---------------------------------------------------- ** */ { uchar bufr[128]; int result; /* Create the NBT Session Request message. */ result = MakeSessReq( bufr, Called, Calling ); /* Send the NBT Session Request message. */ result = send( sock, bufr, result, 0 ); if( result < 0 ) Fail( "Error sending Session Request message: %s\n", strerror( errno ) ); /* Now wait for and handle the reply (2 seconds). */ result = RecvTimeout( sock, bufr, 128, 2000 ); if( result == 0 ) { printf( "Timeout waiting for NBT Session Response.\n" ); return; } switch( *bufr ) { case SESS_POS_RESP: /* We got what we wanted. */ printf( "Positive Session Response.\n" ); return; case SESS_NEG_RESP: /* Report an error. */ NegResponse( bufr, result ); exit( EXIT_FAILURE ); case SESS_RETARGET: /* We've been retargeted. */ Retarget( bufr, result ); exit( EXIT_FAILURE ); default: /* Not a response we expected. */ Fail( "Unexpected response from server.\n" ); break; } } /* RequestNBTSession */ int OpenTCPSession( struct in_addr dst_IP, ushort dst_port ) /* ---------------------------------------------------- ** * Open a TCP session with the specified server. * Return the connected socket. * ---------------------------------------------------- ** */ { int sock; int result; struct sockaddr_in sock_addr; /* Create the socket. */ sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if( sock < 0 ) Fail( "Failed to create socket(); %s.\n", strerror( errno ) ); /* Connect the socket to the server at the other end. */ sock_addr.sin_addr = dst_IP; sock_addr.sin_family = AF_INET; sock_addr.sin_port = htons( dst_port ); result = connect( sock, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_in) ); if( result < 0 ) Fail( "Failed to create socket(); %s.\n", strerror( errno ) ); return( sock ); } /* OpenTCPSession */ int main( int argc, char *argv[] ) /* ---------------------------------------------------- ** * Program mainline. * Parse the command-line input and open the connection * to the server. * ---------------------------------------------------- ** */ { uchar Called[34]; uchar Calling[34]; struct in_addr dst_addr; int dst_port = 139; int sock; /* Check for the correct number of arguments. */ if( argc < 3 || argc > 4 ) { printf( "Usage: %s <NAME> <IP> [<PORT>]\n", argv[0] ); exit( EXIT_FAILURE ); } /* Encode the destination name. */ if( '*' == *(argv[1]) ) (void)L2_Encode( Called, "*SMBSERVER", 0x20, 0x20, "" ); else (void)L2_Encode( Called, argv[1], 0x20, 0x20, "" ); /* Create a (bogus) Calling Name. */ (void)L2_Encode( Calling, "SMBCLIENT", 0x20, 0x00, "" ); /* Read the destination IP address. * We could do a little more work and resolve * the Called Name, but that would add a lot * of code to the example. */ if( 0 == inet_aton( argv[2], &dst_addr ) ) { printf( "Invalid IP.\n" ); printf( "Usage: %s <NAME> <IP> [<PORT>]\n", argv[0] ); exit( EXIT_FAILURE ); } /* Read the (optional) port number. */ if( argc == 4 ) { dst_port = atoi( argv[3] ); if( 0 == dst_port ) { printf( "Invalid Port number.\n" ); printf( "Usage: %s <NAME> <IP> [<PORT>]\n", argv[0] ); exit( EXIT_FAILURE ); } } /* Open the session. */ sock = OpenTCPSession( dst_addr, dst_port ); /* Comment out the next call for raw TCP. */ RequestNBTSession( sock, Called, Calling ); /* ** Do real work here. ** */ return( EXIT_SUCCESS ); } /* main */
$Revision: 1.9 $ $Date: 2003/02/23 02:09:20 $ |
Copyright © 2002 Christopher R. Hertel Released under the terms of the LGPL |