1#include <unistd.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <sys/socket.h>
5#include <netinet/in.h>
6#include <fcntl.h>
7#include <linux/ip.h>
8#include <linux/icmp.h>
9
10unsigned short in_cksum(unsigned short *, int);
11
12int icmp_check(char *src_addr, char *dst_addr)
13{
14	struct iphdr* ip;
15	struct iphdr* ip_reply;
16	struct icmphdr* icmp;
17	struct sockaddr_in connection;
18	char* packet;
19	int payload_size = 5;
20	char* buffer;
21	int sockfd;
22	int optval;
23	int addrlen;
24	int siz;
25	int ping_result;
26
27	printf("Source address: %s\n", src_addr);
28	printf("Destination address: %s\n", dst_addr);
29
30	/* allocate all necessary memory */
31	int packet_size = sizeof(struct iphdr) + sizeof(struct icmphdr) + payload_size ;
32	packet = malloc(packet_size);
33	if(packet == NULL){
34		perror("malloc packet");
35		return 0;
36	}
37	buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
38	if(buffer == NULL){
39		perror("malloc buffer");
40		return 0;
41	}
42
43	memset(packet, 0, packet_size);
44	ip = (struct iphdr*) packet;
45	icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));
46
47	/* here the ip packet is set up */
48	ip->ihl = 5;
49	ip->version = 4;
50	ip->tos = 0;
51	ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);
52	ip->id = htons(0);
53	ip->frag_off = 0;
54	ip->ttl = 1;
55	ip->protocol = IPPROTO_ICMP;
56	ip->saddr = inet_addr(src_addr);
57	ip->daddr = inet_addr(dst_addr);
58	ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));
59
60	if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1){
61		free(packet);
62		free(buffer);
63		perror("socket");
64		exit(EXIT_FAILURE);
65		return 0;
66	}
67
68	connection.sin_family = AF_INET;
69	connection.sin_addr.s_addr = inet_addr(dst_addr);
70	memset(&connection.sin_zero, 0, sizeof (connection.sin_zero));
71
72	/*
73	 *  IP_HDRINCL must be set on the socket so that
74	 *  the kernel does not attempt to automatically add
75	 *  a default ip header to the packet
76	 */
77	optval = 1;
78	if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) == -1)
79	{
80        perror("setsockopt");
81        return (0);
82	}
83
84	if ( fcntl(sockfd, F_SETFL, O_NONBLOCK) != 0 )
85	{
86		perror("Request nonblocking I/O");
87		return 1;
88	}
89
90	/*
91	 * here the icmp packet is created
92	 * also the ip checksum is generated
93	 */
94	icmp->type = ICMP_ECHO;
95	icmp->code = 0;
96	icmp->un.echo.id = random();
97	icmp->un.echo.sequence = random();
98	icmp->checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
99
100	/*
101	 *  now the packet is sent
102	 */
103
104	// sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));
105	sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(connection));
106	printf("Sent %d byte packet to %s\n", sizeof(packet), dst_addr);
107
108	int rc;
109	struct timeval timeout = {3, 0}; //wait max 3 seconds for a reply
110	fd_set read_set;
111
112	memset(&read_set, 0, sizeof read_set);
113	FD_ZERO(&read_set);
114	FD_SET(sockfd, &read_set);
115
116	rc = select(sockfd +1, &read_set, NULL, NULL, &timeout);
117	if(rc == 0){
118		puts("Got no reply\n");
119		ping_result = 0;
120		return 0;
121	}else if(rc < 0){
122		perror("Select");
123		ping_result = 0;
124	}
125
126	/*
127	 *  now we listen for responses
128	 */
129	addrlen = sizeof(connection);
130	if (( siz = recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0,
131				(struct sockaddr *)&connection, (socklen_t *)&addrlen)) == -1){
132		perror("recv");
133		ping_result = 0;
134	}else{
135		printf("Received %d byte reply from %s:\n", siz , dst_addr);
136		// ip_reply = (struct iphdr*) buffer;
137		// printf("ID: %d\n", ntohs(ip_reply->id));
138		// printf("TTL: %d\n", ip_reply->ttl);
139		ping_result = 1;
140	}
141
142	free(packet);
143	free(buffer);
144	FD_ZERO(&read_set);
145	close(sockfd);
146	FD_CLR(sockfd, &read_set);
147
148	if(ping_result == 0){
149		return 0;
150	}else{
151		return 1;
152	}
153}
154
155/*
156 * in_cksum --
157 * Checksum routine for Internet Protocol
158 * family headers (C Version)
159 */
160unsigned short in_cksum(unsigned short *addr, int len)
161{
162	register int sum = 0;
163	u_short answer = 0;
164	register u_short *w = addr;
165	register int nleft = len;
166	/*
167	* Our algorithm is simple, using a 32 bit accumulator (sum), we add
168	* sequential 16 bit words to it, and at the end, fold back all the
169	* carry bits from the top 16 bits into the lower 16 bits.
170	*/
171	while (nleft > 1)
172	{
173	  sum += *w++;
174	  nleft -= 2;
175	}
176	/* mop up an odd byte, if necessary */
177	if (nleft == 1)
178	{
179	  *(u_char *) (&answer) = *(u_char *) w;
180	  sum += answer;
181	}
182	/* add back carry outs from top 16 bits to low 16 bits */
183	sum = (sum >> 16) + (sum & 0xffff);       /* add hi 16 to low 16 */
184	sum += (sum >> 16);               /* add carry */
185	answer = ~sum;              /* truncate to 16 bits */
186	return (answer);
187}
188
189