source: lib/protocols_l3.c @ 75453c2

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

Fix byte ordering issue

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