nmsg  0.9.0
ipdg.c
1 /*
2  * Copyright (c) 2009-2012 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 /* Macros. */
24 
25 #define advance_pkt(pkt, len, sz) do { \
26  (pkt) += (sz); \
27  (len) -= (sz); \
28 } while (0)
29 
30 /* Export. */
31 
33 nmsg_ipdg_parse(struct nmsg_ipdg *dg, unsigned etype, size_t len,
34  const u_char *pkt)
35 {
36  return (_nmsg_ipdg_parse_reasm(dg, etype, len, pkt,
37  NULL, NULL, NULL, NULL, 0));
38 }
39 
41 nmsg_ipdg_parse_pcap(struct nmsg_ipdg *dg, struct nmsg_pcap *pcap,
42  struct pcap_pkthdr *pkt_hdr, const u_char *pkt)
43 {
44  int defrag = 0;
45  size_t len = pkt_hdr->caplen;
46  unsigned etype = 0;
47  unsigned new_len = NMSG_IPSZ_MAX;
48  nmsg_res res;
49 
50  /* only operate on complete packets */
51  if (pkt_hdr->caplen != pkt_hdr->len)
52  return (nmsg_res_again);
53 
54  /* process data link header */
55  switch (pcap->datalink) {
56  case DLT_EN10MB: {
57  const struct nmsg_ethhdr *eth;
58 
59  if (len < sizeof(*eth))
60  return (nmsg_res_again);
61 
62  eth = (const struct nmsg_ethhdr *) pkt;
63  advance_pkt(pkt, len, sizeof(struct nmsg_ethhdr));
64  load_net16(&eth->ether_type, &etype);
65  if (etype == ETHERTYPE_VLAN) {
66  if (len < 4)
67  return (nmsg_res_again);
68  advance_pkt(pkt, len, 2);
69  load_net16(pkt, &etype);
70  advance_pkt(pkt, len, 2);
71  }
72  break;
73  }
74  case DLT_RAW: {
75  const struct nmsg_iphdr *ip;
76 
77  if (len < sizeof(*ip))
78  return (nmsg_res_again);
79  ip = (const struct nmsg_iphdr *) pkt;
80 
81  if (ip->ip_v == 4) {
82  etype = ETHERTYPE_IP;
83  } else if (ip->ip_v == 6) {
84  etype = ETHERTYPE_IPV6;
85  } else {
86  return (nmsg_res_again);
87  }
88  break;
89  }
90 #ifdef DLT_LINUX_SLL
91  case DLT_LINUX_SLL: {
92  if (len < 16)
93  return (nmsg_res_again);
94  advance_pkt(pkt, len, ETHER_HDR_LEN);
95  load_net16(pkt, &etype);
96  advance_pkt(pkt, len, 2);
97  break;
98  }
99 #endif
100  } /* end switch */
101 
102  res = _nmsg_ipdg_parse_reasm(dg, etype, len, pkt, pcap->reasm,
103  &new_len, pcap->new_pkt, &defrag,
104  pkt_hdr->ts.tv_sec);
105  if (res == nmsg_res_success && defrag == 1) {
106  /* refilter the newly reassembled datagram */
107  struct bpf_insn *fcode = pcap->userbpf.bf_insns;
108 
109  if (fcode != NULL &&
110  bpf_filter(fcode, (u_char *) dg->network, dg->len_network,
111  dg->len_network) == 0)
112  {
113  return (nmsg_res_again);
114  }
115  }
116  return (res);
117 }
118 
119 nmsg_res
120 _nmsg_ipdg_parse_reasm(struct nmsg_ipdg *dg, unsigned etype, size_t len,
121  const u_char *pkt, struct _nmsg_ipreasm *reasm,
122  unsigned *new_len, u_char *new_pkt, int *defrag,
123  uint64_t timestamp)
124 {
125  bool is_fragment = false;
126  unsigned frag_hdr_offset = 0;
127  unsigned tp_payload_len = 0;
128 
129  dg->network = pkt;
130  dg->len_network = len;
131 
132  /* process network header */
133  switch (etype) {
134  case ETHERTYPE_IP: {
135  const struct nmsg_iphdr *ip;
136  unsigned ip_off;
137 
138  ip = (const struct nmsg_iphdr *) dg->network;
139  advance_pkt(pkt, len, ip->ip_hl << 2);
140 
141  load_net16(&ip->ip_off, &ip_off);
142  if ((ip_off & IP_OFFMASK) != 0 ||
143  (ip_off & IP_MF) != 0)
144  {
145  is_fragment = true;
146  }
147  dg->proto_network = PF_INET;
148  dg->proto_transport = ip->ip_p;
149  break;
150  }
151  case ETHERTYPE_IPV6: {
152  const struct ip6_hdr *ip6;
153  uint16_t payload_len;
154  uint8_t nexthdr;
155  unsigned thusfar;
156 
157  if (len < sizeof(*ip6))
158  return (nmsg_res_again);
159  ip6 = (const struct ip6_hdr *) dg->network;
160  if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
161  return (nmsg_res_again);
162 
163  nexthdr = ip6->ip6_nxt;
164  thusfar = sizeof(struct ip6_hdr);
165  load_net16(&ip6->ip6_plen, &payload_len);
166 
167  while (nexthdr == IPPROTO_ROUTING ||
168  nexthdr == IPPROTO_HOPOPTS ||
169  nexthdr == IPPROTO_FRAGMENT ||
170  nexthdr == IPPROTO_DSTOPTS ||
171  nexthdr == IPPROTO_AH ||
172  nexthdr == IPPROTO_ESP)
173  {
174  struct {
175  uint8_t nexthdr;
176  uint8_t length;
177  } ext_hdr;
178  uint16_t ext_hdr_len;
179 
180  /* catch broken packets */
181  if ((thusfar + sizeof(ext_hdr)) > len)
182  return (nmsg_res_again);
183 
184  if (nexthdr == IPPROTO_FRAGMENT) {
185  frag_hdr_offset = thusfar;
186  is_fragment = true;
187  break;
188  }
189 
190  memcpy(&ext_hdr, (const u_char *) ip6 + thusfar,
191  sizeof(ext_hdr));
192  nexthdr = ext_hdr.nexthdr;
193  ext_hdr_len = (8 * (ntohs(ext_hdr.length) + 1));
194 
195  if (ext_hdr_len > payload_len)
196  return (nmsg_res_again);
197 
198  thusfar += ext_hdr_len;
199  payload_len -= ext_hdr_len;
200  }
201 
202  if ((thusfar + payload_len) > len || payload_len == 0)
203  return (nmsg_res_again);
204 
205  advance_pkt(pkt, len, thusfar);
206 
207  dg->proto_network = PF_INET6;
208  dg->proto_transport = nexthdr;
209  break;
210  }
211  default:
212  return (nmsg_res_again);
213  break;
214  } /* end switch */
215 
216  /* handle IPv4 and IPv6 fragments */
217  if (is_fragment == true && reasm != NULL) {
218  bool rres;
219 
220  rres = reasm_ip_next(reasm, dg->network, dg->len_network,
221  frag_hdr_offset, timestamp,
222  new_pkt, new_len);
223  if (rres == false || *new_len == 0) {
224  /* not all fragments have been received */
225  return (nmsg_res_again);
226  }
227  /* the datagram has been fully reassembled */
228  if (defrag != NULL)
229  *defrag = 1;
230  return (nmsg_ipdg_parse(dg, etype, *new_len, new_pkt));
231  }
232  if (is_fragment == true && reasm == NULL)
233  return (nmsg_res_again);
234 
235  dg->transport = pkt;
236  dg->len_transport = len;
237 
238  /* process transport header */
239  switch (dg->proto_transport) {
240  case IPPROTO_UDP: {
241  struct nmsg_udphdr *udp;
242 
243  if (len < sizeof(struct nmsg_udphdr))
244  return (nmsg_res_again);
245  udp = (struct nmsg_udphdr *) pkt;
246  load_net16(&udp->uh_ulen, &tp_payload_len);
247  if (tp_payload_len >= 8)
248  tp_payload_len -= 8;
249  advance_pkt(pkt, len, sizeof(struct nmsg_udphdr));
250 
251  dg->payload = pkt;
252  dg->len_payload = tp_payload_len;
253  if (dg->len_payload > len)
254  dg->len_payload = len;
255  break;
256  }
257  default:
258  return (nmsg_res_again);
259  break;
260  } /* end switch */
261 
262  return (nmsg_res_success);
263 }
264 
265 nmsg_res
266 nmsg_ipdg_parse_pcap_raw(struct nmsg_ipdg *dg, int datalink, const uint8_t *pkt, size_t len)
267 {
268  bool is_initial_fragment = false;
269  bool is_fragment = false;
270  unsigned etype = 0;
271  unsigned tp_payload_len = 0;
272 
273  /* process data link header */
274  switch (datalink) {
275  case DLT_EN10MB: {
276  const struct nmsg_ethhdr *eth;
277 
278  if (len < sizeof(*eth))
279  return (nmsg_res_again);
280 
281  eth = (const struct nmsg_ethhdr *) pkt;
282  advance_pkt(pkt, len, sizeof(struct nmsg_ethhdr));
283  load_net16(&eth->ether_type, &etype);
284  if (etype == ETHERTYPE_VLAN) {
285  if (len < 4)
286  return (nmsg_res_again);
287  advance_pkt(pkt, len, 2);
288  load_net16(pkt, &etype);
289  advance_pkt(pkt, len, 2);
290  }
291  break;
292  }
293  case DLT_RAW: {
294  const struct nmsg_iphdr *ip;
295 
296  if (len < sizeof(*ip))
297  return (nmsg_res_again);
298  ip = (const struct nmsg_iphdr *) pkt;
299 
300  if (ip->ip_v == 4) {
301  etype = ETHERTYPE_IP;
302  } else if (ip->ip_v == 6) {
303  etype = ETHERTYPE_IPV6;
304  } else {
305  return (nmsg_res_again);
306  }
307  break;
308  }
309 #ifdef DLT_LINUX_SLL
310  case DLT_LINUX_SLL: {
311  if (len < 16)
312  return (nmsg_res_again);
313  advance_pkt(pkt, len, ETHER_HDR_LEN);
314  load_net16(pkt, &etype);
315  advance_pkt(pkt, len, 2);
316  break;
317  }
318 #endif
319  } /* end switch */
320 
321  dg->network = pkt;
322  dg->len_network = len;
323 
324  /* process network header */
325  switch (etype) {
326  case ETHERTYPE_IP: {
327  const struct nmsg_iphdr *ip;
328  unsigned ip_off;
329 
330  ip = (const struct nmsg_iphdr *) dg->network;
331  advance_pkt(pkt, len, ip->ip_hl << 2);
332 
333  load_net16(&ip->ip_off, &ip_off);
334  if ((ip_off & IP_OFFMASK) != 0 ||
335  (ip_off & IP_MF) != 0)
336  {
337  is_fragment = true;
338  }
339  if ((ip_off & IP_OFFMASK) == 0)
340  is_initial_fragment = true;
341  dg->proto_network = PF_INET;
342  dg->proto_transport = ip->ip_p;
343  break;
344  }
345  case ETHERTYPE_IPV6: {
346  const struct ip6_hdr *ip6;
347  const struct ip6_frag *frag;
348  uint16_t payload_len;
349  uint8_t nexthdr;
350  unsigned thusfar;
351 
352  if (len < sizeof(*ip6))
353  return (nmsg_res_again);
354  ip6 = (const struct ip6_hdr *) dg->network;
355  if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
356  return (nmsg_res_again);
357 
358  nexthdr = ip6->ip6_nxt;
359  thusfar = sizeof(struct ip6_hdr);
360  load_net16(&ip6->ip6_plen, &payload_len);
361 
362  while (nexthdr == IPPROTO_ROUTING ||
363  nexthdr == IPPROTO_HOPOPTS ||
364  nexthdr == IPPROTO_FRAGMENT ||
365  nexthdr == IPPROTO_DSTOPTS ||
366  nexthdr == IPPROTO_AH ||
367  nexthdr == IPPROTO_ESP)
368  {
369  struct {
370  uint8_t nexthdr;
371  uint8_t length;
372  } ext_hdr;
373  uint16_t ext_hdr_len;
374 
375  /* catch broken packets */
376  if ((thusfar + sizeof(ext_hdr)) > len)
377  return (nmsg_res_again);
378 
379  if (nexthdr == IPPROTO_FRAGMENT) {
380  is_fragment = true;
381  frag = (const struct ip6_frag *) (dg->network + thusfar);
382  if ((frag->ip6f_offlg & IP6F_OFF_MASK) == 0)
383  is_initial_fragment = true;
384  }
385 
386  memcpy(&ext_hdr, (const u_char *) ip6 + thusfar,
387  sizeof(ext_hdr));
388  nexthdr = ext_hdr.nexthdr;
389  ext_hdr_len = (8 * (ntohs(ext_hdr.length) + 1));
390 
391  if (ext_hdr_len > payload_len)
392  return (nmsg_res_again);
393 
394  thusfar += ext_hdr_len;
395  payload_len -= ext_hdr_len;
396 
397  if (is_fragment)
398  break;
399  }
400 
401  if ((thusfar + payload_len) > len || payload_len == 0)
402  return (nmsg_res_again);
403 
404  advance_pkt(pkt, len, thusfar);
405 
406  dg->proto_network = PF_INET6;
407  dg->proto_transport = nexthdr;
408  break;
409  }
410  default:
411  return (nmsg_res_again);
412  break;
413  } /* end switch */
414 
415  if (is_fragment) {
416  if (is_initial_fragment) {
417  dg->transport = pkt;
418  dg->len_transport = len;
419  } else {
420  dg->transport = NULL;
421  dg->len_transport = 0;
422  dg->payload = pkt;
423  dg->len_payload = len;
424  return (nmsg_res_success);
425  }
426  } else {
427  dg->transport = pkt;
428  dg->len_transport = len;
429  }
430 
431  /* process transport header */
432  switch (dg->proto_transport) {
433  case IPPROTO_UDP: {
434  struct nmsg_udphdr *udp;
435 
436  if (len < sizeof(struct nmsg_udphdr))
437  return (nmsg_res_again);
438  udp = (struct nmsg_udphdr *) pkt;
439  load_net16(&udp->uh_ulen, &tp_payload_len);
440  if (tp_payload_len >= 8)
441  tp_payload_len -= 8;
442  advance_pkt(pkt, len, sizeof(struct nmsg_udphdr));
443 
444  dg->payload = pkt;
445  dg->len_payload = tp_payload_len;
446  if (dg->len_payload > len)
447  dg->len_payload = len;
448  break;
449  }
450  case IPPROTO_TCP: {
451  struct nmsg_tcphdr *tcp;
452 
453  if (len < sizeof(struct nmsg_tcphdr))
454  return (nmsg_res_again);
455  tcp = (struct nmsg_tcphdr *) pkt;
456  tp_payload_len = dg->len_network - 4 * tcp->th_off;
457  advance_pkt(pkt, len, 4 * tcp->th_off);
458  dg->payload = pkt;
459  dg->len_payload = tp_payload_len;
460  if (dg->len_payload > len)
461  dg->len_payload = len;
462  break;
463  }
464  case IPPROTO_ICMP: {
465  if (len < sizeof(struct nmsg_icmphdr))
466  return (nmsg_res_again);
467  advance_pkt(pkt, len, sizeof(struct nmsg_icmphdr));
468  dg->payload = pkt;
469  dg->len_payload = len;
470  break;
471  }
472  default:
473  return (nmsg_res_again);
474  break;
475  } /* end switch */
476 
477  return (nmsg_res_success);
478 }
nmsg_res
nmsg result code
Definition: res.h:25
success
Definition: res.h:26
nmsg_res nmsg_ipdg_parse_pcap_raw(struct nmsg_ipdg *dg, int datalink, const uint8_t *pkt, size_t len)
Like nmsg_ipdg_parse_pcap(), but performs no fragment handling.
Definition: ipdg.c:266
caller should try again
Definition: res.h:35
unsigned len_network
length starting from network
Definition: ipdg.h:37
int proto_transport
transport protocol
Definition: ipdg.h:36
Parsed IP datagram.
Definition: ipdg.h:34
unsigned len_payload
length starting from payload
Definition: ipdg.h:39
#define NMSG_IPSZ_MAX
Maximize size of an IP datagram.
Definition: constants.h:102
nmsg_res nmsg_ipdg_parse(struct nmsg_ipdg *dg, unsigned etype, size_t len, const u_char *pkt)
Parse IP packets from the network layer, discarding fragments.
Definition: ipdg.c:33
const u_char * payload
pointer to application payload
Definition: ipdg.h:42
const u_char * transport
pointer to transport header
Definition: ipdg.h:41
unsigned len_transport
length starting from transport
Definition: ipdg.h:38
const u_char * network
pointer to network header
Definition: ipdg.h:40
int proto_network
PF_* value.
Definition: ipdg.h:35
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.