Annotation of embedaddon/strongswan/src/libipsec/ip_packet.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2012-2014 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: 
                     17: #include "ip_packet.h"
                     18: 
                     19: #include <library.h>
                     20: #include <utils/debug.h>
                     21: 
                     22: #include <sys/types.h>
                     23: 
                     24: #ifndef WIN32
                     25: #include <netinet/in.h>
                     26: #include <netinet/ip.h>
                     27: #ifdef HAVE_NETINET_IP6_H
                     28: #include <netinet/ip6.h>
                     29: #endif
                     30: #else
                     31: struct ip {
                     32: #if BYTE_ORDER == LITTLE_ENDIAN
                     33:        uint8_t ip_hl: 4;
                     34:        uint8_t ip_v: 4;
                     35: #elif BYTE_ORDER == BIG_ENDIAN
                     36:        uint8_t ip_v: 4;
                     37:        uint8_t ip_hl: 4;
                     38: #endif
                     39:        uint8_t ip_tos;
                     40:        uint16_t ip_len;
                     41:        uint16_t ip_id;
                     42:        uint16_t ip_off;
                     43:        uint8_t ip_ttl;
                     44:        uint8_t ip_p;
                     45:        uint16_t ip_sum;
                     46:        struct in_addr ip_src, ip_dst;
                     47: } __attribute__((packed));
                     48: struct ip6_hdr {
                     49:        uint32_t ip6_flow; /* 4 bit version, 8 bit TC, 20 bit flow label */
                     50:        uint16_t ip6_plen;
                     51:        uint8_t ip6_nxt;
                     52:        uint8_t ip6_hlim;
                     53:        struct in6_addr ip6_src, ip6_dst;
                     54: } __attribute__((packed));
                     55: struct ip6_ext {
                     56:        uint8_t ip6e_nxt;
                     57:        uint8_t ip6e_len;
                     58: } __attribute__((packed));
                     59: #define HAVE_NETINET_IP6_H /* not really, but we only need the structs above */
                     60: #endif
                     61: 
                     62: #ifndef IP_OFFMASK
                     63: #define IP_OFFMASK 0x1fff
                     64: #endif
                     65: 
                     66: /**
                     67:  * TCP header, defined here because platforms disagree regarding member names
                     68:  * and unfortunately Android does not define a variant with BSD names.
                     69:  */
                     70: struct tcphdr {
                     71:        uint16_t source;
                     72:        uint16_t dest;
                     73:        uint32_t seq;
                     74:        uint32_t ack_seq;
                     75:        uint16_t flags;
                     76:        uint16_t window;
                     77:        uint16_t check;
                     78:        uint16_t urg_ptr;
                     79: } __attribute__((packed));
                     80: 
                     81: /**
                     82:  * UDP header, similar to the TCP header the system headers disagree on member
                     83:  * names.  Linux uses a union and on Android we could define __FAVOR_BSD to get
                     84:  * the BSD member names, but this is simpler and more consistent with the above.
                     85:  */
                     86: struct udphdr {
                     87:        uint16_t source;
                     88:        uint16_t dest;
                     89:        uint16_t len;
                     90:        uint16_t check;
                     91: } __attribute__((packed));
                     92: 
                     93: typedef struct private_ip_packet_t private_ip_packet_t;
                     94: 
                     95: /**
                     96:  * Private additions to ip_packet_t.
                     97:  */
                     98: struct private_ip_packet_t {
                     99: 
                    100:        /**
                    101:         * Public members
                    102:         */
                    103:        ip_packet_t public;
                    104: 
                    105:        /**
                    106:         * Source address
                    107:         */
                    108:        host_t *src;
                    109: 
                    110:        /**
                    111:         * Destination address
                    112:         */
                    113:        host_t *dst;
                    114: 
                    115:        /**
                    116:         * IP packet
                    117:         */
                    118:        chunk_t packet;
                    119: 
                    120:        /**
                    121:         * IP payload (points into packet)
                    122:         */
                    123:        chunk_t payload;
                    124: 
                    125:        /**
                    126:         * IP version
                    127:         */
                    128:        uint8_t version;
                    129: 
                    130:        /**
                    131:         * Protocol|Next Header field
                    132:         */
                    133:        uint8_t next_header;
                    134: 
                    135: };
                    136: 
                    137: METHOD(ip_packet_t, get_version, uint8_t,
                    138:        private_ip_packet_t *this)
                    139: {
                    140:        return this->version;
                    141: }
                    142: 
                    143: METHOD(ip_packet_t, get_source, host_t*,
                    144:        private_ip_packet_t *this)
                    145: {
                    146:        return this->src;
                    147: }
                    148: 
                    149: METHOD(ip_packet_t, get_destination, host_t*,
                    150:        private_ip_packet_t *this)
                    151: {
                    152:        return this->dst;
                    153: }
                    154: 
                    155: METHOD(ip_packet_t, get_encoding, chunk_t,
                    156:        private_ip_packet_t *this)
                    157: {
                    158:        return this->packet;
                    159: }
                    160: 
                    161: METHOD(ip_packet_t, get_payload, chunk_t,
                    162:        private_ip_packet_t *this)
                    163: {
                    164:        return this->payload;
                    165: }
                    166: 
                    167: METHOD(ip_packet_t, get_next_header, uint8_t,
                    168:        private_ip_packet_t *this)
                    169: {
                    170:        return this->next_header;
                    171: }
                    172: 
                    173: METHOD(ip_packet_t, clone_, ip_packet_t*,
                    174:        private_ip_packet_t *this)
                    175: {
                    176:        return ip_packet_create(chunk_clone(this->packet));
                    177: }
                    178: 
                    179: METHOD(ip_packet_t, destroy, void,
                    180:        private_ip_packet_t *this)
                    181: {
                    182:        this->src->destroy(this->src);
                    183:        this->dst->destroy(this->dst);
                    184:        chunk_free(&this->packet);
                    185:        free(this);
                    186: }
                    187: 
                    188: /**
                    189:  * Parse transport protocol header
                    190:  */
                    191: static bool parse_transport_header(chunk_t packet, uint8_t proto,
                    192:                                                                   uint16_t *sport, uint16_t *dport)
                    193: {
                    194:        switch (proto)
                    195:        {
                    196:                case IPPROTO_UDP:
                    197:                {
                    198:                        struct udphdr *udp;
                    199: 
                    200:                        if (packet.len < sizeof(*udp))
                    201:                        {
                    202:                                DBG1(DBG_ESP, "UDP packet too short");
                    203:                                return FALSE;
                    204:                        }
                    205:                        udp = (struct udphdr*)packet.ptr;
                    206:                        *sport = ntohs(udp->source);
                    207:                        *dport = ntohs(udp->dest);
                    208:                        break;
                    209:                }
                    210:                case IPPROTO_TCP:
                    211:                {
                    212:                        struct tcphdr *tcp;
                    213: 
                    214:                        if (packet.len < sizeof(*tcp))
                    215:                        {
                    216:                                DBG1(DBG_ESP, "TCP packet too short");
                    217:                                return FALSE;
                    218:                        }
                    219:                        tcp = (struct tcphdr*)packet.ptr;
                    220:                        *sport = ntohs(tcp->source);
                    221:                        *dport = ntohs(tcp->dest);
                    222:                        break;
                    223:                }
                    224:                default:
                    225:                        break;
                    226:        }
                    227:        return TRUE;
                    228: }
                    229: 
                    230: #ifdef HAVE_NETINET_IP6_H
                    231: /**
                    232:  * Skip to the actual payload and parse the transport header.
                    233:  */
                    234: static bool parse_transport_header_v6(struct ip6_hdr *ip, chunk_t packet,
                    235:                                                                          chunk_t *payload, uint8_t *proto,
                    236:                                                                          uint16_t *sport, uint16_t *dport)
                    237: {
                    238:        struct ip6_ext *ext;
                    239:        bool fragment = FALSE;
                    240: 
                    241:        *proto = ip->ip6_nxt;
                    242:        *payload = chunk_skip(packet, 40);
                    243:        while (payload->len >= sizeof(struct ip6_ext))
                    244:        {
                    245:                switch (*proto)
                    246:                {
                    247:                        case 44:  /* Fragment Header */
                    248:                                fragment = TRUE;
                    249:                                /* skip the header */
                    250:                        case 0:   /* Hop-by-Hop Options Header */
                    251:                        case 43:  /* Routing Header */
                    252:                        case 60:  /* Destination Options Header */
                    253:                        case 135: /* Mobility Header */
                    254:                        case 139: /* HIP */
                    255:                        case 140: /* Shim6 */
                    256:                                /* simply skip over these headers for now */
                    257:                                ext = (struct ip6_ext*)payload->ptr;
                    258:                                *proto = ext->ip6e_nxt;
                    259:                                *payload = chunk_skip(*payload, 8 * (ext->ip6e_len + 1));
                    260:                                continue;
                    261:                        default:
                    262:                                /* assume anything else is an upper layer protocol but only
                    263:                                 * attempt to parse the transport header for non-fragmented
                    264:                                 * packets as there is no guarantee that initial fragments
                    265:                                 * contain the transport header, depending on the number and
                    266:                                 * type of extension headers */
                    267:                                if (!fragment &&
                    268:                                        !parse_transport_header(*payload, *proto, sport, dport))
                    269:                                {
                    270:                                        return FALSE;
                    271:                                }
                    272:                                break;
                    273:                }
                    274:                break;
                    275:        }
                    276:        return TRUE;
                    277: }
                    278: #endif /* HAVE_NETINET_IP6_H */
                    279: 
                    280: /**
                    281:  * Described in header.
                    282:  */
                    283: ip_packet_t *ip_packet_create(chunk_t packet)
                    284: {
                    285:        private_ip_packet_t *this;
                    286:        uint8_t version, next_header;
                    287:        uint16_t sport = 0, dport = 0;
                    288:        host_t *src, *dst;
                    289:        chunk_t payload;
                    290: 
                    291:        if (packet.len < 1)
                    292:        {
                    293:                DBG1(DBG_ESP, "IP packet too short");
                    294:                goto failed;
                    295:        }
                    296: 
                    297:        version = (packet.ptr[0] & 0xf0) >> 4;
                    298: 
                    299:        switch (version)
                    300:        {
                    301:                case 4:
                    302:                {
                    303:                        struct ip *ip;
                    304: 
                    305:                        if (packet.len < sizeof(struct ip))
                    306:                        {
                    307:                                DBG1(DBG_ESP, "IPv4 packet too short");
                    308:                                goto failed;
                    309:                        }
                    310:                        ip = (struct ip*)packet.ptr;
                    311:                        /* remove any RFC 4303 TFC extra padding */
                    312:                        packet.len = min(packet.len, untoh16(&ip->ip_len));
                    313:                        payload = chunk_skip(packet, ip->ip_hl * 4);
                    314:                        if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
                    315:                                !parse_transport_header(payload, ip->ip_p, &sport, &dport))
                    316:                        {
                    317:                                goto failed;
                    318:                        }
                    319:                        src = host_create_from_chunk(AF_INET,
                    320:                                                                                 chunk_from_thing(ip->ip_src), sport);
                    321:                        dst = host_create_from_chunk(AF_INET,
                    322:                                                                                 chunk_from_thing(ip->ip_dst), dport);
                    323:                        next_header = ip->ip_p;
                    324:                        break;
                    325:                }
                    326: #ifdef HAVE_NETINET_IP6_H
                    327:                case 6:
                    328:                {
                    329:                        struct ip6_hdr *ip;
                    330: 
                    331:                        if (packet.len < sizeof(*ip))
                    332:                        {
                    333:                                DBG1(DBG_ESP, "IPv6 packet too short");
                    334:                                goto failed;
                    335:                        }
                    336:                        ip = (struct ip6_hdr*)packet.ptr;
                    337:                        /* remove any RFC 4303 TFC extra padding */
                    338:                        packet.len = min(packet.len, 40 + untoh16((void*)&ip->ip6_plen));
                    339:                        if (!parse_transport_header_v6(ip, packet, &payload, &next_header,
                    340:                                                                                   &sport, &dport))
                    341:                        {
                    342:                                goto failed;
                    343:                        }
                    344:                        src = host_create_from_chunk(AF_INET6,
                    345:                                                                                 chunk_from_thing(ip->ip6_src), sport);
                    346:                        dst = host_create_from_chunk(AF_INET6,
                    347:                                                                                 chunk_from_thing(ip->ip6_dst), dport);
                    348:                        break;
                    349:                }
                    350: #endif /* HAVE_NETINET_IP6_H */
                    351:                default:
                    352:                        DBG1(DBG_ESP, "unsupported IP version");
                    353:                        goto failed;
                    354:        }
                    355: 
                    356:        INIT(this,
                    357:                .public = {
                    358:                        .get_version = _get_version,
                    359:                        .get_source = _get_source,
                    360:                        .get_destination = _get_destination,
                    361:                        .get_next_header = _get_next_header,
                    362:                        .get_encoding = _get_encoding,
                    363:                        .get_payload = _get_payload,
                    364:                        .clone = _clone_,
                    365:                        .destroy = _destroy,
                    366:                },
                    367:                .src = src,
                    368:                .dst = dst,
                    369:                .packet = packet,
                    370:                .payload = payload,
                    371:                .version = version,
                    372:                .next_header = next_header,
                    373:        );
                    374:        return &this->public;
                    375: 
                    376: failed:
                    377:        chunk_free(&packet);
                    378:        return NULL;
                    379: }
                    380: 
                    381: /**
                    382:  * Calculate the checksum for the pseudo IP header
                    383:  */
                    384: static uint16_t pseudo_header_checksum(host_t *src, host_t *dst,
                    385:                                                                                uint8_t proto, chunk_t payload)
                    386: {
                    387:        switch (src->get_family(src))
                    388:        {
                    389:                case AF_INET:
                    390:                {
                    391:                        struct __attribute__((packed)) {
                    392:                                uint32_t src;
                    393:                                uint32_t dst;
                    394:                                u_char zero;
                    395:                                u_char proto;
                    396:                                uint16_t len;
                    397:                        } pseudo = {
                    398:                                .proto = proto,
                    399:                                .len = htons(payload.len),
                    400:                        };
                    401:                        memcpy(&pseudo.src, src->get_address(src).ptr,
                    402:                                   sizeof(pseudo.src));
                    403:                        memcpy(&pseudo.dst, dst->get_address(dst).ptr,
                    404:                                   sizeof(pseudo.dst));
                    405:                        return chunk_internet_checksum(chunk_from_thing(pseudo));
                    406:                }
                    407:                case AF_INET6:
                    408:                {
                    409:                        struct __attribute__((packed)) {
                    410:                                u_char src[16];
                    411:                                u_char dst[16];
                    412:                                uint32_t len;
                    413:                                u_char zero[3];
                    414:                                u_char next_header;
                    415:                        } pseudo = {
                    416:                                .next_header = proto,
                    417:                                .len = htons(payload.len),
                    418:                        };
                    419:                        memcpy(&pseudo.src, src->get_address(src).ptr,
                    420:                                   sizeof(pseudo.src));
                    421:                        memcpy(&pseudo.dst, dst->get_address(dst).ptr,
                    422:                                   sizeof(pseudo.dst));
                    423:                        return chunk_internet_checksum(chunk_from_thing(pseudo));
                    424:                }
                    425:        }
                    426:        return 0xffff;
                    427: }
                    428: 
                    429: /**
                    430:  * Apply transport ports and calculate header checksums
                    431:  */
                    432: static void fix_transport_header(host_t *src, host_t *dst, uint8_t proto,
                    433:                                                                 chunk_t payload)
                    434: {
                    435:        uint16_t sum = 0, sport, dport;
                    436: 
                    437:        sport = src->get_port(src);
                    438:        dport = dst->get_port(dst);
                    439: 
                    440:        switch (proto)
                    441:        {
                    442:                case IPPROTO_UDP:
                    443:                {
                    444:                        struct udphdr *udp;
                    445: 
                    446:                        if (payload.len < sizeof(*udp))
                    447:                        {
                    448:                                return;
                    449:                        }
                    450:                        udp = (struct udphdr*)payload.ptr;
                    451:                        if (sport != 0)
                    452:                        {
                    453:                                udp->source = htons(sport);
                    454:                        }
                    455:                        if (dport != 0)
                    456:                        {
                    457:                                udp->dest = htons(dport);
                    458:                        }
                    459:                        udp->check = 0;
                    460:                        sum = pseudo_header_checksum(src, dst, proto, payload);
                    461:                        udp->check = chunk_internet_checksum_inc(payload, sum);
                    462:                        break;
                    463:                }
                    464:                case IPPROTO_TCP:
                    465:                {
                    466:                        struct tcphdr *tcp;
                    467: 
                    468:                        if (payload.len < sizeof(*tcp))
                    469:                        {
                    470:                                return;
                    471:                        }
                    472:                        tcp = (struct tcphdr*)payload.ptr;
                    473:                        if (sport != 0)
                    474:                        {
                    475:                                tcp->source = htons(sport);
                    476:                        }
                    477:                        if (dport != 0)
                    478:                        {
                    479:                                tcp->dest = htons(dport);
                    480:                        }
                    481:                        tcp->check = 0;
                    482:                        sum = pseudo_header_checksum(src, dst, proto, payload);
                    483:                        tcp->check = chunk_internet_checksum_inc(payload, sum);
                    484:                        break;
                    485:                }
                    486:                default:
                    487:                        break;
                    488:        }
                    489: }
                    490: 
                    491: /**
                    492:  * Described in header.
                    493:  */
                    494: ip_packet_t *ip_packet_create_from_data(host_t *src, host_t *dst,
                    495:                                                                                uint8_t next_header, chunk_t data)
                    496: {
                    497:        chunk_t packet;
                    498:        int family;
                    499: 
                    500:        family = src->get_family(src);
                    501:        if (family != dst->get_family(dst))
                    502:        {
                    503:                DBG1(DBG_ESP, "address family does not match");
                    504:                return NULL;
                    505:        }
                    506: 
                    507:        switch (family)
                    508:        {
                    509:                case AF_INET:
                    510:                {
                    511:                        struct ip ip = {
                    512:                                .ip_v = 4,
                    513:                                .ip_hl = 5,
                    514:                                .ip_len = htons(20 + data.len),
                    515:                                .ip_ttl = 0x80,
                    516:                                .ip_p = next_header,
                    517:                        };
                    518:                        memcpy(&ip.ip_src, src->get_address(src).ptr, sizeof(ip.ip_src));
                    519:                        memcpy(&ip.ip_dst, dst->get_address(dst).ptr, sizeof(ip.ip_dst));
                    520:                        ip.ip_sum = chunk_internet_checksum(chunk_from_thing(ip));
                    521: 
                    522:                        packet = chunk_cat("cc", chunk_from_thing(ip), data);
                    523:                        fix_transport_header(src, dst, next_header, chunk_skip(packet, 20));
                    524:                        return ip_packet_create(packet);
                    525:                }
                    526: #ifdef HAVE_NETINET_IP6_H
                    527:                case AF_INET6:
                    528:                {
                    529:                        struct ip6_hdr ip = {
                    530:                                .ip6_flow = htonl(6 << 28),
                    531:                                .ip6_plen = htons(data.len),
                    532:                                .ip6_nxt = next_header,
                    533:                                .ip6_hlim = 0x80,
                    534:                        };
                    535:                        memcpy(&ip.ip6_src, src->get_address(src).ptr, sizeof(ip.ip6_src));
                    536:                        memcpy(&ip.ip6_dst, dst->get_address(dst).ptr, sizeof(ip.ip6_dst));
                    537: 
                    538:                        packet = chunk_cat("cc", chunk_from_thing(ip), data);
                    539:                        fix_transport_header(src, dst, next_header, chunk_skip(packet, 40));
                    540:                        return ip_packet_create(packet);
                    541:                }
                    542: #endif /* HAVE_NETINET_IP6_H */
                    543:                default:
                    544:                        DBG1(DBG_ESP, "unsupported address family");
                    545:                        return NULL;
                    546:        }
                    547: }
                    548: 
                    549: /**
                    550:  * Described in header.
                    551:  */
                    552: ip_packet_t *ip_packet_create_udp_from_data(host_t *src, host_t *dst,
                    553:                                                                                        chunk_t data)
                    554: {
                    555:        struct udphdr udp = {
                    556:                .len = htons(8 + data.len),
                    557:                .check = 0,
                    558:        };
                    559:        ip_packet_t *packet;
                    560: 
                    561:        data = chunk_cat("cc", chunk_from_thing(udp), data);
                    562:        packet = ip_packet_create_from_data(src, dst, IPPROTO_UDP, data);
                    563:        chunk_free(&data);
                    564:        return packet;
                    565: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>