+++ /dev/null
-##dhcp-probe-01-pcap-loop.patch - wrap pcap_dispatch in a loop
---- src/dhcp_probe.c 2009-08-16 12:24:10.000000000 +0300
-+++ src/dhcp_probe.c 2009-08-16 11:52:26.000000000 +0300
-@@ -59,6 +59,7 @@
- volatile sig_atomic_t reopen_log_file; /* for signal handler */
- volatile sig_atomic_t reopen_capture_file; /* for signal handler */
- volatile sig_atomic_t quit_requested; /* for signal requested */
-+volatile sig_atomic_t alarm_fired; /* for signal requested */
-
- pcap_t *pd = NULL; /* libpcap - packet capture descriptor used for actual packet capture */
- pcap_t *pd_template = NULL; /* libpcap - packet capture descriptor just used as template */
-@@ -74,6 +75,27 @@
- int use_8021q = 0;
- int vlan_id = 0;
-
-+/* capture packets from pcap for timeout seconds */
-+int
-+loop_for_packets(int timeout)
-+{
-+ int packets_recv = 0;
-+
-+ alarm_fired = 0;
-+ alarm(timeout);
-+
-+ do {
-+ int pcap_rc = pcap_dispatch(pd, -1, process_response, NULL);
-+ if (pcap_rc == -1)
-+ report(LOG_ERR, "pcap_dispatch(): %s", pcap_geterr(pd));
-+ else if (pcap_rc > 0)
-+ packets_recv += pcap_rc;
-+ } while(! alarm_fired && !quit_requested);
-+
-+ return packets_recv;
-+}
-+
-+
- int
- main(int argc, char **argv)
- {
-@@ -84,7 +106,6 @@
- struct sigaction sa;
- FILE *pid_fp;
- char *cwd = CWD;
-- int i;
-
- int write_packet_len;
- int bytes_written;
-@@ -98,9 +119,6 @@
- int linktype;
- char pcap_errbuf[PCAP_ERRBUF_SIZE], pcap_errbuf2[PCAP_ERRBUF_SIZE];
-
-- /* for libnet */
-- char libnet_errbuf[LIBNET_ERRBUF_SIZE];
--
- /* get progname = last component of argv[0] */
- prog = strrchr(argv[0], '/');
- if (prog)
-@@ -265,6 +283,8 @@
- reread_config_file = 0; /* set by signal handler */
- reopen_log_file = 0; /* set by signal handler */
- reopen_capture_file = 0; /* set by signal handler */
-+ quit_requested = 0;
-+ alarm_fired = 0;
-
- ifname = strdup(argv[optind]); /* interface name is a required final argument */
-
-@@ -332,6 +352,13 @@
- report(LOG_ERR, "sigaction: %s", get_errmsg());
- my_exit(1, 1, 1);
- }
-+ sigemptyset(&sa.sa_mask);
-+ sa.sa_handler = catcher;
-+ sa.sa_flags = 0;
-+ if (sigaction(SIGALRM, &sa, NULL) < 0) {
-+ report(LOG_ERR, "sigaction: %s", get_errmsg());
-+ my_exit(1, 1, 1);
-+ }
-
-
-
-@@ -479,8 +506,9 @@
-
- for (l = libnet_cq_head(); libnet_cq_last(); l = libnet_cq_next()) { /* write one flavor packet and listen for answers */
-
-- int pcap_rc;
-+ int packets_recv;
- int pcap_open_retries;
-+
-
- /* We set up for packet capture BEFORE writing our packet, to minimize the delay
- between our writing and when we are able to start capturing. (I cannot tell from
-@@ -569,33 +597,16 @@
- report(LOG_DEBUG, "listening for answers for %d milliseconds", GetResponse_wait_time());
-
-
-- /* XXX I often find that pcap_dispatch() returns well before the timeout specified earlier.
-- I ensure that there's no alarm() still left over before we start, and also ensure we don't
-- get interrupted by SIGCHLD (possible since process_response() could fork an alert_program or alert_program2 child).
-- But we STILL often return from pcap_dispatch() too soon!
-- April 2001: An update to the pcap(3) man page around version 0.6 (?), along with postings
-- on the tcpdump workers mailing list explains what's going on. The timeout specified in
-- pcap_open_live() isn't a timeout in the sense one might expect. The pcap_dispatch() call
-- can return sooner than expected (even immediately), or if no packets are received, might
-- never return at all; the behavior is platform-dependant. I don't have a way to work
-- around this issue; it means this program just won't work reliably (or at all) on some
-- platforms.
-- */
--
-- alarm(0); /* just in case a previous alarm was still left */
--
- sigemptyset(&new_sigset);
- sigaddset(&new_sigset, SIGCHLD);
- sigprocmask(SIG_BLOCK, &new_sigset, &old_sigset); /* block SIGCHLD */
-
-- pcap_rc = pcap_dispatch(pd, -1, process_response, NULL);
-+ packets_recv = loop_for_packets(GetResponse_wait_time() / 1000);;
-
- sigprocmask(SIG_SETMASK, &old_sigset, NULL); /* unblock SIGCHLD */
-
-- if (pcap_rc < 0)
-- report(LOG_ERR, "pcap_dispatch(): %s", pcap_geterr(pd));
-- else if (debug > 10)
-- report(LOG_DEBUG, "done listening, captured %d packets", pcap_rc);
-+ if (debug > 10)
-+ report(LOG_DEBUG, "done listening, captured %d packets", packets_recv);
-
- /* I was hoping that perhaps pcap_stats() would return a nonzero number of packets dropped when
- the buffer size specified to pcap_open_live() turns out to be too small -- so we could
-@@ -688,6 +699,7 @@
- pcap_close(pd_template);
-
- my_exit(0, 1, 1);
-+ return 0; /* make gcc happy */
- }
-
-
-@@ -986,9 +998,6 @@
- /* Perform all necessary functions to handle a request to reconfigure.
- Must not be called until after initial configuration is complete.
- */
--
-- int i;
--
- if (! read_configfile(config_file)) {
- my_exit(1, 1, 1);
- }
-@@ -1050,8 +1059,14 @@
-
- if ((sig == SIGINT) || (sig == SIGTERM) || (sig == SIGQUIT)) { /* quit gracefully */
- quit_requested = 1;
-+ /* pcap wraps the socket read inside a loop, so the signal doesn't
-+ interrupt it without an explicit call to pcap_breakloop */
-+ pcap_breakloop(pd);
-+ return;
-+ } else if (sig == SIGALRM) { /* timer */
-+ pcap_breakloop(pd);
-+ alarm_fired = 1;
- return;
--
- } else if (sig == SIGHUP) { /* re-read config file */
- /* Doing the reread while in the signal handler is way too dangerous.
- We'll do it at the start or end of the next main event loop.
-
-
##dhcp-probe-02-keep-pcap.patch - add option to keep pcap open all the time
---- src/dhcp_probe.c.01 2009-08-16 11:52:26.000000000 +0300
-+++ src/dhcp_probe.c 2009-08-16 12:31:22.000000000 +0300
-@@ -49,6 +49,7 @@
+--- src/dhcp_probe.c.orig 2021-01-18 20:17:29.000000000 +0100
++++ src/dhcp_probe.c 2024-04-20 21:59:22.184598775 +0200
+@@ -49,6 +49,7 @@ char *capture_file = NULL;
*/
int snaplen = CAPTURE_BUFSIZE;
int socket_receive_timeout_feature = 0;
char *prog = NULL;
char *logfile_name = NULL;
-@@ -75,6 +76,89 @@
+@@ -75,6 +76,113 @@ struct ether_addr my_eaddr;
int use_8021q = 0;
int vlan_id = 0;
+ return promiscuous;
+}
+
-+int init_pcap(int promiscuous, bpf_u_int32 netmask)
++int init_pcap(int promiscuous)
+{
+ /* open packet capture descriptor */
+ /* XXX On Solaris 7, sometimes pcap_open_live() fails with a message like:
+ } /* failure */
+ } while (pcap_open_retries--);
+
-+
+ if (pcap_errbuf[0] != '\0')
+ /* even on success, a warning may be produced */
+ report(LOG_WARNING, "pcap_open_live(%s): succeeded but with warning: %s", ifname, pcap_errbuf);
+ /* make sure this interface is ethernet */
+ linktype = pcap_datalink(pd);
+ if (linktype != DLT_EN10MB) {
++ /* In libpcap 0.9.8 on Solaris 9 SPARC, this only happened if you pointed us to an interface
++ that truly had the wrong datalink type.
++ It was not a transient error, so we exited.
++ However, by libpcap version 1.1.1 on Solaris 9 SPARC, this happens from time to time;
++ pcap_datalink() returns 0, indicating DLT_NULL.
++ Perhaps that's a bug introduced after libpcap 0.9.8.
++ As this seems to be a transient error, we no longer exit, but instead just log the error,
++ and skip the rest of the current cycle.
++ A side effect of this change is that when you DO mistakenly point dhcp_probe to
++ a non-Ethernet interface (the error is not transient), we keep trying instead
++ of exiting. If a future libpcap change returns to the old behavior (where the
++ interface type remains consistent), we should go back to the old behavior of exiting.
++ */
++ /*
+ report(LOG_ERR, "interface %s link layer type %d not ethernet", ifname, linktype);
+ my_exit(1, 1, 1);
++ */
++ report(LOG_ERR, "interface %s link layer type %d not ethernet, skipping rest of this probe cycle", ifname, linktype);
++ return -1; /* break for (l) ... */
+ }
+ /* compile bpf filter to select just udp/ip traffic to udp port bootpc */
-+ if (pcap_compile(pd, &bpf_code, "udp dst port bootpc", 1, netmask) < 0) {
++ /* Although one would expect frames on an untagged logical network interface to arrive without any 802.1Q tag,
++ some Ethernet drivers will deliver some frames with an 802.1Q tag in which vlan==0.
++ This may be because the frame arrived with an 802.1Q tag in which the 802.1p priority was non-zero.
++ To preserve that priority field, they retain the 802.1Q tag and set the vlan field to 0.
++ As per spec, a frame received with 802.1Q tag in which vlan == 0 should be treated as an untagged frame.
++ So our bpf filter needs to include both untagged and tagged frames.
++ */
++ if (pcap_compile(pd, &bpf_code, "udp dst port bootpc or (vlan and udp dst port bootpc)", 1, PCAP_NETMASK_UNKNOWN) < 0) {
+ report(LOG_ERR, "pcap_compile: %s", pcap_geterr(pd));
+ my_exit(1, 1, 1);
+ }
+reset_pcap()
+{
+ /* close packet capture descriptor */
-+ pcap_close(pd);
++ pcap_close(pd);
++ pd = NULL;
+}
+
- /* capture packets from pcap for timeout seconds */
int
- loop_for_packets(int timeout)
-@@ -115,8 +199,6 @@
+ main(int argc, char **argv)
+ {
+@@ -93,8 +201,6 @@ main(int argc, char **argv)
+ int receive_and_process_responses_rc;
/* for libpcap */
- bpf_u_int32 netnumber, netmask;
- struct bpf_program bpf_code;
- int linktype;
char pcap_errbuf[PCAP_ERRBUF_SIZE], pcap_errbuf2[PCAP_ERRBUF_SIZE];
/* get progname = last component of argv[0] */
-@@ -126,7 +208,7 @@
+@@ -104,7 +210,7 @@ main(int argc, char **argv)
else
prog = argv[0];
switch (c) {
case 'c':
if (optarg[0] != '/') {
-@@ -151,6 +233,9 @@
+@@ -129,6 +235,9 @@ main(int argc, char **argv)
case 'h':
usage();
my_exit(0, 0, 0);
case 'l':
if (optarg[0] != '/') {
fprintf(stderr, "%s: invalid log file '%s', must be an absolute pathname\n", prog, optarg);
-@@ -447,8 +532,10 @@
+@@ -435,8 +544,10 @@ main(int argc, char **argv)
}
}
+ if (keep_pcap)
-+ init_pcap(need_promiscuous(), netmask);
++ init_pcap(need_promiscuous());
+
while (1) { /* MAIN EVENT LOOP */
- int promiscuous;
libnet_t *l; /* to iterate through libnet context queue */
/* struct pcap_stat ps; */ /* to hold pcap stats */
-@@ -489,26 +576,9 @@
+@@ -477,25 +588,9 @@ main(int argc, char **argv)
interface in promiscuous mode as little as possible, since that can affect the host's performance.
*/
int packets_recv;
- int pcap_open_retries;
--
/* We set up for packet capture BEFORE writing our packet, to minimize the delay
between our writing and when we are able to start capturing. (I cannot tell from
-@@ -518,54 +588,9 @@
+@@ -505,78 +600,10 @@ main(int argc, char **argv)
we wanted!
*/
- sleep(PCAP_OPEN_LIVE_RETRY_DELAY); /* before next retry */
- }
- } /* failure */
-- }
++ if (! keep_pcap) {
++ if (init_pcap(need_promiscuous()))
++ break; /* for l... */
+ }
- if (pcap_errbuf[0] != '\0')
- /* even on success, a warning may be produced */
- report(LOG_WARNING, "pcap_open_live(%s): succeeded but with warning: %s", ifname, pcap_errbuf);
- /* make sure this interface is ethernet */
- linktype = pcap_datalink(pd);
- if (linktype != DLT_EN10MB) {
+- /* In libpcap 0.9.8 on Solaris 9 SPARC, this only happened if you pointed us to an interface
+- that truly had the wrong datalink type.
+- It was not a transient error, so we exited.
+- However, by libpcap version 1.1.1 on Solaris 9 SPARC, this happens from time to time;
+- pcap_datalink() returns 0, indicating DLT_NULL.
+- Perhaps that's a bug introduced after libpcap 0.9.8.
+- As this seems to be a transient error, we no longer exit, but instead just log the error,
+- and skip the rest of the current cycle.
+- A side effect of this change is that when you DO mistakenly point dhcp_probe to
+- a non-Ethernet interface (the error is not transient), we keep trying instead
+- of exiting. If a future libpcap change returns to the old behavior (where the
+- interface type remains consistent), we should go back to the old behavior of exiting.
+- */
+- /*
- report(LOG_ERR, "interface %s link layer type %d not ethernet", ifname, linktype);
- my_exit(1, 1, 1);
+- */
+- report(LOG_ERR, "interface %s link layer type %d not ethernet, skipping rest of this probe cycle", ifname, linktype);
+- break; /* for (l) ... */
- }
+-
- /* compile bpf filter to select just udp/ip traffic to udp port bootpc */
-- if (pcap_compile(pd, &bpf_code, "udp dst port bootpc", 1, netmask) < 0) {
+- /* Although one would expect frames on an untagged logical network interface to arrive without any 802.1Q tag,
+- some Ethernet drivers will deliver some frames with an 802.1Q tag in which vlan==0.
+- This may be because the frame arrived with an 802.1Q tag in which the 802.1p priority was non-zero.
+- To preserve that priority field, they retain the 802.1Q tag and set the vlan field to 0.
+- As per spec, a frame received with 802.1Q tag in which vlan == 0 should be treated as an untagged frame.
+- So our bpf filter needs to include both untagged and tagged frames.
+- */
+- if (pcap_compile(pd, &bpf_code, "udp dst port bootpc or (vlan and udp dst port bootpc)", 1, PCAP_NETMASK_UNKNOWN) < 0) {
- report(LOG_ERR, "pcap_compile: %s", pcap_geterr(pd));
- my_exit(1, 1, 1);
- }
- }
- if (socket_receive_timeout_feature)
- set_pcap_timeout(pd);
--
-+ if (! keep_pcap)
-+ init_pcap(need_promiscuous(), netmask);
-+
+
/* write one packet */
- if (debug > 10)
-@@ -621,7 +646,8 @@
+@@ -630,8 +657,8 @@ main(int argc, char **argv)
*/
/* close packet capture descriptor */
- pcap_close(pd);
+- pd = NULL;
+ if (! keep_pcap)
+ reset_pcap();
- /* check for 'quit' request after each packet, since waiting until end of probe cycle
+ /* check for 'quit' request after sending each packet, since waiting until end of probe cycle
would impose a substantial delay. */
-@@ -669,7 +695,7 @@
+@@ -679,7 +706,7 @@ main(int argc, char **argv)
reconfigure(write_packet_len);
reread_config_file = 0;
}
/* We allow must signals that come in during our sleep() to interrupt us. E.g. we want to cut short
our sleep when we're signalled to exit. But we must block SIGCHLD during our sleep. That's because
if we forked an alert_program or alert_program2 child above, its termination will likely happen while we're sleeping;
-@@ -684,7 +710,19 @@
+@@ -694,7 +721,21 @@ main(int argc, char **argv)
sigaddset(&new_sigset, SIGCHLD);
sigprocmask(SIG_BLOCK, &new_sigset, &old_sigset); /* block SIGCHLD */
+ waiting. We shouldn't get any since we don't send any requests
+ but this should prevent any buffers from accidentally filling
+ with unhandled packets. */
-+ int packets_recv = loop_for_packets(time_to_sleep);
++ int packets_recv = 0, receive_and_process_responses_rc;
++ if ((receive_and_process_responses_rc = receive_and_process_responses(time_to_sleep)) >= 0)
++ packets_recv = receive_and_process_responses_rc;
+
+ if (packets_recv && debug > 10)
+ report(LOG_DEBUG, "captured %d packets while sleeping", packets_recv);
sigprocmask(SIG_SETMASK, &old_sigset, NULL); /* unblock SIGCHLD */
-@@ -692,8 +730,10 @@
+@@ -702,8 +743,10 @@ main(int argc, char **argv)
} /* MAIN EVENT LOOP */
if (pd_template) /* only used if a capture file requested */
pcap_close(pd_template);
-@@ -1142,6 +1182,7 @@
+@@ -1284,6 +1327,7 @@ usage(void)
fprintf(stderr, " -d debuglevel enable debugging at specified level\n");
fprintf(stderr, " -f don't fork (only use for debugging)\n");
fprintf(stderr, " -h display this help message then exit\n");
##dhcp-probe-03-drop-privs.patch - add option to change uid after setup
---- src/dhcp_probe.c.02 2009-08-16 12:31:22.000000000 +0300
-+++ src/dhcp_probe.c 2009-08-16 13:47:29.000000000 +0300
+--- src/dhcp_probe.c.orig 2024-04-20 21:59:54.841088526 +0200
++++ src/dhcp_probe.c 2024-04-20 22:23:32.870073070 +0200
@@ -26,6 +26,9 @@
#include "report.h"
#include "utils.h"
+
#ifndef lint
static const char rcsid[] = "dhcp_probe version " VERSION;
- static const char copyright[] = "Copyright 2000-2008, The Trustees of Princeton University. All rights reserved.";
-@@ -50,6 +53,8 @@
+ static const char copyright[] = "Copyright 2000-2021, The Trustees of Princeton University. All rights reserved.";
+@@ -50,6 +53,8 @@ char *capture_file = NULL;
int snaplen = CAPTURE_BUFSIZE;
int socket_receive_timeout_feature = 0;
int keep_pcap = 0;
char *prog = NULL;
char *logfile_name = NULL;
-@@ -179,6 +184,40 @@
- return packets_recv;
+@@ -183,6 +188,41 @@ reset_pcap()
+ pd = NULL;
}
+/* drop privileges */
+ fclose(pid_fp);
+ }
+}
-
++
int
main(int argc, char **argv)
-@@ -188,7 +227,6 @@
+ {
+@@ -190,7 +230,6 @@ main(int argc, char **argv)
extern char *optarg;
extern int optind, opterr, optopt;
struct sigaction sa;
char *cwd = CWD;
int write_packet_len;
-@@ -208,7 +246,7 @@
+@@ -210,7 +249,7 @@ main(int argc, char **argv)
else
prog = argv[0];
switch (c) {
case 'c':
if (optarg[0] != '/') {
-@@ -283,6 +321,10 @@
+@@ -285,6 +324,10 @@ main(int argc, char **argv)
}
break;
}
case 'T':
socket_receive_timeout_feature = 1;
break;
-@@ -351,16 +393,6 @@
+@@ -353,16 +396,6 @@ main(int argc, char **argv)
my_exit(1, 0, 1);
}
if (! read_configfile(config_file)) {
my_exit(1, 1, 1);
}
-@@ -535,6 +567,12 @@
+@@ -547,6 +580,12 @@ main(int argc, char **argv)
if (keep_pcap)
- init_pcap(need_promiscuous(), netmask);
+ init_pcap(need_promiscuous());
+ if (drop_privs)
+ drop_privileges(username);
while (1) { /* MAIN EVENT LOOP */
libnet_t *l; /* to iterate through libnet context queue */
/* struct pcap_stat ps; */ /* to hold pcap stats */
-@@ -1189,6 +1227,7 @@
+@@ -1332,6 +1371,7 @@ usage(void)
fprintf(stderr, " -Q vlan_id tag outgoing frames with an 802.1Q VLAN ID\n");
fprintf(stderr, " -s capture_bufsize override default capture bufsize [%d]\n", CAPTURE_BUFSIZE);
fprintf(stderr, " -T enable the socket receive timeout feature\n");