]> mj.ucw.cz Git - netgrind.git/blob - netgrind/ip.c
TODO: A note on IPv6
[netgrind.git] / netgrind / ip.c
1 /*
2  *      Netgrind -- IP Layer Analyser
3  *
4  *      (c) 2003--2013 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU General Public License.
8  */
9
10 #include "lib/lib.h"
11 #include "netgrind/pkt.h"
12 #include "netgrind/netgrind.h"
13
14 #include <stdio.h>
15 #include <netinet/in.h>
16 #include <netinet/ip.h>
17
18 uns accept_broken_checksums;
19
20 uns tcpip_calc_checksum(void *data, uns len, uns csum)
21 {
22   /* FIXME: This is awfully slow and it probably consumes most of our run time */
23   byte *x = data;
24
25   while (len >= 2)
26     {
27       csum += (x[0] << 8) | x[1];
28       if (csum & 0xffff0000)
29         {
30           csum &= 0x0000ffff;
31           csum++;
32         }
33       x += 2;
34       len -= 2;
35     }
36   if (len)
37     {
38       csum += x[0] << 8;
39       if (csum & 0xffff0000)
40         {
41           csum &= 0x0000ffff;
42           csum++;
43         }
44     }
45   return csum;
46 }
47
48 uns tcpip_verify_checksum(uns csum)
49 {
50   if (accept_broken_checksums)
51     return 1;
52   else
53     return (csum == 0xffff);
54 }
55
56 struct pkt_stats stat_ip_in, stat_ip_invalid, stat_ip_uninteresting, stat_ip_fragmented, stat_ip_badsum;
57
58 void ip_got_packet(struct pkt *p)
59 {
60   struct iphdr *iph;
61
62   pkt_account(&stat_ip_in, p);
63   if (!(iph = pkt_peek(p, sizeof(*iph))))
64     goto invalid;
65   if (iph->ihl < 5)
66     goto invalid;
67   if (iph->version != 4)
68     goto invalid;
69   uns hdrlen = 4*iph->ihl;
70   if (pkt_len(p) < hdrlen)
71     goto invalid;
72   if (!tcpip_verify_checksum(tcpip_calc_checksum(p->data, hdrlen, 0)))
73     {
74       pkt_account(&stat_ip_badsum, p);
75       goto drop;
76     }
77   uns len = ntohs(iph->tot_len);
78   if (len < hdrlen || len > pkt_len(p))
79     goto invalid;
80   pkt_unappend(p, pkt_len(p) - len);
81   pkt_pop(p, hdrlen);
82
83   if (iph->protocol != IPPROTO_TCP)
84     {
85       pkt_account(&stat_ip_uninteresting, p);
86       goto drop;
87     }
88   /* XXX: Fragmentation not supported yet, but well-behaved TCP stacks don't use it anyway */
89   if (ntohs(iph->frag_off) & 0x3fff)
90     {
91       pkt_account(&stat_ip_fragmented, p);
92       goto drop;
93     }
94   tcp_got_packet(iph, p);
95   return;
96
97  invalid:
98   pkt_account(&stat_ip_invalid, p);
99  drop:
100   pkt_free(p);
101 }