source: lib/protocols_l3.c @ 11c0f44

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