summaryrefslogtreecommitdiffstats
path: root/VNFs/DPPD-PROX/tools/flow_extract/pcappkt.cpp
blob: 91708bb10d1b34abfb209cced1046f6a3c8dfcee (plain)
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
/*
// Copyright (c) 2010-2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

#include <pcap.h>
#include <inttypes.h>
#include <cstring>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include "allocator.hpp"
#include "pcappkt.hpp"

Allocator *PcapPkt::allocator = NULL;

void* PcapPkt::operator new(size_t size)
{
	if (allocator)
		return allocator->alloc(size);
	else
		return ::operator new(size);
}

void PcapPkt::operator delete(void *pointer)
{
	if (!allocator)
		:: operator delete(pointer);
}

PcapPkt::PcapPkt(uint8_t *mem)
{
	header = *(struct pcap_pkthdr *)mem;
	mem += sizeof(header);
	buf = new uint8_t[header.len];
	memcpy(buf, mem, header.len);
}

PcapPkt::PcapPkt()
{
	buf = new uint8_t[1514];
	memset(&header, 0, sizeof(header));
}

PcapPkt::PcapPkt(const PcapPkt& other)
{
	if (!allocator) {
		buf = new uint8_t[other.len()];
	}
	else {
		buf = (uint8_t *)allocator->alloc(other.len());
	}

	memcpy(buf, other.buf, other.len());
	header = other.header;
}

PcapPkt::~PcapPkt()
{
	if (!allocator)
		delete[] buf;
}

#define ETYPE_IPv4	0x0008	/* IPv4 in little endian */
#define ETYPE_IPv6	0xDD86	/* IPv6 in little endian */
#define ETYPE_ARP	0x0608	/* ARP in little endian */
#define ETYPE_VLAN	0x0081	/* 802-1aq - VLAN */
#define ETYPE_MPLSU	0x4788	/* MPLS unicast */
#define ETYPE_MPLSM	0x4888	/* MPLS multicast */
#define ETYPE_8021ad	0xA888	/* Q-in-Q */
#define ETYPE_LLDP	0xCC88	/* Link Layer Discovery Protocol (LLDP) */
#define ETYPE_EoGRE	0x5865	/* EoGRE in little endian */

struct ipv4_hdr {
	uint8_t  version_ihl;		/**< version and header length */
	uint8_t  type_of_service;	/**< type of service */
	uint16_t total_length;		/**< length of packet */
	uint16_t packet_id;		/**< packet ID */
	uint16_t fragment_offset;	/**< fragmentation offset */
	uint8_t  time_to_live;		/**< time to live */
	uint8_t  next_proto_id;		/**< protocol ID */
	uint16_t hdr_checksum;		/**< header checksum */
	uint32_t src_addr;		/**< source address */
	uint32_t dst_addr;		/**< destination address */
} __attribute__((__packed__));

struct ether_addr {
	uint8_t addr_bytes[6]; /**< Address bytes in transmission order */
} __attribute__((__packed__));

struct ether_hdr {
	struct ether_addr d_addr; /**< Destination address. */
	struct ether_addr s_addr; /**< Source address. */
	uint16_t ether_type;      /**< Frame type. */
} __attribute__((__packed__));

struct vlan_hdr {
	uint16_t vlan_tci; /**< Priority (3) + CFI (1) + Identifier Code (12) */
	uint16_t eth_proto;/**< Ethernet type of encapsulated frame. */
} __attribute__((__packed__));

struct udp_hdr {
	uint16_t src_port;    /**< UDP source port. */
	uint16_t dst_port;    /**< UDP destination port. */
	uint16_t dgram_len;   /**< UDP datagram length */
	uint16_t dgram_cksum; /**< UDP datagram checksum */
} __attribute__((__packed__));

struct pkt_tuple PcapPkt::parsePkt(const uint8_t **l4_hdr, uint16_t *hdr_len, const uint8_t **l5, uint32_t *l5_len) const
{
	struct pkt_tuple pt = {0};

	const struct ether_hdr *peth = (struct ether_hdr *)buf;
	int l2_types_count = 0;
	const struct ipv4_hdr* pip = 0;

	switch (peth->ether_type) {
	case ETYPE_IPv4:
			pip = (const struct ipv4_hdr *)(peth + 1);
		break;
	case ETYPE_VLAN: {
		const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
		if (vlan->eth_proto == ETYPE_IPv4) {
			pip = (const struct ipv4_hdr *)(peth + 1);
		}
		else if (vlan->eth_proto == ETYPE_VLAN) {
			const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
			if (vlan->eth_proto == ETYPE_IPv4) {
				pip = (const struct ipv4_hdr *)(peth + 1);
			}
			else if (vlan->eth_proto == ETYPE_IPv6) {
				throw 0;
			}
			else {
				/* TODO: handle BAD PACKET */
				throw 0;
			}
		}
	}
		break;
	case ETYPE_8021ad: {
		const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
		if (vlan->eth_proto == ETYPE_VLAN) {
			const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
			if (vlan->eth_proto == ETYPE_IPv4) {
				pip = (const struct ipv4_hdr *)(peth + 1);
			}
			else {
				throw 0;
			}
		}
		else {
			throw 0;
		}
	}
		break;
	case ETYPE_MPLSU:
		break;
	default:
		break;
	}

	/* L3 */
	if ((pip->version_ihl >> 4) == 4) {

		if ((pip->version_ihl & 0x0f) != 0x05) {
			/* TODO: optional fields */
			throw 0;
		}

		pt.proto_id = pip->next_proto_id;
		pt.src_addr = pip->src_addr;
		pt.dst_addr = pip->dst_addr;
	}
	else {
		/* TODO: IPv6 and bad packets */
		throw 0;
	}

	/* L4 parser */
	if (pt.proto_id == IPPROTO_UDP) {
		const struct udp_hdr *udp = (const struct udp_hdr*)(pip + 1);
		if (l4_hdr)
			*l4_hdr = (const uint8_t*)udp;
		if (hdr_len)
			*hdr_len = (const uint8_t*)udp - buf;
		pt.src_port = udp->src_port;
		pt.dst_port = udp->dst_port;
		if (l5)
			*l5 = ((const uint8_t*)udp) + sizeof(struct udp_hdr);
		if (l5_len)
			*l5_len = ntohs(udp->dgram_len) - sizeof(struct udp_hdr);
	}
	else if (pt.proto_id == IPPROTO_TCP) {
		const struct tcp_hdr *tcp = (const struct tcp_hdr *)(pip + 1);
		if (l4_hdr)
			*l4_hdr = (const uint8_t*)tcp;
		if (hdr_len)
			*hdr_len = (const uint8_t*)tcp - buf;
		pt.src_port = tcp->src_port;
		pt.dst_port = tcp->dst_port;

		if (l5)
			*l5 = ((const uint8_t*)tcp) + ((tcp->data_off >> 4)*4);
		if (l5_len)
			*l5_len = ntohs(pip->total_length) - sizeof(struct ipv4_hdr) - ((tcp->data_off >> 4)*4);
	}
	else {
		fprintf(stderr, "unsupported protocol %d\n", pt.proto_id);
		throw 0;
	}

	return pt;
}

void PcapPkt::toMem(uint8_t *mem) const
{
	memcpy(mem, &header, sizeof(header));
	mem += sizeof(header);
	memcpy(mem, buf, header.len);
}

void PcapPkt::fromMem(uint8_t *mem)
{
	memcpy(&header, mem, sizeof(header));
	mem += sizeof(header);
	memcpy(buf, mem, header.len);
}

void PcapPkt::toFile(ofstream *file) const
{
	file->write(reinterpret_cast<const char *>(&header), sizeof(header));
	file->write(reinterpret_cast<const char *>(buf), header.len);
}
size_t PcapPkt::memSize() const
{
	return sizeof(header) + header.len;
}

PcapPkt::L4Proto PcapPkt::getProto() const
{
	struct pkt_tuple pt = parsePkt();
	return pt.proto_id == IPPROTO_TCP? PROTO_TCP : PROTO_UDP;
}

ostream& operator<<(ostream& stream, const pkt_tuple &other)
{
       	stream << other.src_addr << ","
	       << other.dst_addr << ","
	       << (int)other.proto_id << ","
	       << other.src_port << ","
	       << other.dst_port;
	return stream;
}