Linux original socket (2)-icmp request and receipt, linux-icmp

Source: Internet
Author: User

Linux original socket (2)-icmp request and receipt, linux-icmp

I. Overview

The previous arp request used the original socket of the link layer. Icmp is encapsulated in ip datagram, so icmp requests can directly use the original socket at the network layer, that is, the first parameter of socket () is PF_INET. As follows:

1 sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);

Different types of icmp packets have different formats. We use the icmp echo request and the echo Response Message format (that is, the packet type used by the ping program) as an example:

If the type is 8, the request is returned. If the value is 0, the response is returned. The Checksum must be calculated by yourself. The identifier is generally the process ID of the program. Number customization, generally starting from 1. The timestamp can be placed in the option data to calculate the time consumed by ping!

The icmp packet structure is defined in netinet/ip_icmp.h.

 1 struct icmp 2 { 3   u_int8_t  icmp_type;    /* type of message, see below */ 4   u_int8_t  icmp_code;    /* type sub code */ 5   u_int16_t icmp_cksum;    /* ones complement checksum of struct */ 6   union 7   { 8     u_char ih_pptr;        /* ICMP_PARAMPROB */ 9     struct in_addr ih_gwaddr;    /* gateway address */10     struct ih_idseq        /* echo datagram */11     {12       u_int16_t icd_id;13       u_int16_t icd_seq;14     } ih_idseq;15     u_int32_t ih_void;16 17     /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */18     struct ih_pmtu19     {20       u_int16_t ipm_void;21       u_int16_t ipm_nextmtu;22     } ih_pmtu;23 24     struct ih_rtradv25     {26       u_int8_t irt_num_addrs;27       u_int8_t irt_wpa;28       u_int16_t irt_lifetime;29     } ih_rtradv;30   } icmp_hun;31 #define    icmp_pptr    icmp_hun.ih_pptr32 #define    icmp_gwaddr    icmp_hun.ih_gwaddr33 #define    icmp_id        icmp_hun.ih_idseq.icd_id34 #define    icmp_seq    icmp_hun.ih_idseq.icd_seq35 #define    icmp_void    icmp_hun.ih_void36 #define    icmp_pmvoid    icmp_hun.ih_pmtu.ipm_void37 #define    icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu38 #define    icmp_num_addrs    icmp_hun.ih_rtradv.irt_num_addrs39 #define    icmp_wpa    icmp_hun.ih_rtradv.irt_wpa40 #define    icmp_lifetime    icmp_hun.ih_rtradv.irt_lifetime41   union42   {43     struct44     {45       u_int32_t its_otime;46       u_int32_t its_rtime;47       u_int32_t its_ttime;48     } id_ts;49     struct50     {51       struct ip idi_ip;52       /* options and then 64 bits of data */53     } id_ip;54     struct icmp_ra_addr id_radv;55     u_int32_t   id_mask;56     u_int8_t    id_data[1];57   } icmp_dun;58 #define    icmp_otime    icmp_dun.id_ts.its_otime59 #define    icmp_rtime    icmp_dun.id_ts.its_rtime60 #define    icmp_ttime    icmp_dun.id_ts.its_ttime61 #define    icmp_ip        icmp_dun.id_ip.idi_ip62 #define    icmp_radv    icmp_dun.id_radv63 #define    icmp_mask    icmp_dun.id_mask64 #define    icmp_data    icmp_dun.id_data65 };

Ii. icmp request code

1/** 2 * @ file icmp_request.c 3 */4 5 # include <stdio. h> 6 # include <stdlib. h> 7 # include <string. h> 8 # include <unistd. h> 9 # include <sys/socket. h> 10 # include <arpa/inet. h> 11 # include <netinet/in. h> 12 # include <netinet/ip_icmp.h> 13 # include <sys/time. h> 14 15/* icmp packet length */16 # define ICMP_PACKET_LEN sizeof (struct icmp) 17 18 void err_exit (const char * err_msg) 19 {20 perror (err_msg); 21 exi T (1); 22} 23 24/* checksum */25 unsigned short check_sum (unsigned short * addr, int len) 26 {27 int nleft = len; 28 int sum = 0; 29 unsigned short * w = addr; 30 unsigned short answer = 0; 31 32 while (nleft> 1) 33 {34 sum + = * w ++; 35 nleft-= 2; 36} 37 if (nleft = 1) 38 {39 * (unsigned char *) (& answer) = * (unsigned char *) w; 40 sum + = answer; 41} 42 43 sum = (sum> 16) + (sum & 0 xffff); 44 sum + = (Sum> 16); 45 answer = ~ Sum; 46 47 return answer; 48} 49 50/* fill in icmp packets */51 struct icmp * fill_icmp_packet (int icmp_type, int icmp_sequ) 52 {53 struct icmp * icmp_packet; 54 55 icmp_packet = (struct icmp *) malloc (bytes); 56 icmp_packet-> icmp_type = icmp_type; 57 icmp_packet-> icmp_code = 0; 58 icmp_packet-> icmp_cksum = 0; 59 icmp_packet-> icmp_id = htons (getpid (); 60 icmp_packet-> icmp_seq = icmp_sequ; 61/* when sending */62 gettimeofday (struct timeval *) icmp_packet-> icmp_data, NULL); 63/* checksum */64 icmp_packet-> icmp_cksum = check_sum (unsigned short *) icmp_packet, ICMP_PACKET_LEN); 65 66 return icmp_packet; 67} 68 69/* Send icmp request */70 void icmp_request (const char * dst_ip, int icmp_type, int icmp_sequ) 71 {72 struct sockaddr_in dst_addr; 73 struct icmp * icmp_packet; 74 int sockfd, ret_len; 75 char buf [ICMP _ PACKET_LEN]; 76 77/* request address */78 bzero (& dst_addr, sizeof (struct sockaddr_in); 79 rows = AF_INET; 80 rows = inet_addr (dst_ip ); 81 82 if (sockfd = socket (PF_INET, SOCK_RAW, IPPROTO_ICMP) =-1) 83 err_exit ("sockfd ()"); 84 85/* icmp packet */86 icmp_packet = fill_icmp_packet (icmp_type, icmp_sequ); 87 memcpy (buf, icmp_packet, ICMP_PACKET_LEN); 88 89/* Send request */90 re T_len = sendto (sockfd, buf, ICMP_PACKET_LEN, 0, (struct sockaddr *) & dst_addr, sizeof (struct sockaddr_in); 91 if (ret_len> 0) 92 printf ("sendto () OK !!! \ N "); 93 94 close (sockfd); 95} 96 97 int main (int argc, const char * argv []) 98 {99 if (argc! = 2) 100 {101 printf ("usage: % s dst_ip \ n", argv [0]); 102 exit (1 ); 103} 104 105/* Send icmp request */106 icmp_request (argv [1], 8, 1); 107 108 109 return 0}

Process: The target IP address of the icmp request received by the command line. The value of icmp is 8 and the serial number is 1. Then, create the network address structure through the target IP address, then create the original ICMP socket, fill in the icmp packet, and fill in the sending time to the icmp data structure.

Iii. icmp receiving code

1/** 2 * @ file icmp_recv.c 3 */4 5 # include <stdio. h> 6 # include <stdlib. h> 7 # include <string. h> 8 # include <unistd. h> 9 # include <sys/time. h> 10 # include <sys/socket. h> 11 # include <arpa/inet. h> 12 # include <netinet/in. h> 13 # include <netinet/ip. h> 14 # include <netinet/ip_icmp.h> 15 16/* IP header length */17 # define IP_HEADER_LEN sizeof (struct ip) 18/* icmp packet length */19 # define ICMP_PACKET_LEN sizeof (struct icmp) 20/* IP + ICMP length */21 # define IP_ICMP_PACKET_LEN IP_HEADER_LEN + ICMP_PACKET_LEN22 23 void err_exit (const char * err_msg) 24 {25 perror (err_msg); 26 exit (1 ); 27} 28 29/* calculating the millisecond difference between the sending time and the receiving time */30 float time_interval (struct timeval * recv_time, struct timeval * send_time) 31 {32 float msec = 0; 33 34/* if the receipt time is less subtle than the sending time */35 if (recv_time-> TV _usec <send_time-> TV _usec) 36 {37 recv_time-> TV _sec-= 1; 38 recv_time-> TV _usec + = 1000000; 39} 40 msec = (recv_time-> TV _sec-send_time-> TV _sec) * 1000.0 + (recv_time-> TV _usec-send_time-> TV _usec) /1000.0; 41 42 return msec; 43} 44 45 int main (void) 46 {47 struct ip * ip_header; 48 struct icmp * icmp_packet; 49 char buf [IP_ICMP_PACKET_LEN]; 50 struct timeval * recv_timeval, * send_timeval; 51 int sockfd, ret_len; 52 53 if (sockfd = socket (PF_INET, SOCK_RAW, IPPROTO_ICMP) =-1) 54 err_exit ("sockfd ()"); 55 56 recv_timeval = malloc (sizeof (struct timeval); 57 while (1) 58 {59 ret_len = recv (sockfd, buf, IP_ICMP_PACKET_LEN, 0); 60 if (ret_len> 0) 61 {62/* Receipt time */63 gettimeofday (recv_timeval, NULL ); 64/* retrieve ip header */65/* retrieve icmp packet */66 ip_header = (struct ip *) buf; 67 icmp_packet = (struct icmp *) (buf + IP_HEADER_LEN ); 68/* retrieve the sending time */69 send_timeval = (struct timeval *) icmp_packet-> icmp_data; 70 printf ("===================================\ n "); 71 printf ("from ip: % s \ n", inet_ntoa (ip_header-> ip_src); 72 printf ("icmp_type: % d \ n", icmp_packet-> icmp_type ); 73 printf ("icmp_code: % d \ n", icmp_packet-> icmp_code); 74 printf ("time interval: %. 3fms \ n ", time_interval (recv_timeval, send_timeval); 75} 76} 77 78 free (recv_timeval); 79 close (sockfd); 80 return 0; 81}

Process: Create an ICMP-type original socket and receive it directly. First obtain the receiving time, and then extract the ip header, icmp packet, and then the icmp request time. Obtain the source ip address from the ip header and the type and code number of the message from the icmp message. The difference in milliseconds is calculated based on the sending time and receipt time!

Iv. Experiment

1. Open wireshark and observe it together. Run icmp_recv as root and then icmp_request

The icmp type is 0 and the code is 0. The response time is similar to that of our program.

2. Now we request an inaccessible IP address.

When the host fails, the returned icmp message type is 3 and the code is 1. Because the message structure is different, the outgoing time is not normal, so the time interval calculated here is not normal. The result in wireshark is that the local machine automatically broadcasts an arp request, but no machine answers the local machine.

Some icmp types:

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.