diff options
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 183 |
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 |