about summary refs log tree commit diff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..444bf4f
--- /dev/null
+++ b/main.c
@@ -0,0 +1,183 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#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;
+}
\ No newline at end of file