Before entering a variety of powerful raw socket applications, we will first explain how to establish a raw socket and how to use the established raw socket to send and receive IP packets.
Create raw socket
On Windows, to use raw socket, you must first initialize Winsock:
// Start Winsock Wsadata; If (wsastartup (makeword (2, 1), & wsadata )! = 0) { Cerr <"failed to find Winsock 2.1 or better." <Endl; Return 1; } |
Makeword (2, 1) forms a version field, Version 2.1. Similarly, makeword (2, 2) means Version 2.2. Makeword is defined:
Inline word makeword (const byte whigh, const byte wlow) { Return (Word) whigh) <8 | wlow; } |
Therefore, makeword (2, 1) is actually equivalent to 0x0201. Similarly, 0x0101 can be equivalent to makeword (1, 1 ).
The function used with wsastartup () is wsacleanup (), which is called after all sockets are used up, for example:
Void sock_cleanup () { # Ifdef Win32 Sockcount --; If (sockcount = 0) Wsacleanup (); # Endif } |
Next, define a socket handle:
Socket SD; // raw socket handle |
You can use the wsasocket () function to create a socket and assign the handle to the defined SD. The prototype is as follows:
Socket wsasocket (int af, int type, int protocol, lpwsaprotocol_info Lpprotocolinfo, group G, DWORD dwflags ); |
The parameters are defined:
AF: The address family, which is generally af_inet and refers to the IPv4 (the Internet Protocol version 4) address family.
Type: socket type. If you create the original socket, use sock_raw;
Protocol: protocol type, such as ipproto_tcp and ipproto_udp;
Lpprotocolinfo: wsaprotocol_info struct pointer;
Dwflags: Specifies the socket property flag.
For example, the following code defines the source socket of the ICMP protocol type:
SD = wsasocket (af_inet, sock_raw, ipproto_icmp, 0, 0, 0 ); |
You can also use the socket () function to create a socket:
Socket wsaapi socket (int af, int type, int Protocol ); |
The Parameter definition is the same as that of the wsasocket () function.
To use the socket () function to create a socket, you also need to bind the socket with sockaddr:
Sockaddr_in addr_in;
Addr_in.sin_family = af_inet; Addr_in.sin_port = inaddr_any; Addr_in.sin_addr.s_un.s_addr = getlocalip ();
Nretcode = BIND (SD, (struct sockaddr *) & addr_in, sizeof (addr_in )); If (socket_error = nretcode) { Printf ("BIND error! % D \ n ", wsagetlasterror ()); } |
The struct sockaddr_in (that is, sockaddr_in) used is:
Struct sockaddr_in { Unsigned short sin_family; Unsigned short int sin_port; Struct in_addr sin_addr; Unsigned char sin_zero [8]; } |
The struct sockaddr type of the second parameter of the BIND () function is defined:
Struct sockaddr { Unisgned short as_family; Char sa_data [14]; }; |
In fact, the BIND () function uses struct sockaddr to consider compatibility. In the end, the memory usage of struct sockaddr and struct sockaddr_in is equivalent. The struct in_addr member in struct sockaddr_in occupies 4 bytes and is a 32-bit IP address. It is defined:
Typedef struct in_addr { Union { Struct { U_char s_b1, s_b2, s_b3, s_b4; } S_un_ B; Struct { U_short s_w1, s_w2; } S_un_w; U_long s_addr; } S_un; } In_addr, * pin_addr, far * lpin_addr; |
Defining a 32-bit IP address as a consortium will enable users to read and write the same IP address in bytes, half words, or words.. Comrades, note that this technique is widely used in many software development scenarios to define data structures.
To control the packet sending method, we may use the following very important function to set socket options:
Int setsockopt ( Socket S, // socket handle Int level, // option level, such as sol_socket Int optname, // option name, such as so_broadcast Const char * optval, // The buffer pointer of the option value Int optlen // Option Buffer Length ); |
For example, when the level is sol_socket, we can set the so_broadcast Boolean option to control whether the socket transmits and receives broadcast messages.
The following code setsThe ipproto_ip level ip_hdrincl option is true, enabling programmers to handle the IP packet header in person.:
// Set the IP header operation options Bool flag = true; Setsockopt (SD, ipproto_ip, ip_hdrincl, (char *) & flag, sizeof (FLAG ); |
The following functions are used to control sockets:
Int ioctlsocket ( Socket s, Long cmd, // command U_long * argp // command parameter pointer ); |
The following code allows the socket to receive all packets (sniffer mode ):
U_long imode = 1; Ioctlsocket (SD, sio_rcvall, & imode); // Let sockraw accept all the data
|
Raw socket sends packets
The function for sending messages is:
Int sendto ( Socket S, // socket handle Const char * Buf, // sending Buffer Int Len, // number of bytes to be sent Int flags, // method flag Const struct sockaddr * To, // target address Int tolen // target address Length ); |
Or
Int send ( Socket S, // socket handle that has established a connection Const char * Buf, Int Len, Int flags ); |
The 1st parameters of the send () function can only be a socket handle with established connections. Therefore, this function no longer requires the input of the target address parameter.
The Return Value of the function is the number of bytes actually sent. If socket_error is returned, you can use wsagetlasterror () to obtain the cause of the error. See the following example:
Raw socket receives packets
The function for receiving packets is:
Int recvfrom ( Socket S, // socket handle Char * Buf, // receiving buffer Int Len, // Number of buffer bytes Int flags, // method flag Struct sockaddr * From, // Source Address Int * fromlen ); |
Or
Int Recv ( Socket S, // socket handle that has established a connection Char * Buf, Int Len, Int flags ); |
The 1st parameters of the Recv () function can only be a socket handle with established connections. Therefore, the function does not need to input source address parameters.
The Return Value of the function is the number of actually received bytes. If socket_error is returned, we can use the wsagetlasterror () function to obtain the cause of the error. See the following example:
Int bread = recvfrom (SD, (char *) recv_buf, packet_size + sizeof (ipheader), 0, (Sockaddr *) & source, & fromlen ); If (bread = socket_error) { //... Read failed If (wsagetlasterror () = wsaemsgsize) { //... Receiving buffer is too small } Return-1; } |
The original socket receives packets according to the following rules: if the protocol type of the received packet matches the defined original socket, all received data is copied to the socket; if the socket is bound to a local address, then, only the destination address in the IP address header of the received data is equal to the local address, and the received data is copied to the socket. If the socket defines the remote address, only when the source address in the received data IP header matches the remote address, the received data is copied to the socket.
Create a message
When raw socket is used to send packets, the IP address header, TCP header, and UDP header of the packet must be assigned by the programmer in person to achieve great flexibility. The following program uses raw socket to send TCP packets and creates a header completely manually:
Int sendtcp (unsigned short desport, unsigned long desip) { Wsadata; Socket sock; Sockaddr_in addr_in; Ipheader; Tcpheader; Psdheader;
Char szsendbuf [max_len] = {0 }; Bool flag; Int rect, ntimeover;
If (wsastartup (makeword (2, 2), & wsadata )! = 0) { Printf ("wsastartup error! \ N "); Return false; }
If (sock = wsasocket (af_inet, sock_raw, ipproto_raw, null, 0, Wsa_flag_overlapped) = invalid_socket) { Printf ("socket setup error! \ N "); Return false; } Flag = true; If (setsockopt (sock, ipproto_ip, ip_hdrincl, (char *) & flag, sizeof (FLAG) = socket_error) { Printf ("setsockopt ip_hdrincl error! \ N "); Return false; }
Ntimeover= 1000; If (setsockopt (sock, sol_socket, so_sndtimeo, (char *) & ntimeover, sizeof (Ntimeover) = socket_error) { Printf ("setsockopt so_sndtimeo error! \ N "); Return false; } Addr_in.sin_family = af_inet; Addr_in.sin_port = htons (desport ); Addr_in.sin_addr.s_un.s_addr = inet_addr (desip );
// Fill in the IP Header Ipheader. h_verlen = (4 <4 | sizeof (ipheader)/sizeof (unsigned long )); // Ipheader. TOS = 0; Ipheader. total_len = htons (sizeof (ipheader) + sizeof (tcpheader )); Ipheader. ident = 1; Ipheader. frag_and_flags = 0; Ipheader. TTL = 128; Ipheader. proto = ipproto_tcp; Ipheader. checksum = 0; Ipheader. sourceip = inet_addr ("localhost "); Ipheader. destip = desip;
// Fill the TCP Header Tcpheader. th_dport = htons (desport ); Tcpheader. th_sport = htons (source_port); // source port number Tcpheader. th_seq = htonl (0x12345678 ); Tcpheader. th_ack = 0; Tcpheader. th_lenres = (sizeof (tcpheader)/4 <4 | 0 ); Tcpheader. th_flag = 2; // flag detection, 2 is SYN Tcpheader. th_win = htons (512 ); Tcpheader. th_urp = 0; Tcpheader. th_sum = 0;
Psdheader. saddr = ipheader. sourceip; Psdheader. daddr = ipheader. destip; Psdheader. mbz = 0; Psdheader. ptcl = ipproto_tcp; Psdheader. tcpl = htons (sizeof (tcpheader ));
// Calculate the checksum Memcpy (szsendbuf, & psdheader, sizeof (psdheader )); Memcpy (szsendbuf + sizeof (psdheader), & tcpheader, sizeof (tcpheader )); Tcpheader. th_sum = checksum (unsigned short *) szsendbuf, sizeof (psdheader) + sizeof (Tcpheader )); Memcpy (szsendbuf, & ipheader, sizeof (ipheader )); Memcpy (szsendbuf + sizeof (ipheader), & tcpheader, sizeof (tcpheader )); Memset (szsendbuf + sizeof (ipheader) + sizeof (tcpheader), 0, 4 ); Ipheader. checksum = checksum (unsigned short *) szsendbuf, sizeof (ipheader) + sizeof (Tcpheader ));
Memcpy (szsendbuf, & ipheader, sizeof (ipheader ));
Rect = sendto (sock, szsendbuf, sizeof (ipheader) + sizeof (tcpheader), 0, (Struct sockaddr *) & addr_in, sizeof (addr_in )); If (rect = socket_error) { Printf ("send error! : % D \ n ", wsagetlasterror ()); Return false; } Else Printf ("Send OK! \ N ");
Closesocket (sock ); Wsacleanup ();
Return rect; }
|
Int bwrote = sendto (SD, (char *) send_buf, packet_size, 0, (sockaddr *) & DEST, Sizeof (DEST )); If (bwrote = socket_error) { //... Failed to send If (wsagetlasterror () = ...) { //... } Return-1; } Else if (bwrote <packet_size) { //... Sent byte <bytes to be sent }
|