feature: flags -F, --max_retries and --ttl (wip)

This commit is contained in:
0x35c 2025-05-31 16:37:24 +02:00
parent ee2af274d9
commit dbed6dc7cd
6 changed files with 120 additions and 31 deletions

View File

@ -1,18 +1,22 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#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);

View File

@ -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;
};

View File

@ -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;
};

View File

@ -1,5 +1,6 @@
#include <ctype.h>
#include <getopt.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@ -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)

View File

@ -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);

View File

@ -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)
&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)