1 /*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 * Perry Lorier
9 * Shane Alcock
10 *
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 * $Id: linktypes.c 1859 2014-02-20 21:38:06Z salcock $
31 *
32 */
33
34 #include "config.h"
35 #include "libtrace.h"
36
37 #include "rt_protocol.h"
38 #include <assert.h>
39 #include "libtrace_int.h"
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "libtrace_arphrd.h"
44
45
46 /* This file maps libtrace types to/from pcap DLT and erf types
47 *
48 * When adding a new linktype to libtrace, add the mapping(s) here,
49 * and add the understanding of the type to get_ip(), and perhaps
50 * get_{source,destination}_mac (if your linklayer has mac's)
51 */
52
pcap_linktype_to_libtrace(libtrace_dlt_t linktype)53 libtrace_linktype_t pcap_linktype_to_libtrace(libtrace_dlt_t linktype)
54 {
55 switch(linktype) {
56 case TRACE_DLT_RAW:
57 case TRACE_DLT_LINKTYPE_RAW: return TRACE_TYPE_NONE;
58 case TRACE_DLT_EN10MB: return TRACE_TYPE_ETH;
59 case TRACE_DLT_IEEE802_11: return TRACE_TYPE_80211;
60 case TRACE_DLT_LINUX_SLL: return TRACE_TYPE_LINUX_SLL;
61 case TRACE_DLT_PFLOG: return TRACE_TYPE_PFLOG;
62 case TRACE_DLT_IEEE802_11_RADIO: return TRACE_TYPE_80211_RADIO;
63 case TRACE_DLT_ATM_RFC1483: return TRACE_TYPE_LLCSNAP;
64 case TRACE_DLT_PPP: return TRACE_TYPE_PPP;
65 case TRACE_DLT_PPP_SERIAL: return TRACE_TYPE_POS;
66 case TRACE_DLT_C_HDLC: return TRACE_TYPE_HDLC_POS;
67 case TRACE_DLT_OPENBSD_LOOP: return TRACE_TYPE_OPENBSD_LOOP;
68 /* Unhandled */
69 case TRACE_DLT_ERROR:
70 case TRACE_DLT_NULL: /* Raw IP frame with a BSD specific
71 * header If you want raw L3 headers
72 * use TRACE_DLT_RAW
73 */
74 break;
75 }
76 return TRACE_TYPE_UNKNOWN;
77 }
78
libtrace_to_pcap_dlt(libtrace_linktype_t type)79 libtrace_dlt_t libtrace_to_pcap_dlt(libtrace_linktype_t type)
80 {
81 /* If pcap doesn't have a DLT, you can either ask pcap to register
82 * you a DLT, (and perhaps write a tcpdump decoder for it), or you
83 * can add it to demote_packet
84 */
85 switch(type) {
86 case TRACE_TYPE_NONE: return TRACE_DLT_RAW;
87 case TRACE_TYPE_ETH: return TRACE_DLT_EN10MB;
88 case TRACE_TYPE_80211: return TRACE_DLT_IEEE802_11;
89 case TRACE_TYPE_LINUX_SLL: return TRACE_DLT_LINUX_SLL;
90 case TRACE_TYPE_PFLOG: return TRACE_DLT_PFLOG;
91 case TRACE_TYPE_80211_RADIO: return TRACE_DLT_IEEE802_11_RADIO;
92 case TRACE_TYPE_LLCSNAP: return TRACE_DLT_ATM_RFC1483;
93 case TRACE_TYPE_PPP: return TRACE_DLT_PPP;
94 case TRACE_TYPE_HDLC_POS: return TRACE_DLT_C_HDLC;
95 /* Theres more than one type of PPP. Who knew? */
96 case TRACE_TYPE_POS: return TRACE_DLT_PPP_SERIAL;
97 case TRACE_TYPE_OPENBSD_LOOP: return TRACE_DLT_OPENBSD_LOOP;
98
99 /* Below here are unsupported conversions */
100 /* Despite hints to the contrary, there is no DLT
101 * for 'raw atm packets that happen to be missing
102 * the HEC' or even 'raw atm packets that have a hec'.
103 *
104 * The closest are DLT_ATM_RFC1483 but that doesn't
105 * include the ATM header, only the LLCSNAP header.
106 */
107 case TRACE_TYPE_ATM:
108 /* pcap has no DLT for DUCK */
109 case TRACE_TYPE_DUCK:
110 /* Used for test traces within WAND */
111 case TRACE_TYPE_80211_PRISM:
112 /* Probably == PPP */
113 /* TODO: We haven't researched these yet */
114 case TRACE_TYPE_AAL5:
115 case TRACE_TYPE_METADATA:
116 case TRACE_TYPE_NONDATA:
117 break;
118 case TRACE_TYPE_UNKNOWN:
119 break;
120 }
121 return TRACE_DLT_ERROR;
122 }
123
pcap_dlt_to_pcap_linktype(libtrace_dlt_t linktype)124 static libtrace_dlt_t pcap_dlt_to_pcap_linktype(libtrace_dlt_t linktype)
125 {
126 switch (linktype) {
127 case TRACE_DLT_RAW: return TRACE_DLT_LINKTYPE_RAW;
128 default:
129 return linktype;
130 }
131 }
132
libtrace_to_pcap_linktype(libtrace_linktype_t type)133 libtrace_dlt_t libtrace_to_pcap_linktype(libtrace_linktype_t type)
134 {
135 return pcap_dlt_to_pcap_linktype(libtrace_to_pcap_dlt(type));
136 }
137
pcap_linktype_to_rt(libtrace_dlt_t linktype)138 libtrace_rt_types_t pcap_linktype_to_rt(libtrace_dlt_t linktype)
139 {
140 /* For pcap the rt type is just the linktype + a fixed value */
141 return pcap_dlt_to_pcap_linktype(linktype) + TRACE_RT_DATA_DLT;
142 }
143
bpf_linktype_to_rt(libtrace_dlt_t linktype)144 libtrace_rt_types_t bpf_linktype_to_rt(libtrace_dlt_t linktype) {
145 return pcap_dlt_to_pcap_linktype(linktype) + TRACE_RT_DATA_BPF;
146
147 }
148
rt_to_pcap_linktype(libtrace_rt_types_t rt_type)149 libtrace_dlt_t rt_to_pcap_linktype(libtrace_rt_types_t rt_type)
150 {
151
152 if (rt_type >= TRACE_RT_DATA_DLT && rt_type < TRACE_RT_DATA_DLT_END) {
153 /* RT type is in the pcap range */
154 return rt_type - TRACE_RT_DATA_DLT;
155 }
156 else if (rt_type >= TRACE_RT_DATA_BPF && rt_type < TRACE_RT_DATA_BPF_END) {
157 return rt_type - TRACE_RT_DATA_BPF;
158 }
159
160 fprintf(stderr, "Error: RT type %u cannot be converted to a pcap DLT\n", rt_type);
161 assert(rt_type >= TRACE_RT_DATA_DLT && rt_type < TRACE_RT_DATA_BPF_END);
162 return 0; /* satisfy warnings */
163 }
164
erf_type_to_libtrace(uint8_t erf)165 libtrace_linktype_t erf_type_to_libtrace(uint8_t erf)
166 {
167 switch (erf) {
168 case TYPE_HDLC_POS: return TRACE_TYPE_HDLC_POS;
169 case TYPE_ETH: return TRACE_TYPE_ETH;
170 case TYPE_ATM: return TRACE_TYPE_ATM;
171 case TYPE_AAL5: return TRACE_TYPE_AAL5;
172 case TYPE_DSM_COLOR_ETH:return TRACE_TYPE_ETH;
173 case TYPE_IPV4: return TRACE_TYPE_NONE;
174 case TYPE_IPV6: return TRACE_TYPE_NONE;
175 }
176 return ~0U;
177 }
178
libtrace_to_erf_type(libtrace_linktype_t linktype)179 uint8_t libtrace_to_erf_type(libtrace_linktype_t linktype)
180 {
181 switch(linktype) {
182 case TRACE_TYPE_HDLC_POS: return TYPE_HDLC_POS;
183 case TRACE_TYPE_ETH: return TYPE_ETH;
184 case TRACE_TYPE_ATM: return TYPE_ATM;
185 case TRACE_TYPE_AAL5: return TYPE_AAL5;
186
187 /* Not technically correct! Could be IPv6 packet
188 *
189 * TODO: Maybe we want TRACE_TYPE_RAW_IPV4 and
190 * TRACE_TYPE_RAW_IPV6 to replace TRACE_TYPE_NONE.
191 * Still need a good way to figure out how to convert
192 * TRACE_DLT_LINKTYPE_RAW into the correct type for the
193 * IP version though :( */
194 case TRACE_TYPE_NONE: return TYPE_IPV4;
195 /* Unsupported conversions */
196 case TRACE_TYPE_LLCSNAP:
197 case TRACE_TYPE_DUCK:
198 case TRACE_TYPE_80211_RADIO:
199 case TRACE_TYPE_80211_PRISM:
200 case TRACE_TYPE_80211:
201 case TRACE_TYPE_PFLOG:
202 case TRACE_TYPE_LINUX_SLL:
203 case TRACE_TYPE_PPP:
204 case TRACE_TYPE_POS:
205 case TRACE_TYPE_METADATA:
206 case TRACE_TYPE_NONDATA:
207 case TRACE_TYPE_OPENBSD_LOOP:
208 case TRACE_TYPE_UNKNOWN:
209 break;
210 }
211 return 255;
212 }
213
arphrd_type_to_libtrace(unsigned int arphrd)214 libtrace_linktype_t arphrd_type_to_libtrace(unsigned int arphrd) {
215 switch(arphrd) {
216 case LIBTRACE_ARPHRD_ETHER: return TRACE_TYPE_ETH;
217 case LIBTRACE_ARPHRD_EETHER: return TRACE_TYPE_ETH;
218 case LIBTRACE_ARPHRD_IEEE80211: return TRACE_TYPE_80211;
219 case LIBTRACE_ARPHRD_IEEE80211_RADIOTAP: return TRACE_TYPE_80211_RADIO;
220 case LIBTRACE_ARPHRD_PPP: return TRACE_TYPE_NONE;
221 case LIBTRACE_ARPHRD_LOOPBACK: return TRACE_TYPE_ETH;
222 case LIBTRACE_ARPHRD_NONE: return TRACE_TYPE_NONE;
223 }
224 printf("Unknown ARPHRD %08x\n",arphrd);
225 return ~0U;
226 }
227
libtrace_to_arphrd_type(libtrace_linktype_t linktype)228 unsigned int libtrace_to_arphrd_type(libtrace_linktype_t linktype) {
229 switch(linktype) {
230 case TRACE_TYPE_ETH: return LIBTRACE_ARPHRD_ETHER;
231 case TRACE_TYPE_80211: return LIBTRACE_ARPHRD_IEEE80211;
232 case TRACE_TYPE_80211_RADIO: return LIBTRACE_ARPHRD_IEEE80211_RADIOTAP;
233 default: break;
234 }
235 return ~0U;
236 }
237
238 /** Prepends a Linux SLL header to the packet.
239 *
240 * Packets that don't support direction tagging are annoying, especially
241 * when we have direction tagging information! So this converts the packet
242 * to TRACE_TYPE_LINUX_SLL which does support direction tagging. This is a
243 * pcap style packet for the reason that it means it works with bpf filters.
244 *
245 * @note this will copy the packet, so use sparingly if possible.
246 */
promote_packet(libtrace_packet_t * packet)247 void promote_packet(libtrace_packet_t *packet)
248 {
249 if (packet->trace->format->type == TRACE_FORMAT_PCAP) {
250 char *tmpbuffer;
251 libtrace_sll_header_t *hdr;
252
253 if (pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type))
254 == TRACE_TYPE_LINUX_SLL) {
255 /* This is already been promoted, so ignore it */
256 return;
257 }
258
259 /* This should be easy, just prepend the header */
260 tmpbuffer= (char*)malloc(
261 sizeof(libtrace_sll_header_t)
262 +trace_get_capture_length(packet)
263 +trace_get_framing_length(packet)
264 );
265
266 hdr=(libtrace_sll_header_t*)((char*)tmpbuffer
267 +trace_get_framing_length(packet));
268
269 hdr->halen=htons(6);
270 hdr->pkttype=TRACE_SLL_OUTGOING;
271
272 switch(pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type))) {
273 case TRACE_TYPE_NONE:
274 trace_get_layer3(packet, &hdr->protocol, NULL);
275 hdr->hatype = htons(LIBTRACE_ARPHRD_PPP);
276 hdr->protocol=htons(hdr->protocol);
277 break;
278 case TRACE_TYPE_ETH:
279 hdr->hatype = htons(LIBTRACE_ARPHRD_ETHER);
280 hdr->protocol=htons(0x0060); /* ETH_P_LOOP */
281 break;
282 default:
283 /* failed */
284 return;
285 }
286 memcpy(tmpbuffer,packet->header,
287 trace_get_framing_length(packet));
288 memcpy(tmpbuffer
289 +sizeof(libtrace_sll_header_t)
290 +trace_get_framing_length(packet),
291 packet->payload,
292 trace_get_capture_length(packet));
293 if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
294 packet->buf_control=TRACE_CTRL_PACKET;
295 }
296 else {
297 free(packet->buffer);
298 }
299 packet->buffer=tmpbuffer;
300 packet->header=tmpbuffer;
301 packet->payload=tmpbuffer+trace_get_framing_length(packet);
302 packet->type=pcap_linktype_to_rt(TRACE_DLT_LINUX_SLL);
303 ((struct libtrace_pcapfile_pkt_hdr_t*) packet->header)->caplen+=
304 sizeof(libtrace_sll_header_t);
305 ((struct libtrace_pcapfile_pkt_hdr_t*) packet->header)->wirelen+=
306 sizeof(libtrace_sll_header_t);
307 trace_clear_cache(packet);
308 return;
309 }
310 }
311
312 /* Try and remove any extraneous encapsulation that may have been added to
313 * a packet. Effectively the opposite to promote_packet.
314 *
315 * Returns true if demotion was possible, false if not.
316 */
demote_packet(libtrace_packet_t * packet)317 bool demote_packet(libtrace_packet_t *packet)
318 {
319 uint8_t type;
320 uint16_t ha_type, next_proto;
321 libtrace_sll_header_t *sll = NULL;
322 uint32_t remaining = 0;
323 char *tmp;
324 struct timeval tv;
325 static libtrace_t *trace = NULL;
326 switch(trace_get_link_type(packet)) {
327 case TRACE_TYPE_ATM:
328 remaining=trace_get_capture_length(packet);
329 packet->payload=trace_get_payload_from_atm(
330 packet->payload,&type,&remaining);
331 if (!packet->payload)
332 return false;
333 tmp=(char*)malloc(
334 trace_get_capture_length(packet)
335 +sizeof(libtrace_pcapfile_pkt_hdr_t)
336 );
337
338 tv=trace_get_timeval(packet);
339 ((libtrace_pcapfile_pkt_hdr_t*)tmp)->ts_sec=tv.tv_sec;
340 ((libtrace_pcapfile_pkt_hdr_t*)tmp)->ts_usec=tv.tv_usec;
341 ((libtrace_pcapfile_pkt_hdr_t*)tmp)->wirelen
342 = trace_get_wire_length(packet)-(trace_get_capture_length(packet)-remaining);
343 ((libtrace_pcapfile_pkt_hdr_t*)tmp)->caplen
344 = remaining;
345
346 memcpy(tmp+sizeof(libtrace_pcapfile_pkt_hdr_t),
347 packet->payload,
348 (size_t)remaining);
349 if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
350 packet->buf_control=TRACE_CTRL_PACKET;
351 }
352 else {
353 free(packet->buffer);
354 }
355 packet->buffer=tmp;
356 packet->header=tmp;
357 packet->payload=tmp+sizeof(libtrace_pcapfile_pkt_hdr_t);
358 packet->type=pcap_linktype_to_rt(TRACE_DLT_ATM_RFC1483);
359
360 if (trace == NULL) {
361 trace = trace_create_dead("pcapfile:-");
362 }
363
364 packet->trace=trace;
365
366 /* Invalidate caches */
367 trace_clear_cache(packet);
368 return true;
369
370 case TRACE_TYPE_LINUX_SLL:
371 sll = (libtrace_sll_header_t *)(packet->payload);
372
373 ha_type = ntohs(sll->hatype);
374 next_proto = ntohs(sll->protocol);
375
376 /* Preserved from older libtrace behaviour */
377 if (ha_type == LIBTRACE_ARPHRD_PPP)
378 packet->type = pcap_linktype_to_rt(TRACE_DLT_RAW);
379 /* Don't decide trace type based on ha_type,
380 * decide based on the protocol header that is
381 * coming up!
382 */
383 else if (next_proto == TRACE_ETHERTYPE_LOOPBACK)
384 packet->type = pcap_linktype_to_rt(TRACE_DLT_EN10MB);
385 else if (next_proto == TRACE_ETHERTYPE_IP)
386 packet->type = pcap_linktype_to_rt(TRACE_DLT_RAW);
387 else if (next_proto == TRACE_ETHERTYPE_IPV6)
388 packet->type = pcap_linktype_to_rt(TRACE_DLT_RAW);
389 else
390 return false;
391
392 /* Skip the Linux SLL header */
393 packet->payload=(void*)((char*)packet->payload
394 +sizeof(libtrace_sll_header_t));
395 trace_set_capture_length(packet,
396 trace_get_capture_length(packet)
397 -sizeof(libtrace_sll_header_t));
398
399 /* Invalidate caches */
400 trace_clear_cache(packet);
401 break;
402 default:
403 return false;
404 }
405
406 /* Invalidate caches */
407 trace_clear_cache(packet);
408 return true;
409 }
410