[BACK]Return to npf_inet.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / net / npf

Annotation of src/sys/net/npf/npf_inet.c, Revision 1.32.4.2

1.32.4.2! skrll       1: /*     $NetBSD: npf_inet.c,v 1.32.4.1 2015/12/27 12:10:07 skrll Exp $  */
1.1       rmind       2:
                      3: /*-
1.29      rmind       4:  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
1.1       rmind       5:  * All rights reserved.
                      6:  *
                      7:  * This material is based upon work partially supported by The
                      8:  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: /*
1.22      rmind      33:  * Various protocol related helper routines.
1.12      rmind      34:  *
                     35:  * This layer manipulates npf_cache_t structure i.e. caches requested headers
                     36:  * and stores which information was cached in the information bit field.
                     37:  * It is also responsibility of this layer to update or invalidate the cache
                     38:  * on rewrites (e.g. by translation routines).
1.1       rmind      39:  */
                     40:
                     41: #include <sys/cdefs.h>
1.32.4.2! skrll      42: __KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.32.4.1 2015/12/27 12:10:07 skrll Exp $");
1.1       rmind      43:
                     44: #include <sys/param.h>
1.11      rmind      45: #include <sys/types.h>
1.1       rmind      46:
1.4       rmind      47: #include <net/pfil.h>
                     48: #include <net/if.h>
                     49: #include <net/ethertypes.h>
                     50: #include <net/if_ether.h>
                     51:
1.1       rmind      52: #include <netinet/in_systm.h>
                     53: #include <netinet/in.h>
1.32.4.1  skrll      54: #include <netinet6/in6_var.h>
1.1       rmind      55: #include <netinet/ip.h>
1.4       rmind      56: #include <netinet/ip6.h>
1.1       rmind      57: #include <netinet/tcp.h>
                     58: #include <netinet/udp.h>
                     59: #include <netinet/ip_icmp.h>
                     60:
                     61: #include "npf_impl.h"
                     62:
                     63: /*
1.27      rmind      64:  * npf_fixup{16,32}_cksum: incremental update of the Internet checksum.
1.1       rmind      65:  */
                     66:
                     67: uint16_t
                     68: npf_fixup16_cksum(uint16_t cksum, uint16_t odatum, uint16_t ndatum)
                     69: {
                     70:        uint32_t sum;
                     71:
                     72:        /*
                     73:         * RFC 1624:
                     74:         *      HC' = ~(~HC + ~m + m')
1.27      rmind      75:         *
                     76:         * Note: 1's complement sum is endian-independent (RFC 1071, page 2).
1.1       rmind      77:         */
1.27      rmind      78:        sum = ~cksum & 0xffff;
                     79:        sum += (~odatum & 0xffff) + ndatum;
1.1       rmind      80:        sum = (sum >> 16) + (sum & 0xffff);
                     81:        sum += (sum >> 16);
                     82:
1.27      rmind      83:        return ~sum & 0xffff;
1.1       rmind      84: }
                     85:
                     86: uint16_t
                     87: npf_fixup32_cksum(uint16_t cksum, uint32_t odatum, uint32_t ndatum)
                     88: {
1.27      rmind      89:        uint32_t sum;
                     90:
                     91:        /*
                     92:         * Checksum 32-bit datum as as two 16-bit.  Note, the first
                     93:         * 32->16 bit reduction is not necessary.
                     94:         */
                     95:        sum = ~cksum & 0xffff;
                     96:        sum += (~odatum & 0xffff) + (ndatum & 0xffff);
1.1       rmind      97:
1.27      rmind      98:        sum += (~odatum >> 16) + (ndatum >> 16);
                     99:        sum = (sum >> 16) + (sum & 0xffff);
                    100:        sum += (sum >> 16);
                    101:        return ~sum & 0xffff;
1.1       rmind     102: }
                    103:
                    104: /*
1.4       rmind     105:  * npf_addr_cksum: calculate checksum of the address, either IPv4 or IPv6.
                    106:  */
                    107: uint16_t
1.19      rmind     108: npf_addr_cksum(uint16_t cksum, int sz, const npf_addr_t *oaddr,
                    109:     const npf_addr_t *naddr)
1.4       rmind     110: {
1.19      rmind     111:        const uint32_t *oip32 = (const uint32_t *)oaddr;
                    112:        const uint32_t *nip32 = (const uint32_t *)naddr;
1.4       rmind     113:
                    114:        KASSERT(sz % sizeof(uint32_t) == 0);
                    115:        do {
                    116:                cksum = npf_fixup32_cksum(cksum, *oip32++, *nip32++);
                    117:                sz -= sizeof(uint32_t);
                    118:        } while (sz);
                    119:
                    120:        return cksum;
                    121: }
                    122:
                    123: /*
1.26      rmind     124:  * npf_addr_sum: provide IP addresses as a XORed 32-bit integer.
1.4       rmind     125:  * Note: used for hash function.
1.1       rmind     126:  */
1.4       rmind     127: uint32_t
1.26      rmind     128: npf_addr_mix(const int sz, const npf_addr_t *a1, const npf_addr_t *a2)
1.1       rmind     129: {
1.4       rmind     130:        uint32_t mix = 0;
1.1       rmind     131:
1.5       rmind     132:        KASSERT(sz > 0 && a1 != NULL && a2 != NULL);
                    133:
1.26      rmind     134:        for (int i = 0; i < (sz >> 2); i++) {
                    135:                mix ^= a1->s6_addr32[i];
                    136:                mix ^= a2->s6_addr32[i];
1.4       rmind     137:        }
                    138:        return mix;
                    139: }
1.1       rmind     140:
1.13      rmind     141: /*
                    142:  * npf_addr_mask: apply the mask to a given address and store the result.
                    143:  */
                    144: void
                    145: npf_addr_mask(const npf_addr_t *addr, const npf_netmask_t mask,
                    146:     const int alen, npf_addr_t *out)
1.12      rmind     147: {
1.13      rmind     148:        const int nwords = alen >> 2;
1.12      rmind     149:        uint_fast8_t length = mask;
                    150:
                    151:        /* Note: maximum length is 32 for IPv4 and 128 for IPv6. */
                    152:        KASSERT(length <= NPF_MAX_NETMASK);
                    153:
1.13      rmind     154:        for (int i = 0; i < nwords; i++) {
                    155:                uint32_t wordmask;
                    156:
1.12      rmind     157:                if (length >= 32) {
1.13      rmind     158:                        wordmask = htonl(0xffffffff);
1.12      rmind     159:                        length -= 32;
1.13      rmind     160:                } else if (length) {
                    161:                        wordmask = htonl(0xffffffff << (32 - length));
                    162:                        length = 0;
1.12      rmind     163:                } else {
1.13      rmind     164:                        wordmask = 0;
1.12      rmind     165:                }
1.13      rmind     166:                out->s6_addr32[i] = addr->s6_addr32[i] & wordmask;
1.12      rmind     167:        }
                    168: }
                    169:
                    170: /*
                    171:  * npf_addr_cmp: compare two addresses, either IPv4 or IPv6.
                    172:  *
1.13      rmind     173:  * => Return 0 if equal and negative/positive if less/greater accordingly.
1.12      rmind     174:  * => Ignore the mask, if NPF_NO_NETMASK is specified.
                    175:  */
                    176: int
                    177: npf_addr_cmp(const npf_addr_t *addr1, const npf_netmask_t mask1,
1.13      rmind     178:     const npf_addr_t *addr2, const npf_netmask_t mask2, const int alen)
1.12      rmind     179: {
1.13      rmind     180:        npf_addr_t realaddr1, realaddr2;
1.12      rmind     181:
                    182:        if (mask1 != NPF_NO_NETMASK) {
1.13      rmind     183:                npf_addr_mask(addr1, mask1, alen, &realaddr1);
                    184:                addr1 = &realaddr1;
1.12      rmind     185:        }
                    186:        if (mask2 != NPF_NO_NETMASK) {
1.13      rmind     187:                npf_addr_mask(addr2, mask2, alen, &realaddr2);
                    188:                addr2 = &realaddr2;
1.12      rmind     189:        }
1.13      rmind     190:        return memcmp(addr1, addr2, alen);
1.12      rmind     191: }
                    192:
1.4       rmind     193: /*
                    194:  * npf_tcpsaw: helper to fetch SEQ, ACK, WIN and return TCP data length.
1.12      rmind     195:  *
                    196:  * => Returns all values in host byte-order.
1.4       rmind     197:  */
                    198: int
1.12      rmind     199: npf_tcpsaw(const npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win)
1.4       rmind     200: {
1.19      rmind     201:        const struct tcphdr *th = npc->npc_l4.tcp;
1.8       rmind     202:        u_int thlen;
1.1       rmind     203:
1.7       zoltan    204:        KASSERT(npf_iscached(npc, NPC_TCP));
1.1       rmind     205:
1.4       rmind     206:        *seq = ntohl(th->th_seq);
                    207:        *ack = ntohl(th->th_ack);
                    208:        *win = (uint32_t)ntohs(th->th_win);
1.8       rmind     209:        thlen = th->th_off << 2;
1.1       rmind     210:
1.7       zoltan    211:        if (npf_iscached(npc, NPC_IP4)) {
1.19      rmind     212:                const struct ip *ip = npc->npc_ip.v4;
1.21      rmind     213:                return ntohs(ip->ip_len) - npc->npc_hlen - thlen;
1.12      rmind     214:        } else if (npf_iscached(npc, NPC_IP6)) {
1.19      rmind     215:                const struct ip6_hdr *ip6 = npc->npc_ip.v6;
1.8       rmind     216:                return ntohs(ip6->ip6_plen) - thlen;
1.7       zoltan    217:        }
                    218:        return 0;
1.1       rmind     219: }
                    220:
                    221: /*
1.4       rmind     222:  * npf_fetch_tcpopts: parse and return TCP options.
1.1       rmind     223:  */
                    224: bool
1.32      rmind     225: npf_fetch_tcpopts(npf_cache_t *npc, uint16_t *mss, int *wscale)
1.1       rmind     226: {
1.32      rmind     227:        nbuf_t *nbuf = npc->npc_nbuf;
1.19      rmind     228:        const struct tcphdr *th = npc->npc_l4.tcp;
1.4       rmind     229:        int topts_len, step;
1.19      rmind     230:        void *nptr;
1.4       rmind     231:        uint8_t val;
1.19      rmind     232:        bool ok;
1.4       rmind     233:
1.7       zoltan    234:        KASSERT(npf_iscached(npc, NPC_IP46));
                    235:        KASSERT(npf_iscached(npc, NPC_TCP));
1.10      rmind     236:
1.4       rmind     237:        /* Determine if there are any TCP options, get their length. */
                    238:        topts_len = (th->th_off << 2) - sizeof(struct tcphdr);
                    239:        if (topts_len <= 0) {
                    240:                /* No options. */
1.1       rmind     241:                return false;
1.4       rmind     242:        }
                    243:        KASSERT(topts_len <= MAX_TCPOPTLEN);
1.1       rmind     244:
1.4       rmind     245:        /* First step: IP and TCP header up to options. */
1.21      rmind     246:        step = npc->npc_hlen + sizeof(struct tcphdr);
1.19      rmind     247:        nbuf_reset(nbuf);
1.4       rmind     248: next:
1.19      rmind     249:        if ((nptr = nbuf_advance(nbuf, step, 1)) == NULL) {
                    250:                ok = false;
                    251:                goto done;
1.4       rmind     252:        }
1.19      rmind     253:        val = *(uint8_t *)nptr;
1.12      rmind     254:
1.4       rmind     255:        switch (val) {
                    256:        case TCPOPT_EOL:
                    257:                /* Done. */
1.19      rmind     258:                ok = true;
                    259:                goto done;
1.4       rmind     260:        case TCPOPT_NOP:
                    261:                topts_len--;
                    262:                step = 1;
                    263:                break;
                    264:        case TCPOPT_MAXSEG:
1.19      rmind     265:                if ((nptr = nbuf_advance(nbuf, 2, 2)) == NULL) {
                    266:                        ok = false;
                    267:                        goto done;
1.4       rmind     268:                }
                    269:                if (mss) {
1.19      rmind     270:                        if (*mss) {
                    271:                                memcpy(nptr, mss, sizeof(uint16_t));
                    272:                        } else {
                    273:                                memcpy(mss, nptr, sizeof(uint16_t));
                    274:                        }
1.4       rmind     275:                }
                    276:                topts_len -= TCPOLEN_MAXSEG;
1.19      rmind     277:                step = 2;
1.4       rmind     278:                break;
                    279:        case TCPOPT_WINDOW:
1.10      rmind     280:                /* TCP Window Scaling (RFC 1323). */
1.19      rmind     281:                if ((nptr = nbuf_advance(nbuf, 2, 1)) == NULL) {
                    282:                        ok = false;
                    283:                        goto done;
1.4       rmind     284:                }
1.19      rmind     285:                val = *(uint8_t *)nptr;
1.4       rmind     286:                *wscale = (val > TCP_MAX_WINSHIFT) ? TCP_MAX_WINSHIFT : val;
                    287:                topts_len -= TCPOLEN_WINDOW;
1.19      rmind     288:                step = 1;
1.4       rmind     289:                break;
                    290:        default:
1.19      rmind     291:                if ((nptr = nbuf_advance(nbuf, 1, 1)) == NULL) {
                    292:                        ok = false;
                    293:                        goto done;
1.4       rmind     294:                }
1.19      rmind     295:                val = *(uint8_t *)nptr;
1.16      rmind     296:                if (val < 2 || val > topts_len) {
1.19      rmind     297:                        ok = false;
                    298:                        goto done;
1.4       rmind     299:                }
                    300:                topts_len -= val;
                    301:                step = val - 1;
                    302:        }
1.12      rmind     303:
1.6       rmind     304:        /* Any options left? */
1.4       rmind     305:        if (__predict_true(topts_len > 0)) {
                    306:                goto next;
                    307:        }
1.19      rmind     308:        ok = true;
                    309: done:
                    310:        if (nbuf_flag_p(nbuf, NBUF_DATAREF_RESET)) {
1.32      rmind     311:                npf_recache(npc);
1.19      rmind     312:        }
                    313:        return ok;
1.1       rmind     314: }
                    315:
1.19      rmind     316: static int
                    317: npf_cache_ip(npf_cache_t *npc, nbuf_t *nbuf)
1.1       rmind     318: {
1.19      rmind     319:        const void *nptr = nbuf_dataptr(nbuf);
                    320:        const uint8_t ver = *(const uint8_t *)nptr;
                    321:        int flags = 0;
1.12      rmind     322:
1.4       rmind     323:        switch (ver >> 4) {
1.12      rmind     324:        case IPVERSION: {
1.19      rmind     325:                struct ip *ip;
1.12      rmind     326:
1.19      rmind     327:                ip = nbuf_ensure_contig(nbuf, sizeof(struct ip));
                    328:                if (ip == NULL) {
                    329:                        return 0;
1.4       rmind     330:                }
1.12      rmind     331:
1.4       rmind     332:                /* Check header length and fragment offset. */
1.10      rmind     333:                if ((u_int)(ip->ip_hl << 2) < sizeof(struct ip)) {
1.19      rmind     334:                        return 0;
1.4       rmind     335:                }
                    336:                if (ip->ip_off & ~htons(IP_DF | IP_RF)) {
                    337:                        /* Note fragmentation. */
1.19      rmind     338:                        flags |= NPC_IPFRAG;
1.4       rmind     339:                }
1.12      rmind     340:
1.4       rmind     341:                /* Cache: layer 3 - IPv4. */
1.14      rmind     342:                npc->npc_alen = sizeof(struct in_addr);
1.28      rmind     343:                npc->npc_ips[NPF_SRC] = (npf_addr_t *)&ip->ip_src;
                    344:                npc->npc_ips[NPF_DST] = (npf_addr_t *)&ip->ip_dst;
1.7       zoltan    345:                npc->npc_hlen = ip->ip_hl << 2;
1.19      rmind     346:                npc->npc_proto = ip->ip_p;
                    347:
                    348:                npc->npc_ip.v4 = ip;
                    349:                flags |= NPC_IP4;
1.4       rmind     350:                break;
1.12      rmind     351:        }
1.4       rmind     352:
1.12      rmind     353:        case (IPV6_VERSION >> 4): {
1.19      rmind     354:                struct ip6_hdr *ip6;
                    355:                struct ip6_ext *ip6e;
                    356:                size_t off, hlen;
                    357:
                    358:                ip6 = nbuf_ensure_contig(nbuf, sizeof(struct ip6_hdr));
                    359:                if (ip6 == NULL) {
                    360:                        return 0;
1.7       zoltan    361:                }
1.19      rmind     362:
                    363:                /* Set initial next-protocol value. */
                    364:                hlen = sizeof(struct ip6_hdr);
                    365:                npc->npc_proto = ip6->ip6_nxt;
1.13      rmind     366:                npc->npc_hlen = hlen;
1.7       zoltan    367:
1.12      rmind     368:                /*
1.19      rmind     369:                 * Advance by the length of the current header.
1.12      rmind     370:                 */
1.19      rmind     371:                off = nbuf_offset(nbuf);
                    372:                while (nbuf_advance(nbuf, hlen, 0) != NULL) {
                    373:                        ip6e = nbuf_ensure_contig(nbuf, sizeof(*ip6e));
                    374:                        if (ip6e == NULL) {
                    375:                                return 0;
                    376:                        }
                    377:
1.13      rmind     378:                        /*
                    379:                         * Determine whether we are going to continue.
                    380:                         */
1.19      rmind     381:                        switch (npc->npc_proto) {
1.13      rmind     382:                        case IPPROTO_HOPOPTS:
1.7       zoltan    383:                        case IPPROTO_DSTOPTS:
                    384:                        case IPPROTO_ROUTING:
1.19      rmind     385:                                hlen = (ip6e->ip6e_len + 1) << 3;
1.7       zoltan    386:                                break;
                    387:                        case IPPROTO_FRAGMENT:
1.13      rmind     388:                                hlen = sizeof(struct ip6_frag);
1.19      rmind     389:                                flags |= NPC_IPFRAG;
1.7       zoltan    390:                                break;
                    391:                        case IPPROTO_AH:
1.19      rmind     392:                                hlen = (ip6e->ip6e_len + 2) << 2;
1.7       zoltan    393:                                break;
                    394:                        default:
1.13      rmind     395:                                hlen = 0;
                    396:                                break;
                    397:                        }
                    398:
                    399:                        if (!hlen) {
1.7       zoltan    400:                                break;
                    401:                        }
1.19      rmind     402:                        npc->npc_proto = ip6e->ip6e_nxt;
1.13      rmind     403:                        npc->npc_hlen += hlen;
                    404:                }
1.7       zoltan    405:
1.23      rmind     406:                /*
                    407:                 * Re-fetch the header pointers (nbufs might have been
                    408:                 * reallocated).  Restore the original offset (if any).
                    409:                 */
1.19      rmind     410:                nbuf_reset(nbuf);
1.23      rmind     411:                ip6 = nbuf_dataptr(nbuf);
1.19      rmind     412:                if (off) {
                    413:                        nbuf_advance(nbuf, off, 0);
                    414:                }
                    415:
1.12      rmind     416:                /* Cache: layer 3 - IPv6. */
1.14      rmind     417:                npc->npc_alen = sizeof(struct in6_addr);
1.28      rmind     418:                npc->npc_ips[NPF_SRC] = (npf_addr_t *)&ip6->ip6_src;
                    419:                npc->npc_ips[NPF_DST]= (npf_addr_t *)&ip6->ip6_dst;
1.19      rmind     420:
                    421:                npc->npc_ip.v6 = ip6;
                    422:                flags |= NPC_IP6;
1.7       zoltan    423:                break;
1.12      rmind     424:        }
1.4       rmind     425:        default:
1.19      rmind     426:                break;
1.4       rmind     427:        }
1.19      rmind     428:        return flags;
1.1       rmind     429: }
                    430:
                    431: /*
1.4       rmind     432:  * npf_cache_all: general routine to cache all relevant IP (v4 or v6)
1.12      rmind     433:  * and TCP, UDP or ICMP headers.
1.19      rmind     434:  *
                    435:  * => nbuf offset shall be set accordingly.
1.1       rmind     436:  */
1.10      rmind     437: int
1.32      rmind     438: npf_cache_all(npf_cache_t *npc)
1.1       rmind     439: {
1.32      rmind     440:        nbuf_t *nbuf = npc->npc_nbuf;
1.19      rmind     441:        int flags, l4flags;
                    442:        u_int hlen;
                    443:
                    444:        /*
                    445:         * This routine is a main point where the references are cached,
                    446:         * therefore clear the flag as we reset.
                    447:         */
                    448: again:
                    449:        nbuf_unset_flag(nbuf, NBUF_DATAREF_RESET);
1.1       rmind     450:
1.19      rmind     451:        /*
                    452:         * First, cache the L3 header (IPv4 or IPv6).  If IP packet is
                    453:         * fragmented, then we cannot look into L4.
                    454:         */
                    455:        flags = npf_cache_ip(npc, nbuf);
                    456:        if ((flags & NPC_IP46) == 0 || (flags & NPC_IPFRAG) != 0) {
1.23      rmind     457:                nbuf_unset_flag(nbuf, NBUF_DATAREF_RESET);
1.19      rmind     458:                npc->npc_info |= flags;
                    459:                return flags;
1.1       rmind     460:        }
1.19      rmind     461:        hlen = npc->npc_hlen;
                    462:
                    463:        switch (npc->npc_proto) {
1.1       rmind     464:        case IPPROTO_TCP:
1.19      rmind     465:                /* Cache: layer 4 - TCP. */
                    466:                npc->npc_l4.tcp = nbuf_advance(nbuf, hlen,
                    467:                    sizeof(struct tcphdr));
                    468:                l4flags = NPC_LAYER4 | NPC_TCP;
1.10      rmind     469:                break;
1.1       rmind     470:        case IPPROTO_UDP:
1.19      rmind     471:                /* Cache: layer 4 - UDP. */
                    472:                npc->npc_l4.udp = nbuf_advance(nbuf, hlen,
                    473:                    sizeof(struct udphdr));
                    474:                l4flags = NPC_LAYER4 | NPC_UDP;
1.10      rmind     475:                break;
1.1       rmind     476:        case IPPROTO_ICMP:
1.19      rmind     477:                /* Cache: layer 4 - ICMPv4. */
                    478:                npc->npc_l4.icmp = nbuf_advance(nbuf, hlen,
                    479:                    offsetof(struct icmp, icmp_void));
                    480:                l4flags = NPC_LAYER4 | NPC_ICMP;
                    481:                break;
1.15      spz       482:        case IPPROTO_ICMPV6:
1.19      rmind     483:                /* Cache: layer 4 - ICMPv6. */
                    484:                npc->npc_l4.icmp6 = nbuf_advance(nbuf, hlen,
                    485:                    offsetof(struct icmp6_hdr, icmp6_data32));
                    486:                l4flags = NPC_LAYER4 | NPC_ICMP;
                    487:                break;
                    488:        default:
                    489:                l4flags = 0;
1.10      rmind     490:                break;
1.1       rmind     491:        }
1.19      rmind     492:
                    493:        if (nbuf_flag_p(nbuf, NBUF_DATAREF_RESET)) {
                    494:                goto again;
                    495:        }
                    496:
                    497:        /* Add the L4 flags if nbuf_advance() succeeded. */
                    498:        if (l4flags && npc->npc_l4.hdr) {
                    499:                flags |= l4flags;
                    500:        }
                    501:        npc->npc_info |= flags;
                    502:        return flags;
                    503: }
                    504:
                    505: void
1.32      rmind     506: npf_recache(npf_cache_t *npc)
1.19      rmind     507: {
1.32      rmind     508:        nbuf_t *nbuf = npc->npc_nbuf;
1.24      martin    509:        const int mflags __diagused = npc->npc_info & (NPC_IP46 | NPC_LAYER4);
1.25      mrg       510:        int flags __diagused;
1.19      rmind     511:
                    512:        nbuf_reset(nbuf);
                    513:        npc->npc_info = 0;
1.32      rmind     514:        flags = npf_cache_all(npc);
                    515:
1.19      rmind     516:        KASSERT((flags & mflags) == mflags);
                    517:        KASSERT(nbuf_flag_p(nbuf, NBUF_DATAREF_RESET) == 0);
1.1       rmind     518: }
                    519:
                    520: /*
1.19      rmind     521:  * npf_rwrip: rewrite required IP address.
1.4       rmind     522:  */
                    523: bool
1.28      rmind     524: npf_rwrip(const npf_cache_t *npc, u_int which, const npf_addr_t *addr)
1.4       rmind     525: {
                    526:        KASSERT(npf_iscached(npc, NPC_IP46));
1.28      rmind     527:        KASSERT(which == NPF_SRC || which == NPF_DST);
1.4       rmind     528:
1.28      rmind     529:        memcpy(npc->npc_ips[which], addr, npc->npc_alen);
1.4       rmind     530:        return true;
                    531: }
                    532:
                    533: /*
1.19      rmind     534:  * npf_rwrport: rewrite required TCP/UDP port.
1.1       rmind     535:  */
                    536: bool
1.28      rmind     537: npf_rwrport(const npf_cache_t *npc, u_int which, const in_port_t port)
1.1       rmind     538: {
1.21      rmind     539:        const int proto = npc->npc_proto;
1.4       rmind     540:        in_port_t *oport;
1.1       rmind     541:
1.4       rmind     542:        KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
1.1       rmind     543:        KASSERT(proto == IPPROTO_TCP || proto == IPPROTO_UDP);
1.28      rmind     544:        KASSERT(which == NPF_SRC || which == NPF_DST);
1.1       rmind     545:
1.19      rmind     546:        /* Get the offset and store the port in it. */
1.4       rmind     547:        if (proto == IPPROTO_TCP) {
1.19      rmind     548:                struct tcphdr *th = npc->npc_l4.tcp;
1.28      rmind     549:                oport = (which == NPF_SRC) ? &th->th_sport : &th->th_dport;
1.1       rmind     550:        } else {
1.19      rmind     551:                struct udphdr *uh = npc->npc_l4.udp;
1.28      rmind     552:                oport = (which == NPF_SRC) ? &uh->uh_sport : &uh->uh_dport;
1.1       rmind     553:        }
1.19      rmind     554:        memcpy(oport, &port, sizeof(in_port_t));
1.1       rmind     555:        return true;
                    556: }
                    557:
                    558: /*
1.19      rmind     559:  * npf_rwrcksum: rewrite IPv4 and/or TCP/UDP checksum.
1.1       rmind     560:  */
                    561: bool
1.28      rmind     562: npf_rwrcksum(const npf_cache_t *npc, u_int which,
1.19      rmind     563:     const npf_addr_t *addr, const in_port_t port)
1.1       rmind     564: {
1.28      rmind     565:        const npf_addr_t *oaddr = npc->npc_ips[which];
1.21      rmind     566:        const int proto = npc->npc_proto;
1.19      rmind     567:        const int alen = npc->npc_alen;
1.18      rmind     568:        uint16_t *ocksum;
                    569:        in_port_t oport;
                    570:
1.19      rmind     571:        KASSERT(npf_iscached(npc, NPC_LAYER4));
1.28      rmind     572:        KASSERT(which == NPF_SRC || which == NPF_DST);
1.18      rmind     573:
1.4       rmind     574:        if (npf_iscached(npc, NPC_IP4)) {
1.19      rmind     575:                struct ip *ip = npc->npc_ip.v4;
                    576:                uint16_t ipsum = ip->ip_sum;
1.4       rmind     577:
1.19      rmind     578:                /* Recalculate IPv4 checksum and rewrite. */
                    579:                ip->ip_sum = npf_addr_cksum(ipsum, alen, oaddr, addr);
1.4       rmind     580:        } else {
                    581:                /* No checksum for IPv6. */
                    582:                KASSERT(npf_iscached(npc, NPC_IP6));
                    583:        }
                    584:
1.18      rmind     585:        /* Nothing else to do for ICMP. */
1.30      rmind     586:        if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
1.4       rmind     587:                return true;
                    588:        }
1.7       zoltan    589:        KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
1.4       rmind     590:
1.18      rmind     591:        /*
                    592:         * Calculate TCP/UDP checksum:
                    593:         * - Skip if UDP and the current checksum is zero.
                    594:         * - Fixup the IP address change.
                    595:         * - Fixup the port change, if required (non-zero).
                    596:         */
1.4       rmind     597:        if (proto == IPPROTO_TCP) {
1.19      rmind     598:                struct tcphdr *th = npc->npc_l4.tcp;
1.4       rmind     599:
1.18      rmind     600:                ocksum = &th->th_sum;
1.28      rmind     601:                oport = (which == NPF_SRC) ? th->th_sport : th->th_dport;
1.4       rmind     602:        } else {
1.19      rmind     603:                struct udphdr *uh = npc->npc_l4.udp;
1.4       rmind     604:
                    605:                KASSERT(proto == IPPROTO_UDP);
1.18      rmind     606:                ocksum = &uh->uh_sum;
                    607:                if (*ocksum == 0) {
1.4       rmind     608:                        /* No need to update. */
                    609:                        return true;
                    610:                }
1.28      rmind     611:                oport = (which == NPF_SRC) ? uh->uh_sport : uh->uh_dport;
1.18      rmind     612:        }
                    613:
1.19      rmind     614:        uint16_t cksum = npf_addr_cksum(*ocksum, alen, oaddr, addr);
1.18      rmind     615:        if (port) {
                    616:                cksum = npf_fixup16_cksum(cksum, oport, port);
1.4       rmind     617:        }
1.1       rmind     618:
1.19      rmind     619:        /* Rewrite TCP/UDP checksum. */
                    620:        memcpy(ocksum, &cksum, sizeof(uint16_t));
1.4       rmind     621:        return true;
                    622: }
                    623:
1.29      rmind     624: /*
1.30      rmind     625:  * npf_napt_rwr: perform address and/or port translation.
                    626:  */
                    627: int
                    628: npf_napt_rwr(const npf_cache_t *npc, u_int which,
                    629:     const npf_addr_t *addr, const in_addr_t port)
                    630: {
                    631:        const unsigned proto = npc->npc_proto;
                    632:
                    633:        /*
                    634:         * Rewrite IP and/or TCP/UDP checksums first, since we need the
                    635:         * current (old) address/port for the calculations.  Then perform
                    636:         * the address translation i.e. rewrite source or destination.
                    637:         */
                    638:        if (!npf_rwrcksum(npc, which, addr, port)) {
                    639:                return EINVAL;
                    640:        }
                    641:        if (!npf_rwrip(npc, which, addr)) {
                    642:                return EINVAL;
                    643:        }
                    644:        if (port == 0) {
                    645:                /* Done. */
                    646:                return 0;
                    647:        }
                    648:
                    649:        switch (proto) {
                    650:        case IPPROTO_TCP:
                    651:        case IPPROTO_UDP:
                    652:                /* Rewrite source/destination port. */
                    653:                if (!npf_rwrport(npc, which, port)) {
                    654:                        return EINVAL;
                    655:                }
                    656:                break;
                    657:        case IPPROTO_ICMP:
1.32.4.2! skrll     658: #ifdef INET6
1.30      rmind     659:        case IPPROTO_ICMPV6:
                    660:                KASSERT(npf_iscached(npc, NPC_ICMP));
                    661:                /* Nothing. */
                    662:                break;
1.32.4.2! skrll     663: #endif
1.30      rmind     664:        default:
                    665:                return ENOTSUP;
                    666:        }
                    667:        return 0;
                    668: }
                    669:
                    670: /*
1.29      rmind     671:  * IPv6-to-IPv6 Network Prefix Translation (NPTv6), as per RFC 6296.
                    672:  */
                    673:
1.32.4.2! skrll     674: #ifdef INET6
1.29      rmind     675: int
                    676: npf_npt66_rwr(const npf_cache_t *npc, u_int which, const npf_addr_t *pref,
                    677:     npf_netmask_t len, uint16_t adj)
                    678: {
                    679:        npf_addr_t *addr = npc->npc_ips[which];
                    680:        unsigned remnant, word, preflen = len >> 4;
                    681:        uint32_t sum;
                    682:
                    683:        KASSERT(which == NPF_SRC || which == NPF_DST);
                    684:
                    685:        if (!npf_iscached(npc, NPC_IP6)) {
                    686:                return EINVAL;
                    687:        }
                    688:        if (len <= 48) {
                    689:                /*
                    690:                 * The word to adjust.  Cannot translate the 0xffff
                    691:                 * subnet if /48 or shorter.
                    692:                 */
                    693:                word = 3;
                    694:                if (addr->s6_addr16[word] == 0xffff) {
                    695:                        return EINVAL;
                    696:                }
                    697:        } else {
                    698:                /*
                    699:                 * Also, all 0s or 1s in the host part are disallowed for
                    700:                 * longer than /48 prefixes.
                    701:                 */
                    702:                if ((addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0) ||
                    703:                    (addr->s6_addr32[2] == ~0U && addr->s6_addr32[3] == ~0U))
                    704:                        return EINVAL;
                    705:
                    706:                /* Determine the 16-bit word to adjust. */
                    707:                for (word = 4; word < 8; word++)
                    708:                        if (addr->s6_addr16[word] != 0xffff)
                    709:                                break;
                    710:        }
                    711:
                    712:        /* Rewrite the prefix. */
                    713:        for (unsigned i = 0; i < preflen; i++) {
                    714:                addr->s6_addr16[i] = pref->s6_addr16[i];
                    715:        }
                    716:
                    717:        /*
                    718:         * If prefix length is within a 16-bit word (not dividable by 16),
                    719:         * then prepare a mask, determine the word and adjust it.
                    720:         */
                    721:        if ((remnant = len - (preflen << 4)) != 0) {
                    722:                const uint16_t wordmask = (1U << remnant) - 1;
                    723:                const unsigned i = preflen;
                    724:
                    725:                addr->s6_addr16[i] = (pref->s6_addr16[i] & wordmask) |
                    726:                    (addr->s6_addr16[i] & ~wordmask);
                    727:        }
                    728:
                    729:        /*
                    730:         * Performing 1's complement sum/difference.
                    731:         */
                    732:        sum = addr->s6_addr16[word] + adj;
                    733:        while (sum >> 16) {
                    734:                sum = (sum >> 16) + (sum & 0xffff);
                    735:        }
                    736:        if (sum == 0xffff) {
                    737:                /* RFC 1071. */
                    738:                sum = 0x0000;
                    739:        }
                    740:        addr->s6_addr16[word] = sum;
                    741:        return 0;
                    742: }
1.32.4.2! skrll     743: #endif
1.29      rmind     744:
1.13      rmind     745: #if defined(DDB) || defined(_NPF_TESTING)
                    746:
1.31      rmind     747: const char *
                    748: npf_addr_dump(const npf_addr_t *addr, int alen)
1.13      rmind     749: {
1.32.4.2! skrll     750: #ifdef INET6
1.31      rmind     751:        if (alen == sizeof(struct in_addr)) {
1.32.4.2! skrll     752: #else
        !           753:                KASSERT(alen == sizeof(struct in_addr));
        !           754: #endif
1.31      rmind     755:                struct in_addr ip;
                    756:                memcpy(&ip, addr, alen);
                    757:                return inet_ntoa(ip);
1.32.4.2! skrll     758: #ifdef INET6
1.31      rmind     759:        }
1.32.4.1  skrll     760:        return ip6_sprintf(addr);
1.32.4.2! skrll     761: #endif
1.13      rmind     762: }
                    763:
                    764: #endif

CVSweb <webmaster@jp.NetBSD.org>