feature: flags -F, --max_retries and --ttl (wip)
This commit is contained in:
parent
ee2af274d9
commit
dbed6dc7cd
@ -1,18 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
|
|
||||||
#define NB_OPTIONS 6
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
// long options
|
||||||
FL_HELP,
|
FL_HELP,
|
||||||
FL_PORTS,
|
FL_PORTS,
|
||||||
FL_IP,
|
FL_IP,
|
||||||
FL_FILE,
|
FL_FILE,
|
||||||
FL_SPEEDUP,
|
FL_SPEEDUP,
|
||||||
FL_SCAN,
|
FL_SCAN,
|
||||||
|
FL_MAXRETRIES,
|
||||||
|
FL_TTL,
|
||||||
|
// short options
|
||||||
|
FL_FAST,
|
||||||
} e_flag;
|
} e_flag;
|
||||||
|
|
||||||
struct option_lst {
|
struct option_lst {
|
||||||
@ -22,6 +26,7 @@ struct option_lst {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct option_lst *parse_options(int ac, char *const *av);
|
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);
|
char *get_option_arg(const struct option_lst *options, e_flag flag);
|
||||||
int parse_ports(const char *arg, uint16_t *start, uint16_t *end);
|
int parse_ports(const char *arg, uint16_t *start, uint16_t *end);
|
||||||
e_scantype parse_type(const char *arg);
|
e_scantype parse_type(const char *arg);
|
||||||
|
@ -20,6 +20,8 @@ struct scan {
|
|||||||
uint16_t port_start;
|
uint16_t port_start;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
e_scantype type;
|
e_scantype type;
|
||||||
|
uint8_t ttl;
|
||||||
|
uint8_t max_retries;
|
||||||
struct response *response;
|
struct response *response;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ struct thread {
|
|||||||
uint16_t port_end;
|
uint16_t port_end;
|
||||||
char *dest_addr;
|
char *dest_addr;
|
||||||
e_scantype type;
|
e_scantype type;
|
||||||
|
uint8_t max_retries;
|
||||||
|
uint8_t ttl;
|
||||||
struct host host;
|
struct host host;
|
||||||
struct response *responses;
|
struct response *responses;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.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)
|
char *get_option_arg(const struct option_lst *options, e_flag flag)
|
||||||
{
|
{
|
||||||
if (!options)
|
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)
|
int parse_ports(const char *arg, uint16_t *p_start, uint16_t *p_end)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
if (!arg) {
|
if (!arg)
|
||||||
*p_start = 1;
|
return -1;
|
||||||
*p_end = 1024;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (; isdigit(arg[i]); i++)
|
for (; isdigit(arg[i]); i++)
|
||||||
;
|
;
|
||||||
int start = atoi(arg);
|
int start = atoi(arg);
|
||||||
if (arg[i] == '\0')
|
if (arg[i] == '\0') {
|
||||||
|
*p_start = start;
|
||||||
|
*p_end = start;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
if (arg[i++] != '-')
|
if (arg[i++] != '-')
|
||||||
goto error;
|
goto error;
|
||||||
int end = atoi(arg + i);
|
int end = atoi(arg + i);
|
||||||
@ -82,7 +93,7 @@ error:
|
|||||||
static int check_arg(e_flag flag, const char *arg)
|
static int check_arg(e_flag flag, const char *arg)
|
||||||
{
|
{
|
||||||
switch (flag) {
|
switch (flag) {
|
||||||
case FL_SPEEDUP:
|
case FL_SPEEDUP: {
|
||||||
for (size_t i = 0; arg[i]; i++)
|
for (size_t i = 0; arg[i]; i++)
|
||||||
if (!isdigit(arg[i]))
|
if (!isdigit(arg[i]))
|
||||||
return -1;
|
return -1;
|
||||||
@ -96,6 +107,7 @@ static int check_arg(e_flag flag, const char *arg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case FL_SCAN:
|
case FL_SCAN:
|
||||||
if (!strcmp(arg, "SYN"))
|
if (!strcmp(arg, "SYN"))
|
||||||
break;
|
break;
|
||||||
@ -110,6 +122,37 @@ static int check_arg(e_flag flag, const char *arg)
|
|||||||
if (!strcmp(arg, "UDP"))
|
if (!strcmp(arg, "UDP"))
|
||||||
break;
|
break;
|
||||||
return -1;
|
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:
|
default:
|
||||||
break;
|
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 *parse_options(int ac, char *const *av)
|
||||||
{
|
{
|
||||||
struct option_lst *head = NULL;
|
struct option_lst *head = NULL;
|
||||||
const struct option options[NB_OPTIONS] = {
|
const struct option options[] = {
|
||||||
{"help", no_argument, 0, 0},
|
{"help", no_argument, 0, 0},
|
||||||
{"ports", required_argument, 0, 0},
|
{"ports", required_argument, 0, 0},
|
||||||
{"ip", required_argument, 0, 0},
|
{"ip", required_argument, 0, 0},
|
||||||
{"file", required_argument, 0, 0},
|
{"file", required_argument, 0, 0},
|
||||||
{"speedup", required_argument, 0, 0},
|
{"speedup", required_argument, 0, 0},
|
||||||
{"scan", required_argument, 0, 0},
|
{"scan", required_argument, 0, 0},
|
||||||
|
{"max_retries", required_argument, 0, 0},
|
||||||
|
{"ttl", required_argument, 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
c = getopt_long(ac, av, "", options, &option_index);
|
c = getopt_long(ac, av, "F", options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
else if (c)
|
switch (c) {
|
||||||
|
case 'F':
|
||||||
|
add_option(&head, FL_FAST, optarg);
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
return NULL;
|
return NULL;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (check_arg(option_index, optarg) < 0)
|
if (check_arg(option_index, optarg) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (add_option(&head, option_index, optarg) < 0)
|
if (add_option(&head, option_index, optarg) < 0)
|
||||||
|
20
src/scan.c
20
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,
|
static int send_recv_packet(const struct scan *data, int sockfd, pcap_t *handle)
|
||||||
pcap_t *handle)
|
|
||||||
{
|
{
|
||||||
send_packet(data, sockfd);
|
send_packet(data, sockfd);
|
||||||
uint8_t timer = 0;
|
uint8_t timer = 0;
|
||||||
@ -49,9 +48,12 @@ static void send_recv_packet(const struct scan *data, int sockfd,
|
|||||||
break;
|
break;
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
}
|
}
|
||||||
if (timer == TIMEOUT * 100)
|
|
||||||
no_response(data);
|
|
||||||
pcap_breakloop(handle);
|
pcap_breakloop(handle);
|
||||||
|
if (timer == TIMEOUT * 100) {
|
||||||
|
no_response(data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int scan(struct scan *data)
|
int scan(struct scan *data)
|
||||||
@ -102,11 +104,17 @@ int scan(struct scan *data)
|
|||||||
if (data->type == SCAN_ALL) {
|
if (data->type == SCAN_ALL) {
|
||||||
for (e_scantype type = SCAN_NULL; type < SCAN_ALL; type++) {
|
for (e_scantype type = SCAN_NULL; type < SCAN_ALL; type++) {
|
||||||
data->type = 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;
|
data->type = SCAN_ALL;
|
||||||
} else {
|
} 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);
|
pcap_close(handle);
|
||||||
|
46
src/thread.c
46
src/thread.c
@ -33,6 +33,8 @@ void *routine(void *p_data)
|
|||||||
.host = &thread_data->host,
|
.host = &thread_data->host,
|
||||||
.port_start = thread_data->port_start,
|
.port_start = thread_data->port_start,
|
||||||
.type = thread_data->type,
|
.type = thread_data->type,
|
||||||
|
.max_retries = thread_data->max_retries,
|
||||||
|
.ttl = thread_data->ttl,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (uint16_t port = thread_data->port_start;
|
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++) {
|
for (uint8_t i = 0; i < nb_threads; i++) {
|
||||||
memcpy(&threads[i].host, host, sizeof(struct host));
|
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);
|
const char *ports = get_option_arg(options, FL_PORTS);
|
||||||
if (parse_ports(ports, &threads[i].port_start,
|
if (parse_ports(ports, &threads[i].port_start,
|
||||||
&threads[i].port_end) < 0)
|
&threads[i].port_end) < 0) {
|
||||||
goto error;
|
if (!option_isset(options, FL_FAST))
|
||||||
|
goto error;
|
||||||
|
threads[i].port_end = 128;
|
||||||
|
}
|
||||||
threads[i].type = parse_type(get_option_arg(options, FL_SCAN));
|
threads[i].type = parse_type(get_option_arg(options, FL_SCAN));
|
||||||
if (threads[i].type < 0)
|
if (threads[i].type < 0)
|
||||||
goto error;
|
goto error;
|
||||||
threads[i].dest_addr = ip_addr;
|
threads[i].dest_addr = ip_addr;
|
||||||
threads[i].responses = responses;
|
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;
|
return threads;
|
||||||
@ -80,29 +93,36 @@ error:
|
|||||||
int create_threads(const struct option_lst *options, char *ip_addr,
|
int create_threads(const struct option_lst *options, char *ip_addr,
|
||||||
struct response *responses)
|
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;
|
struct host host;
|
||||||
if (get_interface_name(&host) < 0)
|
if (get_interface_name(&host) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
const char *arg = get_option_arg(options, FL_SPEEDUP);
|
uint16_t port_start = 1;
|
||||||
// Launche single thread routine if it's a 1 port scan or if no speedup
|
uint16_t port_end = 1024;
|
||||||
// option was passed
|
const char *ports = get_option_arg(options, FL_PORTS);
|
||||||
if (!arg || !port_end) {
|
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 =
|
struct thread *thread_data =
|
||||||
init_threads_data(options, ip_addr, &host, responses, 1);
|
init_threads_data(options, ip_addr, &host, responses, 1);
|
||||||
thread_data->port_start = port_start;
|
|
||||||
thread_data->port_end = port_end;
|
|
||||||
g_start = true;
|
g_start = true;
|
||||||
routine(thread_data);
|
routine(thread_data);
|
||||||
free(thread_data);
|
free(thread_data);
|
||||||
return 0;
|
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 =
|
struct thread *threads_data =
|
||||||
init_threads_data(options, ip_addr, &host, responses, nb_threads);
|
init_threads_data(options, ip_addr, &host, responses, nb_threads);
|
||||||
if (!threads_data)
|
if (!threads_data)
|
||||||
|
Loading…
Reference in New Issue
Block a user