#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 |