From c07ea8048f817b7f8032a12fcf314d6ca678718d Mon Sep 17 00:00:00 2001 From: williamhedenskog <94441813+pilsnerfrajz@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:22:08 +0200 Subject: [PATCH 1/5] Add SYN to host discovery techniques --- src/main.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index ef7841d..8b78de0 100644 --- a/src/main.c +++ b/src/main.c @@ -13,6 +13,9 @@ #define RETRIES 3 #define MSG_BUF_SIZE 2048 +#define DISCOVERY_PORT_COUNT 3 + +static unsigned short discovery_ports[DISCOVERY_PORT_COUNT] = {22, 80, 443}; /** * @brief Print a message to a stream and to a file if provided. @@ -55,10 +58,21 @@ static int default_scan(FILE *fp, char *target) char *msg = "[!] ARP failed, falling back to ICMP\n"; print_wrapper(stdout, fp, msg); rv = ping(target, RETRIES); - if (rv != SUCCESS) + if (rv == SUCCESS) { - print_err(stderr, "[-] ping", rv); - print_err(fp, "[-] ping", rv); + return 0; + } + + msg = "[!] Ping failed, falling back to TCP SYN\n"; + print_wrapper(stdout, fp, msg); + + short is_up = 0; + short is_open_port = 0; + rv = port_scan(target, discovery_ports, DISCOVERY_PORT_COUNT, &is_open_port, &is_up, NULL); + if (rv != SUCCESS || !is_up) + { + msg = "[-] Host discovery failed. Host is down, aborting scan\n"; + print_wrapper(stderr, fp, msg); return NO_RESPONSE; } @@ -278,8 +292,9 @@ int main(int argc, char *argv[]) print_wrapper(stdout, fp, msg_buf); memset(msg_buf, 0, MSG_BUF_SIZE); short is_open_port = 0; + short is_up = 0; - rv = port_scan(target, port_arr, port_count, &is_open_port, &res_arr); + rv = port_scan(target, port_arr, port_count, &is_open_port, &is_up, &res_arr); if (rv != SUCCESS) { print_err(stderr, "[-] port_scan", rv); From 1b0e427a7dc98f4128a2182d5b9e46db7bbeaea6 Mon Sep 17 00:00:00 2001 From: williamhedenskog <94441813+pilsnerfrajz@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:23:31 +0200 Subject: [PATCH 2/5] Add flag to indicate if host is up --- include/syn_scan.h | 2 ++ src/syn_scan.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/include/syn_scan.h b/include/syn_scan.h index 6860632..3b754ed 100644 --- a/include/syn_scan.h +++ b/include/syn_scan.h @@ -18,6 +18,7 @@ * @param port_arr The array of ports to scan. * @param count The number of ports in the array. * @param is_open_port Whether any open ports were found. + * @param is_up Whether the host is up. * @param result_arr Pointer to an array to store the results of the scan. * @return `int` Returns SUCCESS on success, or an error code from `error.h` on failure. */ @@ -25,6 +26,7 @@ int port_scan(char *address, unsigned short *port_arr, int count, short *is_open_port, + short *is_up, unsigned short **result_arr); /** diff --git a/src/syn_scan.c b/src/syn_scan.c index f50f648..d85da2f 100644 --- a/src/syn_scan.c +++ b/src/syn_scan.c @@ -65,6 +65,7 @@ struct callback_data { short loopback_flag; short any_open; /* Flag if any open port is found */ + short is_up; /* Flag if host is up */ volatile short port_status[65536]; }; @@ -145,6 +146,11 @@ static void tcp_process_pkt(u_char *user, const struct pcap_pkthdr *pkt_hdr, } } + if (tcp_hdr->flags) + { + c_data->is_up = 1; + } + if ((tcp_hdr->flags & SYN_ACK) == SYN_ACK) { c_data->port_status[ntohs(tcp_hdr->sport)] = OPEN; @@ -857,6 +863,7 @@ int port_scan(char *address, unsigned short *port_arr, int port_count, short *is_open_port, + short *is_up, unsigned short **result_arr) { if (test_print) @@ -1102,6 +1109,7 @@ int port_scan(char *address, } *is_open_port = c_data.any_open; + *is_up = c_data.is_up; /* Save results to supplied result_arr for use in caller */ if (result_arr != NULL) From 53ae22ec1bb3fbee6bb825270c8e0ec54d994910 Mon Sep 17 00:00:00 2001 From: williamhedenskog <94441813+pilsnerfrajz@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:25:25 +0200 Subject: [PATCH 3/5] Update arguments --- tests/syn_scan_test.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/syn_scan_test.c b/tests/syn_scan_test.c index 3fa51e9..ff4a928 100644 --- a/tests/syn_scan_test.c +++ b/tests/syn_scan_test.c @@ -70,15 +70,16 @@ void syn_scan_test(void) } short is_open = 0; + short is_up = 0; - if ((ret = port_scan("127.0.0.1", test_arr, TEST_ARR_LEN, &is_open, NULL)) == SUCCESS) + if ((ret = port_scan("127.0.0.1", test_arr, TEST_ARR_LEN, &is_open, &is_up, NULL)) == SUCCESS) printf("└ ✅ Localhost IPv4 Port scan test: Passed\n"); else { print_err(stderr, "└ ❌ Localhost IPv4 Port scan test failed", ret); } - if ((ret = port_scan("::1", test_arr, TEST_ARR_LEN, &is_open, NULL)) == SUCCESS) + if ((ret = port_scan("::1", test_arr, TEST_ARR_LEN, &is_open, &is_up, NULL)) == SUCCESS) printf("└ ✅ Localhost IPv6 Port scan test: Passed\n"); else { @@ -101,7 +102,7 @@ void syn_scan_test(void) if (ping(lan_dev, 3) == SUCCESS) { - if ((ret = port_scan(lan_dev, test_arr, TEST_ARR_LEN, &is_open, NULL)) == SUCCESS) + if ((ret = port_scan(lan_dev, test_arr, TEST_ARR_LEN, &is_open, &is_up, NULL)) == SUCCESS) printf("└ ✅ IPv4 LAN device port scan test: Passed\n"); else { @@ -128,14 +129,14 @@ void syn_scan_test(void) print_err(stderr, "❌ IPv6 Lan Port scan test failed", ret); }*/ - if ((ret = port_scan("scanme.nmap.org", scanme_ports, 4, &is_open, NULL)) == SUCCESS) + if ((ret = port_scan("scanme.nmap.org", scanme_ports, 4, &is_open, &is_up, NULL)) == SUCCESS) printf("└ ✅ External IPv4 Port scan test: Passed\n"); else { print_err(stderr, "└ ❌ External IPv4 Port scan test failed", ret); } - if ((ret = port_scan("2600:3c01::f03c:91ff:fe18:bb2f", scanme_ports, 4, &is_open, NULL)) == SUCCESS) + if ((ret = port_scan("2600:3c01::f03c:91ff:fe18:bb2f", scanme_ports, 4, &is_open, &is_up, NULL)) == SUCCESS) printf("└ ✅ External IPv6 Port scan test: Passed\n"); else { From de19f0f1793ae3f85053a2d545c4c970d60a3754 Mon Sep 17 00:00:00 2001 From: williamhedenskog <94441813+pilsnerfrajz@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:47:33 +0200 Subject: [PATCH 4/5] Add flag for SYN host check --- include/cli.h | 2 ++ src/cli.c | 32 ++++++++++++++++++++++---------- src/main.c | 26 ++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/include/cli.h b/include/cli.h index 84b57ad..c51e2ab 100644 --- a/include/cli.h +++ b/include/cli.h @@ -19,6 +19,7 @@ void usage(FILE *stream); * @param no_host_disc Flag to skip host discovery. * @param force_ping Flag to force ICMP. * @param force_arp Flag to force ARP. + * @param force_syn Flag to force SYN scan. * @param write_file Pointer to store the write_file path. * @return int 0 on success, CLI_PARSE on error. */ @@ -30,6 +31,7 @@ int parse_cli(int argc, int *no_host_disc, int *force_ping, int *force_arp, + int *force_syn, char **write_file); #endif diff --git a/src/cli.c b/src/cli.c index 7c6bdcd..2f64c48 100644 --- a/src/cli.c +++ b/src/cli.c @@ -24,14 +24,15 @@ static void banner(FILE *stream) "disco - network utility for host discovery and port enumeration\n" "author: pilsnerfrajz\n\n"); fprintf(stream, - "usage: disco target [-h] [-p port(s)] [-o] [-n] [-P] [-a] [-w file]\n" + "usage: disco target [-h] [-p ports] [-o] [-n] [-P] [-a] [-S] [-w file]\n" "options:\n" " target : host to scan (IP address or domain)\n" " -p, --ports : ports to scan, e.g., -p 1-1024 or -p 21,22,80\n" - " -o, --open : show open ports only (default: open or unknown)\n" + " -o, --open : show open ports only (default: open or filtered)\n" " -n, --no-check : skip host status check\n" " -P, --ping-only : force ICMP host discovery (skip ARP attempt)\n" - " -a, --arp-only : force ARP host discovery (skip ICMP fallback)\n" + " -a, --arp-only : force ARP host discovery (skip ICMP fallback)\n" + " -S, --syn-only : force SYN host discovery (skip ARP and ICMP)\n" " -w, --write : write results to a file\n" " -h, --help : display this message\n"); } @@ -45,21 +46,23 @@ void usage(FILE *stream) else { fprintf(stream, - "[!] usage: disco target [-h] [-p port(s)] [-o] [-n] [-P] [-a] [-w file]\n" + "[!] usage: disco target [-h] [-p ports] [-o] [-n] [-P] [-a] [-S] [-w file]\n" " options:\n" " target : host to scan (IP address or domain)\n" " -p, --ports : ports to scan, e.g., -p 1-1024 or -p 21,22,80\n" - " -o, --open : show open ports only (default: open or unknown)\n" + " -o, --open : show open ports only (default: open or filtered)\n" " -n, --no-check : skip host status check\n" " -P, --ping-only : force ICMP host discovery (skip ARP attempt)\n" - " -a, --arp-only : force ARP host discovery (skip ICMP fallback)\n" + " -a, --arp-only : force ARP host discovery (skip ICMP fallback)\n" + " -S, --syn-only : force SYN host discovery (skip ARP and ICMP)\n" " -w, --write : write results to a file\n" " -h, --help : display this message\n"); } } int parse_cli(int argc, char *argv[], char **target, char **ports, int *show_open, - int *no_host_disc, int *force_ping, int *force_arp, char **write_file) + int *no_host_disc, int *force_ping, int *force_arp, int *force_syn, + char **write_file) { /* Reset optind for multiple tests to work properly*/ optind = 1; @@ -97,6 +100,12 @@ int parse_cli(int argc, char *argv[], char **target, char **ports, int *show_ope NULL, 'a', }, + { + "syn-only", + no_argument, + NULL, + 'S', + }, { "open", no_argument, @@ -112,7 +121,7 @@ int parse_cli(int argc, char *argv[], char **target, char **ports, int *show_ope {0, 0, 0, 0}}; int option; - while ((option = getopt_long(argc, argv, "p:nhPaow:", options, NULL)) != -1) + while ((option = getopt_long(argc, argv, "p:nhPaSow:", options, NULL)) != -1) { switch (option) { @@ -167,6 +176,9 @@ int parse_cli(int argc, char *argv[], char **target, char **ports, int *show_ope case 'a': *force_arp = 1; break; + case 'S': + *force_syn = 1; + break; case 'h': usage(stdout); return CLI_PARSE; @@ -220,9 +232,9 @@ int parse_cli(int argc, char *argv[], char **target, char **ports, int *show_ope } } - if (*force_arp + *force_ping + *no_host_disc > 1) + if (*force_arp + *force_ping + *force_syn + *no_host_disc > 1) { - fprintf(stderr, "[-] Conflicting options. Only one of -P, -a and -n can be used at once\n"); + fprintf(stderr, "[-] Conflicting options. Only one of -P, -a, -S and -n can be used at once\n"); usage(stderr); return CLI_PARSE; } diff --git a/src/main.c b/src/main.c index 8b78de0..5eeb046 100644 --- a/src/main.c +++ b/src/main.c @@ -71,7 +71,7 @@ static int default_scan(FILE *fp, char *target) rv = port_scan(target, discovery_ports, DISCOVERY_PORT_COUNT, &is_open_port, &is_up, NULL); if (rv != SUCCESS || !is_up) { - msg = "[-] Host discovery failed. Host is down, aborting scan\n"; + msg = "[-] Host discovery failed. Host is down, aborting\n"; print_wrapper(stderr, fp, msg); return NO_RESPONSE; } @@ -180,11 +180,12 @@ int main(int argc, char *argv[]) int no_host_disc = 0; int force_ping = 0; int force_arp = 0; + int force_syn = 0; int show_open = 0; int up = 0; int rv = 0; - if (parse_cli(argc, argv, &target, &ports, &show_open, &no_host_disc, &force_ping, &force_arp, &write_file) != 0) + if (parse_cli(argc, argv, &target, &ports, &show_open, &no_host_disc, &force_ping, &force_arp, &force_syn, &write_file) != 0) { return CLI_PARSE; } @@ -244,7 +245,24 @@ int main(int argc, char *argv[]) up = 1; } - if (ports == NULL && no_host_disc && !force_arp && !force_ping) + if (force_syn) + { + msg = "[!] Forcing TCP SYN host discovery (skipping ARP and ICMP)\n"; + print_wrapper(stdout, fp, msg); + short is_up = 0; + short is_open_port = 0; + rv = port_scan(target, discovery_ports, DISCOVERY_PORT_COUNT, &is_open_port, &is_up, NULL); + if (rv != SUCCESS || !is_up) + { + msg = "[-] TCP SYN host discovery failed. Host is down, aborting\n"; + print_wrapper(stderr, fp, msg); + rv = NO_RESPONSE; + goto cleanup; + } + up = 1; + } + + if (ports == NULL && no_host_disc && !force_arp && !force_ping && !force_syn) { msg = "[!] Doing nothing. Use '-p' with the '-n' option!\n\n"; print_wrapper(stderr, fp, msg); @@ -259,7 +277,7 @@ int main(int argc, char *argv[]) print_wrapper(stdout, fp, msg); } - if (!no_host_disc && !force_arp && !force_ping) + if (!no_host_disc && !force_arp && !force_ping && !force_syn) { rv = default_scan(fp, target); if (rv != 0) From 0800a38d804f09ffdc852ac5102317706b1141a4 Mon Sep 17 00:00:00 2001 From: williamhedenskog <94441813+pilsnerfrajz@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:47:44 +0200 Subject: [PATCH 5/5] Update tests to accomodate -S flag --- tests/cli_test.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cli_test.c b/tests/cli_test.c index ee605c0..ebf86a2 100644 --- a/tests/cli_test.c +++ b/tests/cli_test.c @@ -64,6 +64,7 @@ void cli_test(void) int no_host_disc = 0; int force_ping = 0; int force_arp = 0; + int force_syn = 0; int show_open = 0; char *help[] = {"program", "-h"}; @@ -78,11 +79,11 @@ void cli_test(void) "127.0.0.1", "::1"}; - parse_cli(2, help, &target, &ports, &show_open, &no_host_disc, &force_ping, &force_arp, NULL); + parse_cli(2, help, &target, &ports, &show_open, &no_host_disc, &force_ping, &force_arp, &force_syn, NULL); test(0, ports, 0, target, no_host_disc, force_ping, force_arp); - parse_cli(11, parse, &target, &ports, &show_open, &no_host_disc, &force_ping, &force_arp, NULL); + parse_cli(11, parse, &target, &ports, &show_open, &no_host_disc, &force_ping, &force_arp, &force_syn, NULL); test(6, ports, 1, target, no_host_disc, force_ping, force_arp);