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:                               &ether->ether_shost, sizeof(struct ether_addr));
        !           135:                        memcpy(ns->eth_dst_addr,
        !           136:                               &ether->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>