2 // Copyright (c) 2010-2017 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
20 #include <arpa/inet.h>
24 #include "allocator.hpp"
25 #include "pcappkt.hpp"
27 Allocator *PcapPkt::allocator = NULL;
29 void* PcapPkt::operator new(size_t size)
32 return allocator->alloc(size);
34 return ::operator new(size);
37 void PcapPkt::operator delete(void *pointer)
40 :: operator delete(pointer);
43 PcapPkt::PcapPkt(uint8_t *mem)
45 header = *(struct pcap_pkthdr *)mem;
46 mem += sizeof(header);
47 buf = new uint8_t[header.len];
48 memcpy(buf, mem, header.len);
53 buf = new uint8_t[1514];
54 memset(&header, 0, sizeof(header));
57 PcapPkt::PcapPkt(const PcapPkt& other)
60 buf = new uint8_t[other.len()];
63 buf = (uint8_t *)allocator->alloc(other.len());
66 memcpy(buf, other.buf, other.len());
67 header = other.header;
76 #define ETYPE_IPv4 0x0008 /* IPv4 in little endian */
77 #define ETYPE_IPv6 0xDD86 /* IPv6 in little endian */
78 #define ETYPE_ARP 0x0608 /* ARP in little endian */
79 #define ETYPE_VLAN 0x0081 /* 802-1aq - VLAN */
80 #define ETYPE_MPLSU 0x4788 /* MPLS unicast */
81 #define ETYPE_MPLSM 0x4888 /* MPLS multicast */
82 #define ETYPE_8021ad 0xA888 /* Q-in-Q */
83 #define ETYPE_LLDP 0xCC88 /* Link Layer Discovery Protocol (LLDP) */
84 #define ETYPE_EoGRE 0x5865 /* EoGRE in little endian */
87 uint8_t version_ihl; /**< version and header length */
88 uint8_t type_of_service; /**< type of service */
89 uint16_t total_length; /**< length of packet */
90 uint16_t packet_id; /**< packet ID */
91 uint16_t fragment_offset; /**< fragmentation offset */
92 uint8_t time_to_live; /**< time to live */
93 uint8_t next_proto_id; /**< protocol ID */
94 uint16_t hdr_checksum; /**< header checksum */
95 uint32_t src_addr; /**< source address */
96 uint32_t dst_addr; /**< destination address */
97 } __attribute__((__packed__));
100 uint8_t addr_bytes[6]; /**< Address bytes in transmission order */
101 } __attribute__((__packed__));
104 struct ether_addr d_addr; /**< Destination address. */
105 struct ether_addr s_addr; /**< Source address. */
106 uint16_t ether_type; /**< Frame type. */
107 } __attribute__((__packed__));
110 uint16_t vlan_tci; /**< Priority (3) + CFI (1) + Identifier Code (12) */
111 uint16_t eth_proto;/**< Ethernet type of encapsulated frame. */
112 } __attribute__((__packed__));
115 uint16_t src_port; /**< UDP source port. */
116 uint16_t dst_port; /**< UDP destination port. */
117 uint16_t dgram_len; /**< UDP datagram length */
118 uint16_t dgram_cksum; /**< UDP datagram checksum */
119 } __attribute__((__packed__));
121 struct pkt_tuple PcapPkt::parsePkt(const uint8_t **l4_hdr, uint16_t *hdr_len, const uint8_t **l5, uint32_t *l5_len) const
123 struct pkt_tuple pt = {0};
125 const struct ether_hdr *peth = (struct ether_hdr *)buf;
126 int l2_types_count = 0;
127 const struct ipv4_hdr* pip = 0;
129 switch (peth->ether_type) {
131 pip = (const struct ipv4_hdr *)(peth + 1);
134 const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
135 if (vlan->eth_proto == ETYPE_IPv4) {
136 pip = (const struct ipv4_hdr *)(peth + 1);
138 else if (vlan->eth_proto == ETYPE_VLAN) {
139 const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
140 if (vlan->eth_proto == ETYPE_IPv4) {
141 pip = (const struct ipv4_hdr *)(peth + 1);
143 else if (vlan->eth_proto == ETYPE_IPv6) {
147 /* TODO: handle BAD PACKET */
154 const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
155 if (vlan->eth_proto == ETYPE_VLAN) {
156 const struct vlan_hdr *vlan = (const struct vlan_hdr *)(peth + 1);
157 if (vlan->eth_proto == ETYPE_IPv4) {
158 pip = (const struct ipv4_hdr *)(peth + 1);
176 if ((pip->version_ihl >> 4) == 4) {
178 if ((pip->version_ihl & 0x0f) != 0x05) {
179 /* TODO: optional fields */
183 pt.proto_id = pip->next_proto_id;
184 pt.src_addr = pip->src_addr;
185 pt.dst_addr = pip->dst_addr;
188 /* TODO: IPv6 and bad packets */
193 if (pt.proto_id == IPPROTO_UDP) {
194 const struct udp_hdr *udp = (const struct udp_hdr*)(pip + 1);
196 *l4_hdr = (const uint8_t*)udp;
198 *hdr_len = (const uint8_t*)udp - buf;
199 pt.src_port = udp->src_port;
200 pt.dst_port = udp->dst_port;
202 *l5 = ((const uint8_t*)udp) + sizeof(struct udp_hdr);
204 *l5_len = ntohs(udp->dgram_len) - sizeof(struct udp_hdr);
206 else if (pt.proto_id == IPPROTO_TCP) {
207 const struct tcp_hdr *tcp = (const struct tcp_hdr *)(pip + 1);
209 *l4_hdr = (const uint8_t*)tcp;
211 *hdr_len = (const uint8_t*)tcp - buf;
212 pt.src_port = tcp->src_port;
213 pt.dst_port = tcp->dst_port;
216 *l5 = ((const uint8_t*)tcp) + ((tcp->data_off >> 4)*4);
218 *l5_len = ntohs(pip->total_length) - sizeof(struct ipv4_hdr) - ((tcp->data_off >> 4)*4);
221 fprintf(stderr, "unsupported protocol %d\n", pt.proto_id);
228 void PcapPkt::toMem(uint8_t *mem) const
230 memcpy(mem, &header, sizeof(header));
231 mem += sizeof(header);
232 memcpy(mem, buf, header.len);
235 void PcapPkt::fromMem(uint8_t *mem)
237 memcpy(&header, mem, sizeof(header));
238 mem += sizeof(header);
239 memcpy(buf, mem, header.len);
242 void PcapPkt::toFile(ofstream *file) const
244 file->write(reinterpret_cast<const char *>(&header), sizeof(header));
245 file->write(reinterpret_cast<const char *>(buf), header.len);
247 size_t PcapPkt::memSize() const
249 return sizeof(header) + header.len;
252 PcapPkt::L4Proto PcapPkt::getProto() const
254 struct pkt_tuple pt = parsePkt();
255 return pt.proto_id == IPPROTO_TCP? PROTO_TCP : PROTO_UDP;
258 ostream& operator<<(ostream& stream, const pkt_tuple &other)
260 stream << other.src_addr << ","
261 << other.dst_addr << ","
262 << (int)other.proto_id << ","
263 << other.src_port << ","