#include "dns.h" #include "host.h" #include "interval.h" #include "packet.h" #include "print.h" #include "setting.h" #include "statistics.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool loop = true; static void signal_handler(int code) { (void) code; loop = false; } static int create_socket(struct setting const *settings) { int ret; (void)settings; int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sockfd == -1) { print_err("open socket failed, maybe try in root (:"); return -1; } ret = setsockopt(sockfd, IPPROTO_IP, IP_TTL, &settings->ttl, sizeof(settings->ttl)); if (ret != 0) { close(sockfd); print_err("Failed to setsockopt(): ttl"); return -1; } struct timeval tv = {2, 0}; ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); if (ret != 0) { close(sockfd); print_err("Failed to setsockopt(): recv timeout"); return -1; } return sockfd; } static int preload(struct setting const *settings, int sockfd, char const *packet, size_t packet_size) { for (size_t i = 0; i < settings->preload; i++) { if (sendto(sockfd, packet, packet_size, 0, (struct sockaddr *) &settings->dest.ip, sizeof(settings->dest.ip)) == -1) return 1; } return 0; } static int check_reply(struct sockaddr_in const *me, struct sockaddr_in const *sender, char *sent, char *received, size_t sent_size, size_t recv_size) { if (sent_size != recv_size) return 0; if (((struct icmphdr *)sent)->type != 0) return 0; if (check_packet_conformity(sent, received, sent_size)) return 1; return memcmp(sender, me, sizeof(struct sockaddr_in)); } int main(int ac, char **av) { (void) ac; struct statistics stats; struct setting settings; int ret = get_setting(av + 1, &settings); if (ret == -1) return 0; if (ret) goto error0; size_t packet_size = sizeof(struct icmphdr) + settings.payload_size; size_t recv_packet_size = packet_size + sizeof(struct iphdr); signal(SIGINT, signal_handler); if (dns_lookup(&settings.dest)) goto error0; int sockfd = create_socket(&settings); if (sockfd == -1) goto error0; char *packet = packet_create(settings.payload_size); if (packet == NULL) goto error1; char *buffer; buffer = malloc((recv_packet_size) * sizeof(char)); if (buffer == NULL) { print_err("error: allocation failed."); goto error2; } struct sockaddr_in sender; socklen_t len = sizeof(sender); bzero(&stats, sizeof(struct statistics)); print_header(&settings); if (preload(&settings, sockfd, packet, packet_size)) goto error3; while (loop) { struct timeval stop, start; gettimeofday(&start, NULL); if (sendto(sockfd, packet, packet_size, 0, (struct sockaddr *) &settings.dest.ip, sizeof(settings.dest.ip)) == -1) { print_err("error: send packet failed."); goto error2; } stats.packets_sent++; ssize_t ret = 0; do { ret = recvfrom(sockfd, buffer, recv_packet_size, 0, (struct sockaddr *) &sender, &len); gettimeofday(&stop, NULL); } while (ret >= 0 && check_reply(&settings.dest.ip, &sender, packet, buffer + sizeof(struct iphdr), packet_size, ret)); if (ret >= (ssize_t) (sizeof(struct icmphdr) + sizeof(struct iphdr))) { if (((struct icmphdr *) (buffer + sizeof(struct iphdr)))->type == 0) stats.packets_received++; print_recv(&settings, buffer, &start, &stop, &sender); } double interval = get_interval(&start, &stop); if (interval < 1000) usleep((1000 - interval) * 1e3); if (packet_update(packet, settings.payload_size)) goto error3; } free(packet); free(buffer); close(sockfd); print_statistics(&stats, &settings); return 0; error3: free(buffer); error2: free(packet); error1: close(sockfd); error0: return 1; }