source: lib/protocols_l3.c @ 411666a

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