source: lib/protocols_l3.c @ 35782f6

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