1 ##dhcp-probe-02-keep-pcap.patch - add option to keep pcap open all the time
2 --- src/dhcp_probe.c.01 2009-08-16 11:52:26.000000000 +0300
3 +++ src/dhcp_probe.c 2009-08-16 12:31:22.000000000 +0300
6 int snaplen = CAPTURE_BUFSIZE;
7 int socket_receive_timeout_feature = 0;
11 char *logfile_name = NULL;
16 +int need_promiscuous(void)
18 + /* If we're going to claim a chaddr different than my_eaddr, some of the responses
19 + may come back to chaddr (as opposed to my_eaddr or broadcast), so we'll need to
20 + listen promiscuously.
21 + If we're going to claim an ether_src different than my_eaddr, in theory that should
22 + make no difference; bootp/dhcp servers should rely on chaddr, not ether_src. Still,
23 + it's possible there's a server out there that does it wrong, and might therefore mistakenly
24 + send responses to ether_src. So lets also listen promiscuously if ether_src != my_eaddr.
26 + int promiscuous = 0;
27 + if (bcmp(GetChaddr(), &my_eaddr, sizeof(struct ether_addr)) ||
28 + bcmp(GetEther_src(), &my_eaddr, sizeof(struct ether_addr)))
33 +int init_pcap(int promiscuous, bpf_u_int32 netmask)
35 + /* open packet capture descriptor */
36 + /* XXX On Solaris 7, sometimes pcap_open_live() fails with a message like:
37 + pcap_open_live qfe0: recv_ack: info unexpected primitive ack 0x8
38 + It's not clear what causes this, or what the 0x8 code indicates.
39 + The error appears to be transient; retrying sometimes will work, so I've wrapped the call in a retry loop.
40 + I've also added a delay after each failure; perhaps the failure has something to do with the fact that
41 + we call pcap_open_live() so soon after pcap_close() (for the second and succeeding packets in each cycle);
42 + adding a delay might help in that case.
44 + struct bpf_program bpf_code;
45 + char pcap_errbuf[PCAP_ERRBUF_SIZE];
47 + int pcap_open_retries = PCAP_OPEN_LIVE_RETRY_MAX;
50 + pcap_errbuf[0] = '\0'; /* so we can tell if a warning was produced on success */
51 + if ((pd = pcap_open_live(ifname, snaplen, promiscuous, GetResponse_wait_time(), pcap_errbuf)) != NULL) {
52 + break; /* success */
53 + } else { /* failure */
54 + if (pcap_open_retries == 0) {
55 + report(LOG_DEBUG, "pcap_open_live(%s): %s; retry count (%d) exceeded, giving up", ifname, pcap_errbuf, PCAP_OPEN_LIVE_RETRY_MAX);
59 + report(LOG_DEBUG, "pcap_open_live(%s): %s; will retry", ifname, pcap_errbuf);
60 + sleep(PCAP_OPEN_LIVE_RETRY_DELAY); /* before next retry */
63 + } while (pcap_open_retries--);
66 + if (pcap_errbuf[0] != '\0')
67 + /* even on success, a warning may be produced */
68 + report(LOG_WARNING, "pcap_open_live(%s): succeeded but with warning: %s", ifname, pcap_errbuf);
70 + /* make sure this interface is ethernet */
71 + linktype = pcap_datalink(pd);
72 + if (linktype != DLT_EN10MB) {
73 + report(LOG_ERR, "interface %s link layer type %d not ethernet", ifname, linktype);
76 + /* compile bpf filter to select just udp/ip traffic to udp port bootpc */
77 + if (pcap_compile(pd, &bpf_code, "udp dst port bootpc", 1, netmask) < 0) {
78 + report(LOG_ERR, "pcap_compile: %s", pcap_geterr(pd));
81 + /* install compiled filter */
82 + if (pcap_setfilter(pd, &bpf_code) < 0) {
83 + report(LOG_ERR, "pcap_setfilter: %s", pcap_geterr(pd));
86 + if (socket_receive_timeout_feature)
87 + set_pcap_timeout(pd);
95 + /* close packet capture descriptor */
99 /* capture packets from pcap for timeout seconds */
101 loop_for_packets(int timeout)
105 bpf_u_int32 netnumber, netmask;
106 - struct bpf_program bpf_code;
108 char pcap_errbuf[PCAP_ERRBUF_SIZE], pcap_errbuf2[PCAP_ERRBUF_SIZE];
110 /* get progname = last component of argv[0] */
115 - while ((c = getopt(argc, argv, "c:d:fhl:o:p:Q:s:Tvw:")) != EOF) {
116 + while ((c = getopt(argc, argv, "c:d:fhkl:o:p:Q:s:Tvw:")) != EOF) {
119 if (optarg[0] != '/') {
128 if (optarg[0] != '/') {
129 fprintf(stderr, "%s: invalid log file '%s', must be an absolute pathname\n", prog, optarg);
135 + init_pcap(need_promiscuous(), netmask);
137 while (1) { /* MAIN EVENT LOOP */
139 libnet_t *l; /* to iterate through libnet context queue */
140 /* struct pcap_stat ps; */ /* to hold pcap stats */
143 interface in promiscuous mode as little as possible, since that can affect the host's performance.
146 - /* If we're going to claim a chaddr different than my_eaddr, some of the responses
147 - may come back to chaddr (as opposed to my_eaddr or broadcast), so we'll need to
148 - listen promiscuously.
149 - If we're going to claim an ether_src different than my_eaddr, in theory that should
150 - make no difference; bootp/dhcp servers should rely on chaddr, not ether_src. Still,
151 - it's possible there's a server out there that does it wrong, and might therefore mistakenly
152 - send responses to ether_src. So lets also listen promiscuously if ether_src != my_eaddr.
154 - if (bcmp(GetChaddr(), &my_eaddr, sizeof(struct ether_addr)) ||
155 - bcmp(GetEther_src(), &my_eaddr, sizeof(struct ether_addr)))
161 for (l = libnet_cq_head(); libnet_cq_last(); l = libnet_cq_next()) { /* write one flavor packet and listen for answers */
164 - int pcap_open_retries;
167 /* We set up for packet capture BEFORE writing our packet, to minimize the delay
168 between our writing and when we are able to start capturing. (I cannot tell from
173 - /* open packet capture descriptor */
174 - /* XXX On Solaris 7, sometimes pcap_open_live() fails with a message like:
175 - pcap_open_live qfe0: recv_ack: info unexpected primitive ack 0x8
176 - It's not clear what causes this, or what the 0x8 code indicates.
177 - The error appears to be transient; retrying sometimes will work, so I've wrapped the call in a retry loop.
178 - I've also added a delay after each failure; perhaps the failure has something to do with the fact that
179 - we call pcap_open_live() so soon after pcap_close() (for the second and succeeding packets in each cycle);
180 - adding a delay might help in that case.
182 - pcap_open_retries = PCAP_OPEN_LIVE_RETRY_MAX;
183 - while (pcap_open_retries--) {
184 - pcap_errbuf[0] = '\0'; /* so we can tell if a warning was produced on success */
185 - if ((pd = pcap_open_live(ifname, snaplen, promiscuous, GetResponse_wait_time(), pcap_errbuf)) != NULL) {
186 - break; /* success */
187 - } else { /* failure */
188 - if (pcap_open_retries == 0) {
189 - report(LOG_DEBUG, "pcap_open_live(%s): %s; retry count (%d) exceeded, giving up", ifname, pcap_errbuf, PCAP_OPEN_LIVE_RETRY_MAX);
193 - report(LOG_DEBUG, "pcap_open_live(%s): %s; will retry", ifname, pcap_errbuf);
194 - sleep(PCAP_OPEN_LIVE_RETRY_DELAY); /* before next retry */
198 - if (pcap_errbuf[0] != '\0')
199 - /* even on success, a warning may be produced */
200 - report(LOG_WARNING, "pcap_open_live(%s): succeeded but with warning: %s", ifname, pcap_errbuf);
202 - /* make sure this interface is ethernet */
203 - linktype = pcap_datalink(pd);
204 - if (linktype != DLT_EN10MB) {
205 - report(LOG_ERR, "interface %s link layer type %d not ethernet", ifname, linktype);
208 - /* compile bpf filter to select just udp/ip traffic to udp port bootpc */
209 - if (pcap_compile(pd, &bpf_code, "udp dst port bootpc", 1, netmask) < 0) {
210 - report(LOG_ERR, "pcap_compile: %s", pcap_geterr(pd));
213 - /* install compiled filter */
214 - if (pcap_setfilter(pd, &bpf_code) < 0) {
215 - report(LOG_ERR, "pcap_setfilter: %s", pcap_geterr(pd));
218 - if (socket_receive_timeout_feature)
219 - set_pcap_timeout(pd);
222 + init_pcap(need_promiscuous(), netmask);
224 /* write one packet */
230 /* close packet capture descriptor */
235 /* check for 'quit' request after each packet, since waiting until end of probe cycle
236 would impose a substantial delay. */
238 reconfigure(write_packet_len);
239 reread_config_file = 0;
243 /* We allow must signals that come in during our sleep() to interrupt us. E.g. we want to cut short
244 our sleep when we're signalled to exit. But we must block SIGCHLD during our sleep. That's because
245 if we forked an alert_program or alert_program2 child above, its termination will likely happen while we're sleeping;
247 sigaddset(&new_sigset, SIGCHLD);
248 sigprocmask(SIG_BLOCK, &new_sigset, &old_sigset); /* block SIGCHLD */
250 - sleep(time_to_sleep);
252 + /* If we're going to keep the packet capture running,
253 + we might as well read off all the packets received while
254 + waiting. We shouldn't get any since we don't send any requests
255 + but this should prevent any buffers from accidentally filling
256 + with unhandled packets. */
257 + int packets_recv = loop_for_packets(time_to_sleep);
259 + if (packets_recv && debug > 10)
260 + report(LOG_DEBUG, "captured %d packets while sleeping", packets_recv);
262 + sleep(time_to_sleep);
265 sigprocmask(SIG_SETMASK, &old_sigset, NULL); /* unblock SIGCHLD */
269 } /* MAIN EVENT LOOP */
272 /* we only reach here after receiving a signal requesting we quit */
277 if (pd_template) /* only used if a capture file requested */
278 pcap_close(pd_template);
279 @@ -1142,6 +1182,7 @@
280 fprintf(stderr, " -d debuglevel enable debugging at specified level\n");
281 fprintf(stderr, " -f don't fork (only use for debugging)\n");
282 fprintf(stderr, " -h display this help message then exit\n");
283 + fprintf(stderr, " -k keep pcap open constantly (don't recreate on each cycle)\n");
284 fprintf(stderr, " -l log_file log to file instead of syslog\n");
285 fprintf(stderr, " -o capture_file enable capturing of unexpected answers\n");
286 fprintf(stderr, " -p pid_file override default pid file [%s]\n", PID_FILE);