File: linktypes.c

package info (click to toggle)
libtrace3 3.0.7-1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 3,676 kB
  • ctags: 3,140
  • sloc: ansic: 20,551; sh: 10,125; cpp: 1,384; makefile: 415; yacc: 96; lex: 50
file content (390 lines) | stat: -rw-r--r-- 11,434 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
/*
 * This file is part of libtrace
 *
 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton, 
 * New Zealand.
 *
 * Authors: Daniel Lawson 
 *          Perry Lorier
 *          Shane Alcock 
 *          
 * All rights reserved.
 *
 * This code has been developed by the University of Waikato WAND 
 * research group. For further information please see http://www.wand.net.nz/
 *
 * libtrace is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * libtrace is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libtrace; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: linktypes.c 1646 2010-08-02 03:49:15Z salcock $
 *
 */

#include "config.h"
#include "libtrace.h"

#include "rt_protocol.h"
#include <assert.h>
#include "libtrace_int.h"
#include <stdlib.h>
#include <string.h>

#ifndef WIN32
#include <net/if_arp.h>
#endif

#ifndef ARPHRD_ETHER
#define ARPHRD_ETHER    1               /* Ethernet 10/100Mbps.  */
#endif

#ifndef ARPHRD_EETHER
#define ARPHRD_EETHER    2               /* Experimental Ethernet 10/100Mbps.  */
#endif

#ifndef ARPHRD_PPP
#define ARPHRD_PPP      512
#endif

#ifndef ARPHRD_IEEE80211
#define ARPHRD_IEEE80211	801
#endif

#ifndef ARPHRD_NONE
#define ARPHRD_NONE	0xFFFE
#endif


/* This file maps libtrace types to/from pcap DLT and erf types
 *
 * When adding a new linktype to libtrace, add the mapping(s) here,
 * and add the understanding of the type to get_ip(), and perhaps
 * get_{source,destination}_mac (if your linklayer has mac's)
 */

libtrace_linktype_t pcap_linktype_to_libtrace(libtrace_dlt_t linktype)
{
	switch(linktype) {
		case TRACE_DLT_RAW:
		case TRACE_DLT_LINKTYPE_RAW: return TRACE_TYPE_NONE;
		case TRACE_DLT_EN10MB: return TRACE_TYPE_ETH;
		case TRACE_DLT_IEEE802_11: return TRACE_TYPE_80211;
		case TRACE_DLT_LINUX_SLL: return TRACE_TYPE_LINUX_SLL;
		case TRACE_DLT_PFLOG: return TRACE_TYPE_PFLOG;
        	case TRACE_DLT_IEEE802_11_RADIO: return TRACE_TYPE_80211_RADIO;
		case TRACE_DLT_ATM_RFC1483: return TRACE_TYPE_LLCSNAP;
		case TRACE_DLT_PPP: return TRACE_TYPE_PPP;
		case TRACE_DLT_PPP_SERIAL: return TRACE_TYPE_POS;
		case TRACE_DLT_C_HDLC: return TRACE_TYPE_HDLC_POS;
		/* Unhandled */
		case TRACE_DLT_NULL: 	/* Raw IP frame with a BSD specific
					 * header If you want raw L3 headers
					 * use TRACE_DLT_RAW
					 */
			break;
	}
	return ~0U;
}

libtrace_dlt_t libtrace_to_pcap_dlt(libtrace_linktype_t type)
{
	/* If pcap doesn't have a DLT, you can either ask pcap to register
	 * you a DLT, (and perhaps write a tcpdump decoder for it), or you
	 * can add it to demote_packet
	 */
	switch(type) {
		case TRACE_TYPE_NONE: return TRACE_DLT_RAW; 
		case TRACE_TYPE_ETH: return TRACE_DLT_EN10MB;
		case TRACE_TYPE_80211: return TRACE_DLT_IEEE802_11;
		case TRACE_TYPE_LINUX_SLL: return TRACE_DLT_LINUX_SLL;
		case TRACE_TYPE_PFLOG: return TRACE_DLT_PFLOG;
		case TRACE_TYPE_80211_RADIO: return TRACE_DLT_IEEE802_11_RADIO;
		case TRACE_TYPE_LLCSNAP: return TRACE_DLT_ATM_RFC1483;
		case TRACE_TYPE_PPP:	return TRACE_DLT_PPP;
		case TRACE_TYPE_HDLC_POS: return TRACE_DLT_C_HDLC;
		/* Theres more than one type of PPP.  Who knew? */
		case TRACE_TYPE_POS:	return TRACE_DLT_PPP_SERIAL; 

		/* Below here are unsupported conversions */
		/* Despite hints to the contrary, there is no DLT
		 * for 'raw atm packets that happen to be missing
		 * the HEC' or even 'raw atm packets that have a hec'.
		 *
		 * The closest are DLT_ATM_RFC1483 but that doesn't
		 * include the ATM header, only the LLCSNAP header.
		 */
		case TRACE_TYPE_ATM: 
		/* pcap has no DLT for DUCK */
		case TRACE_TYPE_DUCK:
		/* Used for test traces within WAND */
		case TRACE_TYPE_80211_PRISM: 	
		/* Probably == PPP */
		/* TODO: We haven't researched these yet */
		case TRACE_TYPE_AAL5:
		case TRACE_TYPE_METADATA:
		case TRACE_TYPE_NONDATA:
			break;
	}
	return ~0U;
}

static libtrace_dlt_t pcap_dlt_to_pcap_linktype(libtrace_dlt_t linktype)
{
	switch (linktype) {
		case TRACE_DLT_RAW: return TRACE_DLT_LINKTYPE_RAW;
		default:
				    return linktype;
	}
}

libtrace_dlt_t libtrace_to_pcap_linktype(libtrace_linktype_t type)
{
	return pcap_dlt_to_pcap_linktype(libtrace_to_pcap_dlt(type));
}

libtrace_rt_types_t pcap_linktype_to_rt(libtrace_dlt_t linktype) 
{
	/* For pcap the rt type is just the linktype + a fixed value */
	return pcap_dlt_to_pcap_linktype(linktype) + TRACE_RT_DATA_DLT;
}

libtrace_dlt_t rt_to_pcap_linktype(libtrace_rt_types_t rt_type)
{
	assert(rt_type >= TRACE_RT_DATA_DLT);
	return rt_type - TRACE_RT_DATA_DLT;
}

libtrace_linktype_t erf_type_to_libtrace(uint8_t erf)
{
	switch (erf) {
		case TYPE_HDLC_POS:	return TRACE_TYPE_HDLC_POS;
		case TYPE_ETH:		return TRACE_TYPE_ETH;
		case TYPE_ATM:		return TRACE_TYPE_ATM;
		case TYPE_AAL5:		return TRACE_TYPE_AAL5;
		case TYPE_DSM_COLOR_ETH:return TRACE_TYPE_ETH;
	}
	return ~0U;
}

uint8_t libtrace_to_erf_type(libtrace_linktype_t linktype)
{
	switch(linktype) {
		case TRACE_TYPE_HDLC_POS: return TYPE_HDLC_POS;
		case TRACE_TYPE_ETH:	return TYPE_ETH;
		case TRACE_TYPE_ATM:	return TYPE_ATM;
		case TRACE_TYPE_AAL5:	return TYPE_AAL5;
		/* Unsupported conversions */
		case TRACE_TYPE_LLCSNAP: 
		case TRACE_TYPE_DUCK:
		case TRACE_TYPE_80211_RADIO:
		case TRACE_TYPE_80211_PRISM:
		case TRACE_TYPE_80211:
		case TRACE_TYPE_PFLOG:
		case TRACE_TYPE_NONE:
		case TRACE_TYPE_LINUX_SLL:
		case TRACE_TYPE_PPP:
		case TRACE_TYPE_POS:
		case TRACE_TYPE_METADATA:
		case TRACE_TYPE_NONDATA:
			break;
	}
	return 255;
}

libtrace_linktype_t arphrd_type_to_libtrace(unsigned int arphrd) {
	switch(arphrd) {
		case ARPHRD_ETHER: return TRACE_TYPE_ETH;	
		case ARPHRD_EETHER: return TRACE_TYPE_ETH;	
		case ARPHRD_IEEE80211: return TRACE_TYPE_80211;
		case ARPHRD_80211_RADIOTAP: return TRACE_TYPE_80211_RADIO;
		case ARPHRD_PPP: return TRACE_TYPE_NONE;
		case ARPHRD_NONE: return TRACE_TYPE_NONE;
	}
	printf("Unknown ARPHRD %08x\n",arphrd);
	return ~0U;
}

unsigned int libtrace_to_arphrd_type(libtrace_linktype_t linktype) {
	switch(linktype) {
		case TRACE_TYPE_ETH: return ARPHRD_ETHER;
		case TRACE_TYPE_80211: return ARPHRD_IEEE80211;
		case TRACE_TYPE_80211_RADIO: return ARPHRD_80211_RADIOTAP;
	  	default: break;
	}
	return ~0U;
}

/** Prepends a Linux SLL header to the packet.
 * 
 * Packets that don't support direction tagging are annoying, especially
 * when we have direction tagging information!  So this converts the packet
 * to TRACE_TYPE_LINUX_SLL which does support direction tagging.  This is a
 * pcap style packet for the reason that it means it works with bpf filters.
 *
 * @note this will copy the packet, so use sparingly if possible.
 */
void promote_packet(libtrace_packet_t *packet)
{
	if (packet->trace->format->type == TRACE_FORMAT_PCAP) {
		char *tmpbuffer;
		libtrace_sll_header_t *hdr;

		if (pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type))
			== TRACE_TYPE_LINUX_SLL) {
			/* This is already been promoted, so ignore it */
			return;
		}

		/* This should be easy, just prepend the header */
		tmpbuffer= (char*)malloc(
				sizeof(libtrace_sll_header_t)
				+trace_get_capture_length(packet)
				+trace_get_framing_length(packet)
				);

		hdr=(libtrace_sll_header_t*)((char*)tmpbuffer
			+trace_get_framing_length(packet));

		hdr->halen=htons(6);
		hdr->pkttype=TRACE_SLL_OUTGOING;

		switch(pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type))) {
			case TRACE_TYPE_NONE:
				trace_get_layer3(packet, &hdr->protocol, NULL);
				hdr->hatype = htons(ARPHRD_PPP);
				hdr->protocol=htons(hdr->protocol);
				break;
			case TRACE_TYPE_ETH:
				hdr->hatype = htons(ARPHRD_ETHER);
				hdr->protocol=htons(0x0060); /* ETH_P_LOOP */
				break;
			default:
				/* failed */
				return;
		}
		memcpy(tmpbuffer,packet->header,
				trace_get_framing_length(packet));
		memcpy(tmpbuffer
				+sizeof(libtrace_sll_header_t)
				+trace_get_framing_length(packet),
				packet->payload,
				trace_get_capture_length(packet));
		if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
			packet->buf_control=TRACE_CTRL_PACKET;
		}
		else {
			free(packet->buffer);
		}
		packet->buffer=tmpbuffer;
		packet->header=tmpbuffer;
		packet->payload=tmpbuffer+trace_get_framing_length(packet);
		packet->type=pcap_linktype_to_rt(TRACE_DLT_LINUX_SLL);
		((struct libtrace_pcapfile_pkt_hdr_t*) packet->header)->caplen+=
			sizeof(libtrace_sll_header_t);
		((struct libtrace_pcapfile_pkt_hdr_t*) packet->header)->wirelen+=
			sizeof(libtrace_sll_header_t);
		return;
	}
}

/* Try and remove any extraneous encapsulation that may have been added to
 * a packet. Effectively the opposite to promote_packet.
 *
 * Returns true if demotion was possible, false if not.
 */
bool demote_packet(libtrace_packet_t *packet)
{
	uint8_t type;
	uint32_t remaining = 0;
	char *tmp;
	struct timeval tv;
	static libtrace_t *trace = NULL;
	switch(trace_get_link_type(packet)) {
		case TRACE_TYPE_ATM:
			remaining=trace_get_capture_length(packet);
			packet->payload=trace_get_payload_from_atm(
				packet->payload,&type,&remaining);
			if (!packet->payload)
				return false;
			tmp=(char*)malloc(
				trace_get_capture_length(packet)
				+sizeof(libtrace_pcapfile_pkt_hdr_t)
				);

			tv=trace_get_timeval(packet);
			((libtrace_pcapfile_pkt_hdr_t*)tmp)->ts_sec=tv.tv_sec;
			((libtrace_pcapfile_pkt_hdr_t*)tmp)->ts_usec=tv.tv_usec;
			((libtrace_pcapfile_pkt_hdr_t*)tmp)->wirelen
				= trace_get_wire_length(packet)-(trace_get_capture_length(packet)-remaining);
			((libtrace_pcapfile_pkt_hdr_t*)tmp)->caplen
				= remaining;

			memcpy(tmp+sizeof(libtrace_pcapfile_pkt_hdr_t),
					packet->payload,
					(size_t)remaining);
			if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
				packet->buf_control=TRACE_CTRL_PACKET;
			}
			else {
				free(packet->buffer);
			}
			packet->buffer=tmp;
			packet->header=tmp;
			packet->payload=tmp+sizeof(libtrace_pcapfile_pkt_hdr_t);
			packet->type=pcap_linktype_to_rt(TRACE_DLT_ATM_RFC1483);
			
			if (trace == NULL) {
				trace = trace_create_dead("pcapfile:-");
			}

			packet->trace=trace;

			/* Invalidate caches */
			packet->l3_header = NULL;
			packet->capture_length = -1;

			return true;

		case TRACE_TYPE_LINUX_SLL:
			switch(ntohs(((libtrace_sll_header_t*)packet->payload)
					->hatype)) {
				case ARPHRD_PPP:
					packet->type=pcap_linktype_to_rt(TRACE_DLT_RAW);
					break;
				case ARPHRD_ETHER:
					packet->type=pcap_linktype_to_rt(TRACE_DLT_EN10MB);
					break;
				default:
					/* Dunno how to demote this packet */
					return false;
			}
			/* Skip the Linux SLL header */
			packet->payload=(void*)((char*)packet->payload
					+sizeof(libtrace_sll_header_t));
			trace_set_capture_length(packet,
				trace_get_capture_length(packet)
					-sizeof(libtrace_sll_header_t));

			/* Invalidate caches */
			packet->l3_header = NULL;
			packet->capture_length = -1;
			break;
		default:
			return false;
	}

	/* Invalidate caches */
	packet->l3_header = NULL;
	packet->capture_length = -1;
	return true;
}