Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ TEST_OBJS := $(notdir $(patsubst %.c,%.o, $(wildcard $(TESTS_DIR)/*.c)))

CC := gcc
CFLAGS := -Wall -Wextra -pedantic -Werror
CFLAGSTEST := -Wall -Wextra -pedantic -Werror -fsanitize=address -g
LDFLAGS := -lpcap -lpthread

$(NAME): dir $(OBJS)
Expand All @@ -19,13 +20,21 @@ $(OBJS):
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/$@ -c $(SRC_DIR)/$*.c

test: dir $(TEST_OBJS) $(OBJS)
@$(CC) $(CFLAGS) -o $(TESTS_DIR)/$(BIN_DIR)/run_all_tests \
@$(CC) $(CFLAGSTEST) -o $(TESTS_DIR)/$(BIN_DIR)/run_all_tests \
$(patsubst %,$(BUILD_DIR)/%, $(filter-out main.o, $(OBJS))) \
$(patsubst %,$(TESTS_DIR)/$(BUILD_DIR)/%, $(TEST_OBJS)) $(LDFLAGS)
@sudo $(TESTS_DIR)/$(BIN_DIR)/run_all_tests

@echo "\n-- SEPARATE LEAK TESTS --"
@$(MAKE) leaks

$(TEST_OBJS):
@$(CC) $(CFLAGS) -o $(TESTS_DIR)/$(BUILD_DIR)/$@ -c $(TESTS_DIR)/$*.c
@$(CC) $(CFLAGSTEST) -o $(TESTS_DIR)/$(BUILD_DIR)/$@ -c $(TESTS_DIR)/$*.c

leaks: CFLAGS := $(CFLAGSTEST)
leaks: clean dir $(NAME)
@sudo chmod +x $(TESTS_DIR)/leaks.sh
@sudo $(TESTS_DIR)/leaks.sh
@$(MAKE) clean

dir:
@mkdir -p $(BIN_DIR) $(BUILD_DIR) $(TESTS_DIR)/$(BIN_DIR) \
Expand All @@ -35,4 +44,4 @@ clean:
@rm -rf $(BUILD_DIR) $(BIN_DIR) $(TESTS_DIR)/$(BIN_DIR) \
$(TESTS_DIR)/$(BUILD_DIR)

.PHONY: dir test clean
.PHONY: dir test clean leaks
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ Disco is a cross-platform network utility available on Linux and macOS. It suppo
- [Usage](#usage)
- [Examples](#examples)
- [Testing](#testing)
- [Integration Tests](#integration-tests)
- [Memory Leak Tests](#memory-leak-tests)
- [Technical Details](#technical-details)
- [Address Resolution Protocol (ARP)](#address-resolution-protocol-arp)
- [ICMP Echo Request (Ping)](#icmp-echo-request-ping)
- [TCP SYN Scanning](#tcp-syn-scanning)
- [OS Fingerprinting](#os-fingerprinting)
- [Network Diagnostics](#network-diagnostics)

## Installation
1. Clone the repository
Expand Down Expand Up @@ -69,7 +73,7 @@ disco - network utility for host discovery and port enumeration
author: pilsnerfrajz

usage: disco target [-h] [-p ports] [-o] [-n] [-P] [-a] [-S]
[-w file] [-f]
[-w file] [-f]
options:
target : host to scan (IP address or domain)
-p, --ports : ports to scan, e.g., -p 1-1024 or -p 21,22,80
Expand Down Expand Up @@ -98,6 +102,8 @@ sudo ./bin/disco 127.0.0.1 -n -p 1-65535
```

## Testing

### Integration Tests
The program includes comprehensive **integration tests** that validate real network functionality. Run with `make test` from the project root to test:
- ARP
- Requests to LAN devices
Expand All @@ -111,13 +117,14 @@ The program includes comprehensive **integration tests** that validate real netw
- Port scan of IPv4/IPv6 localhost
- Port scan of LAN device
- Port scan of IPv4/IPv6 external hosts
- CLI
- Setting all available CLI arguments
- Printing of usage message with `-h` flag
- OS Fingerprinting
- Windows, Linux and BSD-like (e.g. macOS) systems
- Memory leaks (see Section [Memory Leak Tests](#memory-leak-tests))

Some tests may fail due to hardcoded IP addresses and port numbers not accessible or open on the targets in your network. Test cases that involve localhost or domains should still pass however.

The future plan is to implement these tests in a CI pipeline using Docker to ensure working features, regardless of device and network configurations.
### Memory Leak Tests
Memory leak tests are included to ensure proper memory management. These tests utilize the `AddressSanitizer` available in `clang`. Run with `make leaks` from the project root to execute leak tests with various argument combinations. Each test will report if any memory leaks were detected.

## Technical Details
Disco is implemented in C using `libpcap` for frame injection and packet filtering. This section describes the implementation of ARP, ping and port scanning in more detail for those interested.
Expand Down
6 changes: 6 additions & 0 deletions src/arp.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ int arp(char *address)
return PCAP_OPEN;
}

/* Free memory */
free(if_name);

if (pcap_inject(handle, &arp_frame, sizeof(arp_frame)) < 0)
{
pcap_close(handle);
Expand Down Expand Up @@ -210,6 +213,9 @@ int arp(char *address)
return PCAP_FILTER;
}

/* Free filter malloc */
pcap_freecode(&filter);

struct callback_data c_data = {0};
memcpy(&c_data.arp_frame, &arp_frame, sizeof(c_data.arp_frame));
c_data.reply_found = 0;
Expand Down
3 changes: 1 addition & 2 deletions src/ping.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,7 @@ int ping(char *address, int tries)
free(reply_hdr);
}
}

if (dst->ai_family == AF_INET6)
else if (dst->ai_family == AF_INET6)
{
for (int attempt = 0; attempt < tries; attempt++)
{
Expand Down
4 changes: 4 additions & 0 deletions src/syn_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,10 @@ static int pcap_filter_setup(char *address, struct src_info src_info)
{
return PCAP_FILTER;
}

/* Free filter malloc */
pcap_freecode(&filter);

return 0;
}

Expand Down
7 changes: 5 additions & 2 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,16 @@ struct addrinfo *get_dst_addr_struct(char *dst, int sock_type)
return NULL;
}

res->ai_addr = malloc(sizeof(struct addrinfo));
/* Clear struct in case there is garbage */
memset(res, 0, sizeof(struct addrinfo));

res->ai_addr = malloc(temp->ai_addrlen);
if (res->ai_addr == NULL)
{
freeaddrinfo(dst_info);
return NULL;
}
memcpy(res->ai_addr, temp->ai_addr, sizeof(struct addrinfo));
memcpy(res->ai_addr, temp->ai_addr, temp->ai_addrlen);
res->ai_family = temp->ai_family;
res->ai_addrlen = temp->ai_addrlen;

Expand Down
2 changes: 1 addition & 1 deletion tests/fingerprint_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

void fingerprint_tests(void)
{
printf("-- Fingerprint Tests --\n");
printf("-- FINGERPRINT TESTS --\n");

set_test_print_flag(0);

Expand Down
72 changes: 72 additions & 0 deletions tests/leaks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/bash

BIN="./bin/disco"

run_test() {
ERR_LOG=$(mktemp)

# run binary with argument
$BIN "$@" > /dev/null 2> "$ERR_LOG"
if grep -q "Sanitizer" "$ERR_LOG"; then
echo "❌ Leak test with arguments '$@': failed"
cat "$ERR_LOG"
exit 1
else
echo "✅ Leak test with arguments '$@': passed"
fi
rm -f "$ERR_LOG"
}

run_test "-h"
run_test --help
run_test

run_test localhost -P
run_test localhost --ping-only
run_test localhost -a
run_test localhost --arp-only
run_test localhost -S
run_test localhost --syn-only
run_test localhost -n

run_test localhost -p 80
run_test localhost -p 22,80,443
run_test localhost -p 1-100
run_test localhost -p 1-5,80,8080-8090

run_test localhost -p 0
run_test localhost -p 70000
run_test localhost -p 80,,22
run_test 0.0.0.0 -P
run_test 255.255.255.255 -P

run_test localhost -P -w out.txt
rm -f out.txt

run_test localhost -p 80 -o -f
run_test localhost -n -p 22,80 -w out.txt
rm -f out.txt

run_test 192.168.1.1 -P
run_test 192.168.1.1 --ping-only
run_test 192.168.1.1 -a
run_test 192.168.1.1 --arp-only
run_test 192.168.1.1 -S
run_test 192.168.1.1 --syn-only
run_test 192.168.1.1 -n

run_test 192.168.1.1 -p 80
run_test 192.168.1.1 -p 22,80,443
run_test 192.168.1.1 -p 1-100
run_test 192.168.1.1 -p 1-5,80,8080-8090

run_test 192.168.1.1 -p 0
run_test 192.168.1.1 -p 70000
run_test 192.168.1.1 -p 80,,22

run_test 192.168.1.1 -P -w out.txt
rm -f out.txt

run_test 192.168.1.1 -p 80 -o -f
run_test 192.168.1.1 -n -p 22,80 -w out.txt
rm -f out.txt
Loading