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