source: lib/protocols_l3.c @ aa22b5b

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since aa22b5b was aa22b5b, checked in by Perry Lorier <perry@…>, 13 years ago

If we have a complete header, but truncated at the end of it, we shouldn't return NULL from
get_payload_from_* functions so we can distinguish it from a truncated header.

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/* Protocol decodes for Layer 3 protocols */
2#include "libtrace.h"
3#include "protocols.h"
4#include <assert.h>
5
6libtrace_ip_t *trace_get_ip(libtrace_packet_t *packet) 
7{
8        uint16_t ethertype;
9        void *ret;
10
11        uint32_t remaining = trace_get_capture_length(packet);
12
13        ret = trace_get_layer3(packet,&ethertype,&remaining);
14
15        if (!ret || ethertype!=0x0800)
16                return NULL;
17
18        /* Make sure we have at least a base IPv4 header */
19        if (remaining < sizeof(libtrace_ip_t)) 
20                return NULL;
21       
22        /* Not an IPv4 packet */
23        if (((libtrace_ip_t*)ret)->ip_v != 4)
24                return NULL;
25
26        return (libtrace_ip_t*)ret;
27}
28
29libtrace_ip6_t *trace_get_ip6(libtrace_packet_t *packet) 
30{
31        uint16_t ethertype;
32        void *ret;
33
34        uint32_t remaining = trace_get_capture_length(packet);
35
36        ret = trace_get_layer3(packet,&ethertype,&remaining);
37
38        if (!ret || ethertype!=0x86DD)
39                return NULL;
40
41        return (libtrace_ip6_t*)ret;
42}
43
44#define SW_IP_OFFMASK 0x1fff
45
46DLLEXPORT void *trace_get_payload_from_ip(libtrace_ip_t *ipptr, uint8_t *prot,
47                uint32_t *remaining) 
48{
49        void *trans_ptr = 0;
50
51        assert(ipptr != NULL);
52        assert(ipptr->ip_v == 4);
53
54        if ((ntohs(ipptr->ip_off) & SW_IP_OFFMASK) != 0) {
55                if (remaining)
56                        *remaining = 0;         
57                return NULL;
58        }
59
60        if (remaining) {
61                if (*remaining<(ipptr->ip_hl*4U)) {
62                        *remaining = 0;
63                        return NULL;
64                }
65                *remaining-=(ipptr->ip_hl * 4);
66        }
67
68        trans_ptr = (void *)((char *)ipptr + (ipptr->ip_hl * 4));
69
70        if (prot) *prot = ipptr->ip_p;
71
72        return trans_ptr;
73}
74
75void *trace_get_payload_from_ip6(libtrace_ip6_t *ipptr, uint8_t *prot,
76                uint32_t *remaining) 
77{
78        void *payload = (char*)ipptr+sizeof(libtrace_ip6_t);
79        uint8_t nxt;
80
81        assert (ipptr != NULL);
82        nxt = ipptr->nxt;       
83        if (remaining) {
84                if (*remaining<sizeof(libtrace_ip6_t)) {
85                        *remaining = 0;
86                        return NULL;
87                }
88                *remaining-=sizeof(libtrace_ip6_t);
89        }
90
91        while(1) {
92                switch (nxt) {
93                        case 0: /* hop by hop options */
94                        case 43: /* routing */
95                        case 44: /* fragment */
96                        case 50: /* ESP */
97                        case 51: /* AH */
98                        case 60: /* Destination options */
99                                {
100                                        uint16_t len=((libtrace_ip6_ext_t*)payload)->len
101                                        +sizeof(libtrace_ip6_ext_t);
102
103                                        if (remaining) {
104                                                if (*remaining < len) {
105                                                        /* Snap too short */
106                                                        *remaining = 0;
107                                                        return NULL;
108                                                }
109                                                *remaining-=len;
110                                        }
111
112                                        payload=(char*)payload+len;
113                                        nxt=((libtrace_ip6_ext_t*)payload)->nxt;
114                                        continue;
115                                }
116                        default:
117                                if (prot) *prot=nxt;
118                                return payload;
119                }
120        }
121}
122
123DLLEXPORT void *trace_get_layer3(const libtrace_packet_t *packet,
124                uint16_t *ethertype,
125                uint32_t *remaining)
126{
127        void *iphdr;
128        uint16_t dummy_ethertype;
129        void *link;
130        uint32_t dummy_remaining;
131        libtrace_linktype_t linktype;
132
133        if (!ethertype) ethertype=&dummy_ethertype;
134
135        if (!remaining) remaining=&dummy_remaining;
136
137        /* use l3 cache */
138        if (packet->l3_header)
139        {
140                link = trace_get_packet_buffer(packet,&linktype,remaining);
141
142                if (!link)
143                        return NULL;
144
145                *ethertype = packet->l3_ethertype;
146                *remaining -= (packet->l3_header - link);
147
148                return packet->l3_header;
149        }
150
151        link = trace_get_layer2(packet,&linktype,remaining);
152        iphdr = trace_get_payload_from_layer2(
153                        link,
154                        linktype,
155                        ethertype,
156                        remaining);
157
158        for(;;) {
159                if (!iphdr || *remaining == 0)
160                        break;
161                switch(*ethertype) {
162                case 0x8100: /* VLAN */
163                        iphdr=trace_get_payload_from_vlan(
164                                          iphdr,ethertype,remaining);
165                        continue;
166                case 0x8847: /* MPLS */
167                        iphdr=trace_get_payload_from_mpls(
168                                          iphdr,ethertype,remaining);
169
170                        if (iphdr && ethertype == 0x0) {
171                                iphdr=trace_get_payload_from_ethernet(
172                                                iphdr,ethertype,remaining);
173                        }
174                        continue;
175                case 0x8864: /* PPPoE */
176                        iphdr = trace_get_payload_from_pppoe(iphdr, ethertype,
177                                        remaining);
178                        continue;
179                default:
180                        break;
181                }
182
183                break;
184        }
185
186        if (!iphdr || *remaining == 0)
187                return NULL;
188
189        /* Store values in the cache for later */
190        /* Cast away constness, nasty, but this is just a cache */
191        ((libtrace_packet_t*)packet)->l3_ethertype = *ethertype;
192        ((libtrace_packet_t*)packet)->l3_header = iphdr;
193
194        return iphdr;
195}
196
197/* parse an ip or tcp option
198 * @param[in,out] ptr   the pointer to the current option
199 * @param[in,out] len   the length of the remaining buffer
200 * @param[out] type     the type of the option
201 * @param[out] optlen   the length of the option
202 * @param[out] data     the data of the option
203 *
204 * @returns bool true if there is another option (and the fields are filled in)
205 *               or false if this was the last option.
206 *
207 * This updates ptr to point to the next option after this one, and updates
208 * len to be the number of bytes remaining in the options area.  Type is updated
209 * to be the code of this option, and data points to the data of this option,
210 * with optlen saying how many bytes there are.
211 *
212 * @note Beware of fragmented packets.
213 * @author Perry Lorier
214 */
215DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
216                        unsigned char *type,
217                        unsigned char *optlen,
218                        unsigned char **data)
219{
220        if (*len<=0)
221                return 0;
222        *type=**ptr;
223        switch(*type) {
224                case 0: /* End of options */
225                        return 0;
226                case 1: /* Pad */
227                        (*ptr)++;
228                        (*len)--;
229                        return 1;
230                default:
231                        *optlen = *(*ptr+1);
232                        if (*optlen<2)
233                                return 0; /* I have no idea wtf is going on
234                                           * with these packets
235                                           */
236                        (*len)-=*optlen;
237                        (*data)=(*ptr+2);
238                        (*ptr)+=*optlen;
239                        if (*len<0)
240                                return 0;
241                        return 1;
242        }
243        assert(0);
244}
245
246DLLEXPORT struct sockaddr *trace_get_source_address(
247                const libtrace_packet_t *packet, struct sockaddr *addr)
248{
249        uint16_t ethertype;
250        uint32_t remaining;
251        void *l3;
252        struct ports_t *ports;
253        static struct sockaddr_storage dummy;
254
255        if (!addr)
256                addr=(struct sockaddr*)&dummy;
257
258        l3 = trace_get_layer3(packet,&ethertype,&remaining);
259
260        if (!l3)
261                return NULL;
262
263        switch (ethertype) {
264                case 0x0800: /* IPv4 */
265                {
266                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
267                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
268                        ports = (struct ports_t*)
269                                trace_get_payload_from_ip(ip,NULL,&remaining);
270                        addr4->sin_family=AF_INET;
271                        if (ports && remaining>=sizeof(*ports))
272                                addr4->sin_port=ports->src;
273                        else
274                                addr4->sin_port=0;
275                        addr4->sin_addr=ip->ip_src;
276                        return addr;
277                }
278                case 0x86DD: /* IPv6 */
279                {
280                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
281                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
282                        ports = (struct ports_t*)
283                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
284                        addr6->sin6_family=AF_INET6;
285                        if (ports && remaining>=sizeof(*ports))
286                                addr6->sin6_port=ports->src;
287                        else
288                                addr6->sin6_port=0;
289                        addr6->sin6_flowinfo=0;
290                        addr6->sin6_addr=ip6->ip_src;
291                        return addr;
292                }
293                default:
294                        return NULL;
295        }
296}
297
298DLLEXPORT struct sockaddr *trace_get_destination_address(
299                const libtrace_packet_t *packet, struct sockaddr *addr)
300{
301        uint16_t ethertype;
302        uint32_t remaining;
303        void *l3;
304        struct ports_t *ports;
305        static struct sockaddr_storage dummy;
306
307        if (!addr)
308                addr=(struct sockaddr*)&dummy;
309
310        l3 = trace_get_layer3(packet,&ethertype,&remaining);
311
312        if (!l3)
313                return NULL;
314
315        switch (ethertype) {
316                case 0x0800: /* IPv4 */
317                {
318                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
319                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
320                        ports = (struct ports_t*)
321                                trace_get_payload_from_ip(ip,NULL,&remaining);
322                        addr4->sin_family=AF_INET;
323                        if (ports && remaining>=sizeof(*ports))
324                                addr4->sin_port=ports->dst;
325                        else
326                                addr4->sin_port=0;
327                        addr4->sin_addr=ip->ip_dst;
328                        return addr;
329                }
330                case 0x86DD: /* IPv6 */
331                {
332                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
333                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
334                        ports = (struct ports_t*)
335                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
336                        addr6->sin6_family=AF_INET6;
337                        if (ports && remaining>=sizeof(*ports))
338                                addr6->sin6_port=ports->dst;
339                        else
340                                addr6->sin6_port=0;
341                        addr6->sin6_flowinfo=0;
342                        addr6->sin6_addr=ip6->ip_dst;
343                        return addr;
344                }
345                default:
346                        return NULL;
347        }
348}
349
350
Note: See TracBrowser for help on using the repository browser.