source: lib/protocols_l3.c @ ad36006

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

Fix typo.

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