[BACK]Return to ip_ether.c CVS log [TXT][DIR] Up to [local] / sys / netinet

Annotation of sys/netinet/ip_ether.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: ip_ether.c,v 1.50 2007/02/20 19:37:40 claudio Exp $  */
                      2: /*
                      3:  * The author of this code is Angelos D. Keromytis (kermit@adk.gr)
                      4:  *
                      5:  * This code was written by Angelos D. Keromytis for OpenBSD in October 1999.
                      6:  *
                      7:  * Copyright (C) 1999-2001 Angelos D. Keromytis.
                      8:  *
                      9:  * Permission to use, copy, and modify this software with or without fee
                     10:  * is hereby granted, provided that this entire notice is included in
                     11:  * all copies of any software which is or includes a copy or
                     12:  * modification of this software.
                     13:  * You may use this code under the GNU public license if you so wish. Please
                     14:  * contribute changes back to the authors under this freer than GPL license
                     15:  * so that we may further the use of strong encryption without limitations to
                     16:  * all.
                     17:  *
                     18:  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
                     19:  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
                     20:  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
                     21:  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
                     22:  * PURPOSE.
                     23:  */
                     24:
                     25: /*
                     26:  * Ethernet-inside-IP processing (RFC3378).
                     27:  */
                     28:
                     29: #include "bridge.h"
                     30:
                     31: #include <sys/param.h>
                     32: #include <sys/systm.h>
                     33: #include <sys/mbuf.h>
                     34: #include <sys/socket.h>
                     35: #include <sys/sysctl.h>
                     36:
                     37: #include <net/if.h>
                     38: #include <net/route.h>
                     39: #include <net/bpf.h>
                     40:
                     41: #ifdef INET
                     42: #include <netinet/in.h>
                     43: #include <netinet/in_systm.h>
                     44: #include <netinet/ip.h>
                     45: #include <netinet/in_pcb.h>
                     46: #include <netinet/ip_var.h>
                     47: #endif /* INET */
                     48:
                     49: #include <netinet/ip_ether.h>
                     50: #include <netinet/if_ether.h>
                     51: #include <net/if_bridge.h>
                     52: #include <net/if_gif.h>
                     53:
                     54: #include "gif.h"
                     55: #include "bpfilter.h"
                     56:
                     57: #ifdef ENCDEBUG
                     58: #define DPRINTF(x)     if (encdebug) printf x
                     59: #else
                     60: #define DPRINTF(x)
                     61: #endif
                     62:
                     63: /*
                     64:  * We can control the acceptance of EtherIP packets by altering the sysctl
                     65:  * net.inet.etherip.allow value. Zero means drop them, all else is acceptance.
                     66:  */
                     67: int etherip_allow = 0;
                     68:
                     69: struct etheripstat etheripstat;
                     70:
                     71: /*
                     72:  * etherip_input gets called when we receive an encapsulated packet,
                     73:  * either because we got it at a real interface, or because AH or ESP
                     74:  * were being used in tunnel mode (in which case the rcvif element will
                     75:  * contain the address of the encX interface associated with the tunnel.
                     76:  */
                     77:
                     78: void
                     79: etherip_input(struct mbuf *m, ...)
                     80: {
                     81:        union sockaddr_union ssrc, sdst;
                     82:        struct ether_header eh;
                     83:        int iphlen;
                     84:        struct etherip_header eip;
                     85:        u_int8_t v;
                     86:        va_list ap;
                     87:
                     88: #if NGIF > 0
                     89:        struct gif_softc *sc;
                     90: #if NBRIDGE > 0
                     91:        int s;
                     92: #endif /* NBRIDGE */
                     93: #endif /* NGIF */
                     94:
                     95:        va_start(ap, m);
                     96:        iphlen = va_arg(ap, int);
                     97:        va_end(ap);
                     98:
                     99:        etheripstat.etherip_ipackets++;
                    100:
                    101:        /* If we do not accept EtherIP explicitly, drop. */
                    102:        if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) {
                    103:                DPRINTF(("etherip_input(): dropped due to policy\n"));
                    104:                etheripstat.etherip_pdrops++;
                    105:                m_freem(m);
                    106:                return;
                    107:        }
                    108:
                    109:        /*
                    110:         * Make sure there's at least an ethernet header's and an EtherIP
                    111:         * header's of worth of data after the outer IP header.
                    112:         */
                    113:        if (m->m_pkthdr.len < iphlen + sizeof(struct ether_header) +
                    114:            sizeof(struct etherip_header)) {
                    115:                DPRINTF(("etherip_input(): encapsulated packet too short\n"));
                    116:                etheripstat.etherip_hdrops++;
                    117:                m_freem(m);
                    118:                return;
                    119:        }
                    120:
                    121:        /* Verify EtherIP version number */
                    122:        m_copydata(m, iphlen, sizeof(struct etherip_header), (caddr_t)&eip);
                    123:        if ((eip.eip_ver & ETHERIP_VER_VERS_MASK) != ETHERIP_VERSION) {
                    124:                DPRINTF(("etherip_input(): received EtherIP version number "
                    125:                    "%d not suppoorted\n", (v >> 4) & 0xff));
                    126:                etheripstat.etherip_adrops++;
                    127:                m_freem(m);
                    128:                return;
                    129:        }
                    130:
                    131:        /*
                    132:         * Note that the other potential failure of the above check is that the
                    133:         * second nibble of the EtherIP header (the reserved part) is not
                    134:         * zero; this is also invalid protocol behaviour.
                    135:         */
                    136:        if (eip.eip_ver & ETHERIP_VER_RSVD_MASK) {
                    137:                DPRINTF(("etherip_input(): received EtherIP invalid EtherIP "
                    138:                    "header (reserved field non-zero\n"));
                    139:                etheripstat.etherip_adrops++;
                    140:                m_freem(m);
                    141:                return;
                    142:        }
                    143:
                    144:        /* Finally, the pad value must be zero. */
                    145:        if (eip.eip_pad) {
                    146:                DPRINTF(("etherip_input(): received EtherIP invalid "
                    147:                    "pad value\n"));
                    148:                etheripstat.etherip_adrops++;
                    149:                m_freem(m);
                    150:                return;
                    151:        }
                    152:
                    153:        /* Make sure the ethernet header at least is in the first mbuf. */
                    154:        if (m->m_len < iphlen + sizeof(struct ether_header) +
                    155:            sizeof(struct etherip_header)) {
                    156:                if ((m = m_pullup(m, iphlen + sizeof(struct ether_header) +
                    157:                    sizeof(struct etherip_header))) == NULL) {
                    158:                        DPRINTF(("etherip_input(): m_pullup() failed\n"));
                    159:                        etheripstat.etherip_adrops++;
                    160:                        return;
                    161:                }
                    162:        }
                    163:
                    164:        /* Copy the addresses for use later. */
                    165:        bzero(&ssrc, sizeof(ssrc));
                    166:        bzero(&sdst, sizeof(sdst));
                    167:
                    168:        v = *mtod(m, u_int8_t *);
                    169:        switch (v >> 4) {
                    170: #ifdef INET
                    171:        case 4:
                    172:                ssrc.sa.sa_len = sdst.sa.sa_len = sizeof(struct sockaddr_in);
                    173:                ssrc.sa.sa_family = sdst.sa.sa_family = AF_INET;
                    174:                m_copydata(m, offsetof(struct ip, ip_src),
                    175:                    sizeof(struct in_addr),
                    176:                    (caddr_t) &ssrc.sin.sin_addr);
                    177:                m_copydata(m, offsetof(struct ip, ip_dst),
                    178:                    sizeof(struct in_addr),
                    179:                    (caddr_t) &sdst.sin.sin_addr);
                    180:                break;
                    181: #endif /* INET */
                    182: #ifdef INET6
                    183:        case 6:
                    184:                ssrc.sa.sa_len = sdst.sa.sa_len = sizeof(struct sockaddr_in6);
                    185:                ssrc.sa.sa_family = sdst.sa.sa_family = AF_INET6;
                    186:                m_copydata(m, offsetof(struct ip6_hdr, ip6_src),
                    187:                    sizeof(struct in6_addr),
                    188:                    (caddr_t) &ssrc.sin6.sin6_addr);
                    189:                m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
                    190:                    sizeof(struct in6_addr),
                    191:                    (caddr_t) &sdst.sin6.sin6_addr);
                    192:                break;
                    193: #endif /* INET6 */
                    194:        default:
                    195:                DPRINTF(("etherip_input(): invalid protocol %d\n", v));
                    196:                m_freem(m);
                    197:                etheripstat.etherip_hdrops++;
                    198:                return /* EAFNOSUPPORT */;
                    199:        }
                    200:
                    201:        /* Chop off the `outer' IP and EtherIP headers and reschedule. */
                    202:        m_adj(m, iphlen + sizeof(struct etherip_header));
                    203:
                    204:        /* Statistics */
                    205:        etheripstat.etherip_ibytes += m->m_pkthdr.len;
                    206:
                    207:        /* Copy ethernet header */
                    208:        m_copydata(m, 0, sizeof(eh), (void *) &eh);
                    209:
                    210:        /* Reset the flags based on the inner packet */
                    211:        m->m_flags &= ~(M_BCAST|M_MCAST|M_AUTH|M_CONF|M_AUTH_AH);
                    212:        if (eh.ether_dhost[0] & 1) {
                    213:                if (bcmp((caddr_t) etherbroadcastaddr,
                    214:                    (caddr_t)eh.ether_dhost, sizeof(etherbroadcastaddr)) == 0)
                    215:                        m->m_flags |= M_BCAST;
                    216:                else
                    217:                        m->m_flags |= M_MCAST;
                    218:        }
                    219:
                    220: #if NGIF > 0
                    221:        /* Find appropriate gif(4) interface */
                    222:        LIST_FOREACH(sc, &gif_softc_list, gif_list) {
                    223:                if ((sc->gif_psrc == NULL) ||
                    224:                    (sc->gif_pdst == NULL) ||
                    225:                    !(sc->gif_if.if_flags & (IFF_UP|IFF_RUNNING)))
                    226:                        continue;
                    227:
                    228:                if (!bcmp(sc->gif_psrc, &sdst, sc->gif_psrc->sa_len) &&
                    229:                    !bcmp(sc->gif_pdst, &ssrc, sc->gif_pdst->sa_len) &&
                    230:                    sc->gif_if.if_bridge != NULL)
                    231:                        break;
                    232:        }
                    233:
                    234:        /* None found. */
                    235:        if (sc == NULL) {
                    236:                DPRINTF(("etherip_input(): no interface found\n"));
                    237:                etheripstat.etherip_noifdrops++;
                    238:                m_freem(m);
                    239:                return;
                    240:        }
                    241: #if NBPFILTER > 0
                    242:        if (sc->gif_if.if_bpf)
                    243:                bpf_mtap_af(sc->gif_if.if_bpf, AF_LINK, m, BPF_DIRECTION_IN);
                    244: #endif
                    245:
                    246:        /* Trim the beginning of the mbuf, to remove the ethernet header. */
                    247:        m_adj(m, sizeof(struct ether_header));
                    248:
                    249: #if NBRIDGE > 0
                    250:        /*
                    251:         * Tap the packet off here for a bridge. bridge_input() returns
                    252:         * NULL if it has consumed the packet.  In the case of gif's,
                    253:         * bridge_input() returns non-NULL when an error occurs.
                    254:         */
                    255:        m->m_pkthdr.rcvif = &sc->gif_if;
                    256:        if (m->m_flags & (M_BCAST|M_MCAST))
                    257:                sc->gif_if.if_imcasts++;
                    258:
                    259:        s = splnet();
                    260:        m = bridge_input(&sc->gif_if, &eh, m);
                    261:        splx(s);
                    262:        if (m == NULL)
                    263:                return;
                    264: #endif /* NBRIDGE */
                    265: #endif /* NGIF */
                    266:
                    267:        etheripstat.etherip_noifdrops++;
                    268:        m_freem(m);
                    269:        return;
                    270: }
                    271:
                    272: int
                    273: etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
                    274:               int protoff)
                    275: {
                    276: #ifdef INET
                    277:        struct ip *ipo;
                    278: #endif /* INET */
                    279:
                    280: #ifdef INET6
                    281:        struct ip6_hdr *ip6;
                    282: #endif /* INET6 */
                    283:
                    284:        struct etherip_header eip;
                    285:        struct mbuf *m0;
                    286:        ushort hlen;
                    287:
                    288:        /* Some address family sanity checks. */
                    289:        if ((tdb->tdb_src.sa.sa_family != 0) &&
                    290:            (tdb->tdb_src.sa.sa_family != AF_INET) &&
                    291:            (tdb->tdb_src.sa.sa_family != AF_INET6)) {
                    292:                DPRINTF(("etherip_output(): IP in protocol-family <%d> "
                    293:                    "attempted, aborting", tdb->tdb_src.sa.sa_family));
                    294:                etheripstat.etherip_adrops++;
                    295:                m_freem(m);
                    296:                return EINVAL;
                    297:        }
                    298:
                    299:        if ((tdb->tdb_dst.sa.sa_family != AF_INET) &&
                    300:            (tdb->tdb_dst.sa.sa_family != AF_INET6)) {
                    301:                DPRINTF(("etherip_output(): IP in protocol-family <%d> "
                    302:                    "attempted, aborting", tdb->tdb_dst.sa.sa_family));
                    303:                etheripstat.etherip_adrops++;
                    304:                m_freem(m);
                    305:                return EINVAL;
                    306:        }
                    307:
                    308:        if (tdb->tdb_dst.sa.sa_family != tdb->tdb_src.sa.sa_family) {
                    309:                DPRINTF(("etherip_output(): mismatch in tunnel source and "
                    310:                    "destination address protocol families (%d/%d), aborting",
                    311:                    tdb->tdb_src.sa.sa_family, tdb->tdb_dst.sa.sa_family));
                    312:                etheripstat.etherip_adrops++;
                    313:                m_freem(m);
                    314:                return EINVAL;
                    315:        }
                    316:
                    317:        switch (tdb->tdb_dst.sa.sa_family) {
                    318: #ifdef INET
                    319:        case AF_INET:
                    320:                hlen = sizeof(struct ip);
                    321:                break;
                    322: #endif /* INET */
                    323: #ifdef INET6
                    324:        case AF_INET6:
                    325:                hlen = sizeof(struct ip6_hdr);
                    326:                break;
                    327: #endif /* INET6 */
                    328:        default:
                    329:                DPRINTF(("etherip_output(): unsupported tunnel protocol "
                    330:                    "family <%d>, aborting", tdb->tdb_dst.sa.sa_family));
                    331:                etheripstat.etherip_adrops++;
                    332:                m_freem(m);
                    333:                return EINVAL;
                    334:        }
                    335:
                    336:        /* Don't forget the EtherIP header. */
                    337:        hlen += sizeof(struct etherip_header);
                    338:
                    339:        if (!(m->m_flags & M_PKTHDR)) {
                    340:                DPRINTF(("etherip_output(): mbuf is not a header\n"));
                    341:                m_freem(m);
                    342:                return (ENOBUFS);
                    343:        }
                    344:
                    345:        MGETHDR(m0, M_DONTWAIT, MT_DATA);
                    346:        if (m0 == NULL) {
                    347:                DPRINTF(("etherip_output(): M_GETHDR failed\n"));
                    348:                etheripstat.etherip_adrops++;
                    349:                m_freem(m);
                    350:                return ENOBUFS;
                    351:        }
                    352:        M_MOVE_PKTHDR(m0, m);
                    353:        m0->m_next = m;
                    354:        m0->m_len = hlen;
                    355:        m0->m_pkthdr.len += hlen;
                    356:        m = m0;
                    357:
                    358:        /* Statistics */
                    359:        etheripstat.etherip_opackets++;
                    360:        etheripstat.etherip_obytes += m->m_pkthdr.len - hlen;
                    361:
                    362:        switch (tdb->tdb_dst.sa.sa_family) {
                    363: #ifdef INET
                    364:        case AF_INET:
                    365:                ipo = mtod(m, struct ip *);
                    366:
                    367:                ipo->ip_v = IPVERSION;
                    368:                ipo->ip_hl = 5;
                    369:                ipo->ip_len = htons(m->m_pkthdr.len);
                    370:                ipo->ip_ttl = ip_defttl;
                    371:                ipo->ip_p = IPPROTO_ETHERIP;
                    372:                ipo->ip_tos = 0;
                    373:                ipo->ip_off = 0;
                    374:                ipo->ip_sum = 0;
                    375:                ipo->ip_id = htons(ip_randomid());
                    376:
                    377:                /*
                    378:                 * We should be keeping tunnel soft-state and send back
                    379:                 * ICMPs as needed.
                    380:                 */
                    381:
                    382:                ipo->ip_src = tdb->tdb_src.sin.sin_addr;
                    383:                ipo->ip_dst = tdb->tdb_dst.sin.sin_addr;
                    384:                break;
                    385: #endif /* INET */
                    386: #ifdef INET6
                    387:        case AF_INET6:
                    388:                ip6 = mtod(m, struct ip6_hdr *);
                    389:
                    390:                ip6->ip6_flow = 0;
                    391:                ip6->ip6_nxt = IPPROTO_ETHERIP;
                    392:                ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
                    393:                ip6->ip6_vfc |= IPV6_VERSION;
                    394:                ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
                    395:                ip6->ip6_hlim = ip_defttl;
                    396:                ip6->ip6_dst = tdb->tdb_dst.sin6.sin6_addr;
                    397:                ip6->ip6_src = tdb->tdb_src.sin6.sin6_addr;
                    398:                break;
                    399: #endif /* INET6 */
                    400:        }
                    401:
                    402:        /* Set the version number */
                    403:        eip.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
                    404:        eip.eip_pad = 0;
                    405:        m_copyback(m, hlen - sizeof(struct etherip_header),
                    406:            sizeof(struct etherip_header), &eip);
                    407:
                    408:        *mp = m;
                    409:
                    410:        return 0;
                    411: }
                    412:
                    413: int
                    414: etherip_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
                    415:        int *name;
                    416:        u_int namelen;
                    417:        void *oldp, *newp;
                    418:        size_t *oldlenp, newlen;
                    419: {
                    420:        /* All sysctl names at this level are terminal. */
                    421:        if (namelen != 1)
                    422:                return (ENOTDIR);
                    423:
                    424:        switch (name[0]) {
                    425:        case ETHERIPCTL_ALLOW:
                    426:                return (sysctl_int(oldp, oldlenp, newp, newlen,
                    427:                    &etherip_allow));
                    428:        default:
                    429:                return (ENOPROTOOPT);
                    430:        }
                    431:        /* NOTREACHED */
                    432: }

CVSweb