"Fossies" - the Fresh Open Source Software Archive 
Member "tcpflow-1.6.1/src/datalink.cpp" (19 Feb 2021, 9272 Bytes) of package /linux/misc/tcpflow-1.6.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "datalink.cpp" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.5.0_vs_1.6.1.
1 /**
2 *
3 * This file is part of tcpflow. Originally by Jeremy Elson
4 * <jelson@circlemud.org>, rewritten by Simson Garfinkel.
5 *
6 * Initial Release: 7 April 1999.
7 *
8 * This source code is under the GNU Public License (GPL). See
9 * COPYING for details.
10 *
11 * This file contains datalink handlers which are called by the pcap callback.
12 * The purpose of each handler is to make a packet_info() object and then call
13 * process_packet. The packet_info() object contains both the original
14 * MAC-layer (with some of the fields broken out) and the packet data layer.
15 *
16 * For wifi datalink handlers, please see datalink_wifi.cpp
17 */
18
19 #include <stddef.h>
20 #include "tcpflow.h"
21
22 /* The DLT_NULL packet header is 4 bytes long. It contains a network
23 * order 32 bit integer that specifies the family, e.g. AF_INET.
24 * DLT_NULL is used by the localhost interface.
25 */
26 #define NULL_HDRLEN 4
27
28 /* Some systems hasn't defined ETHERTYPE_IPV6 */
29 #ifndef ETHERTYPE_IPV6
30 # define ETHERTYPE_IPV6 0x86DD
31 #endif
32
33 #ifndef ETH_P_QINQ1
34 # define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
35 #endif
36
37 #ifndef ETH_P_8021AD
38 # define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
39 #endif
40
41
42 int32_t datalink_tdelta = 0;
43
44 #pragma GCC diagnostic ignored "-Wcast-align"
45 void dl_null(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
46 {
47 u_int caplen = h->caplen;
48 u_int length = h->len;
49 uint32_t family = (uint32_t)*p;
50
51 if (length != caplen) {
52 DEBUG(6) ("warning: only captured %d bytes of %d byte null frame",
53 caplen, length);
54 }
55
56 if (caplen < NULL_HDRLEN) {
57 DEBUG(6) ("warning: received incomplete null frame");
58 return;
59 }
60
61 /* make sure this is AF_INET */
62 if (family != AF_INET && family != AF_INET6) {
63 DEBUG(6)("warning: received null frame with unknown type (type 0x%x) (AF_INET=%x; AF_INET6=%x)",
64 family,AF_INET,AF_INET6);
65 return;
66 }
67 struct timeval tv;
68 be13::packet_info pi(DLT_NULL,h,p,tvshift(tv,h->ts),p+NULL_HDRLEN,caplen - NULL_HDRLEN);
69 be13::plugin::process_packet(pi);
70 }
71 #pragma GCC diagnostic warning "-Wcast-align"
72
73 static uint64_t counter=0;
74 /* DLT_RAW: just a raw IP packet, no encapsulation or link-layer
75 * headers. Used for PPP connections under some OSs including Linux
76 * and IRIX. */
77 void dl_raw(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
78 {
79 if (h->caplen != h->len) {
80 DEBUG(6) ("warning: only captured %d bytes of %d byte raw frame",
81 h->caplen, h->len);
82 }
83 struct timeval tv;
84 be13::packet_info pi(DLT_RAW,h,p,tvshift(tv,h->ts),p, h->caplen);
85 counter++;
86 be13::plugin::process_packet(pi);
87 }
88
89 /* Ethernet datalink handler; used by all 10 and 100 mbit/sec
90 * ethernet. We are given the entire ethernet header so we check to
91 * make sure it's marked as being IP.
92 */
93 #pragma GCC diagnostic ignored "-Wcast-align"
94 void dl_ethernet(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
95 {
96 u_int caplen = h->caplen;
97 u_int length = h->len;
98 struct be13::ether_header *eth_header = (struct be13::ether_header *) p;
99 u_int ether_type_offset = offsetof(struct be13::ether_header, ether_type);
100
101 /* Variables to support VLAN */
102 const u_short *ether_type = NULL;
103 const u_char *ether_data = NULL;
104
105 if (caplen < ether_type_offset) {
106 DEBUG(0) ("error: the captured packet header bytes are shorter than the ether_type offset");
107 return;
108 }
109
110 ether_type = ð_header->ether_type; /* where the ether type is located */
111 ether_data = p+sizeof(struct be13::ether_header); /* where the data is located */
112
113 if (length != caplen) {
114 DEBUG(6) ("warning: only captured %d bytes of %d byte ether frame",
115 caplen, length);
116 }
117
118 /* Handle basic VLAN packets */
119 while (ntohs(*ether_type) == ETHERTYPE_VLAN
120 #ifdef ETH_P_QINQ1
121 || ntohs(*ether_type) == ETH_P_QINQ1
122 #endif
123 #ifdef ETH_P_8021AD
124 || ntohs(*ether_type) == ETH_P_8021AD
125 #endif
126 ) {
127 //vlan = ntohs(*(u_short *)(p+sizeof(struct ether_header)));
128 ether_type += 2; /* skip past VLAN header (note it skips by 2s) */
129 ether_data += 4; /* skip past VLAN header */
130 caplen -= 4;
131 if (caplen < ether_type_offset) {
132 DEBUG(0) ("error: the captured packet header bytes are shorter than the ether_type offset");
133 return;
134 }
135 }
136
137 if (caplen < sizeof(struct be13::ether_header)) {
138 DEBUG(6) ("warning: received incomplete ethernet frame");
139 return;
140 }
141
142 /* Create a packet_info structure with ip data and data length */
143 try {
144 struct timeval tv;
145 be13::packet_info pi(DLT_IEEE802,h,p,tvshift(tv,h->ts),
146 ether_data, caplen - sizeof(struct be13::ether_header));
147 switch (ntohs(*ether_type)){
148 case ETHERTYPE_IP:
149 case ETHERTYPE_IPV6:
150 be13::plugin::process_packet(pi);
151 break;
152
153 #ifdef ETHERTYPE_ARP
154 case ETHERTYPE_ARP:
155 /* What should we do for ARP? */
156 break;
157 #endif
158 #ifdef ETHERTYPE_LOOPBACK
159 case ETHERTYPE_LOOPBACK:
160 /* What do do for loopback? */
161 break;
162 #endif
163 #ifdef ETHERTYPE_REVARP
164 case ETHERTYPE_REVARP:
165 /* What to do for REVARP? */
166 break;
167 #endif
168 default:
169 /* Unknown Ethernet Frame Type */
170 DEBUG(6) ("warning: received ethernet frame with unknown type 0x%x", ntohs(eth_header->ether_type));
171 break;
172 }
173 } catch( std::logic_error e){
174 std::string s(std::string("warning: caught std::logic_error ")
175 + e.what()
176 + std::string(" in packet"));
177 DEBUG(6)(s.c_str());
178 }
179 }
180
181 #pragma GCC diagnostic warning "-Wcast-align"
182
183 /* The DLT_PPP packet header is 4 bytes long. We just move past it
184 * without parsing it. It is used for PPP on some OSs (DLT_RAW is
185 * used by others; see below)
186 */
187 #define PPP_HDRLEN 4
188
189 void dl_ppp(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
190 {
191 u_int caplen = h->caplen;
192 u_int length = h->len;
193
194 if (length != caplen) {
195 DEBUG(6) ("warning: only captured %d bytes of %d byte PPP frame",
196 caplen, length);
197 }
198
199 if (caplen < PPP_HDRLEN) {
200 DEBUG(6) ("warning: received incomplete PPP frame");
201 return;
202 }
203
204 struct timeval tv;
205 be13::packet_info pi(DLT_PPP,h,p,tvshift(tv,h->ts),p + PPP_HDRLEN, caplen - PPP_HDRLEN);
206 be13::plugin::process_packet(pi);
207 }
208
209
210 #ifdef DLT_LINUX_SLL
211 #define SLL_HDR_LEN 16
212
213 #define SLL_ADDRLEN 8
214
215 #ifndef ETHERTYPE_MPLS
216 #define ETHERTYPE_MPLS 0x8847
217 #endif
218 #ifndef ETHERTYPE_MPLS_MULTI
219 #define ETHERTYPE_MPLS_MULTI 0x8848
220 #endif
221
222 #pragma GCC diagnostic ignored "-Wcast-align"
223 void dl_linux_sll(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
224 {
225 u_int caplen = h->caplen;
226 u_int length = h->len;
227
228 if (length != caplen) {
229 DEBUG(6) ("warning: only captured %d bytes of %d byte Linux cooked frame",
230 caplen, length);
231 }
232
233 if (caplen < SLL_HDR_LEN) {
234 DEBUG(6) ("warning: received incomplete Linux cooked frame");
235 return;
236 }
237
238 struct _sll_header {
239 u_int16_t sll_pkttype; /* packet type */
240 u_int16_t sll_hatype; /* link-layer address type */
241 u_int16_t sll_halen; /* link-layer address length */
242 u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
243 u_int16_t sll_protocol; /* protocol */
244 };
245
246 _sll_header *sllp = (_sll_header*)p;
247 u_int mpls_sz = 0;
248 if (ntohs(sllp->sll_protocol) == ETHERTYPE_MPLS) {
249 // unwind MPLS stack
250 do {
251 if(caplen < SLL_HDR_LEN + mpls_sz + 4){
252 DEBUG(6) ("warning: MPLS stack overrun");
253 return;
254 }
255 mpls_sz += 4;
256 caplen -= 4;
257 } while ((p[SLL_HDR_LEN + mpls_sz - 2] & 1) == 0 );
258 }
259
260 struct timeval tv;
261 be13::packet_info pi(DLT_LINUX_SLL,h,p,tvshift(tv,h->ts),p + SLL_HDR_LEN + mpls_sz, caplen - SLL_HDR_LEN);
262 be13::plugin::process_packet(pi);
263 }
264 #endif
265
266 #ifndef DLT_IEEE802_11_RADIO
267 #define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */
268 #endif
269
270 /* List of callbacks for each data link type */
271 dlt_handler_t handlers[] = {
272 { dl_null, DLT_NULL },
273 /* Some systems define DLT_RAW as 12, some as 14, and some as 101.
274 * So it is hard-coded here.
275 */
276 { dl_raw, 12 },
277 { dl_raw, 14 },
278 { dl_raw, 101 },
279 { dl_ethernet, DLT_EN10MB },
280 { dl_ethernet, DLT_IEEE802 },
281 { dl_ppp, DLT_PPP },
282 #ifdef DLT_LINUX_SLL
283 { dl_linux_sll, DLT_LINUX_SLL },
284 #endif
285 #if defined(USE_WIFI) && !defined(WIN32)
286 { dl_ieee802_11_radio, DLT_IEEE802_11 },
287 { dl_ieee802_11_radio, DLT_IEEE802_11_RADIO },
288 { dl_prism, DLT_PRISM_HEADER},
289 #endif
290 { NULL, 0 }
291 };
292
293 pcap_handler find_handler(int datalink_type, const char *device)
294 {
295 int i;
296
297 DEBUG(3) ("looking for handler for datalink type %d for interface %s",
298 datalink_type, device);
299
300 for (i = 0; handlers[i].handler != NULL; i++){
301 if (handlers[i].type == datalink_type){
302 return handlers[i].handler;
303 }
304 }
305
306 die("sorry - unknown datalink type %d on interface %s", datalink_type, device);
307 return NULL; /* NOTREACHED */
308 }