diff --git a/src/dns.c b/src/dns.c index cd1958d..f093cf7 100644 --- a/src/dns.c +++ b/src/dns.c @@ -1,5 +1,6 @@ +#include "host.h" #include "print.h" #include #include @@ -8,7 +9,7 @@ #include #include -int dns_lookup(const char *hostname, char *ipstr) +int dns_lookup(struct hostenv *host) { struct addrinfo filter; @@ -16,48 +17,34 @@ int dns_lookup(const char *hostname, char *ipstr) filter.ai_family = AF_INET; struct addrinfo *responses; - if (getaddrinfo(hostname, NULL, &filter, &responses) != 0) + if (getaddrinfo(host->hostname, NULL, &filter, &responses) != 0) { print_err("dns lookup failed"); return 1; } struct addrinfo *first = responses; - struct in_addr *addr = &(((struct sockaddr_in *) responses->ai_addr)->sin_addr); + struct in_addr *addr = &(((struct sockaddr_in *) first->ai_addr)->sin_addr); - inet_ntop(first->ai_family, addr, ipstr, sizeof(char) * INET_ADDRSTRLEN); + inet_ntop(first->ai_family, addr, host->ipstr, sizeof(char) * INET_ADDRSTRLEN); freeaddrinfo(responses); return 0; } -char *dns_reverse_lookup(const char *ipstr) +int dns_reverse_lookup(struct hostenv *host) { - struct sockaddr_in sa; - char host[NI_MAXHOST]; - - bzero(&sa, sizeof(sa)); - sa.sin_family = AF_INET; - - printf("%s\n", ipstr); - - if (inet_pton(AF_INET, ipstr, &sa.sin_addr) <= 0) - { - print_err("inet_pton failed"); - return NULL; - } - int ret = getnameinfo( - (struct sockaddr *)&sa, sizeof(sa), - host, sizeof(host), + (struct sockaddr *)&host->ip, sizeof(host->ip), + host->reverse_dns, sizeof(host->reverse_dns), NULL, 0, NI_NAMEREQD); if (ret != 0) { print_err("reverse dns failed."); - return NULL; + return 1; } - return strdup(host); + return 0; } \ No newline at end of file diff --git a/src/dns.h b/src/dns.h index e2bbfb5..3cc0395 100644 --- a/src/dns.h +++ b/src/dns.h @@ -1,4 +1,6 @@ #pragma once -int dns_lookup(const char *hostname, char *ipstr); -char *dns_reverse_lookup(const char *ipstr); \ No newline at end of file +#include "host.h" + +int dns_lookup(struct hostenv *host); +int dns_reverse_lookup(struct hostenv *host); \ No newline at end of file diff --git a/src/host.h b/src/host.h index 0190b75..78dddac 100644 --- a/src/host.h +++ b/src/host.h @@ -1,9 +1,11 @@ #pragma once +#include #include -struct host { - char ip[INET_ADDRSTRLEN]; +struct hostenv { + char ipstr[INET_ADDRSTRLEN]; + struct sockaddr_in ip; char *hostname; - char *reverse_dns; + char reverse_dns[NI_MAXHOST]; }; \ No newline at end of file diff --git a/src/main.c b/src/main.c index 8b9374a..239c3b6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,9 @@ #include "dns.h" #include "host.h" #include "packet.h" +#include "parsing.h" #include "print.h" +#include "setting.h" #include #include #include @@ -32,30 +34,81 @@ void signal_handler(int code) loop = false; } +static int parsing_number(const char *str, size_t min, size_t max, size_t *out) +{ + size_t number = 0; + const char *start = str; + + while (*start != '\0') + { + size_t tmp = number * 10 + *start - '0'; + if (tmp < number) + goto value_error; + number = tmp; + start++; + } + + if (min > number || number > max) + goto value_error; + + *out = number; + + return 0; + +value_error: + print_err("invalid argument: '%s': out of range: %zu <= value <= %zu", str, min, max); + return 1; +} + +static int get_setting(char * const *av, struct setting *setting) +{ + struct param parameters[] = { + {NULL, "?", OPTION, false}, + {NULL, "v", OPTION, false}, + {NULL, "f", OPTION, false}, + {NULL, "n", OPTION, false}, + {NULL, "W",ARGUMENT, "0"}, + {"ttl", NULL, ARGUMENT, "116"}, + {NULL, NULL, 0, NULL}, + }; + char *hostname = parsing(av, parameters); + if (hostname == NULL) + return 1; + setting->dest.hostname = hostname; + + setting->help = parameters[0].value; + setting->verbose = parameters[1].value; + setting->flood = parameters[2].value; + setting->numeric_only = parameters[3].value; + if (parsing_number(parameters[4].value, 0, 2147483647, &setting->timeout)) + return 1; + if (parsing_number(parameters[5].value, 0, 255, &setting->ttl)) + return 1; + return 0; +} + int main(int ac, char **av) { (void) ac; - (void) av; + struct setting settings; - struct host host; - - host.hostname = "localhost"; + get_setting(av + 1, &settings); size_t payload_size = 20; size_t packet_size = sizeof(struct icmphdr) + payload_size; signal(SIGINT, signal_handler); - if (dns_lookup(host.hostname, host.ip)) + if (dns_lookup(&settings.dest)) return 5; - host.reverse_dns = dns_reverse_lookup(host.ip); + + settings.dest.ip.sin_family = AF_INET; + settings.dest.ip.sin_port = htons(0); + inet_pton(AF_INET, settings.dest.ipstr, &settings.dest.ip.sin_addr); - struct sockaddr_in dest; - dest.sin_family = AF_INET; - dest.sin_port = htons(0); - inet_pton(AF_INET, host.ip, &dest.sin_addr); + dns_reverse_lookup(&settings.dest); int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); @@ -89,7 +142,7 @@ int main(int ac, char **av) struct timeval stop, start; gettimeofday(&start, NULL); - if (sendto(sockfd, packet, packet_size, 0, (struct sockaddr *) &dest, sizeof(dest)) == -1) + if (sendto(sockfd, packet, packet_size, 0, (struct sockaddr *) &settings.dest.ip, sizeof(settings.dest.ip)) == -1) { print_err("error: send packet failed."); free(packet); @@ -113,7 +166,7 @@ int main(int ac, char **av) double time_interval = ((stop.tv_sec - start.tv_sec) * 1000 + ((double)stop.tv_usec - (double) start.tv_usec) / 1000); struct icmphdr *hdr = (struct icmphdr *) packet; - printf("%zu bytes from %s (%s): icmp_seq=%d, ttl=%u, time=%fms\n", payload_size + sizeof(struct icmphdr) + sizeof(struct iphdr) + sizeof(struct ether_header), host.reverse_dns, host.ip, htons(hdr->un.echo.sequence), 116, time_interval); + printf("%zu bytes from %s (%s): icmp_seq=%d, ttl=%u, time=%fms\n", payload_size + sizeof(struct icmphdr) + sizeof(struct iphdr) + sizeof(struct ether_header), settings.dest.reverse_dns, settings.dest.ipstr, htons(hdr->un.echo.sequence), 116, time_interval); sleep(1); diff --git a/src/parsing.c b/src/parsing.c index 3016686..653e8f0 100644 --- a/src/parsing.c +++ b/src/parsing.c @@ -6,31 +6,22 @@ #include #include -static struct param parameters[] = { - {NULL, "?", OPTION, false}, - {NULL, "v", OPTION, false}, - {NULL, "f", OPTION, false}, - {NULL, "n", OPTION, false}, - {NULL, "w", ARGUMENT, NULL}, - {NULL, "W",ARGUMENT, NULL}, - {"ttl", NULL, ARGUMENT, "116"}, - {NULL, NULL, NULL, NULL}, -}; + static struct param *get_parameter(struct param parameters[], const char *str) { - size_t count = str[0] == '-' + str[1] == '-'; + size_t count = (str[0] == '-') + (str[1] == '-'); for (size_t i = 0; parameters[i].name || parameters[i].alias; i++) { - if (count == 2 && !strcmp(parameters[i].name, str + count)) + if (count == 2 && parameters[i].name != NULL && !strcmp(parameters[i].name, str + count)) return parameters + i; - else if (count == 1 && !strcmp(parameters[i].alias, str + count)) + else if (count == 1 && parameters[i].alias != NULL && !strcmp(parameters[i].alias, str + count)) return parameters + i; } return NULL; } -int parsing(const char * const *av) +char *parsing(char * const *av, struct param parameters[]) { char *host; for (size_t i = 0; av[i]; i++) @@ -55,5 +46,5 @@ int parsing(const char * const *av) host = (char*) av[i]; } } - return 0; + return host; } \ No newline at end of file diff --git a/src/parsing.h b/src/parsing.h index f3d86ef..1d7971f 100644 --- a/src/parsing.h +++ b/src/parsing.h @@ -11,3 +11,5 @@ struct param { e_type type; void *value; }; + +char *parsing(char * const *av, struct param parameters[]); \ No newline at end of file diff --git a/src/setting.h b/src/setting.h new file mode 100644 index 0000000..9f04f78 --- /dev/null +++ b/src/setting.h @@ -0,0 +1,17 @@ +#pragma once + +#include "host.h" + +#include +#include + +struct setting +{ + bool help; + bool verbose; + bool flood; + bool numeric_only; + size_t timeout; + size_t ttl; + struct hostenv dest; +};