Annotation of embedaddon/trafshow/parse_dl.c, revision 1.1
1.1 ! misho 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>