source: lib/protocols_l3.c @ 871281c

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

Make sure NULL is defined.
Make sure stdio is included for printf
Use fprintf, not printf

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