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