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