From dbed6dc7cd0f48c48fde67fb01a7f51e6cd7b344 Mon Sep 17 00:00:00 2001 From: 0x35c <> Date: Sat, 31 May 2025 16:37:24 +0200 Subject: [PATCH] feature: flags -F, --max_retries and --ttl (wip) --- include/parsing.h | 9 ++++-- include/scan.h | 2 ++ include/thread.h | 2 ++ src/parsing.c | 72 ++++++++++++++++++++++++++++++++++++++++------- src/scan.c | 20 +++++++++---- src/thread.c | 46 +++++++++++++++++++++--------- 6 files changed, 120 insertions(+), 31 deletions(-) diff --git a/include/parsing.h b/include/parsing.h index 3b2ed9f..95224d8 100644 --- a/include/parsing.h +++ b/include/parsing.h @@ -1,18 +1,22 @@ #pragma once +#include #include #include "scan.h" -#define NB_OPTIONS 6 - typedef enum { + // long options FL_HELP, FL_PORTS, FL_IP, FL_FILE, FL_SPEEDUP, FL_SCAN, + FL_MAXRETRIES, + FL_TTL, + // short options + FL_FAST, } e_flag; struct option_lst { @@ -22,6 +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); diff --git a/include/scan.h b/include/scan.h index be34b3f..ad37ff0 100644 --- a/include/scan.h +++ b/include/scan.h @@ -20,6 +20,8 @@ struct scan { uint16_t port_start; uint16_t port; e_scantype type; + uint8_t ttl; + uint8_t max_retries; struct response *response; }; diff --git a/include/thread.h b/include/thread.h index 18865f2..cbab99b 100644 --- a/include/thread.h +++ b/include/thread.h @@ -12,6 +12,8 @@ struct thread { uint16_t port_end; char *dest_addr; e_scantype type; + uint8_t max_retries; + uint8_t ttl; struct host host; struct response *responses; }; diff --git a/src/parsing.c b/src/parsing.c index bc672e5..6226a3b 100644 --- a/src/parsing.c +++ b/src/parsing.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -18,6 +19,16 @@ void free_options(struct option_lst *options) } } +bool option_isset(const struct option_lst *options, e_flag flag) +{ + if (!options) + return false; + for (const struct option_lst *it = options; it; it = it->next) + if (it->flag == flag) + return true; + return false; +} + char *get_option_arg(const struct option_lst *options, e_flag flag) { if (!options) @@ -45,16 +56,16 @@ e_scantype parse_type(const char *arg) int parse_ports(const char *arg, uint16_t *p_start, uint16_t *p_end) { size_t i = 0; - if (!arg) { - *p_start = 1; - *p_end = 1024; - return 0; - } + if (!arg) + return -1; for (; isdigit(arg[i]); i++) ; int start = atoi(arg); - if (arg[i] == '\0') + if (arg[i] == '\0') { + *p_start = start; + *p_end = start; return 0; + } if (arg[i++] != '-') goto error; int end = atoi(arg + i); @@ -82,7 +93,7 @@ error: static int check_arg(e_flag flag, const char *arg) { switch (flag) { - case FL_SPEEDUP: + case FL_SPEEDUP: { for (size_t i = 0; arg[i]; i++) if (!isdigit(arg[i])) return -1; @@ -96,6 +107,7 @@ static int check_arg(e_flag flag, const char *arg) return -1; } break; + } case FL_SCAN: if (!strcmp(arg, "SYN")) break; @@ -110,6 +122,37 @@ static int check_arg(e_flag flag, const char *arg) if (!strcmp(arg, "UDP")) break; return -1; + case FL_TTL: { + int nb = atoi(arg); + if (nb == 0) { + dprintf(2, "ft_nmap: cannot set unicast time-to-live: " + "Invalid argument\n"); + return -1; + } else if (nb < 0 || nb > 255) { + dprintf( + 2, + "ft_nmap: invalid argument: '%s': out of range: 0 " + "<= value <= 255\n", + arg); + return -1; + } + break; + } + case FL_MAXRETRIES: { + int nb = atoi(arg); + if (nb == 0) { + dprintf(2, "ft_nmap: cannot set max_retries to 0\n"); + return -1; + } else if (nb < 0 || nb > 255) { + dprintf( + 2, + "ft_nmap: invalid argument: '%s': out of range: 0 " + "<= value <= 255\n", + arg); + return -1; + } + break; + } default: break; } @@ -149,23 +192,32 @@ static int add_option(struct option_lst **head, e_flag flag, char *arg) struct option_lst *parse_options(int ac, char *const *av) { struct option_lst *head = NULL; - const struct option options[NB_OPTIONS] = { + const struct option options[] = { {"help", no_argument, 0, 0}, {"ports", required_argument, 0, 0}, {"ip", required_argument, 0, 0}, {"file", required_argument, 0, 0}, {"speedup", required_argument, 0, 0}, {"scan", required_argument, 0, 0}, + {"max_retries", required_argument, 0, 0}, + {"ttl", required_argument, 0, 0}, }; int c; while (1) { int option_index = 0; - c = getopt_long(ac, av, "", options, &option_index); + c = getopt_long(ac, av, "F", options, &option_index); if (c == -1) break; - else if (c) + switch (c) { + case 'F': + add_option(&head, FL_FAST, optarg); + break; + case '?': return NULL; + default: + break; + } if (check_arg(option_index, optarg) < 0) return NULL; if (add_option(&head, option_index, optarg) < 0) diff --git a/src/scan.c b/src/scan.c index 35f13c6..a2bc280 100644 --- a/src/scan.c +++ b/src/scan.c @@ -39,8 +39,7 @@ static void dispatch_callback(u_char *user, const struct pcap_pkthdr *h, } } -static void send_recv_packet(const struct scan *data, int sockfd, - pcap_t *handle) +static int send_recv_packet(const struct scan *data, int sockfd, pcap_t *handle) { send_packet(data, sockfd); uint8_t timer = 0; @@ -49,9 +48,12 @@ static void send_recv_packet(const struct scan *data, int sockfd, break; usleep(100000); } - if (timer == TIMEOUT * 100) - no_response(data); pcap_breakloop(handle); + if (timer == TIMEOUT * 100) { + no_response(data); + return 0; + } + return 1; } int scan(struct scan *data) @@ -102,11 +104,17 @@ int scan(struct scan *data) if (data->type == SCAN_ALL) { for (e_scantype type = SCAN_NULL; type < SCAN_ALL; type++) { data->type = type; - send_recv_packet(data, sockfd, handle); + for (uint8_t retries = 0; retries < data->max_retries; + retries++) + if (send_recv_packet(data, sockfd, handle)) + break; } data->type = SCAN_ALL; } else { - send_recv_packet(data, sockfd, handle); + for (uint8_t retries = 0; retries < data->max_retries; + retries++) + if (send_recv_packet(data, sockfd, handle)) + break; } pcap_close(handle); diff --git a/src/thread.c b/src/thread.c index 85fc163..d7969e9 100644 --- a/src/thread.c +++ b/src/thread.c @@ -33,6 +33,8 @@ void *routine(void *p_data) .host = &thread_data->host, .port_start = thread_data->port_start, .type = thread_data->type, + .max_retries = thread_data->max_retries, + .ttl = thread_data->ttl, }; for (uint16_t port = thread_data->port_start; @@ -60,15 +62,26 @@ static struct thread *init_threads_data(const struct option_lst *options, } for (uint8_t i = 0; i < nb_threads; i++) { memcpy(&threads[i].host, host, sizeof(struct host)); + threads[i].port_start = 1; + threads[i].port_end = 1024; + if (option_isset(options, FL_FAST)) + threads[i].port_end = 128; 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].port_end) < 0) { + if (!option_isset(options, FL_FAST)) + goto error; + threads[i].port_end = 128; + } 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; } return threads; @@ -80,29 +93,36 @@ error: int create_threads(const struct option_lst *options, char *ip_addr, struct response *responses) { - uint16_t port_start = 0, port_end = 0; - 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); - // Launche single thread routine if it's a 1 port scan or if no speedup - // option was passed - if (!arg || !port_end) { + uint16_t port_start = 1; + uint16_t port_end = 1024; + const char *ports = get_option_arg(options, FL_PORTS); + if (parse_ports(ports, &port_start, &port_end) < 0) { + if (!option_isset(options, FL_FAST)) + return -1; + port_end = 128; + } + + 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); - thread_data->port_start = port_start; - thread_data->port_end = port_end; g_start = true; routine(thread_data); free(thread_data); return 0; } - uint8_t nb_threads = atoi(arg); + uint8_t nb_threads = atoi(nb_threads_str); + if (port_end - port_start < nb_threads) { + dprintf(2, "ft_nmap: number of threads to use must be superior " + "or equals to the ports range\n"); + return -1; + } + struct thread *threads_data = init_threads_data(options, ip_addr, &host, responses, nb_threads); if (!threads_data)