reactos/modules/rostests/tests/iptest/iptest.cpp

476 lines
12 KiB
C++

#include <iostream>
#include <list>
#include <string>
#include <sstream>
extern "C" {
typedef unsigned short u_short;
#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
#include <ddk/tdi.h>
#include <ddk/tdikrnl.h>
#include <ddk/tdiinfo.h>
#include <ddk/ndis.h>
#include <titypes.h>
#include <ip.h>
#include <tcp.h>
#include <receive.h>
#include <lan.h>
#include <routines.h>
};
/* Undis */
extern "C" VOID ExpInitLookasideLists();
std::list<std::string> output_packets;
DWORD DebugTraceLevel = 0x7fffffff;
PVOID GlobalBufferPool, GlobalPacketPool;
#define MAX_DG_SIZE 16384
char hwaddr[6] = { 0x08, 0x00, 0x20, 0x0b, 0xb7, 0xbb };
char hdr[14] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00 };
#define STRINGIFY(x) #x
void display_row( char *data, int off, int len ) {
int i;
printf( "%08x:", off );
for( i = off; i < len && i < off + 16; i++ ) {
printf( " %02x", data[i] & 0xff );
}
printf( " -- " );
for( i = off; i < len && i < off + 16; i++ ) {
printf( "%c", (data[i] >= ' ') ? data[i] : '.' );
}
printf( "\n" );
}
void connect_complete( void *context, NTSTATUS status, unsigned long count ) {
printf( "Connection: status %x\n", status );
}
void receive_complete( void *context, NTSTATUS status, unsigned long count ) {
printf( "Receive: status %s (bytes %d)\n", status, count );
if( !status && count ) {
for( int off = 0; off < count; off += 16 ) {
display_row( (char *)context, off, count );
}
printf( "\n" );
}
}
class SocketObject {
public:
virtual ~SocketObject() { }
virtual int send( char *buf, int len, int *bytes,
struct sockaddr_in *si ) = 0;
virtual int recv( char *buf, int len, int *bytes,
struct sockaddr_in *si ) = 0;
};
UINT TdiAddressSizeFromType( UINT AddressType ) {
switch( AddressType ) {
case TDI_ADDRESS_TYPE_IP:
return sizeof(TA_IP_ADDRESS);
default:
KeBugCheck( 0 );
}
return 0;
}
NTSTATUS TdiBuildNullConnectionInfoInPlace
( PTDI_CONNECTION_INFORMATION ConnInfo,
ULONG Type )
/*
* FUNCTION: Builds a NULL TDI connection information structure
* ARGUMENTS:
* ConnectionInfo = Address of buffer to place connection information
* Type = TDI style address type (TDI_ADDRESS_TYPE_XXX).
* RETURNS:
* Status of operation
*/
{
ULONG TdiAddressSize;
TdiAddressSize = TdiAddressSizeFromType(Type);
RtlZeroMemory(ConnInfo,
sizeof(TDI_CONNECTION_INFORMATION) +
TdiAddressSize);
ConnInfo->OptionsLength = sizeof(ULONG);
ConnInfo->RemoteAddressLength = 0;
ConnInfo->RemoteAddress = NULL;
return STATUS_SUCCESS;
}
NTSTATUS TdiBuildNullConnectionInfo
( PTDI_CONNECTION_INFORMATION *ConnectionInfo,
ULONG Type )
/*
* FUNCTION: Builds a NULL TDI connection information structure
* ARGUMENTS:
* ConnectionInfo = Address of buffer pointer to allocate connection
* information in
* Type = TDI style address type (TDI_ADDRESS_TYPE_XXX).
* RETURNS:
* Status of operation
*/
{
PTDI_CONNECTION_INFORMATION ConnInfo;
ULONG TdiAddressSize;
NTSTATUS Status;
TdiAddressSize = TdiAddressSizeFromType(Type);
ConnInfo = (PTDI_CONNECTION_INFORMATION)
ExAllocatePool(NonPagedPool,
sizeof(TDI_CONNECTION_INFORMATION) +
TdiAddressSize);
if (!ConnInfo)
return STATUS_INSUFFICIENT_RESOURCES;
Status = TdiBuildNullConnectionInfoInPlace( ConnInfo, Type );
if (!NT_SUCCESS(Status))
ExFreePool( ConnInfo );
else
*ConnectionInfo = ConnInfo;
ConnInfo->RemoteAddress = (PTA_ADDRESS)&ConnInfo[1];
ConnInfo->RemoteAddressLength = TdiAddressSize;
return Status;
}
UINT TaLengthOfTransportAddress( PTRANSPORT_ADDRESS Addr ) {
UINT AddrLen = 2 * sizeof( ULONG ) + Addr->Address[0].AddressLength;
printf("AddrLen %x\n", AddrLen);
return AddrLen;
}
NTSTATUS
TdiBuildConnectionInfoInPlace
( PTDI_CONNECTION_INFORMATION ConnectionInfo,
PTA_ADDRESS Address ) {
NTSTATUS Status = STATUS_SUCCESS;
RtlCopyMemory( ConnectionInfo->RemoteAddress,
Address,
ConnectionInfo->RemoteAddressLength );
return Status;
}
NTSTATUS
TdiBuildConnectionInfo
( PTDI_CONNECTION_INFORMATION *ConnectionInfo,
PTA_ADDRESS Address ) {
NTSTATUS Status = TdiBuildNullConnectionInfo( ConnectionInfo,
Address->AddressType );
if( NT_SUCCESS(Status) )
TdiBuildConnectionInfoInPlace( *ConnectionInfo, Address );
return Status;
}
class TCPSocketObject : public SocketObject {
public:
TCPSocketObject( std::string host, int port, NTSTATUS *status ) {
TA_IP_ADDRESS ConnectTo;
PTDI_CONNECTION_INFORMATION ConnInfo;
ConnectTo.TAAddressCount = 1;
ConnectTo.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
ConnectTo.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
ConnectTo.Address[0].Address[0].sin_port = htons(port);
ConnectTo.Address[0].Address[0].in_addr = 0x6a020a0a;
TdiBuildConnectionInfo( &ConnInfo, (PTA_ADDRESS)&ConnectTo );
Connection = TCPAllocateConnectionEndpoint( NULL );
*status = TCPSocket( Connection,
AF_INET,
SOCK_STREAM, IPPROTO_TCP );
if( !*status )
*status = TCPConnect( Connection,
ConnInfo,
NULL,
connect_complete,
NULL );
}
~TCPSocketObject() {
TCPClose( Connection );
if( Connection ) TCPFreeConnectionEndpoint( Connection );
}
int send( char *buf, int len, int *bytes, struct sockaddr_in *si ) {
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if( Connection )
Status = TCPSendData( Connection,
buf,
len,
(PULONG)bytes,
0 );
return Status;
}
int recv( char *buf, int len, int *bytes, struct sockaddr_in *si ) {
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if( Connection )
Status = TCPSendData( Connection,
buf,
len,
(PULONG)bytes,
0 );
return Status;
}
private:
PCONNECTION_ENDPOINT Connection;
};
VOID SendPacket( PVOID Context,
PNDIS_PACKET NdisPacket,
UINT Offset,
PVOID LinkAddress,
USHORT Type ) {
PCHAR DataOut;
PUCHAR Addr = (PUCHAR)LinkAddress;
UINT Size;
std::string output_packet;
printf( "Sending packet: %02x:%02x:%02x:%02x:%02x:%02x\n",
Addr[0], Addr[1], Addr[2], Addr[3], Addr[4], Addr[5] );
GetDataPtr( NdisPacket, Offset, &DataOut, &Size );
for( int off = 0; off < Size; off += 16 ) {
display_row( DataOut, off, Size );
}
printf( "\n" );
output_packet += std::string( hwaddr, sizeof(hwaddr) );
output_packet += std::string( (char *)LinkAddress, sizeof(hwaddr) );
output_packet += (char)(Type >> 8);
output_packet += (char)Type;
output_packet += std::string( DataOut + Offset, Size - Offset );
output_packets.push_back( output_packet );
}
#if 0
UINT CopyBufferToBufferChain
( PNDIS_BUFFER DstBuffer, UINT DstOffset, PCHAR SrcData, UINT Length ) {
assert( 0 );
}
#endif
int main( int argc, char **argv ) {
int asock = INVALID_SOCKET, selret, dgrecv, fromsize, err, port = 5001;
int bytes, adapter_id, mtu, speed;
char datagram[MAX_DG_SIZE];
struct fd_set readf;
struct timeval tv;
struct sockaddr_in addr_from = { AF_INET }, addr_to;
std::string word, cmdin, host;
std::list<std::string>::iterator i;
WSADATA wsadata;
NTSTATUS Status;
UNICODE_STRING RegistryUnicodePath;
PCONNECTION_ENDPOINT Connection;
PIP_INTERFACE Interface;
IP_PACKET IPPacket;
LLIP_BIND_INFO BindInfo;
SocketObject *S = NULL;
RtlInitUnicodeString
( &RegistryUnicodePath,
L"\\SYSTEM\\CurrentControlSet\\Services"
L"\\Tcpip" );
ExpInitLookasideLists();
WSAStartup( 0x101, &wsadata );
if( argc > 1 ) port = atoi(argv[1]);
IPStartup( &RegistryUnicodePath );
BindInfo.Context = NULL;
BindInfo.HeaderSize = sizeof(ETH_HEADER);
BindInfo.MTU = 1500; /* MTU for ethernet */
BindInfo.Address = (PUCHAR)hwaddr;
BindInfo.AddressLength = sizeof(hwaddr);
BindInfo.Transmit = SendPacket;
IPCreateInterface( &BindInfo );
asock = socket( AF_INET, SOCK_DGRAM, 0 );
addr_from.sin_port = htons( port );
if( bind( asock, (struct sockaddr *)&addr_from, sizeof( addr_from ) ) ) {
printf( "Bind error\n" );
return 0;
}
while( true ) {
FD_ZERO( &readf );
FD_SET( asock, &readf );
tv.tv_sec = 0;
tv.tv_usec = 10000;
selret = select( asock + 1, &readf, NULL, NULL, &tv );
if( FD_ISSET( asock, &readf ) ) {
fromsize = sizeof( addr_from );
dgrecv = recvfrom( asock, datagram, sizeof(datagram), 0,
(struct sockaddr *)&addr_from, &fromsize );
if( datagram[0] == 'C' && datagram[1] == 'M' &&
datagram[2] == 'D' && datagram[3] == ' ' ) {
int theport, bytes, recvret, off, bytin;
struct sockaddr_in nam;
std::string faddr, word;
std::istringstream
cmdin( std::string( datagram + 4, dgrecv - 4 ) );
cmdin >> word;
/* UDP Section */
if( word == "udpsocket" ) {
/* TCP Section */
} else if( word == "tcpsocket" ) {
cmdin >> host >> port;
S = new TCPSocketObject( host, port, &Status );
fprintf( stderr, "Socket: Result %x\n", Status );
} else if( word == "close" ) {
TCPClose( Connection );
TCPFreeConnectionEndpoint( Connection );
} else if( word == "type" ) {
std::string therest = &cmdin.str()[word.size()];
char* p = &therest[0];
p += strspn ( p, " \t" );
char* src = p;
char* dst = p;
while ( *src )
{
char c = *src++;
if ( c == '\r' || c == '\n' ) break;
if ( c == '\\' )
{
c = *src++;
switch ( c )
{
case 'b': c = '\b'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
}
}
*dst++ = c;
}
*dst = '\0';
if( S )
err = S->send( p, strlen(p), &bytes, NULL );
if( err > 0 ) { bytin = err; err = 0; }
if( err )
fprintf ( stderr, "OskitTCPConnect: error %d\n",
err );
else {
printf ( "wrote %d bytes\n", bytin );
}
} else if( word == "send" ) {
off = 0;
while( cmdin >> word ) {
datagram[off++] =
atoi( (std::string("0x") + word).c_str() );
}
if( (err = S->send( datagram, off, &bytin, NULL )) != 0 ) {
fprintf( stderr, "OskitTCPConnect: error %d\n", err );
} else {
printf( "wrote %d bytes\n", bytin );
}
} else if( word == "recv" ) {
cmdin >> bytes;
if( (err = S->recv( datagram,
sizeof(datagram),
&bytes,
NULL )) != 0 ) {
fprintf( stderr, "OskitTCPRecv: error %d\n", err );
}
/* Misc section */
} else if( word == "end" ) {
return 0;
}
} else if( dgrecv > 14 ) {
addr_to = addr_from;
if( datagram[12] == 8 && datagram[13] == 6 ) {
/* Answer arp query */
char laddr[4];
/* Mark patch as to the previous sender */
memcpy( datagram + 32, datagram + 6, 6 );
memcpy( datagram, datagram + 6, 6 );
/* Mark packet as from us */
memcpy( datagram + 22, hwaddr, 6 );
memcpy( datagram + 6, hwaddr, 6 );
/* Swap inet addresses */
memcpy( laddr, datagram + 28, 4 );
memcpy( datagram + 28, datagram + 38, 4 );
memcpy( datagram + 38, laddr, 4 );
/* Set reply opcode */
datagram[21] = 2;
err = sendto( asock, datagram, dgrecv, 0,
(struct sockaddr *)&addr_to,
sizeof(addr_to) );
if( err != 0 )
printf( "sendto: %d\n", err );
} else {
memcpy( hdr, datagram + 6, 6 );
memcpy( hdr + 6, datagram, 6 );
memcpy( hdr + 12, datagram + 12, 2 );
IPPacket.Header = datagram;
IPPacket.Data = datagram + 14;
IPPacket.TotalSize = dgrecv;
IPReceive( Interface, &IPPacket );
}
}
}
IPTimeout(NULL, NULL, NULL, NULL);
for( i = output_packets.begin(); i != output_packets.end(); i++ ) {
err = sendto( asock, i->c_str(), i->size(), 0,
(struct sockaddr *)&addr_to, sizeof(addr_to) );
fprintf( stderr, "** SENDING PACKET %d bytes **\n", i->size() );
if( err != 0 )
printf( "sendto: %d\n", err );
}
output_packets.clear();
}
}