Original socket BASICS (original socket Series II)

Source: Internet
Author: User
Tags set socket htons

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
}

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.