#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PACKET_SIZE 64 #define ICMP_HEADER_LEN 8 #define VERSION "0.1.3" static volatile sig_atomic_t keep_running = 1; static int sockfd; static uint16_t seq = 0; static int packets_sent = 0; static int packets_received = 0; static int packets_mismatched = 0; static int packets_ttl_attack = 0; static double min_time = -1; static double max_time = -1; static double total_time = 0; static uint16_t identifier; void cleanup(void) { if (sockfd >= 0) { close(sockfd); } } void signal_handler(int signo __attribute__((unused))) { keep_running = 0; } unsigned short checksum(unsigned short *addr, int len) { int nleft = len; int sum = 0; unsigned short *w = addr; unsigned short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(unsigned char *)(&answer) = *(unsigned char *)w; sum += answer; } sum = (sum >> 16) + (sum & 0xFFFF); sum += (sum >> 16); answer = ~sum; return answer; } int main(int argc, char *argv[]) { if (argc == 2 && strcmp(argv[1], "--version") == 0) { printf("fjorker version %s\n", VERSION); exit(0); } if (argc != 2) { fprintf(stderr, "Usage: %s host\n %s --version\n", argv[0], argv[0]); exit(1); } identifier = arc4random() & 0xFFFF; struct hostent *host; struct sockaddr_in addr; struct icmp *icmp; char packet[PACKET_SIZE]; char recv_packet[PACKET_SIZE]; struct timeval tv_out; tv_out.tv_sec = 1; tv_out.tv_usec = 0; if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { if (errno == EPERM) { fprintf(stderr, "Permission denied. Run as root.\n"); } else { perror("socket"); } exit(1); } if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv_out, sizeof(tv_out)) < 0) { perror("setsockopt"); cleanup(); exit(1); } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if (inet_aton(argv[1], &addr.sin_addr) == 0) { if ((host = gethostbyname(argv[1])) == NULL) { fprintf(stderr, "Unknown host %s\n", argv[1]); cleanup(); exit(1); } addr.sin_addr = *(struct in_addr *)host->h_addr; } printf("PING %s (%s): %d data bytes\n", argv[1], inet_ntoa(addr.sin_addr), PACKET_SIZE - ICMP_HEADER_LEN); signal(SIGINT, signal_handler); while (keep_running) { memset(packet, 0, sizeof(packet)); icmp = (struct icmp *)packet; icmp->icmp_type = ICMP_ECHO; icmp->icmp_code = 0; icmp->icmp_id = identifier; icmp->icmp_seq = seq++; packets_sent++; icmp->icmp_cksum = 0; icmp->icmp_cksum = checksum((unsigned short *)icmp, PACKET_SIZE); struct timeval send_time; gettimeofday(&send_time, NULL); if (sendto(sockfd, packet, PACKET_SIZE, 0, (struct sockaddr *)&addr, sizeof(addr)) <= 0) { perror("sendto"); continue; } struct sockaddr_in from; socklen_t fromlen = sizeof(from); int bytes; if ((bytes = recvfrom(sockfd, recv_packet, sizeof(recv_packet), 0, (struct sockaddr *)&from, &fromlen)) > 0) { struct timeval recv_time; gettimeofday(&recv_time, NULL); struct ip *ip = (struct ip *)recv_packet; int ip_header_len = ip->ip_hl << 2; icmp = (struct icmp *)(recv_packet + ip_header_len); if (icmp->icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == identifier) { if (icmp->icmp_seq != seq - 1) { packets_mismatched++; printf("[!] Server returned wrong sequence: got %d, expected %d\n", icmp->icmp_seq, seq - 1); } packets_received++; double elapsed = ((recv_time.tv_sec - send_time.tv_sec) * 1000.0) + ((recv_time.tv_usec - send_time.tv_usec) / 1000.0); if (min_time < 0 || elapsed < min_time) min_time = elapsed; if (max_time < 0 || elapsed > max_time) max_time = elapsed; total_time += elapsed; int ttl = ip->ip_ttl; const char* ttl_warning = ""; if (icmp->icmp_type == ICMP_ECHOREPLY && (ttl < 30 || ttl > 255)) { ttl_warning = " [!] Suspicious TTL value"; packets_ttl_attack++; } printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%.3f ms%s\n", bytes - ip_header_len, inet_ntoa(from.sin_addr), icmp->icmp_seq, ttl, elapsed, ttl_warning); } } sleep(1); } printf("\n--- %s ping statistics ---\n", argv[1]); printf("%d packets transmitted, %d packets received, %.1f%% packet loss\n", packets_sent, packets_received, ((packets_sent - packets_received) * 100.0) / packets_sent); if (packets_mismatched > 0) { printf("%d packets had incorrect sequence numbers\n", packets_mismatched); } if (packets_ttl_attack > 0) { printf("%d packets had suspicious TTL values\n", packets_ttl_attack); } if (packets_received > 0) { double avg = total_time / packets_received; printf("round-trip min/avg/max = %.3f/%.3f/%.3f ms\n", min_time, avg, max_time); } cleanup(); return 0; }