diff --git a/include/dns.h b/include/dns.h index 2f33b4a..b46a37f 100644 --- a/include/dns.h +++ b/include/dns.h @@ -2,5 +2,6 @@ #include -int dns_lookup(char *ip_addr, char *hostname, struct sockaddr_in *addr_con); +int dns_lookup(char *ip_addr, const char *hostname, + struct sockaddr_in *addr_con); int reverse_dns_lookup(char *ip_addr, char *host); diff --git a/include/parsing.h b/include/parsing.h index edfd9d9..6ad15ef 100644 --- a/include/parsing.h +++ b/include/parsing.h @@ -1,5 +1,9 @@ #pragma once +#include + +#include "scan.h" + #define NB_OPTIONS 5 typedef enum { @@ -17,4 +21,6 @@ struct option_lst { }; struct option_lst *parse_options(int ac, char *const *av); -char *get_option_arg(struct option_lst *options, e_flag flag); +const 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); diff --git a/include/scan.h b/include/scan.h index c3d9c62..dfeec28 100644 --- a/include/scan.h +++ b/include/scan.h @@ -11,7 +11,7 @@ typedef enum { SCAN_FIN, SCAN_XMAS, SCAN_UDP, - SCAN_TCP, + SCAN_ALL, } e_scantype; struct scan { diff --git a/include/thread.h b/include/thread.h index ee792a0..18865f2 100644 --- a/include/thread.h +++ b/include/thread.h @@ -3,6 +3,7 @@ #include #include "host.h" +#include "parsing.h" #include "response.h" #include "scan.h" @@ -16,3 +17,5 @@ struct thread { }; void *routine(void *p_data); +int create_threads(const struct option_lst *options, char *ip_addr, + struct response *responses); diff --git a/src/dns.c b/src/dns.c index 5ba90cb..f6ee301 100644 --- a/src/dns.c +++ b/src/dns.c @@ -6,7 +6,8 @@ #include #include -int dns_lookup(char *ip_addr, char *hostname, struct sockaddr_in *addr_con) +int dns_lookup(char *ip_addr, const char *hostname, + struct sockaddr_in *addr_con) { struct hostent *host = gethostbyname2(hostname, AF_INET); if (!host) { diff --git a/src/main.c b/src/main.c index 03d9f1e..f7bd377 100644 --- a/src/main.c +++ b/src/main.c @@ -29,7 +29,7 @@ int main(int ac, char **av) char ip_addr[INET_ADDRSTRLEN]; struct sockaddr_in addr_con; - char *host = get_option_arg(options, FL_IP); + const char *host = get_option_arg(options, FL_IP); if (!host) { dprintf(2, "ft_nmap: address/hostname required\n"); return 1; @@ -41,23 +41,8 @@ int main(int ac, char **av) } struct response responses[1024] = {0}; - - struct thread *single_thread = malloc(sizeof(struct thread)); - if (get_interface_name(&single_thread->host) < 0) + if (create_threads(options, ip_addr, responses) < 0) return 1; - single_thread->dest_addr = ip_addr; - single_thread->port_start = 21; - single_thread->port_end = 1024; - single_thread->responses = responses; - single_thread->type = SCAN_SYN; - if (routine(single_thread) == NULL) { - dprintf(2, "ft_nmap: failed to scan ports\n"); - return 1; - } - - int threads_running = 0; - while (threads_running) - ; return 0; } diff --git a/src/parsing.c b/src/parsing.c index e31f600..1a3bac0 100644 --- a/src/parsing.c +++ b/src/parsing.c @@ -1,17 +1,98 @@ +#include #include #include +#include #include #include +#include #include "parsing.h" -char *get_option_arg(struct option_lst *options, e_flag flag) +const char *get_option_arg(const struct option_lst *options, e_flag flag) { if (!options) - return 0; - for (struct option_lst *it = options; it; it = it->next) + return NULL; + for (const struct option_lst *it = options; it; it = it->next) if (it->flag == flag) return it->arg; + return NULL; +} + +e_scantype parse_type(const char *arg) +{ + const char *types[] = { + "SYN", "NULL", "ACK", "FIN", "XMAS", "UDP", + }; + + if (!arg) + return SCAN_ALL; + for (size_t i = 0; i < 6; i++) + if (!strcmp(arg, types[i])) + return i; + return -1; +} + +int parse_ports(const char *arg, uint16_t *p_start, uint16_t *p_end) +{ + size_t i = 0; + for (; isdigit(arg[i]); i++) + ; + int start = atoi(arg); + if (arg[i++] != '-') + return -1; + int end = atoi(arg + i); + for (; isdigit(arg[i]); i++) + ; + if (arg[i]) + return -1; + if (start >= end) + return -1; + if (end > UINT16_MAX) { + dprintf(2, + "ft_nmap: invalid argument: '%s': out of range: 0 " + "<= value <= %d\n", + arg, UINT16_MAX); + return -1; + } + *p_start = start; + *p_end = end; + return 0; +} + +static int check_arg(e_flag flag, const char *arg) +{ + switch (flag) { + case FL_SPEEDUP: + for (size_t i = 0; arg[i]; i++) + if (!isdigit(arg[i])) + return -1; + int value = atoi(arg); + if (value < 0 || value > 250) { + dprintf(2, + "ft_nmap: invalid argument: '%s': out " + "of range: 0 " + "<= value <= 250\n", + arg); + return -1; + } + break; + case FL_SCAN: + if (!strcmp(arg, "SYN")) + break; + if (!strcmp(arg, "NULL")) + break; + if (!strcmp(arg, "ACK")) + break; + if (!strcmp(arg, "FIN")) + break; + if (!strcmp(arg, "XMAS")) + break; + if (!strcmp(arg, "UDP")) + break; + return -1; + default: + break; + } return 0; } @@ -19,7 +100,7 @@ static int add_option(struct option_lst **head, e_flag flag, char *arg) { struct option_lst *new_option = malloc(sizeof(struct option_lst)); if (!new_option) { - dprintf(2, "ft_ping: allocation of option failed\n"); + dprintf(2, "ft_nmap: allocation of option failed\n"); for (struct option_lst *it = *head; it;) { struct option_lst *tmp = it; it = it->next; @@ -64,6 +145,8 @@ struct option_lst *parse_options(int ac, char *const *av) break; else if (c) return NULL; + if (check_arg(option_index, optarg) < 0) + return NULL; if (add_option(&head, option_index, optarg) < 0) return NULL; } diff --git a/src/thread.c b/src/thread.c index fc4f166..0f41f8c 100644 --- a/src/thread.c +++ b/src/thread.c @@ -1,12 +1,33 @@ #include +#include +#include #include #include +#include +#include +#include +#include "interface.h" +#include "parsing.h" #include "scan.h" #include "thread.h" +uint8_t g_nb_threads; +bool g_start = false; +pthread_mutex_t g_nb_threads_mtx; +pthread_mutex_t g_start_mtx; + void *routine(void *p_data) { + while (1) { + pthread_mutex_lock(&g_start_mtx); + bool start = g_start; + pthread_mutex_unlock(&g_start_mtx); + if (start) + break; + usleep(100); + } + struct thread *thread_data = (struct thread *)p_data; struct scan scan_data = { .dest_addr = thread_data->dest_addr, @@ -20,11 +41,113 @@ void *routine(void *p_data) scan_data.port = port; scan_data.response = &thread_data->responses[port - thread_data->port_start]; - if (scan(&scan_data)) + printf("uwu on port %d\n", port); + if (scan(&scan_data)) { + free(p_data); return NULL; - printf("%d: %s\n", port, - scan_data.response->state == 1 ? "OPEN" : "CLOSED"); + } + printf("%d has state: %d\n", port, scan_data.response->state); } - return p_data; + pthread_mutex_lock(&g_nb_threads_mtx); + g_nb_threads--; + pthread_mutex_unlock(&g_nb_threads_mtx); + free(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 g_nb_threads) +{ + struct thread *threads = malloc(sizeof(struct thread) * g_nb_threads); + if (!threads) { + dprintf(2, "ft_nmap: allocation of threads failed\n"); + return NULL; + } + for (uint8_t i = 0; i < g_nb_threads; i++) { + memcpy(&threads[i].host, host, sizeof(struct host)); + const char *ports = get_option_arg(options, FL_PORTS); + if (parse_ports(ports, &threads[i].port_start, + &threads[i].port_end) < 0) + goto error; + 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; + } + + return threads; +error: + free(threads); + return NULL; +} + +int create_threads(const struct option_lst *options, char *ip_addr, + struct response *responses) +{ + uint16_t port_start, port_end; + const char *ports = get_option_arg(options, FL_PORTS); + if (parse_ports(ports, &port_start, &port_end) < 0) + return -1; + struct host host; + if (get_interface_name(&host) < 0) + return -1; + + const char *arg = get_option_arg(options, FL_SPEEDUP); + if (!arg) { + struct thread *thread_data = + init_threads_data(options, ip_addr, &host, responses, 1); + thread_data->port_start = port_start; + thread_data->port_end = port_end; + routine(thread_data); + return 0; + } + + g_nb_threads = atoi(arg); + struct thread *threads_data = + init_threads_data(options, ip_addr, &host, responses, g_nb_threads); + if (!threads_data) + return -1; + pthread_t *threads = malloc(sizeof(pthread_t) * g_nb_threads); + if (!threads) { + free(threads_data); + return -1; + } + + pthread_mutex_init(&g_nb_threads_mtx, NULL); + pthread_mutex_init(&g_start_mtx, NULL); + + const uint16_t ports_per_thread = + (port_end - port_start) / g_nb_threads; + uint16_t remaining_ports = (port_end - port_start) % g_nb_threads; + for (uint8_t i = 0; i < g_nb_threads; i++) { + threads_data[i].port_start = port_start + i * ports_per_thread; + threads_data[i].port_end = + port_start + (i + 1) * ports_per_thread; + // TODO implement remaining_ports + (void)remaining_ports; + if (pthread_create(&threads[i], NULL, routine, + &threads_data[i])) { + dprintf(2, "ft_nmap: error during pthread_create()\n"); + return -1; + } + } + pthread_mutex_lock(&g_start_mtx); + g_start = true; + pthread_mutex_unlock(&g_start_mtx); + + while (1) { + pthread_mutex_lock(&g_nb_threads_mtx); + bool nb_threads = g_nb_threads; + pthread_mutex_unlock(&g_nb_threads_mtx); + if (nb_threads == 0) + break; + usleep(100); + } + + return 0; }