在看Steven的TCP/IP Illustrated, V1, 改了一个非常简单的ping echo的C代码,在linux上编译通,就当学习吧。
1
#include
<
stdio.h
>
2 #include < sys / types.h >
3 #include < sys / socket.h >
4 #include < arpa / inet.h >
5 #include < netdb.h >
6 #include < netinet / in .h >
7 #include < netinet / ip_icmp.h >
8 #include < signal.h >
9 #include < errno.h >
10
11 static const int DEFDATALEN = 56 ;
12 static const int MAXIPLEN = 60 ; // max len of ip header, 15 * 4
13 static const int MAXICMPLEN = 76 ; // max len of icmp header
14
15 static void noresp( int );
16 static void ping( const char * );
17 u_short in_cksum(u_short * , int );
18 void usage( void );
19
20 int main( int argc, char * argv[])
21 ... {
22
23 if(argc != 2)
24 usage();
25 ping(*++argv);
26 }
27
28 static void noresp( int ign)
29 ... { // signal fun
30 printf("No response ");
31 exit(0);
32 }
33
34 static void ping( const char * host)
35 ... {
36 struct hostent *hp;
37 struct sockaddr_in target;
38 struct icmp *packet;
39 char outpack[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
40 int sock, c;
41
42 if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
43 ...{
44 perror("socket");
45 exit(1);
46 }
47
48 memset(&target, 0, sizeof(struct sockaddr_in));
49 target.sin_family = AF_INET;
50 if(inet_aton(host, (struct in_addr*)&target.sin_addr.s_addr)== 0)
51 ...{
52 hp = gethostbyname(host);
53 if(!hp)
54 ...{
55 fprintf(stderr, "ping: unknown host %s ", host);
56 exit(1);
57 }
58 memcpy(&target.sin_addr, hp->h_addr, 4);
59 }
60
61 memset(outpack, 0, sizeof(outpack));
62 packet = (struct icmp*)outpack;
63 packet->icmp_type = ICMP_ECHO;
64 packet->icmp_id = getpid();
65
66 // checksum
67 packet->icmp_cksum = in_cksum((u_short *)packet, sizeof(outpack));
68 c = sendto(sock, packet, sizeof(outpack), 0, (struct sockaddr*)&target, sizeof(struct sockaddr_in));
69 if(c < 0 || c != sizeof(outpack))
70 ...{
71 perror("sendto");
72 exit(1);
73 }
74
75 // set a timer
76 signal(SIGALRM, noresp);
77 alarm(5);
78 while(1)
79 ...{
80 struct sockaddr_in from;
81 size_t fromlen = sizeof(struct sockaddr_in);
82
83 if (( c = recvfrom(sock, outpack, sizeof(outpack), 0,
84 (struct sockaddr*)&from, &fromlen)) < 0)
85 ...{
86 if (errno == EINTR)
87 continue;
88 perror("recvfrom");
89 continue;
90 }
91
92 if (c >= 76)
93 ...{ // the request ip header is in the reply pack, skip
94 struct iphdr *iphdr = (struct iphdr *)outpack;
95 packet = (struct icmp *)(outpack + (iphdr->ihl<<2));
96 if (packet->icmp_type == ICMP_ECHOREPLY)
97 break;
98 }
99 }
100 printf("%s is alive ", inet_ntoa(target.sin_addr));
101 return;
102 }
103
104 void usage( void )
105 ... {
106 struct sockaddr_in whereto;
107 fprintf(stderr, "Usage: prg host ");
108 exit(1);
109 }
110
111 u_short in_cksum(u_short * addr, int len)
112 ... {
113 int sum = 0, nleft = len;
114 u_short *w = addr, ret;
115
116 while(nleft > 1)
117 ...{
118 sum += *w++;
119 nleft -= 2;
120 }
121 if(nleft == 1)
122 sum += htons(*(u_char*)w << 8);
123
124 sum = (sum >> 16) + (sum & 0xffff);
125 sum += sum >> 16;
126 ret = ~sum;
127 return ret;
128 }
2 #include < sys / types.h >
3 #include < sys / socket.h >
4 #include < arpa / inet.h >
5 #include < netdb.h >
6 #include < netinet / in .h >
7 #include < netinet / ip_icmp.h >
8 #include < signal.h >
9 #include < errno.h >
10
11 static const int DEFDATALEN = 56 ;
12 static const int MAXIPLEN = 60 ; // max len of ip header, 15 * 4
13 static const int MAXICMPLEN = 76 ; // max len of icmp header
14
15 static void noresp( int );
16 static void ping( const char * );
17 u_short in_cksum(u_short * , int );
18 void usage( void );
19
20 int main( int argc, char * argv[])
21 ... {
22
23 if(argc != 2)
24 usage();
25 ping(*++argv);
26 }
27
28 static void noresp( int ign)
29 ... { // signal fun
30 printf("No response ");
31 exit(0);
32 }
33
34 static void ping( const char * host)
35 ... {
36 struct hostent *hp;
37 struct sockaddr_in target;
38 struct icmp *packet;
39 char outpack[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
40 int sock, c;
41
42 if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
43 ...{
44 perror("socket");
45 exit(1);
46 }
47
48 memset(&target, 0, sizeof(struct sockaddr_in));
49 target.sin_family = AF_INET;
50 if(inet_aton(host, (struct in_addr*)&target.sin_addr.s_addr)== 0)
51 ...{
52 hp = gethostbyname(host);
53 if(!hp)
54 ...{
55 fprintf(stderr, "ping: unknown host %s ", host);
56 exit(1);
57 }
58 memcpy(&target.sin_addr, hp->h_addr, 4);
59 }
60
61 memset(outpack, 0, sizeof(outpack));
62 packet = (struct icmp*)outpack;
63 packet->icmp_type = ICMP_ECHO;
64 packet->icmp_id = getpid();
65
66 // checksum
67 packet->icmp_cksum = in_cksum((u_short *)packet, sizeof(outpack));
68 c = sendto(sock, packet, sizeof(outpack), 0, (struct sockaddr*)&target, sizeof(struct sockaddr_in));
69 if(c < 0 || c != sizeof(outpack))
70 ...{
71 perror("sendto");
72 exit(1);
73 }
74
75 // set a timer
76 signal(SIGALRM, noresp);
77 alarm(5);
78 while(1)
79 ...{
80 struct sockaddr_in from;
81 size_t fromlen = sizeof(struct sockaddr_in);
82
83 if (( c = recvfrom(sock, outpack, sizeof(outpack), 0,
84 (struct sockaddr*)&from, &fromlen)) < 0)
85 ...{
86 if (errno == EINTR)
87 continue;
88 perror("recvfrom");
89 continue;
90 }
91
92 if (c >= 76)
93 ...{ // the request ip header is in the reply pack, skip
94 struct iphdr *iphdr = (struct iphdr *)outpack;
95 packet = (struct icmp *)(outpack + (iphdr->ihl<<2));
96 if (packet->icmp_type == ICMP_ECHOREPLY)
97 break;
98 }
99 }
100 printf("%s is alive ", inet_ntoa(target.sin_addr));
101 return;
102 }
103
104 void usage( void )
105 ... {
106 struct sockaddr_in whereto;
107 fprintf(stderr, "Usage: prg host ");
108 exit(1);
109 }
110
111 u_short in_cksum(u_short * addr, int len)
112 ... {
113 int sum = 0, nleft = len;
114 u_short *w = addr, ret;
115
116 while(nleft > 1)
117 ...{
118 sum += *w++;
119 nleft -= 2;
120 }
121 if(nleft == 1)
122 sum += htons(*(u_char*)w << 8);
123
124 sum = (sum >> 16) + (sum & 0xffff);
125 sum += sum >> 16;
126 ret = ~sum;
127 return ret;
128 }