Let me talk about the breakthrough TCP-IP filterfirewall into the intranet (ICMP)

xiaoxiao2021-03-06  41

I. Current situation With the popularity of the Internet network, all medium large companies have established their local area networks and connected to the Internet, and the company's internal staff is also gradually become a topic that everyone cares. Most of the most popular network tools are based on IP protocols, and the two main two protocols are TCP and UDP protocols. HTTP, FTP and other upper protocols are based on the TCP protocol, while DNS, ICQ, TFTP, etc. are built on the UDP protocol. It is often encountered that the company prohibits the UDP protocol (large part of the network communication software is built on the UDP protocol), but only the TCP protocol. In this way, we can forward the UDP datagram via the TCP protocol. The specific implementation principle can see Eyas's "breakthrough TCP-IP filter / firewall into the intranet", which discusses how to implement TCP and UDP Data Improve each other, there will be no more to say this. Now enter the topic, how to achieve the limitations of the ICMP datagram breakthrough?

Second, ICMP Forward Data News ICMP Protocol (Internet Control Messages Protocol, Internet Control Packet Protocol) is a multi-functional protocol, there are many uses on the network, such as ICMP scans, denial of service (DOS) attack, tunnel attacks, And our most commonly used ping procedures. Now use the ICMP protocol to transfer UPD / TCP data for us (assuming that this unit is banned from UPD or TCP protocol). Everyone knows that the general firewall is filtered from the Echo Request packet from the external host, which is our usual ping datagram, but in order to allow the internal host to detect the current state of the external host, most firewalls will not filter. Return response (Echo reply) datagram, and ICMP packets can be transmitted on wide area online so that we can use it to break through the various limits of the gateway. Since the local host is banned from the UDP / TCP protocol, but there is no ban on the gateway, we can first send the UDP / TCP datagram in the form of ICMP to the gateway, then the gateway decoded it, configure UDP / TCP Denual newspapers send to our destination server; Difficulty, this achieves a breakthrough to gateway restrictions, one transmission / reception a total of two unpacking and packages. This paper mainly for the function of using the ICMP protocol to forward the UDP datagram, and use OICQ as a background, as for the use of ICMP protocol to break through TCP restrictions, it is also small.

Third, the QQICMP workflow below is the workflow chart of QQICMP:

QQ client <- udp -> qqicmp (l) <- icmp -> qqicmp (g) <- udp -> tencent server

The QQ client and QQICMP (L) are running on this unit, while QQICMP (g) is running on the gateway (QQICMP (L) and QQICMP (g) are the same program, but the running mode is different: -l run At the local host, -g running on the gateway), I want everyone to know. QQ client and QQICMP (L), QQICMP (g) and the TENCENT server are used in UDP communication, between QQICMP (L) and QQICMP (G) are communication with ICMP.

When sending a data report: First QQICMP (L) listened to the UDP datagram from the QQ client in a specific port, and the decoding package is sent to the gateway in the form of ICMP; QQICMP (g) listens on the ICMP Data Report from QQICMP (L) on the gateway. After the decoding package is sent in the form of UDP to the Tencent server. When the data is received: First QQICMP (g) receives the UDP datagram from the Tencent server on the gateway. After decoding the package, it is sent to QQICMP (L) in the form of ICMP; after QQICMP (L) receives the ICMP datagna, the same decoding A package, then send it to the QQ client in the form of UDP. Fourth, QQICMP code analysis WIN2000 / XP provides the ability to construct the datagram, that is, we can define the contents of the IP datagram, which can, of course, can also monitor various datagrams based on the IP protocol based on the host. In order to send ICMP datagrams and receive all IP datagrams, we must customize the format and checksum of the datagram:

Ypedef struct ipheader

{

Unsigned char h_lenver; / / head length and version

Unsigned char TOS; // service type

Unsigned short total_len; // Total length

UNSIGNED short ident; // packet logo

UNSIGNED short frame_and_flags; // flag and segmentation offset

Unsigned char TTL; // Lifecycle

Unsigned char proto; // protocol type

Unsigned short checksum; // ip checksum

Unsigned int sourceip; // source IP address

Unsigned int desip; // destination IP address

} Ipheader, * piphead;

Typedef struct icmpheader

{

Unsigned char type; // ICMP Type: 0-> Return Answer 8-> Request Request

Unsigned char code; // code

Unsigned short checksum; // iCMP checksum

UNSIGNED SHORT ID; // Identifier

Unsigned short seq; // serial number

} Icmpheader, * picmpheader;

UNSIGNED Short Checksum (unsigned short * buffer, int size) // checksum

{

Unsigned long cksum = 0;

While (size> 0) // Distinguished

{

CKSUM = * Buffer ;

Size- = SizeOf (unsigned short);

}

size

CKSUM = * (unsigned char *) BUFFER;

CKSUM = (CKSUM >> 16) (CKSUM & 0xFFFF); // shift, bit and operation

CKSUM = (CKSUM >> 16);

Return (~ cksum); //

First, we change the server address in the QQ client to 127.0.0.1, the port is changed to QQICMP (L) listening port, of course, you can also maintain the default 8000, so QQICMP (L) should be selected in 8000 port listening QQ The client's data. In summary, the QQ client server port should be the same as the port selected in QQICMP (L). At the same time, the QQ client is also in port 4000 (assuming to be the first QQ on non-intranet host) to listen to Datinarians from QQICMP (L). We can see that one of the main roles of QQICMP (L) is to receive UPD datagrams from QQ clients.

SOCK [0] [0] = Socket (AF_INET, SOCK_DGRAM, 0); // Create a socket based on UDP protocol

Bind (Sock [0] [0], (Struct SockAddr *) & sin [0] [1], addrlen; // Bind to the specified address, specify the port

IRET = Recvfrom (SOCK [0], MsgRecv, SIZEOF (MSGRECV), 0, (Struct SockAddr *) & Tempr, & Addrlen); / / Receive UDP data from QQ clients and then send it to QQICMP as ICMP datagram (g), here you need to construct an ICMP Echo Reply datagram, and populate the received UDP data to the data segment of the ICMP packet.

SOCK [0] [1] = Socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); // Create the original socket of ICMP protocol to send custom datagram

Bind (Sock [0] [1], (Struct SockAddr *) & SIN [0] [2], addrlen; // and bundled to the specified address, specifying the port

IF (Istbcs == 0) // Pack ICMP Datasheet Head

{

ICMphdr.Type = 0; // Type: echo reply

Icmphdr.code = 0; // code

Icmphdr.checksum = 0; // Popular verification to zero

Icmphdr.id = HTONS (65456); // serial number

Icmphdr.seq = htons (65456); // flag, used to filter data report

MEMSET (Msgsend, 0, SIZEOF (MSGSend));

Memcpy (msgsend, & icmphdr, sizeof (icmphdr));

ISTBCS = SizeOf (ICMphDR);

}

Memcpy (Msgsend ISTBCS, MSGRECV, IRET); // will extract the contents of the received UDP dataginary, put it in the upcoming ICMP datagram

Icmphdr.checksum = checksum (ushort *) & msgsend, ileft); // calculate ICMP checksum

Memcpy (msgsend, & icmphdr, sizeof (icmphdr)); // Refilled ICMP header

IRET = Sendto (SOCK [0] [1], Msgsend, Istbcs, 0, (Struct SockAddr *) & Sin [0] [3], AddRlen); // Send ICMP Denager Gateway at the same time, QQICMP (L) listening The IP datagram of the machine, screening out the data newspapers from QQICMP (g),

SOCK [1] [0] = Socket (AF_INET, SOCK_RAW, IPPROTO_IP); // Create the original socket, receive all IP datagram bind (Sock [1] [0], (Struct SockAddr *) & Sin [1] [1], addrlen; // Bind to the specified address, specify the port

DWORD dwbufferlen [10];

DWORD dwbufferinlen = 1;

DWORD DWBYTESRETURNED = 0;

WSAIOCTL (SOCK [1], SiO_RCVALL, & DWBUFFERINLEN, SIZEOF (DWBufferinlen), & DWBufferlen, Sizeof (DwBufferlen), & DWBYTESRETURNED, NULL, NULL

// Set to receive all datagrams and require mstcpip.h header files.

IRET = Recvfrom (SOCK [1] [0], MsgRecv, SizeOf (MsgRecv), 0, (Struct Sockaddr *) & Temp1, & Addrlen); // Receive All Data News

IF (IRET <= 28) //

{

CONTINUE;

}

IF ((ICMphDR-> Type! = 0) || (ICMphDR-> Code! = 0) || ((ICMphDR-> ID)! = HTONS (65456)) || ((ICMphDR-> SEQ)! = Htons (65456))))))

// Do not meet the reception conditions

{

CONTINUE;

}

Memcpy (Msgsend ISTBCS, MSGRECV, IRET); / / The content extracted by the received ICMP datagram is ready to send an unpack in the form of UDP, send the ICMP data received from the gateway to QQ with the UDP datagram. Client,

IDX = 28; // ICMP datagram The first 20 bytes of reports is the IP header, then the 8-byte is the ICMP header.

Iret = sendto (SOCK [1], & msgsend [IDX], Ileft, 0, (Struct SockAddr *) & Sin [1] [3], AddRlen); // Send to QQ client we created two threads Receive and transmit data on both directions (UDP -> ICMP, ICMP -> UDP), if a thread is wrong, recreate the thread, and the thread that is not erroneous remains unchanged.

HThreads [0] = CreateThread (NULL, 0, U2i, (LPVOID) 0, NULL, & HTHREADID [0]); // Create thread 0 for receiving UDP data, sending ICMP data

HThreads [1] = CreateThread (NULL, 0, I2U, (LPVOID) 1, NULL, & HTHREADID [1]); // Create thread 1 receiving ICMP data, sending UDP data

While (1)

{

DWRET = WaitFormultipleObjects (2, hthreads, false, infinite); // Waiting for a thread to end

IF (dwret == Wait_failed) // error

{

Cout << "WaitFormultipleObjects error:" << getLastError () << endl;

Return -1;

}

LOG = dwret-wait_object_0;

IF (log == 0) // thread 0 end {

CloseHandle (hthreads [0]); // Close Thread Handle

CloseSocket (SOCK [0] [1]); // Close the socket

HThreads [0] = CreateThread (NULL, 0, U2i, (LPVOID) 0, NULL, & HTHREADID [0]); // Re-create thread 0

}

ELSE IF (log == 1) // thread 1 end

{

CloseHandle (HTHREADS [1]);

CloseSocket (SOCK [1] [0]);

HThreads [1] = CreateThread (NULL, 0, I2U, (LPVOID) 1, NULL, & HTHREADID [1]);

}

The above is the working principle of QQICMP (L), and QQICMP (g) is running on the gateway, although the mode is different, but the working principle is the same, but the flow direction of the datagram is a bit different.

Five, small knot

This article uses the ICMP protocol to transmit data, but because the ICMP protocol itself, reliability cannot be well guaranteed. In fact, you can also use some other way to break through the gateway restriction, such as the recently disclosed ARP protocol can be used in some cases, of course, the premise is that you have to get some permissions of the gateway. The various methods mentioned above are essentially with other unbidden protocols to forward data that are prohibited from need to transmit, and then send data to the destination host with the original use protocol.

Six, attachment code

#include

#include

#include

#define iMaxSize 64 * 1024

Typedef struct ipheader

{

UNSIGNED Char H_lenver;

UNSIGNED Char TOS;

UNSIGNED SHORT TOTAL_LEN;

UNSIGNED short Ident;

UNSIGNED SHORT FRAG_AND_FLAGS;

UNSIGNED CHAR TTL;

UNSIGNED Char Proto;

UNSIGNED Short Checksum;

Unsigned int sourceip;

Unsigned int desip;

} ipheader;

Typedef struct icmpheader

{

UNSIGNED CHAR TYPE;

UNSIGNED Char Code;

UNSIGNED Short Checksum;

UNSIGNED SHORT SEQ;

UNSIGNED Short ID;

} icmpheader;

Unsigned Short Checksum (unsigned short * buffer, int size)

{

Unsigned long cksum = 0;

While (size> 0)

{

CKSUM = * Buffer ;

Size- = SizeOf (unsigned short);

}

size

CKSUM = * (unsigned char *) BUFFER;

CKSUM = (CKSUM >> 16) (CKSUM & 0xFFF); CKSUM = (CKSUM >> 16);

Return (Unsigned Short) (~ CKSUM);

}

INT Iaddrlen = SizeOf (struct sockaddr_in);

Socket Socki [2] [2];

Struct SockAddr_in Sini [2] [4], SAG, SAL, TEMPIR, TEMPIS

DWORD WINAPI U2i (LPVOID NUM)

{

Unreferenced_Parameter (NUM);

Char msgrecv [imaxsize] = {0}, msgsend [iMaxSize] = {0};

FD_SET FDREAD, FDWRITE;

INT IRET, RET, ISTBCS = 0, ILEFT, IDX = 0;

Struct Icmpheader ICMphdr;

MEMSET (& ICMphDR, 0, SIZEOF (ICMPHDR));

Icmphdr.code = 0;

Icmphdr.id = HTONS (65456);

Icmphdr.seq = HTONS (65456);

ICMphdr.Type = 0;

Icmphdr.checksum = Checksum (UNSIGNED Short *) & icmpHDR, SIZEOF (ICMPHDR));

IF ((SOCKI [0] [1] = Socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == Invalid_socket

{

Cout << "Socket Socki [0] [1] error:" << getLastError () << Endl;

Return -1;

}

IF (Bind (Socki [0], (Struct SockAddr *) & Sini [0] [2], Iaddrlen) == Socket_ERROR)

{

Cout << "Bind Socki [0] [1] error:" << getLastError () << endl;

Return -1;

}

While (1)

{

FD_ZERO (& FDREAD);

FD_ZERO (& fdwrite);

FD_SET (SOCKI [0], & fdread);

FD_SET (SOCKI [0] [1], & fdwrite);

IF ((Ret = SELECT (0, & fdread, & fdwrite, null, null) == Socket_ERROR)

{

Cout << "SELECT IN Thread 0 error:" << getLastError () << endl;

Break;

}

IF (RET> 0)

{

IF (fd_isset (socki [0], & fdread))

{

IRET = Recvfrom (Socki [0], MsgRecv, SizeOf (MsgRecv), 0, (Struct Sockaddr *) & Tempir, & Iaddrlen

IF (IRet == Socket_ERROR)

{

Cout << "/ NRECVFROM SOCKI [0] [0] error:" << getLastError () << endl;

Break;

}

ELSE IF (IRet == 0)

{

Break;

}

IF (Tempir.sin_Port! = SINI [0] [0] .sin_port) {

SINI [0] [0] .sin_port = Tempir.sin_port;

SINI [1] [3] .sin_port = Tempir.sin_Port;

}

Cout << "/ nthread 0 RECV" << IRET << "Bytes from / t" << inet_ntoa (Tempir.sin_ADDR) << ENDL;

IF (istbcs == 0)

{

MEMSET (Msgsend, 0, SIZEOF (MSGSend));

Memcpy (msgsend, & icmphdr, sizeof (icmphdr));

ISTBCS = SizeOf (ICMphDR);

}

Memcpy (Msgsend ISTBCS, MSGRECV, IRET);

ISTBCS = IRET;

MEMSET (MsgRecv, 0, Sizeof (MsgRecv));

}

Else IF (FD_Isset (Socki [0], & fdwrite))

{

Ileft = ISTBCS;

IDX = 0;

While (Ileft> 0)

{

IF (SINI [0] [3] .sin_addr.s_addr == htonl (0))

{

COUT << "SINI [0] [3] .sin_addr.s_addr == htonl (0)" << endl;

ISTBCS = 0;

MEMSET (Msgsend, 0, SIZEOF (MSGSend));

Break;

}

Iret = sendto (Socki [0], & msgsend [IDX], Ileft, 0, (Struct SockAddr *) & Sini [0] [3], IADDRLEN);

IF (IRet == Socket_ERROR)

{

Cout << "Sendto Socki [0] [1] error:" << getLastError () << Endl;

Break;

}

ELSE IF (IRet == 0)

Break;

Cout << "Thread 0 Send" << IRET << "BYTES to /T"<

ileft- = IRET;

IDX = IRET;

}

MEMSET (Msgsend, 0, SIZEOF (MSGSend));

ISTBCS = 0;

}

Sleep (20);

}

}

Return 0;

}

DWORD WINAPI I2U (LPVOID NUM)

{

Unreferenced_Parameter (NUM);

FD_SET FDREAD, FDWRITE;

Char msgrecv [imaxsize] = {0}, msgsend [iMaxSize] = {0};

int RET, IRET, IDX, ISTBCS = 0, ILEFT;

DWORD dwbufferlen [10];

DWORD dwbufferinlen = 1;

DWORD DWBYTESRETURNED = 0;

Struct ipheader * iphdr;

Struct ICMPHEADER * ICMPHDR;

IF ((SOCKI [1] [0] = Socket (AF_INET, SOCK_RAW, IPPROTO_IP)) == Invalid_Socket) {

Cout << "Socket Socki [1] [0] error:" << getLastError () << endl;

Return -1;

}

IF (Socki [1] [0], (Struct SockAddr *) & Sini [1] [1], Iaddrlen == Socket_ERROR)

{

COUT << "Bind Socki [1] [0] error:" << getLastError () << endl;

Return -1;

}

WSAIOCTL (SOCKI [1], SiO_RCVALL, & DWBUFFERINLEN, SIZEOF (DWBufferinlen), & DWBufferlen, SizeOf (DwBufferlen), & DWBYTESRETURNED, NULL, NULL

Iphdr = (struct ipheader *) msgrecv;

ICMPHDR = (struct icmpheader *) (msgrecv sizeof (struct ipheader);

While (1)

{

FD_ZERO (& FDREAD);

FD_ZERO (& fdwrite);

FD_set (Socki [1] [0], & fdread);

FD_SET (SOCKI [1] [1], & fdwrite);

IF ((Ret = SELECT (0, & fdread, & fdwrite, null, null) == Socket_ERROR)

{

Cout << "SELECT IN Thread 1 Error:" << getLastError () << endl;

Break;

}

IF (RET> 0)

{

IF (fd_isset (socki [1] [0], & fdread))

{

IRET = Recvfrom (Socki [1] [0], MsgRecv, SizeOf (MsgRecv), 0, (Struct SockAddr *) & Tempis, & Iaddrlen

IF (IRet == Socket_ERROR)

{

COUT << "Recvfrom Socki [1] [0] error:" << getLastError () << endl;

Break;

}

IF (IRET <= 28)

{

Break;

}

IF ((ICMphDR-> Type! = 0) || (ICMphDR-> Code! = 0) || ((ICMphDR-> ID)! = HTONS (65456)) || ((ICMphDR-> SEQ)! = Htons (65456))))))

{

Break;

}

IF ((SINI [1] [0] .sin_addr.s_addr! = htonl (0)) && (SINI [1] [0] .sin_addr.s_addr! = tempis.sin_addr.s_addr))))

Break;

Else IF (SINI [1] [0] .sin_addr.s_addr == htonl (0))

{

SINI [1] [0] .SIN_ADDR.S_ADDR = Tempis.sin_Addr.s_addr;

SINI [0] [3] .sin_addr.s_addr = Tempis.sin_Addr.s_addr;

}

Cout << "/ nthread 1 RECV" << IRET << "BYTES from /T"<

ISTBCS = IRET;

MEMSET (MsgRecv, 0, Sizeof (MsgRecv));

}

Else IF (FD_Isset (Socki [1], & fdwrite))

{

Ileft = ISTBCS-28;

IDX = 28;

While (Ileft> 0)

{

IRET = Sendto (Socki [1], & msgsend [IDX], Ileft, 0, (Struct Sockaddr *) & Sini [1] [3], Iaddrlen;

IF (IRet == Socket_ERROR)

{

Cout << "Sendto Socki [1] [1] error:" << getLastError () << endl;

Break;

}

ELSE IF (IRet == 0)

Break;

Cout << "Thread 1 Send" << IRET << "BYTES to /T"<

ileft- = IRET;

IDX = IRET;

}

ISTBCS = 0;

MEMSET (Msgsend, 0, SIZEOF (MSGSend));

}

Sleep (20);

}

}

Return 0;

}

Void QqiCMP (Struct SockAddr_in Itarget, Bool Ilocal)

{

Handle ithreads [2];

DWORD ITHREADID [2];

Struct hostent * hp;

Char CNAME [100];

Int dwret, log;

GethostName (CName, Sizeof (CNAME));

HP = gethostbyname (CNAME);

For (int ipnum = 0; hp-> h_addr_list [ipnum]! = null; ipnum )

Sag.sin_addr = * (in_addr *) hp-> h_addr_list [ipnum];

Sag.sin_family = af_INet;

Sag.sin_port = HTONS (65456);

SAL = SAG;

IF (ipnum> 1)

Sal.sin_addr = * (in_addr *) hp-> h_addr_list [ipnum-2];

IF (! ilocal)

{

SINI [0] [0] .sin_addr.s_addr = itarget.sin_addr.s_addr;

SINI [0] [0] .sin_family = AF_INET;

SINI [0] [0] .sin_port = htons (8000);

SINI [0] [1] .sin_addr.s_addr = HTONL (INADDR_Any);

SINI [0] [1] .sin_family = AF_INET;

SINI [0] [1] .sin_port = itarget.sin_port;

SINI [0] [2] = SAL;

MEMSET (& SINI [0] [3], 0, Iaddrlen;

Sini [0] [3] .sin_family = AF_INET;}

Else

{

MEMSET (& SINI [0] [0], 0, Iaddrlen;

SINI [0] [0] .sin_family = AF_INET;

SINI [0] [0] .sin_addr.s_addr = inet_addr ("127.0.0.1");

SINI [0] [1] .sin_addr.s_addr = HTONL (INADDR_Any);

SINI [0] [1] .sin_family = AF_INET;

SINI [0] [1] .sin_port = itarget.sin_port;

SINI [0] [2] = SAL;

SINI [0] [3] .sin_addr.s_addr = itarget.sin_addr.s_addr;

SINI [0] [3] .sin_family = AF_INET;

}

SINI [1] [0] = SINI [0] [3];

SINI [1] [1] = SINI [0] [2];

SINI [1] [2] = SINI [0] [1];

SINI [1] [3] = SINI [0] [0];

IF ((SOCKI [0] [0] = Socket (AF_INET, SOCK_DGRAM, 0) == Invalid_socket)

{

Cout << "Socket Socki [0] [0] error:" << getLastError () << endl;

Return;

}

IF (Bind (Socki [0], (Struct SockAddr *) & Sini [0] [1], Iaddrlen == Socket_ERROR)

{

Cout << "Bind Socki [0] [0] error:" << getLastError () << endl;

Return;

}

SOCKI [1] [1] = SOCKI [0] [0];

Cout << "/ n normal work ..." << Endl;

Ithreads [0] = CreateThread (NULL, 0, U2i, (LPVOID) 0, NULL, & ITHREADID [0]);

Ithreads [1] = CreateThread (NULL, 0, I2U, (LPVOID) 1, NULL, & ITHREADID [1]);

While (1)

{

DWRET = WaitFormultipleObjects (2, Ithreads, False, Infinite);

IF (dwret == Wait_failed)

{

Cout << "WaitFormultipleObjects error:" << getLastError () << endl;

Return;

}

LOG = dwret-wait_object_0;

IF (log == 0)

{

CloseHandle (Ithhreads [0]);

CloseSocket (SOCKI [0] [1]);

Ithreads [0] = CreateThread (NULL, 0, U2i, (LPVOID) 0, NULL, & ITHREADID [0]);

}

ELSE IF (log == 1)

{

CloseHandle (Ithhreads [1]);

CloseSocket (SOCKI [1] [0]);

Ithreads [1] = CreateThread (NULL, 0, I2U, (LPVOID) 1, NULL, & ITHREADID [1]);

}

Else

{

For (int No1 = 0; NO1 <2; NO1 )

{

CloseHandle (ITHREADS [NO1]);

For (int No2 = 0; NO2 <2; NO2 )

CloseSocket (SOCKI [NO1] [NO2]);

}

}

}

Return;

}

转载请注明原文地址:https://www.9cbs.com/read-58250.html

New Post(0)