nmsg  0.9.0
pcap_input.c
1 /*
2  * Copyright (c) 2009, 2011 by Farsight Security, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* Import. */
18 
19 #include <pcap.h>
20 
21 #include "private.h"
22 
23 /* Export. */
24 
25 nmsg_pcap_t
26 nmsg_pcap_input_open(pcap_t *phandle) {
27  struct nmsg_pcap *pcap;
28 
29  pcap = calloc(1, sizeof(*pcap));
30  if (pcap == NULL)
31  return (NULL);
32 
33  pcap->handle = phandle;
34  pcap->datalink = pcap_datalink(phandle);
35  pcap->new_pkt = calloc(1, NMSG_IPSZ_MAX);
36  pcap->reasm = reasm_ip_new();
37  if (pcap->reasm == NULL) {
38  free(pcap->new_pkt);
39  free(pcap);
40  return (NULL);
41  }
42  reasm_ip_set_timeout(pcap->reasm, 60);
43 
44  if (pcap_file(phandle) == NULL)
45  pcap->type = nmsg_pcap_type_live;
46  else
47  pcap->type = nmsg_pcap_type_file;
48 
49  return (pcap);
50 }
51 
53 nmsg_pcap_input_close(nmsg_pcap_t *pcap) {
54  pcap_freecode(&(*pcap)->userbpf);
55  pcap_close((*pcap)->handle);
56  if ((*pcap)->user != NULL)
57  pcap_close((*pcap)->user);
58 
59  reasm_ip_free((*pcap)->reasm);
60 
61  free((*pcap)->new_pkt);
62  free((*pcap)->userbpft);
63  free(*pcap);
64 
65  *pcap = NULL;
66  return (nmsg_res_success);
67 }
68 
70 nmsg_pcap_input_read(nmsg_pcap_t pcap, struct nmsg_ipdg *dg,
71  struct timespec *ts)
72 {
73  const u_char *pkt_data;
74  int pcap_res;
75  struct pcap_pkthdr *pkt_hdr;
76 
77  assert(pcap->raw == false);
78 
79  /* get the next frame from the libpcap source */
80  pcap_res = pcap_next_ex(pcap->handle, &pkt_hdr, &pkt_data);
81  if (pcap_res == 0)
82  return (nmsg_res_again);
83  if (pcap_res == -1) {
84  _nmsg_dprintf(1, "%s: pcap_next_ex() failed: %s\n", __func__,
85  pcap_geterr(pcap->handle));
86  return (nmsg_res_pcap_error);
87  }
88  if (pcap_res == -2)
89  return (nmsg_res_eof);
90 
91  /* get the time of packet reception */
92  ts->tv_sec = pkt_hdr->ts.tv_sec;
93  ts->tv_nsec = pkt_hdr->ts.tv_usec * 1000;
94 
95  /* parse the frame */
96  return (nmsg_ipdg_parse_pcap(dg, pcap, pkt_hdr, pkt_data));
97 }
98 
100 nmsg_pcap_input_read_raw(nmsg_pcap_t pcap, struct pcap_pkthdr **pkt_hdr,
101  const uint8_t **pkt_data, struct timespec *ts)
102 {
103  int pcap_res;
104 
105  assert(pcap->raw == true);
106 
107  /* get the next frame from the libpcap source */
108  pcap_res = pcap_next_ex(pcap->handle, pkt_hdr, (const u_char **) pkt_data);
109  if (pcap_res == 0)
110  return (nmsg_res_again);
111  if (pcap_res == -1) {
112  _nmsg_dprintf(1, "%s: pcap_next_ex() failed: %s\n", __func__,
113  pcap_geterr(pcap->handle));
114  return (nmsg_res_pcap_error);
115  }
116  if (pcap_res == -2)
117  return (nmsg_res_eof);
118 
119  /* get the time of packet reception */
120  ts->tv_sec = (*pkt_hdr)->ts.tv_sec;
121  ts->tv_nsec = (*pkt_hdr)->ts.tv_usec * 1000;
122 
123  return (nmsg_res_success);
124 }
125 
126 void
127 nmsg_pcap_input_set_raw(nmsg_pcap_t pcap, bool raw) {
128  pcap->raw = raw;
129 }
130 
131 nmsg_res
132 nmsg_pcap_input_setfilter_raw(nmsg_pcap_t pcap, const char *userbpft) {
133  bool need_vlan = false;
134  char *tmp, *bpfstr;
135  int res;
136  struct bpf_program bpf;
137 
138  tmp = strdup(userbpft);
139  assert(tmp != NULL);
140 
141  /* open a dummy pcap_t for the user bpf */
142  if (pcap->user == NULL) {
143  pcap->user = pcap_open_dead(DLT_RAW, 1500);
144  if (pcap->user == NULL)
145  return (nmsg_res_memfail);
146  }
147 
148  /* free an old filter set by a previous call */
149  free(pcap->userbpft);
150  pcap_freecode(&pcap->userbpf);
151 
152  /* compile the user's bpf and save it */
153  res = pcap_compile(pcap->user, &pcap->userbpf, (char *) userbpft, 1, 0);
154  if (res != 0) {
155  _nmsg_dprintf(1, "%s: unable to compile bpf '%s': %s\n", __func__,
156  userbpft, pcap_geterr(pcap->handle));
157  return (nmsg_res_failure);
158  }
159  pcap->userbpft = strdup(userbpft);
160 
161  /* test if we can skip vlan tags */
162  res = pcap_compile(pcap->handle, &bpf, "vlan and ip", 1, 0);
163  if (res == 0) {
164  pcap_freecode(&bpf);
165  need_vlan = true;
166  }
167  _nmsg_dprintf(5, "%s: need_vlan=%u\n", __func__, need_vlan);
168 
169  /* construct and compile the final bpf */
170  if (need_vlan) {
171  res = nmsg_asprintf(&bpfstr, "(%s) or (vlan and (%s))", tmp, tmp);
172  if (res == -1) {
173  free(tmp);
174  return (nmsg_res_memfail);
175  }
176  } else {
177  bpfstr = tmp;
178  tmp = NULL;
179  }
180 
181  _nmsg_dprintf(3, "%s: using bpf '%s'\n", __func__, bpfstr);
182  res = pcap_compile(pcap->handle, &bpf, bpfstr, 1, 0);
183  if (res != 0) {
184  _nmsg_dprintf(1, "%s: pcap_compile() failed: %s\n", __func__,
185  pcap_geterr(pcap->handle));
186  free(tmp);
187  free(bpfstr);
188  return (nmsg_res_failure);
189  }
190 
191  /* load the constructed bpf */
192  if (pcap_setfilter(pcap->handle, &bpf) != 0) {
193  _nmsg_dprintf(1, "%s: pcap_setfilter() failed: %s\n", __func__,
194  pcap_geterr(pcap->handle));
195  return (nmsg_res_failure);
196  }
197 
198  /* cleanup */
199  free(tmp);
200  free(bpfstr);
201  pcap_freecode(&bpf);
202 
203  return (nmsg_res_success);
204 }
205 
206 nmsg_res
207 nmsg_pcap_input_setfilter(nmsg_pcap_t pcap, const char *userbpft) {
208  static const char *bpf_ipv4_frags = "(ip[6:2] & 0x3fff != 0)";
209  static const char *bpf_ip = "(ip)";
210  static const char *bpf_ip6 = "(ip6)";
211 
212  bool need_ip6 = true;
213  bool need_ipv4_frags = true;
214  bool need_vlan = false;
215  bool userbpf_ip_only = true;
216  char *tmp, *bpfstr;
217  int res;
218  struct bpf_program bpf;
219 
220  /* open a dummy pcap_t for the user bpf */
221  if (pcap->user == NULL) {
222  pcap->user = pcap_open_dead(DLT_RAW, 1500);
223  if (pcap->user == NULL)
224  return (nmsg_res_memfail);
225  }
226 
227  /* free an old filter set by a previous call */
228  free(pcap->userbpft);
229  pcap_freecode(&pcap->userbpf);
230 
231  /* compile the user's bpf and save it */
232  res = pcap_compile(pcap->user, &pcap->userbpf, (char *) userbpft, 1, 0);
233  if (res != 0) {
234  _nmsg_dprintf(1, "%s: unable to compile bpf '%s': %s\n", __func__,
235  userbpft, pcap_geterr(pcap->handle));
236  return (nmsg_res_failure);
237  }
238  pcap->userbpft = strdup(userbpft);
239 
240  /* test if we can skip ip6 */
241  res = nmsg_asprintf(&tmp, "(%s) and %s", userbpft, bpf_ip6);
242  if (res == -1)
243  return (nmsg_res_memfail);
244  res = pcap_compile(pcap->handle, &bpf, tmp, 1, 0);
245  free(tmp);
246  if (res != 0)
247  need_ip6 = false;
248  else
249  pcap_freecode(&bpf);
250 
251  _nmsg_dprintf(5, "%s: need_ip6=%u\n", __func__, need_ip6);
252 
253  /* test if we can skip ipv4 frags */
254  res = nmsg_asprintf(&tmp, "(%s) and %s", userbpft, bpf_ipv4_frags);
255  if (res == -1)
256  return (nmsg_res_memfail);
257  res = pcap_compile(pcap->handle, &bpf, tmp, 1, 0);
258  free(tmp);
259  if (res != 0)
260  need_ipv4_frags = false;
261  else
262  pcap_freecode(&bpf);
263 
264  _nmsg_dprintf(5, "%s: need_ipv4_frags=%u\n", __func__, need_ipv4_frags);
265 
266  /* test if we can skip vlan tags */
267  res = pcap_compile(pcap->handle, &bpf, "vlan and ip", 1, 0);
268  if (res == 0) {
269  pcap_freecode(&bpf);
270  need_vlan = true;
271  }
272  _nmsg_dprintf(5, "%s: need_vlan=%u\n", __func__, need_vlan);
273 
274  /* test if we can limit the userbpf to ip packets only */
275  res = nmsg_asprintf(&tmp, "%s and (%s)", bpf_ip, userbpft);
276  if (res == -1)
277  return (nmsg_res_memfail);
278  res = pcap_compile(pcap->handle, &bpf, tmp, 1, 0);
279  free(tmp);
280  if (res != 0)
281  userbpf_ip_only = false;
282  else
283  pcap_freecode(&bpf);
284 
285  _nmsg_dprintf(5, "%s: userbpf_ip_only=%u\n", __func__, userbpf_ip_only);
286 
287  /* construct and compile the final bpf */
288  res = nmsg_asprintf(&tmp, "((%s%s(%s))%s%s%s%s)",
289  userbpf_ip_only ? bpf_ip : "",
290  userbpf_ip_only ? " and " : "",
291  userbpft,
292  need_ipv4_frags ? " or " : "",
293  need_ipv4_frags ? bpf_ipv4_frags : "",
294  need_ip6 ? " or " : "",
295  need_ip6 ? bpf_ip6 : "");
296  if (res == -1)
297  return (nmsg_res_memfail);
298 
299  if (need_vlan) {
300  res = nmsg_asprintf(&bpfstr, "%s or (vlan and %s)", tmp, tmp);
301  if (res == -1) {
302  free(tmp);
303  return (nmsg_res_memfail);
304  }
305  } else {
306  bpfstr = tmp;
307  tmp = NULL;
308  }
309 
310  _nmsg_dprintf(3, "%s: using bpf '%s'\n", __func__, bpfstr);
311  res = pcap_compile(pcap->handle, &bpf, bpfstr, 1, 0);
312  if (res != 0) {
313  _nmsg_dprintf(1, "%s: pcap_compile() failed: %s\n", __func__,
314  pcap_geterr(pcap->handle));
315  free(tmp);
316  free(bpfstr);
317  return (nmsg_res_failure);
318  }
319 
320  /* load the constructed bpf */
321  if (pcap_setfilter(pcap->handle, &bpf) != 0) {
322  _nmsg_dprintf(1, "%s: pcap_setfilter() failed: %s\n", __func__,
323  pcap_geterr(pcap->handle));
324  return (nmsg_res_failure);
325  }
326 
327  /* cleanup */
328  free(tmp);
329  free(bpfstr);
330  pcap_freecode(&bpf);
331 
332  return (nmsg_res_success);
333 }
334 
335 int
336 nmsg_pcap_snapshot(nmsg_pcap_t pcap) {
337  return (pcap_snapshot(pcap->handle));
338 }
339 
340 nmsg_pcap_type
341 nmsg_pcap_get_type(nmsg_pcap_t pcap) {
342  return (pcap->type);
343 }
344 
345 int
346 nmsg_pcap_get_datalink(nmsg_pcap_t pcap) {
347  return (pcap->datalink);
348 }
349 
350 bool
351 nmsg_pcap_filter(nmsg_pcap_t pcap, const uint8_t *pkt, size_t len) {
352  struct bpf_insn *fcode;
353 
354  fcode = pcap->userbpf.bf_insns;
355 
356  if (fcode != NULL) {
357  return (bpf_filter(fcode, (u_char *) pkt, len, len) != 0);
358  } else {
359  return (true);
360  }
361 }
bool nmsg_pcap_filter(nmsg_pcap_t pcap, const uint8_t *pkt, size_t len)
Return the result of filtering a packet.
Definition: pcap_input.c:351
nmsg_res
nmsg result code
Definition: res.h:25
success
Definition: res.h:26
int nmsg_pcap_get_datalink(nmsg_pcap_t pcap)
Get the datalink type of the underlying pcap handle.
Definition: pcap_input.c:346
out of memory
Definition: res.h:29
caller should try again
Definition: res.h:35
Parsed IP datagram.
Definition: ipdg.h:34
nmsg_res nmsg_pcap_input_setfilter(nmsg_pcap_t pcap, const char *bpfstr)
Set a bpf filter on an nmsg_pcap_t object.
Definition: pcap_input.c:207
void nmsg_pcap_input_set_raw(nmsg_pcap_t pcap, bool raw)
Set raw mode.
Definition: pcap_input.c:127
#define NMSG_IPSZ_MAX
Maximize size of an IP datagram.
Definition: constants.h:102
nmsg_pcap_t nmsg_pcap_input_open(pcap_t *phandle)
Initialize a new nmsg_pcap_t input from a libpcap source.
Definition: pcap_input.c:26
generic failure
Definition: res.h:27
nmsg_pcap_type nmsg_pcap_get_type(nmsg_pcap_t pcap)
Get the type of the underlying pcap handle.
Definition: pcap_input.c:341
nmsg_res nmsg_pcap_input_read(nmsg_pcap_t pcap, struct nmsg_ipdg *dg, struct timespec *ts)
Read an IP datagram from an nmsg_pcap_t input, performing reassembly if necessary.
Definition: pcap_input.c:70
int nmsg_pcap_snapshot(nmsg_pcap_t pcap)
Get the snapshot length of the underlying pcap handle.
Definition: pcap_input.c:336
libpcap error
Definition: res.h:37
nmsg_res nmsg_pcap_input_read_raw(nmsg_pcap_t pcap, struct pcap_pkthdr **pkt_hdr, const uint8_t **pkt_data, struct timespec *ts)
Read a raw packet from an nmsg_pcap_t input.
Definition: pcap_input.c:100
nmsg_res nmsg_pcap_input_close(nmsg_pcap_t *pcap)
Close an nmsg_pcap_t object and release all associated resources.
Definition: pcap_input.c:53
nmsg_res nmsg_pcap_input_setfilter_raw(nmsg_pcap_t pcap, const char *bpfstr)
Set a bpf filter on an nmsg_pcap_t object.
Definition: pcap_input.c:132
nmsg_res nmsg_ipdg_parse_pcap(struct nmsg_ipdg *dg, nmsg_pcap_t pcap, struct pcap_pkthdr *pkt_hdr, const u_char *pkt)
Parse IP datagrams from the data link layer, performing reassembly if necessary.
end of file
Definition: res.h:28