diff --git a/reactos/apps/tests/iptest/iptest.cpp b/reactos/apps/tests/iptest/iptest.cpp new file mode 100644 index 00000000000..e4420609e1c --- /dev/null +++ b/reactos/apps/tests/iptest/iptest.cpp @@ -0,0 +1,476 @@ +#include +#include +#include +#include +extern "C" { + typedef unsigned short u_short; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +}; + +/* Undis */ +extern "C" VOID ExpInitLookasideLists(); + +std::list 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::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(); + } +} + diff --git a/reactos/apps/tests/iptest/makefile b/reactos/apps/tests/iptest/makefile new file mode 100644 index 00000000000..190e5af9dbe --- /dev/null +++ b/reactos/apps/tests/iptest/makefile @@ -0,0 +1,26 @@ +# +# $Id: makefile,v 1.1 2004/10/04 04:26:00 arty Exp $ + +PATH_TO_TOP = ../../.. + +TARGET_NORC = yes + +TARGET_TYPE = program + +TARGET_APPTYPE = console + +TARGET_NAME = iptest + +TARGET_SDKLIBS = ws2_32.a ip.a oskittcp.a undis.a ntdll.a + +TARGET_OBJECTS = iptest.o + +TARGET_CPPFLAGS = -I$(PATH_TO_TOP)/drivers/lib/oskittcp/include -I$(PATH_TO_TOP)/w32api/include -I$(PATH_TO_TOP)/include -I$(PATH_TO_TOP)/drivers/net/tcpip/include -g + +TARGET_GCCLIBS = stdc++ + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF