1: /*
2: * Copyright (c) 2004 Rinet Corp., Novosibirsk, Russia
3: *
4: * Redistribution and use in source forms, with and without modification,
5: * are permitted provided that this entire comment appears intact.
6: *
7: * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
8: */
9:
10: #ifdef HAVE_CONFIG_H
11: #include <config.h>
12: #endif
13:
14: #include <sys/types.h>
15: #include <sys/socket.h>
16: #ifdef linux
17: #include <linux/if.h>
18: #else
19: #include <net/if.h>
20: #endif
21: #include <netinet/in.h>
22: #include <netinet/in_systm.h>
23: #include <netinet/if_ether.h>
24: #include <netinet/ip.h>
25: #include <string.h>
26: #include <pcap.h>
27:
28: #include "parse_dl.h"
29: #include "parse_ip.h"
30: #include "netstat.h"
31: #include "ethertype.h"
32: #include "sll.h"
33:
34: #ifndef DLT_LINUX_SLL
35: #define DLT_LINUX_SLL 113
36: #endif
37:
38: struct ether_dot1q_header {
39: u_char dhost[ETHER_ADDR_LEN];
40: u_char shost[ETHER_ADDR_LEN];
41: u_int16_t encap_proto;
42: u_int16_t tag;
43: u_int16_t proto;
44: };
45:
46: int
47: is_parse_dl(type)
48: int type;
49: {
50: return (type == DLT_NULL ||
51: type == DLT_LOOP ||
52: type == DLT_EN10MB ||
53: type == DLT_SLIP ||
54: type == DLT_PPP_ETHER ||
55: type == DLT_PPP ||
56: type == DLT_RAW ||
57: type == DLT_C_HDLC ||
58: type == DLT_PPP_SERIAL ||
59: type == DLT_LINUX_SLL);
60: }
61:
62: const char *
63: parse_dl_name(type)
64: int type;
65: {
66: switch (type) {
67: case DLT_NULL:
68: case DLT_LOOP:
69: return "Loopback";
70: case DLT_EN10MB:
71: return "Ethernet";
72: case DLT_SLIP:
73: return "SLIP";
74: case DLT_PPP_ETHER:
75: return "PPP over Ethernet";
76: case DLT_PPP:
77: return "Async PPP";
78: case DLT_RAW:
79: return "raw IP";
80: case DLT_C_HDLC:
81: return "Cisco HDLC";
82: case DLT_PPP_SERIAL:
83: return "Sync PPP";
84: case DLT_LINUX_SLL:
85: return "Linux cooked socket";
86: }
87: return "Unknown";
88: }
89:
90: int
91: parse_dl(ns, dlt, caplen, pktlen, pkt)
92: NETSTAT *ns;
93: int dlt, caplen, pktlen;
94: const u_char *pkt;
95: {
96: const struct ether_header *ether = 0;
97: const struct ip *ip = 0;
98: const u_char *p = pkt;
99: u_int length = pktlen;
100: u_int type, hdrlen;
101: u_char dsap, ssap;
102:
103: /* sanity check */
104: if (!pkt) return -1;
105:
106: switch (dlt) {
107: case DLT_NULL:
108: case DLT_LOOP:
109: if (caplen < 4)
110: return -1;
111: memcpy((u_char *)&type, p, sizeof(type));
112: if (type & 0xffff0000) { /* swap bytes */
113: type = (((type & 0xff) << 24) |
114: ((type & 0xff00) << 8) |
115: ((type & 0xff0000) >> 8) |
116: ((type >> 24) & 0xff));
117: }
118: if (type != AF_INET && type != AF_INET6)
119: return -1;
120: p += 4;
121: ip = (const struct ip *)p;
122: caplen -= 4;
123: length -= 4;
124: break;
125:
126: case DLT_EN10MB:
127: hdrlen = sizeof(struct ether_header);
128: if (caplen < hdrlen)
129: return -1;
130: ether = (struct ether_header *)p;
131: if (ns) {
132: #ifdef HAVE_ETHER_ADDR
133: memcpy(ns->eth_src_addr,
134: ðer->ether_shost, sizeof(struct ether_addr));
135: memcpy(ns->eth_dst_addr,
136: ðer->ether_dhost, sizeof(struct ether_addr));
137: #else
138: memcpy(ns->eth_src_addr,
139: ether->ether_shost, ETHER_ADDR_LEN);
140: memcpy(ns->eth_dst_addr,
141: ether->ether_dhost, ETHER_ADDR_LEN);
142: #endif
143: ns->eth_type = ether->ether_type;
144: }
145: type = ntohs(ether->ether_type);
146: if (type <= ETHERMTU) {
147: /* IEEE 802.3 frame: the type is data length */
148: if (caplen < hdrlen + 3)
149: return -1;
150:
151: /* extract SAP (Service Access Point) IDs */
152: dsap = p[hdrlen];
153: ssap = p[hdrlen + 1];
154: if (ns) {
155: ns->eth_dsap = dsap;
156: ns->eth_ssap = ssap;
157: ns->data_len = type;
158: }
159: type = 0; /* no type known yet */
160:
161: hdrlen += 3; /* skip 802.2 LLC header */
162:
163: if (dsap == 0x06 && ssap == 0x06) {
164: /* 802.3/802.2 encapsulated IP */
165: type = ETHERTYPE_IP;
166:
167: } else if (dsap == 0xAA && ssap == 0xAA) {
168: if (caplen < hdrlen + 5)
169: return -1;
170:
171: /* extract encap type after 3-bytes OUI */
172: type = *(u_int16_t *)(p + hdrlen + 3);
173: if (ns) ns->eth_type = type;
174: type = ntohs(type);
175:
176: hdrlen += 5; /* skip 802.2 SNAP header */
177: }
178: } else if (type == ETHERTYPE_8021Q) {
179: hdrlen = sizeof(struct ether_dot1q_header);
180: if (caplen < hdrlen)
181: return -1;
182: if (ns) ns->eth_tag = ((struct ether_dot1q_header *)p)->tag;
183: type = ntohs(((struct ether_dot1q_header *)p)->proto);
184: }
185: p += hdrlen;
186: if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6)
187: ip = (const struct ip *)p;
188: caplen -= hdrlen;
189: length -= hdrlen;
190: break;
191:
192: case DLT_SLIP:
193: if (caplen < 16)
194: return -1;
195: p += 16;
196: ip = (const struct ip *)p;
197: caplen -= 16;
198: length -= 16;
199: break;
200:
201: case DLT_PPP_ETHER:
202: if (caplen < 6 || p[1])
203: return -1;
204: p += 6;
205: caplen -= 6;
206: length -= 6;
207: /* pass through */
208:
209: case DLT_PPP:
210: if (caplen < 4)
211: return -1;
212: hdrlen = 0;
213: #ifdef SLC_BPFHDR
214: if (dlt == DLT_PPP) {
215: ip = (const struct ip *)(p + SLC_BPFHDR);/* skip bpf pseudo header */
216: p += SLC_BPFHDRLEN; /* now pointer to link level header */
217: }
218: #endif
219: /* PPP address and PPP control fields may be present (-acfc) */
220: if (p[0] == 0xff && p[1] == 0x03) {
221: p += 2;
222: hdrlen += 2;
223: }
224: /* retrive the protocol type */
225: if (*p & 01) { /* compressed protocol field (pfc) */
226: type = *p++;
227: hdrlen++;
228: } else { /* un-compressed protocol field (-pfc) */
229: type = ntohs(*(u_int16_t *)p);
230: p += 2;
231: hdrlen += 2;
232: }
233: /* check for IP or IPv6 */
234: if (type != 0x21 && type != 0x57 &&
235: type != ETHERTYPE_IP && type != ETHERTYPE_IPV6)
236: return -1;
237: #ifdef SLC_BPFHDR
238: if (dlt == DLT_PPP) {
239: caplen -= SLC_BPFHDR;
240: length -= SLC_BPFHDR;
241: } else {
242: ip = (const struct ip *)p;
243: caplen -= hdrlen;
244: length -= hdrlen;
245: }
246: #else
247: ip = (const struct ip *)p;
248: caplen -= hdrlen;
249: length -= hdrlen;
250: #endif
251: break;
252:
253: case DLT_RAW:
254: ip = (const struct ip *)p;
255: break;
256:
257: case DLT_C_HDLC:
258: case DLT_PPP_SERIAL:
259: if (caplen < 4)
260: return -1;
261: /* check for UNICAST or BCAST */
262: if (p[0] != 0x0f && p[0] != 0x8f)
263: return -1;
264: type = ntohs(*(u_int16_t *)&p[2]);
265: if (type != ETHERTYPE_IP && type != ETHERTYPE_IPV6)
266: return -1;
267: p += 4;
268: ip = (const struct ip *)p;
269: caplen -= 4;
270: length -= 4;
271: break;
272:
273: case DLT_LINUX_SLL:
274: if (caplen < SLL_HDR_LEN)
275: return -1;
276: if (ntohs(((struct sll_header *)p)->sll_halen) == ETHER_ADDR_LEN) {
277: if (ns) {
278: /* the source address is in the packet header */
279: memcpy(ns->eth_src_addr,
280: ((struct sll_header *)p)->sll_addr,
281: ETHER_ADDR_LEN);
282: /* just a fake the destination address */
283: memset(ns->eth_dst_addr, 0, ETHER_ADDR_LEN);
284: type = ntohs(((struct sll_header *)p)->sll_pkttype);
285: if (type != LINUX_SLL_OUTGOING) {
286: if (type == LINUX_SLL_BROADCAST)
287: memset(ns->eth_dst_addr, 0xff,
288: ETHER_ADDR_LEN);
289: else if (type == LINUX_SLL_MULTICAST)
290: ns->eth_dst_addr[0] = 1;
291: else ns->eth_dst_addr[ETHER_ADDR_LEN-1] = 1;
292: }
293: ns->eth_type = ((struct sll_header *)p)->sll_protocol;
294: }
295: /* point somewhere to avoid return after switch() */
296: ether = (struct ether_header *)p;
297: }
298: type = ntohs(((struct sll_header *)p)->sll_protocol);
299: p += SLL_HDR_LEN;
300: caplen -= SLL_HDR_LEN;
301: length -= SLL_HDR_LEN;
302: if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6)
303: ip = (const struct ip *)p;
304: break;
305:
306: default:
307: /* Unknown or unsupported data link type */
308: return -1;
309: }
310:
311: if (!ether && !ip)
312: return -1;
313:
314: if (caplen > length)
315: caplen = length;
316:
317: if (ns) {
318: if (!ns->pkt_cnt) ns->pkt_cnt = 1;
319: if (!ns->pkt_len) ns->pkt_len = pktlen;
320: if (!ns->data_len) ns->data_len = length;
321: }
322:
323: hdrlen = (char *)p - (char *)pkt;
324: if (ip && caplen >= sizeof(struct ip)) {
325: int hlen = parse_ip(ns, caplen, ip);
326: if (hlen > 0) hdrlen += hlen;
327: }
328: return hdrlen;
329: }
330:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>