]> git.pld-linux.org Git - packages/dhcp_probe.git/blob - dhcp_probe-virta-02-keep-pcap.patch
- updated to 1.3.1
[packages/dhcp_probe.git] / dhcp_probe-virta-02-keep-pcap.patch
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
4 @@ -49,6 +49,7 @@
5  */
6  int snaplen = CAPTURE_BUFSIZE;
7  int socket_receive_timeout_feature = 0;
8 +int keep_pcap = 0;
9  
10  char *prog = NULL;
11  char *logfile_name = NULL;
12 @@ -75,6 +76,89 @@
13  int use_8021q = 0;
14  int vlan_id = 0;
15  
16 +int need_promiscuous(void)
17 +{
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.
25 +       */
26 +       int promiscuous = 0;
27 +       if (bcmp(GetChaddr(), &my_eaddr, sizeof(struct ether_addr)) ||
28 +           bcmp(GetEther_src(), &my_eaddr, sizeof(struct ether_addr)))
29 +               promiscuous = 1;
30 +       return promiscuous;
31 +}
32 +
33 +int init_pcap(int promiscuous, bpf_u_int32 netmask)
34 +{
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.
43 +                       */
44 +       struct bpf_program bpf_code;
45 +       char pcap_errbuf[PCAP_ERRBUF_SIZE];
46 +       int linktype;
47 +       int pcap_open_retries = PCAP_OPEN_LIVE_RETRY_MAX;
48 +
49 +       do {
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);
56 +                               my_exit(1, 1, 1);
57 +                       } else {
58 +                               if (debug > 1)
59 +                                       report(LOG_DEBUG, "pcap_open_live(%s): %s; will retry", ifname, pcap_errbuf);
60 +                               sleep(PCAP_OPEN_LIVE_RETRY_DELAY); /* before next retry */
61 +                       }
62 +               } /* failure */
63 +       } while (pcap_open_retries--);
64 +       
65 +       
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);
69 +               
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);
74 +               my_exit(1, 1, 1);
75 +       }
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));
79 +               my_exit(1, 1, 1);
80 +       }
81 +       /* install compiled filter */
82 +       if (pcap_setfilter(pd, &bpf_code) < 0) {
83 +               report(LOG_ERR, "pcap_setfilter: %s", pcap_geterr(pd));
84 +               my_exit(1, 1, 1);
85 +       }
86 +       if (socket_receive_timeout_feature)
87 +               set_pcap_timeout(pd);
88 +
89 +       return 0;
90 +}
91 +
92 +void 
93 +reset_pcap() 
94 +{
95 +       /* close packet capture descriptor */
96 +       pcap_close(pd); 
97 +}
98 +
99  /* capture packets from pcap for timeout seconds */
100  int 
101  loop_for_packets(int timeout)
102 @@ -115,8 +199,6 @@
103  
104         /* for libpcap */
105         bpf_u_int32 netnumber,  netmask;
106 -       struct bpf_program bpf_code;
107 -       int linktype;
108         char pcap_errbuf[PCAP_ERRBUF_SIZE], pcap_errbuf2[PCAP_ERRBUF_SIZE];
109  
110         /* get progname = last component of argv[0] */
111 @@ -126,7 +208,7 @@
112         else 
113                 prog = argv[0];
114  
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) {
117                 switch (c) {
118                         case 'c':
119                                 if (optarg[0] != '/') {
120 @@ -151,6 +233,9 @@
121                         case 'h':
122                                 usage();
123                                 my_exit(0, 0, 0);
124 +                       case 'k':
125 +                               keep_pcap = 1;
126 +                               break;
127                         case 'l':
128                                 if (optarg[0] != '/') {
129                                         fprintf(stderr, "%s: invalid log file '%s', must be an absolute pathname\n", prog, optarg);
130 @@ -447,8 +532,10 @@
131                 }
132         }
133  
134 +       if (keep_pcap)
135 +               init_pcap(need_promiscuous(), netmask);
136 +
137         while (1) { /* MAIN EVENT LOOP */
138 -               int promiscuous;
139                 libnet_t *l;                                            /* to iterate through libnet context queue */
140                 /* struct pcap_stat ps; */                      /* to hold pcap stats */
141  
142 @@ -489,26 +576,9 @@
143                    interface in promiscuous mode as little as possible, since that can affect the host's performance.
144                 */
145  
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.
153 -               */
154 -               if (bcmp(GetChaddr(), &my_eaddr, sizeof(struct ether_addr)) ||
155 -                   bcmp(GetEther_src(), &my_eaddr, sizeof(struct ether_addr)))
156 -                       promiscuous = 1;
157 -               else
158 -                       promiscuous = 0;
159 -
160 -
161                 for (l = libnet_cq_head(); libnet_cq_last(); l = libnet_cq_next()) { /* write one flavor packet and listen for answers */
162  
163                         int packets_recv;
164 -                       int pcap_open_retries;
165 -                       
166  
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
169 @@ -518,54 +588,9 @@
170                            we wanted!
171                         */
172  
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.
181 -                       */
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);
190 -                                               my_exit(1, 1, 1);
191 -                                       } else {
192 -                                               if (debug > 1)
193 -                                                       report(LOG_DEBUG, "pcap_open_live(%s): %s; will retry", ifname, pcap_errbuf);
194 -                                               sleep(PCAP_OPEN_LIVE_RETRY_DELAY); /* before next retry */
195 -                                       }
196 -                               } /* failure */
197 -                       }
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);
201 -
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);
206 -                               my_exit(1, 1, 1);
207 -                       }
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));
211 -                               my_exit(1, 1, 1);
212 -                       }
213 -                       /* install compiled filter */
214 -                       if (pcap_setfilter(pd, &bpf_code) < 0) {
215 -                               report(LOG_ERR, "pcap_setfilter: %s", pcap_geterr(pd));
216 -                               my_exit(1, 1, 1);
217 -                       }
218 -                       if (socket_receive_timeout_feature)
219 -                               set_pcap_timeout(pd);
220 -
221 +                       if (! keep_pcap)
222 +                               init_pcap(need_promiscuous(), netmask);
223 +                               
224                         /* write one packet */
225  
226                         if (debug > 10)
227 @@ -621,7 +646,8 @@
228                          */
229  
230                         /* close packet capture descriptor */
231 -                       pcap_close(pd); 
232 +                       if (! keep_pcap)
233 +                               reset_pcap();
234  
235                         /* check for 'quit' request after each packet, since waiting until end of probe cycle
236                            would impose a substantial delay. */
237 @@ -669,7 +695,7 @@
238                         reconfigure(write_packet_len);
239                         reread_config_file = 0;
240                 }
241 -
242 +               
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;
246 @@ -684,7 +710,19 @@
247                 sigaddset(&new_sigset, SIGCHLD);
248                 sigprocmask(SIG_BLOCK, &new_sigset, &old_sigset);  /* block SIGCHLD */
249  
250 -               sleep(time_to_sleep);
251 +               if (keep_pcap) {
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);
258 +
259 +                       if (packets_recv && debug > 10)
260 +                               report(LOG_DEBUG, "captured %d packets while sleeping", packets_recv);
261 +               } else {
262 +                       sleep(time_to_sleep);
263 +               }
264  
265                 sigprocmask(SIG_SETMASK, &old_sigset, NULL);  /* unblock SIGCHLD */
266  
267 @@ -692,8 +730,10 @@
268  
269         } /* MAIN EVENT LOOP */
270  
271 -
272         /* we only reach here after receiving a signal requesting we quit */
273 +       
274 +       if (keep_pcap)
275 +               reset_pcap();
276  
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);
This page took 0.090668 seconds and 3 git commands to generate.