[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     ! 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