Skip to content

Commit

Permalink
Scan for DHCP and RA in parallel at the same time to shorten the over…
Browse files Browse the repository at this point in the history
…all runtime of the dhcp-discover tool

Signed-off-by: DL6ER <[email protected]>
  • Loading branch information
DL6ER committed Dec 5, 2024
1 parent 85d2e7f commit 7b1fc5e
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 47 deletions.
58 changes: 44 additions & 14 deletions src/tools/dhcp-discover.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@

// Maximum time we wait for incoming DHCPOFFERs
// (seconds)
#define DHCPOFFER_TIMEOUT 6
#define DHCPV6_TIMEOUT 4
#define SCAN_TIMEOUT 6

// How many threads do we spawn at maximum?
// This is also the limit for interfaces
Expand Down Expand Up @@ -571,7 +570,7 @@ static void get_dhcp_offer(const int sock, const uint32_t xid, const char *iface
time(&start_time);

// receive as many responses as we can
while(time(&current_time) && (current_time-start_time) < DHCPOFFER_TIMEOUT)
while(time(&current_time) && (current_time-start_time) < SCAN_TIMEOUT)
{
memset(&source, 0, sizeof(source));
memset(&offer_packet, 0, sizeof(offer_packet));
Expand Down Expand Up @@ -675,10 +674,16 @@ static void get_dhcp_offer(const int sock, const uint32_t xid, const char *iface
#endif
}

static void *dhcp_discover_iface(void *args)
static void *dhcp_discover_iface_v4(void *args)
{
// Get interface details
const char *iface = ((struct ifaddrs*)args)->ifa_name;
char *thread_name = malloc(strlen(iface) + 4);
sprintf(thread_name, "%s-v4", iface);

// Set interface name as thread name
prctl(PR_SET_NAME, thread_name, 0, 0, 0);
free(thread_name);

// Set interface name as thread name
prctl(PR_SET_NAME, iface, 0, 0, 0);
Expand Down Expand Up @@ -710,11 +715,24 @@ static void *dhcp_discover_iface(void *args)
if(dhcp_socket > 0)
close(dhcp_socket);

pthread_exit(NULL);
}

static void *dhcp_discover_iface_v6(void *args)
{
// Get interface details
const char *iface = ((struct ifaddrs*)args)->ifa_name;
char *thread_name = malloc(strlen(iface) + 4);
sprintf(thread_name, "%s-v6", iface);

// Set interface name as thread name
prctl(PR_SET_NAME, thread_name, 0, 0, 0);
free(thread_name);

// Perform the same scan for DHCPv6
const int responses = dhcpv6_discover_iface(iface, DHCPV6_TIMEOUT);
if(responses > -1)
printf("DHCPv6 packets received on %s%s%s: %i\n",
cli_bold(), iface, cli_normal(), responses);
const int responses = dhcpv6_discover_iface(iface, SCAN_TIMEOUT);
printf("RAs received on %s%s%s: %i\n",
cli_bold(), iface, cli_normal(), responses);

pthread_exit(NULL);
}
Expand All @@ -741,12 +759,12 @@ int run_dhcp_discover(void)
// Only print to terminal, disable log file
log_ctrl(false, true);

printf("Scanning all your interfaces for DHCPv4 and DHCPv6 servers\n");
printf("Timeout: %d + %d seconds\n", DHCPOFFER_TIMEOUT, DHCPV6_TIMEOUT);
printf("Scanning all your interfaces for DHCP servers and IPv6 routers\n");
printf("Timeout: %d seconds\n", SCAN_TIMEOUT);

// Get interface names for available interfaces on this machine
// and launch a thread for each one
pthread_t scanthread[MAXTHREADS];
pthread_t scanthread[2*MAXTHREADS];
pthread_attr_t attr;
// Initialize thread attributes object with default attribute values
pthread_attr_init(&attr);
Expand Down Expand Up @@ -784,10 +802,19 @@ int run_dhcp_discover(void)
continue;
}

// Create a probing thread for this interface
if(pthread_create(&scanthread[tid], &attr, dhcp_discover_iface, tmp ) != 0)
// Create a DHCP probing thread for this interface
if(pthread_create(&scanthread[tid], &attr, dhcp_discover_iface_v4, tmp ) != 0)
{
printf_locked("Unable to launch thread for interface %s, skipping...",
printf_locked("Unable to launch DHCP thread for interface %s, skipping...",
tmp->ifa_name);
tmp = tmp->ifa_next;
continue;
}

// Create a RA probing thread for this interface
if(pthread_create(&scanthread[2*tid], &attr, dhcp_discover_iface_v6, tmp ) != 0)
{
printf_locked("Unable to launch RA thread for interface %s, skipping...",
tmp->ifa_name);
tmp = tmp->ifa_next;
continue;
Expand All @@ -803,7 +830,10 @@ int run_dhcp_discover(void)

// Wait for all threads to join back with us
for(tid--; tid > -1; tid--)
{
pthread_join(scanthread[tid], NULL);
pthread_join(scanthread[2*tid], NULL);
}

// Free linked-list of interfaces on this client
freeifaddrs(addrs);
Expand Down
74 changes: 41 additions & 33 deletions src/tools/dhcpv6-discover.c
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ static ssize_t recv_adv(int fd, const struct sockaddr_in6 *tgt, const char *ifna
unsigned responses = 0;

// Get the current time and add the timeout
clock_gettime (CLOCK_MONOTONIC, &end);
clock_gettime(CLOCK_MONOTONIC, &end);
end.tv_sec += timeout;

// Receiving packets until timeout
Expand All @@ -665,16 +665,21 @@ static ssize_t recv_adv(int fd, const struct sockaddr_in6 *tgt, const char *ifna
if (val < 0) val = 0;
}

// Wait for reply
// Wait for reply (retries on EINTR)
struct pollfd pollfd = { .fd = fd, .events = POLLIN, .revents = 0 };
val = poll(&pollfd, 1, val);
do {
val = poll(&pollfd, 1, val);
} while (val == -1 && errno == EINTR);

// Check for errors
if (val < 0)
if(val < 0)
{
perror("Polling for ICMPv6 packet");
break;
}

// Check for timeout
if (val == 0)
if(val == 0)
return responses;

// Received a packet
Expand Down Expand Up @@ -721,7 +726,6 @@ static ssize_t recv_adv(int fd, const struct sockaddr_in6 *tgt, const char *ifna
*/
static int do_discoverv6(const int fd, const char *ifname, const unsigned int timeout)
{
unsigned int retry = 3;
struct sockaddr_in6 tgt = { 0 };

// Automatically close the socket on exec
Expand Down Expand Up @@ -749,7 +753,10 @@ static int do_discoverv6(const int fd, const char *ifname, const unsigned int ti
// Resolves target's IPv6 address
const char *hostname = "ff02::2"; // All routers multicast address
if(get_ipv6_by_name(hostname, ifname, &tgt) != 0)
goto error;
{
close(fd);
return -1;
}

char s[INET6_ADDRSTRLEN] = { 0 };
inet_ntop (AF_INET6, &tgt.sin6_addr, s, sizeof (s));
Expand All @@ -762,39 +769,40 @@ static int do_discoverv6(const int fd, const char *ifname, const unsigned int ti
// Build a Router Solicitation message
const ssize_t plen = build_solicit(&packet);
if(plen == -1)
goto error;
{
close(fd);
return -1;
}

while(retry > 0)
/* sends a Solitication */
if(sendto(fd, &packet, plen, 0,
(const struct sockaddr *)&dst,
sizeof(dst)) != plen)
{
/* sends a Solitication */
if(sendto(fd, &packet, plen, 0,
(const struct sockaddr *)&dst,
sizeof(dst)) != plen)
{
perror("Sending ICMPv6 packet");
goto error;
}
retry--;
perror("Sending ICMPv6 packet");
close(fd);
return -1;
}

/* receives an Advertisement */
const ssize_t val = recv_adv(fd, &tgt, ifname, timeout);
if(val > 0)
{
close(fd);
return val;
}
// else if(val == 0) // Timed out
if(val < 0)
goto error;
/* receives an Advertisement */
const ssize_t val = recv_adv(fd, &tgt, ifname, timeout);
if(val > 0)
{
close(fd);
return val;
}
// else if(val == 0) // Timed out
if(val < 0)
{
// Error
perror("Receiving ICMPv6 packet");
close(fd);
return -1;
}

close(fd);
// No DHCPv6 responses received
return 0;

error:
close(fd);
return -1;
return 0;
}

int dhcpv6_discover_iface(const char *ifname, const unsigned int timeout)
Expand Down

0 comments on commit 7b1fc5e

Please sign in to comment.