diff --git a/include/parsing.h b/include/parsing.h index 95224d8..d1069d8 100644 --- a/include/parsing.h +++ b/include/parsing.h @@ -12,7 +12,7 @@ typedef enum { FL_IP, FL_FILE, FL_SPEEDUP, - FL_SCAN, + FL_TYPE, FL_MAXRETRIES, FL_TTL, // short options @@ -26,8 +26,7 @@ struct option_lst { }; struct option_lst *parse_options(int ac, char *const *av); -bool option_isset(const struct option_lst *options, e_flag flag); char *get_option_arg(const struct option_lst *options, e_flag flag); -int parse_ports(const char *arg, uint16_t *start, uint16_t *end); e_scantype parse_type(const char *arg); void free_options(struct option_lst *options); +int parsing(struct scan *general, const struct option_lst *options); \ No newline at end of file diff --git a/include/print.h b/include/print.h index 125f8fb..72e30b1 100644 --- a/include/print.h +++ b/include/print.h @@ -3,6 +3,5 @@ #include "parsing.h" #include "response.h" -void print_host_results(const char *ip_addr, const struct response *responses, - const struct option_lst *options, double scan_time); +void print_host_results(const struct scan *general, double scan_time); void print_usage(void); diff --git a/include/response.h b/include/response.h index 938c671..46e8785 100644 --- a/include/response.h +++ b/include/response.h @@ -22,7 +22,6 @@ typedef enum { }; struct response { - uint16_t port; e_state states[SCAN_ALL]; char *service; }; diff --git a/include/scan.h b/include/scan.h index 46d7735..98ff0b7 100644 --- a/include/scan.h +++ b/include/scan.h @@ -19,14 +19,15 @@ typedef enum { }; struct scan { - const struct host *host; - const char *dest_addr; + struct host host; + char *dest_addr; uint16_t port_start; - uint16_t port; + uint16_t port_end; e_scantype type; uint8_t ttl; uint8_t max_retries; - struct response *response; + struct response *responses; + uint8_t nb_threads; }; int scan(struct scan *data); diff --git a/include/thread.h b/include/thread.h index cbab99b..cbd7aa3 100644 --- a/include/thread.h +++ b/include/thread.h @@ -7,17 +7,4 @@ #include "response.h" #include "scan.h" -struct thread { - uint16_t port_start; - uint16_t port_end; - char *dest_addr; - e_scantype type; - uint8_t max_retries; - uint8_t ttl; - struct host host; - struct response *responses; -}; - -void *routine(void *p_data); -int create_threads(const struct option_lst *options, char *ip_addr, - struct response *responses); +int create_threads(struct scan *general); diff --git a/src/main.c b/src/main.c index 6d8ed92..550ffe3 100644 --- a/src/main.c +++ b/src/main.c @@ -11,23 +11,19 @@ #include "print.h" #include "scan.h" #include "thread.h" +#include "interface.h" -static int scan_host(char *host, const struct option_lst *options) +static int scan_host(struct scan *general) { - char ip_addr[INET_ADDRSTRLEN]; struct sockaddr_in addr_con; - host[strcspn(host, "\n")] = '\0'; - if (dns_lookup(ip_addr, host, &addr_con)) { - dprintf(2, - "ft_nmap: failed to retrieve ip address from " - "'%s'\n", - host); - return 1; + if (dns_lookup(general->dest_addr, general->dest_addr, &addr_con)) { + return -1; } struct response responses[1024] = {0}; - if (create_threads(options, ip_addr, responses) < 0) - return 1; - print_host_results(ip_addr, responses, options, 10); + general->responses = responses; + if (create_threads(general) < 0) + return -1; + print_host_results(general, 10); return 0; } @@ -44,9 +40,20 @@ int main(int ac, char **av) if (options == NULL) return 1; - char *host = get_option_arg(options, FL_IP); - if (host) { - int rv = scan_host(host, options); + struct scan general; + if (parsing(&general, options)) + { + free_options(options); + return 1; + } + + if (get_interface_name(&general.host) < 0) + return -1; + + char *dest_addr = get_option_arg(options, FL_IP); + if (dest_addr) { + general.dest_addr = dest_addr; + int rv = scan_host(&general); free_options(options); return rv; } @@ -64,7 +71,9 @@ int main(int ac, char **av) } char line[256]; while (fgets(line, sizeof(line), hosts_file)) { - if (scan_host(line, options) < 0) { + line[strcspn(line, "\n")] = '\0'; + general.dest_addr = line; + if (scan_host(&general) < 0) { fclose(hosts_file); goto error; } diff --git a/src/packet.c b/src/packet.c index 67827af..3b11c92 100644 --- a/src/packet.c +++ b/src/packet.c @@ -13,7 +13,7 @@ void create_udp_packet(struct udphdr *udphdr, const struct scan *data) { udphdr->source = htons(1234); - udphdr->dest = htons(data->port); + udphdr->dest = htons(data->port_start); udphdr->len = sizeof(struct udphdr); udphdr->check = checksum(udphdr, sizeof(struct udphdr)); } @@ -21,7 +21,7 @@ void create_udp_packet(struct udphdr *udphdr, const struct scan *data) int create_tcp_packet(struct tcphdr *tcphdr, const struct scan *data) { tcphdr->source = htons(1234); - tcphdr->dest = htons(data->port); + tcphdr->dest = htons(data->port_start); tcphdr->doff = sizeof(struct tcphdr) / sizeof(int); tcphdr->fin = data->type == SCAN_XMAS || data->type == SCAN_FIN; tcphdr->syn = data->type == SCAN_SYN; @@ -32,7 +32,7 @@ int create_tcp_packet(struct tcphdr *tcphdr, const struct scan *data) tcphdr->urg_ptr = 0; struct pshdr pshdr; - pshdr.src_addr = inet_addr(data->host->ip); + pshdr.src_addr = inet_addr(data->host.ip); pshdr.dst_addr = inet_addr(data->dest_addr); pshdr.placeholder = 0; pshdr.protocol = IPPROTO_TCP; @@ -69,7 +69,7 @@ static void *create_packet(const struct scan *data, size_t packet_size) iphdr->frag_off = 0; iphdr->ttl = data->ttl; iphdr->protocol = isudp ? IPPROTO_UDP : IPPROTO_TCP; - iphdr->saddr = inet_addr(data->host->ip); + iphdr->saddr = inet_addr(data->host.ip); iphdr->daddr = inet_addr(data->dest_addr); iphdr->check = checksum(packet, packet_size); diff --git a/src/parsing.c b/src/parsing.c index 0e54da2..471c1d6 100644 --- a/src/parsing.c +++ b/src/parsing.c @@ -47,6 +47,7 @@ e_scantype parse_type(const char *arg) for (size_t i = 0; i < 6; i++) if (!strcmp(arg, types_str[i])) return i; + dprintf(2, "ft_nmap: type: invalid argument: '%s'\n", arg); return -1; } @@ -83,7 +84,7 @@ int parse_ports(const char *arg, uint16_t *p_start, uint16_t *p_end) *p_end = end; return 0; error: - dprintf(2, "ft_nmap: invalid argument: '%s'\n", arg); + dprintf(2, "ft_nmap: port: invalid argument: '%s'\n", arg); return -1; } @@ -105,7 +106,7 @@ static int check_arg(e_flag flag, const char *arg) } break; } - case FL_SCAN: + case FL_TYPE: if (!strcmp(arg, "SYN")) break; if (!strcmp(arg, "NULL")) @@ -223,3 +224,28 @@ struct option_lst *parse_options(int ac, char *const *av) } return head; } + +int parsing(struct scan *general, const struct option_lst *options) +{ + general->port_start = 1; + general->port_end = 1024; + if (option_isset(options, FL_FAST)) + general->port_end = 128; + if (parse_ports(get_option_arg(options, FL_PORTS), &general->port_start, &general->port_end)) + return -1; + general->type = parse_type(get_option_arg(options, FL_TYPE)); + if ((int)general->type == -1) + return -1; + const char *max_retries = get_option_arg(options, FL_MAXRETRIES); + general->max_retries = max_retries ? atoi(max_retries) : 1; + const char *ttl = get_option_arg(options, FL_TTL); + general->ttl = ttl ? atoi(ttl) : 48; + const char *nb_threads_str = get_option_arg(options, FL_SPEEDUP); + general->nb_threads = nb_threads_str ? atoi(nb_threads_str) : 1; + if (general->port_end - general->port_start + 1 < general->nb_threads) { + dprintf(2, "ft_nmap: number of threads to use must be superior " + "or equals to the ports range\n"); + return -1; + } + return 0; +} \ No newline at end of file diff --git a/src/print.c b/src/print.c index f001209..f33fbc6 100644 --- a/src/print.c +++ b/src/print.c @@ -1,3 +1,4 @@ +#include #include #include "parsing.h" @@ -9,11 +10,11 @@ void print_usage(void) // TODO } -static void print_port_state(const struct response *response, e_scantype type) +static void print_port_state(uint16_t port, e_scantype type, const struct response * response) { if (type != SCAN_ALL && response->states[type] == CLOSED) return; - printf("%-5d %-12s ", response->port, + printf("%-5d %-12s ", port, response->service ? response->service : "Unassigned"); if (type == SCAN_ALL) for (e_scantype i = SCAN_NULL; i < SCAN_ALL; i++) @@ -25,16 +26,12 @@ static void print_port_state(const struct response *response, e_scantype type) printf("\n"); } -void print_host_results(const char *ip_addr, const struct response *responses, - const struct option_lst *options, double scan_time) +void print_host_results(const struct scan *general, double scan_time) { printf("Scan took %lf secs\n", scan_time); - printf("IP address: %s\n", ip_addr); + printf("IP address: %s\n", general->dest_addr); printf("Open ports:\n"); - uint16_t port_start = 1, port_end = 1024; - parse_ports(get_option_arg(options, FL_PORTS), &port_start, &port_end); - e_scantype type = parse_type(get_option_arg(options, FL_SCAN)); - for (uint16_t i = port_start; i < port_end - port_start; i++) { - print_port_state(&responses[i], type); + for (uint16_t port = general->port_start; port < general->port_end; port++) { + print_port_state(port, general->type, &general->responses[port - general->port_start]); } } diff --git a/src/response.c b/src/response.c index 4deb8d1..1faed4c 100644 --- a/src/response.c +++ b/src/response.c @@ -24,80 +24,80 @@ void tcp_response(const struct tcphdr *tcphdr, const struct scan *data) { const e_scantype type = data->type; if (type == SCAN_UDP) { - dprintf(2, "ft_nmap: error: received a TCP response for an UDP " + dprintf(2, "ft_nmap: error: received a TCP responses for an UDP " "scan\n"); return; } - if (data->response->service == NULL) - data->response->service = get_service_name(data->port, "tcp"); + if (data->responses->service == NULL) + data->responses->service = get_service_name(data->port_start, "tcp"); if (type == SCAN_SYN) { if (tcphdr->ack == 1 && tcphdr->syn == 1) - data->response->states[type] = OPENED; + data->responses->states[type] = OPENED; else if (tcphdr->ack == 1 && tcphdr->rst == 1) - data->response->states[type] = CLOSED; + data->responses->states[type] = CLOSED; } else if (type == SCAN_ACK && tcphdr->rst == 1) - data->response->states[type] = UNFILTERED; + data->responses->states[type] = UNFILTERED; else if (type == SCAN_NULL && tcphdr->rst == 1) - data->response->states[type] = CLOSED; + data->responses->states[type] = CLOSED; else if (type == SCAN_FIN && tcphdr->rst == 1) - data->response->states[type] = CLOSED; + data->responses->states[type] = CLOSED; else if (type == SCAN_XMAS && tcphdr->rst == 1) - data->response->states[type] = CLOSED; + data->responses->states[type] = CLOSED; } void udp_response(const struct udphdr *udphdr, const struct scan *data) { (void)udphdr; if (data->type != SCAN_UDP) { - dprintf(2, "ft_nmap: error: received an UDP response for a TCP " + dprintf(2, "ft_nmap: error: received an UDP responses for a TCP " "scan\n"); return; } - if (data->response->service == NULL) - data->response->service = get_service_name(data->port, "udp"); - data->response->states[SCAN_UDP] = OPENED; + if (data->responses->service == NULL) + data->responses->service = get_service_name(data->port_start, "udp"); + data->responses->states[SCAN_UDP] = OPENED; } void icmp_response(const struct icmphdr *icmphdr, const struct scan *data) { const e_scantype type = data->type; - data->response->service = get_service_name(data->port, "udp"); - if (data->response->service == NULL) - data->response->service = get_service_name(data->port, "tcp"); + data->responses->service = get_service_name(data->port_start, "udp"); + if (data->responses->service == NULL) + data->responses->service = get_service_name(data->port_start, "tcp"); if (type == SCAN_SYN && icmphdr->type == 3) - data->response->states[type] = FILTERED; + data->responses->states[type] = FILTERED; else if (type == SCAN_ACK && icmphdr->type == 3) - data->response->states[type] = FILTERED; + data->responses->states[type] = FILTERED; else if (type == SCAN_NULL && icmphdr->type == 3) - data->response->states[type] = FILTERED; + data->responses->states[type] = FILTERED; else if (type == SCAN_FIN && icmphdr->type == 3) - data->response->states[type] = FILTERED; + data->responses->states[type] = FILTERED; else if (type == SCAN_XMAS && icmphdr->type == 3) - data->response->states[type] = FILTERED; + data->responses->states[type] = FILTERED; else if (type == SCAN_UDP && icmphdr->type == 3 && icmphdr->code == 3) - data->response->states[type] = CLOSED; + data->responses->states[type] = CLOSED; else if (type == SCAN_UDP && icmphdr->type == 3 && icmphdr->code != 3) - data->response->states[type] = FILTERED; + data->responses->states[type] = FILTERED; } void no_response(const struct scan *data) { const e_scantype type = data->type; - data->response->service = get_service_name(data->port, "udp"); - if (data->response->service == NULL) - data->response->service = get_service_name(data->port, "tcp"); + data->responses->service = get_service_name(data->port_start, "udp"); + if (data->responses->service == NULL) + data->responses->service = get_service_name(data->port_start, "tcp"); if (type == SCAN_SYN) - data->response->states[type] = FILTERED; + data->responses->states[type] = FILTERED; else if (type == SCAN_ACK) - data->response->states[type] = FILTERED; + data->responses->states[type] = FILTERED; else if (type == SCAN_NULL) - data->response->states[type] = OPENFILTERED; + data->responses->states[type] = OPENFILTERED; else if (type == SCAN_FIN) - data->response->states[type] = OPENFILTERED; + data->responses->states[type] = OPENFILTERED; else if (type == SCAN_XMAS) - data->response->states[type] = OPENFILTERED; + data->responses->states[type] = OPENFILTERED; else if (type == SCAN_UDP) - data->response->states[type] = OPENFILTERED; + data->responses->states[type] = OPENFILTERED; } diff --git a/src/scan.c b/src/scan.c index 5e10b02..3d8cfa4 100644 --- a/src/scan.c +++ b/src/scan.c @@ -68,13 +68,13 @@ int scan(struct scan *data) char errbuf[PCAP_ERRBUF_SIZE]; bpf_u_int32 net, mask; - if (pcap_lookupnet(data->host->interface, &net, &mask, errbuf) < 0) { + if (pcap_lookupnet(data->host.interface, &net, &mask, errbuf) < 0) { dprintf(2, "ft_nmap: failed to lookup net/mask\n"); return -1; } pcap_t *handle = - pcap_open_live(data->host->interface, BUFSIZ, 0, 1000, errbuf); + pcap_open_live(data->host.interface, BUFSIZ, 0, 1000, errbuf); if (handle == NULL) { dprintf(2, "ft_nmap: failed to open device capture\n"); return -1; @@ -83,7 +83,7 @@ int scan(struct scan *data) struct bpf_program fp; char pcap_expr[BUFSIZ]; sprintf(pcap_expr, "src host %s and src port %d and dst host %s", - data->dest_addr, data->port, data->host->ip); + data->dest_addr, data->port_start, data->host.ip); if (pcap_compile(handle, &fp, pcap_expr, 0, mask) < 0) { dprintf(2, "ft_nmap: failed to compile pcap expression\n"); diff --git a/src/thread.c b/src/thread.c index 5bc2f1a..9e54205 100644 --- a/src/thread.c +++ b/src/thread.c @@ -27,21 +27,15 @@ void *routine(void *p_data) usleep(100); } - struct thread *thread_data = (struct thread *)p_data; - struct scan scan_data = { - .dest_addr = thread_data->dest_addr, - .host = &thread_data->host, - .port_start = thread_data->port_start, - .type = thread_data->type, - .max_retries = thread_data->max_retries, - .ttl = thread_data->ttl, - }; + struct scan *thread_data = p_data; + struct scan scan_data; + memcpy(&scan_data, thread_data, sizeof(struct scan)); for (uint16_t port = thread_data->port_start; port <= thread_data->port_end; port++) { - scan_data.port = port; - scan_data.response = &thread_data->responses[port - 1]; - scan_data.response->port = port; + scan_data.port_start = port; + scan_data.port_end = port; + scan_data.responses = &thread_data->responses[port - thread_data->port_start]; if (scan(&scan_data)) { free(p_data); return NULL; @@ -51,72 +45,47 @@ void *routine(void *p_data) return NULL; } -static struct thread *init_threads_data(const struct option_lst *options, - char *ip_addr, const struct host *host, - struct response *responses, - uint8_t nb_threads) +static struct scan *init_threads_data(const struct scan *general) { - struct thread *threads = malloc(sizeof(struct thread) * nb_threads); - if (!threads) { + struct scan *threads_data = malloc(sizeof(struct scan) * general->nb_threads); + if (!threads_data) { dprintf(2, "ft_nmap: allocation of threads failed\n"); return NULL; } - for (uint8_t i = 0; i < nb_threads; i++) { - memcpy(&threads[i].host, host, sizeof(struct host)); - threads[i].type = parse_type(get_option_arg(options, FL_SCAN)); - if (threads[i].type < 0) - goto error; - threads[i].dest_addr = ip_addr; - threads[i].responses = responses; - char *max_retries = get_option_arg(options, FL_MAXRETRIES); - threads[i].max_retries = max_retries ? atoi(max_retries) : 1; - char *ttl = get_option_arg(options, FL_TTL); - threads[i].ttl = ttl ? atoi(ttl) : 48; + + const uint16_t port_range = general->port_end - general->port_start + 1; + const uint16_t ports_per_thread = port_range / general->nb_threads; + uint16_t remaining_ports = port_range % general->nb_threads; + uint16_t port_start = general->port_start; + for (uint8_t i = 0; i < general->nb_threads; i++) { + memcpy(&threads_data[i], general, sizeof(struct scan)); + threads_data[i].port_start = port_start + i * ports_per_thread; + threads_data[i].port_end = (port_start - 1) + + (i + 1) * ports_per_thread + + (remaining_ports ? 1 : 0); + threads_data[i].responses = general->responses + (threads_data[i].port_start - general->port_start); + if (remaining_ports) { + remaining_ports--; + port_start++; + } } - return threads; -error: - free(threads); - return NULL; + return threads_data; } -int create_threads(const struct option_lst *options, char *ip_addr, - struct response *responses) +int create_threads(struct scan *general) { - struct host host; - if (get_interface_name(&host) < 0) - return -1; - - uint16_t port_start = 1; - uint16_t port_end = 1024; - if (option_isset(options, FL_FAST)) - port_end = 128; - const char *ports = get_option_arg(options, FL_PORTS); - if (parse_ports(ports, &port_start, &port_end) < 0) - return -1; - - const char *nb_threads_str = get_option_arg(options, FL_SPEEDUP); - if (!nb_threads_str) { - struct thread *thread_data = - init_threads_data(options, ip_addr, &host, responses, 1); + if (general->nb_threads == 1) { g_start = true; - routine(thread_data); - free(thread_data); + routine(general); return 0; } - uint8_t nb_threads = atoi(nb_threads_str); - if (port_end - port_start + 1 < nb_threads) { - dprintf(2, "ft_nmap: number of threads to use must be superior " - "or equals to the ports range\n"); + struct scan *threads_data = + init_threads_data(general); + if (threads_data == NULL) return -1; - } - - struct thread *threads_data = - init_threads_data(options, ip_addr, &host, responses, nb_threads); - if (!threads_data) - return -1; - pthread_t *threads = malloc(sizeof(pthread_t) * nb_threads); + pthread_t *threads = malloc(sizeof(pthread_t) * threads_data->nb_threads); if (!threads) { free(threads_data); return -1; @@ -125,18 +94,7 @@ int create_threads(const struct option_lst *options, char *ip_addr, pthread_mutex_init(&g_start_mtx, NULL); pthread_mutex_init(&g_getservent, NULL); - const uint16_t ports_per_thread = - (port_end - port_start + 1) / nb_threads; - uint16_t remaining_ports = (port_end - port_start + 1) % nb_threads; - for (uint8_t i = 0; i < nb_threads; i++) { - threads_data[i].port_start = port_start + i * ports_per_thread; - threads_data[i].port_end = (port_start - 1) + - (i + 1) * ports_per_thread + - (remaining_ports ? 1 : 0); - if (remaining_ports) { - remaining_ports--; - port_start++; - } + for (uint8_t i = 0; i < general->nb_threads; i++) { if (pthread_create(&threads[i], NULL, routine, &threads_data[i])) { dprintf(2, "ft_nmap: error during pthread_create()\n"); @@ -147,7 +105,7 @@ int create_threads(const struct option_lst *options, char *ip_addr, g_start = true; pthread_mutex_unlock(&g_start_mtx); - for (uint8_t i = 0; i < nb_threads; i++) { + for (uint8_t i = 0; i < general->nb_threads; i++) { if (pthread_join(threads[i], NULL)) { dprintf(2, "ft_nmap: error during pthread_join()\n"); return -1;