Annotation of embedaddon/ipsec-tools/src/racoon/sockmisc.c, revision 1.1

1.1     ! misho       1: /*     $NetBSD: sockmisc.c,v 1.19 2011/03/14 17:18:13 tteras Exp $     */
        !             2: 
        !             3: /* Id: sockmisc.c,v 1.24 2006/05/07 21:32:59 manubsd Exp */
        !             4: 
        !             5: /*
        !             6:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
        !             7:  * All rights reserved.
        !             8:  * 
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. Neither the name of the project nor the names of its contributors
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  * 
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            31:  * SUCH DAMAGE.
        !            32:  */
        !            33: 
        !            34: #include "config.h"
        !            35: 
        !            36: #include <sys/types.h>
        !            37: #include <sys/param.h>
        !            38: #include <sys/socket.h>
        !            39: #include <sys/uio.h>
        !            40: 
        !            41: #include <netinet/in.h>
        !            42: #include PATH_IPSEC_H
        !            43: 
        !            44: #if defined(INET6) && !defined(INET6_ADVAPI) && \
        !            45:        defined(IP_RECVDSTADDR) && !defined(IPV6_RECVDSTADDR)
        !            46: #define IPV6_RECVDSTADDR IP_RECVDSTADDR
        !            47: #endif
        !            48: 
        !            49: #include <stdlib.h>
        !            50: #include <stdio.h>
        !            51: #include <string.h>
        !            52: #include <errno.h>
        !            53: #ifdef HAVE_UNISTD_H
        !            54: #include <unistd.h>
        !            55: #endif
        !            56: 
        !            57: #include "var.h"
        !            58: #include "misc.h"
        !            59: #include "vmbuf.h"
        !            60: #include "plog.h"
        !            61: #include "sockmisc.h"
        !            62: #include "debug.h"
        !            63: #include "gcmalloc.h"
        !            64: #include "debugrm.h"
        !            65: #include "libpfkey.h"
        !            66: #include "isakmp_var.h"
        !            67: 
        !            68: #ifdef NOUSE_PRIVSEP
        !            69: #define BIND bind
        !            70: #define SOCKET socket
        !            71: #define SETSOCKOPT setsockopt
        !            72: #else
        !            73: #include "admin.h"
        !            74: #include "privsep.h"
        !            75: #define BIND privsep_bind
        !            76: #define SOCKET privsep_socket
        !            77: #define SETSOCKOPT privsep_setsockopt
        !            78: #endif
        !            79: 
        !            80: const int niflags = 0;
        !            81: 
        !            82: /*
        !            83:  * compare two sockaddr with port, taking care wildcard.
        !            84:  * addr1 is a subject address, addr2 is in a database entry.
        !            85:  * OUT:        0: equal.
        !            86:  *     1: not equal.
        !            87:  */
        !            88: int
        !            89: cmpsaddr(addr1, addr2)
        !            90:        const struct sockaddr *addr1;
        !            91:        const struct sockaddr *addr2;
        !            92: {
        !            93:        caddr_t sa1, sa2;
        !            94:        u_short port1 = IPSEC_PORT_ANY;
        !            95:        u_short port2 = IPSEC_PORT_ANY;
        !            96: 
        !            97:        if (addr1 == NULL && addr2 == NULL)
        !            98:                return CMPSADDR_MATCH;
        !            99: 
        !           100:        if (addr1 == NULL || addr2 == NULL)
        !           101:                return CMPSADDR_MISMATCH;
        !           102: 
        !           103:        if (addr1->sa_family != addr2->sa_family ||
        !           104:            sysdep_sa_len(addr1) != sysdep_sa_len(addr2))
        !           105:                return CMPSADDR_MISMATCH;
        !           106: 
        !           107:        switch (addr1->sa_family) {
        !           108:        case AF_UNSPEC:
        !           109:                break;
        !           110:        case AF_INET:
        !           111:                sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
        !           112:                sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
        !           113:                port1 = ((struct sockaddr_in *)addr1)->sin_port;
        !           114:                port2 = ((struct sockaddr_in *)addr2)->sin_port;
        !           115:                if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
        !           116:                        return CMPSADDR_MISMATCH;
        !           117:                break;
        !           118: #ifdef INET6
        !           119:        case AF_INET6:
        !           120:                sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
        !           121:                sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
        !           122:                port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
        !           123:                port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
        !           124:                if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
        !           125:                        return CMPSADDR_MISMATCH;
        !           126:                if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
        !           127:                    ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
        !           128:                        return CMPSADDR_MISMATCH;
        !           129:                break;
        !           130: #endif
        !           131:        default:
        !           132:                return CMPSADDR_MISMATCH;
        !           133:        }
        !           134: 
        !           135:        if (port1 == port2)
        !           136:                return CMPSADDR_MATCH;
        !           137: 
        !           138:        if (port1 == IPSEC_PORT_ANY ||
        !           139:            port2 == IPSEC_PORT_ANY)
        !           140:                return CMPSADDR_WILDPORT_MATCH;
        !           141: 
        !           142:        return CMPSADDR_WOP_MATCH;
        !           143: }
        !           144: 
        !           145: /* get local address against the destination. */
        !           146: struct sockaddr *
        !           147: getlocaladdr(remote)
        !           148:        struct sockaddr *remote;
        !           149: {
        !           150:        struct sockaddr *local;
        !           151:        u_int local_len = sizeof(struct sockaddr_storage);
        !           152:        int s;  /* for dummy connection */
        !           153: 
        !           154:        /* allocate buffer */
        !           155:        if ((local = racoon_calloc(1, local_len)) == NULL) {
        !           156:                plog(LLV_ERROR, LOCATION, NULL,
        !           157:                        "failed to get address buffer.\n");
        !           158:                goto err;
        !           159:        }
        !           160:        
        !           161:        /* get real interface received packet */
        !           162:        if ((s = SOCKET(remote->sa_family, SOCK_DGRAM, 0)) < 0) {
        !           163:                plog(LLV_ERROR, LOCATION, NULL,
        !           164:                        "socket (%s)\n", strerror(errno));
        !           165:                goto err;
        !           166:        }
        !           167: 
        !           168:        setsockopt_bypass(s, remote->sa_family);
        !           169:        
        !           170:        if (connect(s, remote, sysdep_sa_len(remote)) < 0) {
        !           171:                plog(LLV_ERROR, LOCATION, NULL,
        !           172:                        "connect (%s)\n", strerror(errno));
        !           173:                close(s);
        !           174:                goto err;
        !           175:        }
        !           176: 
        !           177:        if (getsockname(s, local, &local_len) < 0) {
        !           178:                plog(LLV_ERROR, LOCATION, NULL,
        !           179:                        "getsockname (%s)\n", strerror(errno));
        !           180:                close(s);
        !           181:                return NULL;
        !           182:        }
        !           183: 
        !           184:        close(s);
        !           185:        return local;
        !           186: 
        !           187:     err:
        !           188:        if (local != NULL)
        !           189:                racoon_free(local);
        !           190:        return NULL;
        !           191: }
        !           192: 
        !           193: /*
        !           194:  * Receive packet, with src/dst information.  It is assumed that necessary
        !           195:  * setsockopt() have already performed on socket.
        !           196:  */
        !           197: int
        !           198: recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
        !           199:        int s;
        !           200:        void *buf;
        !           201:        size_t buflen;
        !           202:        int flags;
        !           203:        struct sockaddr *from;
        !           204:        socklen_t *fromlen;
        !           205:        struct sockaddr *to;
        !           206:        u_int *tolen;
        !           207: {
        !           208:        int otolen;
        !           209:        socklen_t slen;
        !           210:        int len;
        !           211:        union sockaddr_any sa;
        !           212:        struct msghdr m;
        !           213:        struct cmsghdr *cm;
        !           214:        struct iovec iov[2];
        !           215:        u_char cmsgbuf[256];
        !           216: #if defined(INET6) && defined(INET6_ADVAPI)
        !           217:        struct in6_pktinfo *pi;
        !           218: #endif /*INET6_ADVAPI*/
        !           219:        struct sockaddr_in *sin;
        !           220: #ifdef INET6
        !           221:        struct sockaddr_in6 *sin6;
        !           222: #endif
        !           223: 
        !           224:        slen = sizeof(sa);
        !           225:        if (getsockname(s, &sa.sa, &slen) < 0) {
        !           226:                plog(LLV_ERROR, LOCATION, NULL,
        !           227:                        "getsockname (%s)\n", strerror(errno));
        !           228:                return -1;
        !           229:        }
        !           230: 
        !           231:        m.msg_name = (caddr_t)from;
        !           232:        m.msg_namelen = *fromlen;
        !           233:        iov[0].iov_base = (caddr_t)buf;
        !           234:        iov[0].iov_len = buflen;
        !           235:        m.msg_iov = iov;
        !           236:        m.msg_iovlen = 1;
        !           237:        memset(cmsgbuf, 0, sizeof(cmsgbuf));
        !           238:        cm = (struct cmsghdr *)cmsgbuf;
        !           239:        m.msg_control = (caddr_t)cm;
        !           240:        m.msg_controllen = sizeof(cmsgbuf);
        !           241:        if ((len = recvmsg(s, &m, flags)) < 0) {
        !           242:                plog(LLV_ERROR, LOCATION, NULL,
        !           243:                        "recvmsg (%s)\n", strerror(errno));
        !           244:                return -1;
        !           245:        }
        !           246:        *fromlen = m.msg_namelen;
        !           247: 
        !           248:        otolen = *tolen;
        !           249:        *tolen = 0;
        !           250:        for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
        !           251:             m.msg_controllen != 0 && cm;
        !           252:             cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
        !           253: #if 0
        !           254:                plog(LLV_ERROR, LOCATION, NULL,
        !           255:                        "cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);)
        !           256: #endif
        !           257: #if defined(INET6) && defined(INET6_ADVAPI)
        !           258:                if (sa.sa.sa_family == AF_INET6
        !           259:                 && cm->cmsg_level == IPPROTO_IPV6
        !           260:                 && cm->cmsg_type == IPV6_PKTINFO
        !           261:                 && otolen >= sizeof(*sin6)) {
        !           262:                        pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
        !           263:                        *tolen = sizeof(*sin6);
        !           264:                        sin6 = (struct sockaddr_in6 *)to;
        !           265:                        memset(sin6, 0, sizeof(*sin6));
        !           266:                        sin6->sin6_family = AF_INET6;
        !           267: #ifndef __linux__
        !           268:                        sin6->sin6_len = sizeof(*sin6);
        !           269: #endif
        !           270:                        memcpy(&sin6->sin6_addr, &pi->ipi6_addr,
        !           271:                                sizeof(sin6->sin6_addr));
        !           272:                        /* XXX other cases, such as site-local? */
        !           273:                        if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
        !           274:                                sin6->sin6_scope_id = pi->ipi6_ifindex;
        !           275:                        else
        !           276:                                sin6->sin6_scope_id = 0;
        !           277:                        sin6->sin6_port = sa.sin6.sin6_port;
        !           278:                        otolen = -1;    /* "to" already set */
        !           279:                        continue;
        !           280:                }
        !           281: #endif
        !           282: #ifdef __linux__
        !           283:                if (sa.sa.sa_family == AF_INET
        !           284:                 && cm->cmsg_level == IPPROTO_IP
        !           285:                 && cm->cmsg_type == IP_PKTINFO
        !           286:                 && otolen >= sizeof(sin)) {
        !           287:                        struct in_pktinfo *pi = (struct in_pktinfo *)(CMSG_DATA(cm));
        !           288:                        *tolen = sizeof(*sin);
        !           289:                        sin = (struct sockaddr_in *)to;
        !           290:                        memset(sin, 0, sizeof(*sin));
        !           291:                        sin->sin_family = AF_INET;
        !           292:                        memcpy(&sin->sin_addr, &pi->ipi_addr,
        !           293:                                sizeof(sin->sin_addr));
        !           294:                        sin->sin_port = sa.sin.sin_port;
        !           295:                        otolen = -1;    /* "to" already set */
        !           296:                        continue;
        !           297:                }
        !           298: #endif
        !           299: #if defined(INET6) && defined(IPV6_RECVDSTADDR)
        !           300:                if (sa.sa.sa_family == AF_INET6
        !           301:                      && cm->cmsg_level == IPPROTO_IPV6
        !           302:                      && cm->cmsg_type == IPV6_RECVDSTADDR
        !           303:                      && otolen >= sizeof(*sin6)) {
        !           304:                        *tolen = sizeof(*sin6);
        !           305:                        sin6 = (struct sockaddr_in6 *)to;
        !           306:                        memset(sin6, 0, sizeof(*sin6));
        !           307:                        sin6->sin6_family = AF_INET6;
        !           308:                        sin6->sin6_len = sizeof(*sin6);
        !           309:                        memcpy(&sin6->sin6_addr, CMSG_DATA(cm),
        !           310:                                sizeof(sin6->sin6_addr));
        !           311:                        sin6->sin6_port = sa.sin6.sin6_port;
        !           312:                        otolen = -1;    /* "to" already set */
        !           313:                        continue;
        !           314:                }
        !           315: #endif
        !           316: #ifndef __linux__
        !           317:                if (sa.sa.sa_family == AF_INET
        !           318:                 && cm->cmsg_level == IPPROTO_IP
        !           319:                 && cm->cmsg_type == IP_RECVDSTADDR
        !           320:                 && otolen >= sizeof(*sin)) {
        !           321:                        *tolen = sizeof(*sin);
        !           322:                        sin = (struct sockaddr_in *)to;
        !           323:                        memset(sin, 0, sizeof(*sin));
        !           324:                        sin->sin_family = AF_INET;
        !           325:                        sin->sin_len = sizeof(*sin);
        !           326:                        memcpy(&sin->sin_addr, CMSG_DATA(cm),
        !           327:                                sizeof(sin->sin_addr));
        !           328:                        sin->sin_port = sa.sin.sin_port;
        !           329:                        otolen = -1;    /* "to" already set */
        !           330:                        continue;
        !           331:                }
        !           332: #endif
        !           333:        }
        !           334: 
        !           335:        return len;
        !           336: }
        !           337: 
        !           338: /* send packet, with fixing src/dst address pair. */
        !           339: int
        !           340: sendfromto(s, buf, buflen, src, dst, cnt)
        !           341:        int s, cnt;
        !           342:        const void *buf;
        !           343:        size_t buflen;
        !           344:        struct sockaddr *src;
        !           345:        struct sockaddr *dst;
        !           346: {
        !           347:        struct sockaddr_storage ss;
        !           348:        socklen_t slen;
        !           349:        int len = 0;
        !           350:        int i;
        !           351: 
        !           352:        if (src->sa_family != dst->sa_family) {
        !           353:                plog(LLV_ERROR, LOCATION, NULL,
        !           354:                        "address family mismatch\n");
        !           355:                return -1;
        !           356:        }
        !           357: 
        !           358:        slen = sizeof(ss);
        !           359:        if (getsockname(s, (struct sockaddr *)&ss, &slen) < 0) {
        !           360:                plog(LLV_ERROR, LOCATION, NULL,
        !           361:                        "getsockname (%s)\n", strerror(errno));
        !           362:                return -1;
        !           363:        }
        !           364: 
        !           365:        plog(LLV_DEBUG, LOCATION, NULL,
        !           366:                "sockname %s\n", saddr2str((struct sockaddr *)&ss));
        !           367:        plog(LLV_DEBUG, LOCATION, NULL,
        !           368:                "send packet from %s\n", saddr2str(src));
        !           369:        plog(LLV_DEBUG, LOCATION, NULL,
        !           370:                "send packet to %s\n", saddr2str(dst));
        !           371: 
        !           372:        if (src->sa_family != ss.ss_family) {
        !           373:                plog(LLV_ERROR, LOCATION, NULL,
        !           374:                        "address family mismatch\n");
        !           375:                return -1;
        !           376:        }
        !           377: 
        !           378:        switch (src->sa_family) {
        !           379: #if defined(INET6) && defined(INET6_ADVAPI)
        !           380: // XXX: This block wasn't compiled on Linux - does it work?
        !           381:        case AF_INET6:
        !           382:            {
        !           383:                struct msghdr m;
        !           384:                struct cmsghdr *cm;
        !           385:                struct iovec iov[2];
        !           386:                u_char cmsgbuf[256];
        !           387:                struct in6_pktinfo *pi;
        !           388:                int ifindex;
        !           389:                struct sockaddr_in6 src6, dst6;
        !           390: 
        !           391:                memcpy(&src6, src, sizeof(src6));
        !           392:                memcpy(&dst6, dst, sizeof(dst6));
        !           393: 
        !           394:                /* XXX take care of other cases, such as site-local */
        !           395:                ifindex = 0;
        !           396:                if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr)
        !           397:                 || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) {
        !           398:                        ifindex = src6.sin6_scope_id;   /*???*/
        !           399:                }
        !           400: 
        !           401:                /* XXX some sanity check on dst6.sin6_scope_id */
        !           402: 
        !           403:                /* flowinfo for IKE?  mmm, maybe useful but for now make it 0 */
        !           404:                src6.sin6_flowinfo = dst6.sin6_flowinfo = 0;
        !           405: 
        !           406:                memset(&m, 0, sizeof(m));
        !           407:                m.msg_name = (caddr_t)&dst6;
        !           408:                m.msg_namelen = sizeof(dst6);
        !           409:                iov[0].iov_base = (char *)buf;
        !           410:                iov[0].iov_len = buflen;
        !           411:                m.msg_iov = iov;
        !           412:                m.msg_iovlen = 1;
        !           413: 
        !           414:                memset(cmsgbuf, 0, sizeof(cmsgbuf));
        !           415:                cm = (struct cmsghdr *)cmsgbuf;
        !           416:                m.msg_control = (caddr_t)cm;
        !           417:                m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
        !           418: 
        !           419:                cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
        !           420:                cm->cmsg_level = IPPROTO_IPV6;
        !           421:                cm->cmsg_type = IPV6_PKTINFO;
        !           422:                pi = (struct in6_pktinfo *)CMSG_DATA(cm);
        !           423:                memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr));
        !           424:                pi->ipi6_ifindex = ifindex;
        !           425: 
        !           426:                plog(LLV_DEBUG, LOCATION, NULL,
        !           427:                        "src6 %s %d\n",
        !           428:                        saddr2str((struct sockaddr *)&src6),
        !           429:                        src6.sin6_scope_id);
        !           430:                plog(LLV_DEBUG, LOCATION, NULL,
        !           431:                        "dst6 %s %d\n",
        !           432:                        saddr2str((struct sockaddr *)&dst6),
        !           433:                        dst6.sin6_scope_id);
        !           434: 
        !           435:                for (i = 0; i < cnt; i++) {
        !           436:                        len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
        !           437:                        if (len < 0) {
        !           438:                                plog(LLV_ERROR, LOCATION, NULL,
        !           439:                                        "sendmsg (%s)\n", strerror(errno));
        !           440:                                return -1;
        !           441:                        }
        !           442:                        plog(LLV_DEBUG, LOCATION, NULL,
        !           443:                                "%d times of %d bytes message will be sent "
        !           444:                                "to %s\n",
        !           445:                                i + 1, len, saddr2str(dst));
        !           446:                }
        !           447:                plogdump(LLV_DEBUG, (char *)buf, buflen);
        !           448: 
        !           449:                return len;
        !           450:            }
        !           451: #endif
        !           452: #ifdef __linux__
        !           453:        case AF_INET:
        !           454:            {
        !           455:                struct msghdr m;
        !           456:                struct cmsghdr *cm;
        !           457:                struct iovec iov[2];
        !           458:                u_char cmsgbuf[256];
        !           459:                struct in_pktinfo *pi;
        !           460:                int ifindex = 0;
        !           461:                struct sockaddr_in src6, dst6;
        !           462: 
        !           463:                memcpy(&src6, src, sizeof(src6));
        !           464:                memcpy(&dst6, dst, sizeof(dst6));
        !           465: 
        !           466:                memset(&m, 0, sizeof(m));
        !           467:                m.msg_name = (caddr_t)&dst6;
        !           468:                m.msg_namelen = sizeof(dst6);
        !           469:                iov[0].iov_base = (char *)buf;
        !           470:                iov[0].iov_len = buflen;
        !           471:                m.msg_iov = iov;
        !           472:                m.msg_iovlen = 1;
        !           473: 
        !           474:                memset(cmsgbuf, 0, sizeof(cmsgbuf));
        !           475:                cm = (struct cmsghdr *)cmsgbuf;
        !           476:                m.msg_control = (caddr_t)cm;
        !           477:                m.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
        !           478: 
        !           479:                cm->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
        !           480:                cm->cmsg_level = IPPROTO_IP;
        !           481:                cm->cmsg_type = IP_PKTINFO;
        !           482:                pi = (struct in_pktinfo *)CMSG_DATA(cm);
        !           483:                memcpy(&pi->ipi_spec_dst, &src6.sin_addr, sizeof(src6.sin_addr));
        !           484:                pi->ipi_ifindex = ifindex;
        !           485: 
        !           486:                plog(LLV_DEBUG, LOCATION, NULL,
        !           487:                        "src4 %s\n",
        !           488:                        saddr2str((struct sockaddr *)&src6));
        !           489:                plog(LLV_DEBUG, LOCATION, NULL,
        !           490:                        "dst4 %s\n",
        !           491:                        saddr2str((struct sockaddr *)&dst6));
        !           492: 
        !           493:                for (i = 0; i < cnt; i++) {
        !           494:                        len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
        !           495:                        if (len < 0) {
        !           496:                                plog(LLV_ERROR, LOCATION, NULL,
        !           497:                                        "sendmsg (%s)\n", strerror(errno));
        !           498:                                return -1;
        !           499:                        }
        !           500:                        plog(LLV_DEBUG, LOCATION, NULL,
        !           501:                                "%d times of %d bytes message will be sent "
        !           502:                                "to %s\n",
        !           503:                                i + 1, len, saddr2str(dst));
        !           504:                }
        !           505:                plogdump(LLV_DEBUG, (char *)buf, buflen);
        !           506: 
        !           507:                return len;
        !           508:            }
        !           509: #endif /* __linux__ */
        !           510:        default:
        !           511:            {
        !           512:                int needclose = 0;
        !           513:                int sendsock;
        !           514: 
        !           515:                if (ss.ss_family == src->sa_family && memcmp(&ss, src, sysdep_sa_len(src)) == 0) {
        !           516:                        sendsock = s;
        !           517:                        needclose = 0;
        !           518:                } else {
        !           519:                        int yes = 1;
        !           520:                        /*
        !           521:                         * Use newly opened socket for sending packets.
        !           522:                         * NOTE: this is unsafe, because if the peer is quick enough
        !           523:                         * the packet from the peer may be queued into sendsock.
        !           524:                         * Better approach is to prepare bind'ed udp sockets for
        !           525:                         * each of the interface addresses.
        !           526:                         */
        !           527:                        sendsock = SOCKET(src->sa_family, SOCK_DGRAM, 0);
        !           528:                        if (sendsock < 0) {
        !           529:                                plog(LLV_ERROR, LOCATION, NULL,
        !           530:                                        "socket (%s)\n", strerror(errno));
        !           531:                                return -1;
        !           532:                        }
        !           533:                        if (setsockopt(sendsock, SOL_SOCKET,
        !           534: #ifdef __linux__
        !           535:                                       SO_REUSEADDR,
        !           536: #else
        !           537:                                       SO_REUSEPORT,
        !           538: #endif
        !           539:                                       (void *)&yes, sizeof(yes)) < 0) {
        !           540:                                plog(LLV_ERROR, LOCATION, NULL,
        !           541:                                        "setsockopt SO_REUSEPORT (%s)\n", 
        !           542:                                        strerror(errno));
        !           543:                                close(sendsock);
        !           544:                                return -1;
        !           545:                        }
        !           546: #ifdef IPV6_USE_MIN_MTU
        !           547:                        if (src->sa_family == AF_INET6 &&
        !           548:                            setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
        !           549:                            (void *)&yes, sizeof(yes)) < 0) {
        !           550:                                plog(LLV_ERROR, LOCATION, NULL,
        !           551:                                        "setsockopt IPV6_USE_MIN_MTU (%s)\n", 
        !           552:                                        strerror(errno));
        !           553:                                close(sendsock);
        !           554:                                return -1;
        !           555:                        }
        !           556: #endif
        !           557:                        if (setsockopt_bypass(sendsock, src->sa_family) < 0) {
        !           558:                                close(sendsock);
        !           559:                                return -1;
        !           560:                        }
        !           561: 
        !           562:                        if (BIND(sendsock, (struct sockaddr *)src,
        !           563:                                 sysdep_sa_len(src)) < 0) {
        !           564:                                plog(LLV_ERROR, LOCATION, NULL,
        !           565:                                        "bind 1 (%s)\n", strerror(errno));
        !           566:                                close(sendsock);
        !           567:                                return -1;
        !           568:                        }
        !           569:                        needclose = 1;
        !           570:                }
        !           571: 
        !           572:                for (i = 0; i < cnt; i++) {
        !           573:                        len = sendto(sendsock, buf, buflen, 0, dst, sysdep_sa_len(dst));
        !           574:                        if (len < 0) {
        !           575:                                plog(LLV_ERROR, LOCATION, NULL,
        !           576:                                        "sendto (%s)\n", strerror(errno));
        !           577:                                if (needclose)
        !           578:                                        close(sendsock);
        !           579:                                return len;
        !           580:                        }
        !           581:                        plog(LLV_DEBUG, LOCATION, NULL,
        !           582:                                "%d times of %d bytes message will be sent "
        !           583:                                "to %s\n",
        !           584:                                i + 1, len, saddr2str(dst));
        !           585:                }
        !           586:                plogdump(LLV_DEBUG, (char *)buf, buflen);
        !           587: 
        !           588:                if (needclose)
        !           589:                        close(sendsock);
        !           590: 
        !           591:                return len;
        !           592:            }
        !           593:        }
        !           594: }
        !           595: 
        !           596: int
        !           597: setsockopt_bypass(so, family)
        !           598:        int so, family;
        !           599: {
        !           600:        int level;
        !           601:        char *buf;
        !           602:        char *policy;
        !           603: 
        !           604:        switch (family) {
        !           605:        case AF_INET:
        !           606:                level = IPPROTO_IP;
        !           607:                break;
        !           608: #ifdef INET6
        !           609:        case AF_INET6:
        !           610:                level = IPPROTO_IPV6;
        !           611:                break;
        !           612: #endif
        !           613:        default:
        !           614:                plog(LLV_ERROR, LOCATION, NULL,
        !           615:                        "unsupported address family %d\n", family);
        !           616:                return -1;
        !           617:        }
        !           618: 
        !           619:        policy = "in bypass";
        !           620:        buf = ipsec_set_policy(policy, strlen(policy));
        !           621:        if (buf == NULL) {
        !           622:                plog(LLV_ERROR, LOCATION, NULL,
        !           623:                        "ipsec_set_policy (%s)\n",
        !           624:                        ipsec_strerror());
        !           625:                return -1;
        !           626:        }
        !           627:        if (SETSOCKOPT(so, level,
        !           628:                       (level == IPPROTO_IP ?
        !           629:                                 IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
        !           630:                       buf, ipsec_get_policylen(buf)) < 0) {
        !           631:                plog(LLV_ERROR, LOCATION, NULL,
        !           632:                        "setsockopt IP_IPSEC_POLICY (%s)\n",
        !           633:                        strerror(errno));
        !           634:                return -1;
        !           635:        }
        !           636:        racoon_free(buf);
        !           637: 
        !           638:        policy = "out bypass";
        !           639:        buf = ipsec_set_policy(policy, strlen(policy));
        !           640:        if (buf == NULL) {
        !           641:                plog(LLV_ERROR, LOCATION, NULL,
        !           642:                        "ipsec_set_policy (%s)\n",
        !           643:                        ipsec_strerror());
        !           644:                return -1;
        !           645:        }
        !           646:        if (SETSOCKOPT(so, level,
        !           647:                       (level == IPPROTO_IP ?
        !           648:                                 IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
        !           649:                       buf, ipsec_get_policylen(buf)) < 0) {
        !           650:                plog(LLV_ERROR, LOCATION, NULL,
        !           651:                        "setsockopt IP_IPSEC_POLICY (%s)\n",
        !           652:                        strerror(errno));
        !           653:                return -1;
        !           654:        }
        !           655:        racoon_free(buf);
        !           656: 
        !           657:        return 0;
        !           658: }
        !           659: 
        !           660: struct sockaddr *
        !           661: newsaddr(len)
        !           662:        int len;
        !           663: {
        !           664:        struct sockaddr *new;
        !           665: 
        !           666:        if ((new = racoon_calloc(1, len)) == NULL) {
        !           667:                plog(LLV_ERROR, LOCATION, NULL,
        !           668:                        "%s\n", strerror(errno)); 
        !           669:                goto out;
        !           670:        }
        !           671: 
        !           672: #ifdef __linux__
        !           673:        if (len == sizeof (struct sockaddr_in6))
        !           674:                new->sa_family = AF_INET6;
        !           675:        else
        !           676:                new->sa_family = AF_INET;
        !           677: #else
        !           678:        /* initial */
        !           679:        new->sa_len = len;
        !           680: #endif
        !           681: out:
        !           682:        return new;
        !           683: }
        !           684: 
        !           685: struct sockaddr *
        !           686: dupsaddr(src)
        !           687:        struct sockaddr *src;
        !           688: {
        !           689:        struct sockaddr *dst;
        !           690: 
        !           691:        dst = racoon_calloc(1, sysdep_sa_len(src));
        !           692:        if (dst == NULL) {
        !           693:                plog(LLV_ERROR, LOCATION, NULL,
        !           694:                        "%s\n", strerror(errno)); 
        !           695:                return NULL;
        !           696:        }
        !           697: 
        !           698:        memcpy(dst, src, sysdep_sa_len(src));
        !           699: 
        !           700:        return dst;
        !           701: }
        !           702: 
        !           703: char *
        !           704: saddr2str(saddr)
        !           705:        const struct sockaddr *saddr;
        !           706: {
        !           707:        static char buf[NI_MAXHOST + NI_MAXSERV + 10];
        !           708:        char addr[NI_MAXHOST], port[NI_MAXSERV];
        !           709: 
        !           710:        if (saddr == NULL)
        !           711:                return NULL;
        !           712: 
        !           713:        if (saddr->sa_family == AF_UNSPEC)
        !           714:                snprintf (buf, sizeof(buf), "%s", "anonymous");
        !           715:        else {
        !           716:                GETNAMEINFO(saddr, addr, port);
        !           717:                snprintf(buf, sizeof(buf), "%s[%s]", addr, port);
        !           718:        }
        !           719: 
        !           720:        return buf;
        !           721: }
        !           722: 
        !           723: char *
        !           724: saddrwop2str(saddr)
        !           725:        const struct sockaddr *saddr;
        !           726: {
        !           727:        static char buf[NI_MAXHOST + NI_MAXSERV + 10];
        !           728:        char addr[NI_MAXHOST];
        !           729: 
        !           730:        if (saddr == NULL)
        !           731:                return NULL;
        !           732: 
        !           733:        GETNAMEINFO_NULL(saddr, addr);
        !           734:        snprintf(buf, sizeof(buf), "%s", addr);
        !           735: 
        !           736:        return buf;
        !           737: }
        !           738: 
        !           739: char *
        !           740: naddrwop2str(const struct netaddr *naddr)
        !           741: {
        !           742:        static char buf[NI_MAXHOST + 10];
        !           743:        static const struct sockaddr sa_any;    /* this is initialized to all zeros */
        !           744:        
        !           745:        if (naddr == NULL)
        !           746:                return NULL;
        !           747: 
        !           748:        if (memcmp(&naddr->sa, &sa_any, sizeof(sa_any)) == 0)
        !           749:                snprintf(buf, sizeof(buf), "%s", "any");
        !           750:        else {
        !           751:                snprintf(buf, sizeof(buf), "%s", saddrwop2str(&naddr->sa.sa));
        !           752:                snprintf(&buf[strlen(buf)], sizeof(buf) - strlen(buf), "/%ld", naddr->prefix);
        !           753:        }
        !           754:        return buf;
        !           755: }
        !           756: 
        !           757: char *
        !           758: naddrwop2str_fromto(const char *format, const struct netaddr *saddr,
        !           759:                    const struct netaddr *daddr)
        !           760: {
        !           761:        static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100];
        !           762:        char *src, *dst;
        !           763: 
        !           764:        src = racoon_strdup(naddrwop2str(saddr));
        !           765:        dst = racoon_strdup(naddrwop2str(daddr));
        !           766:        STRDUP_FATAL(src);
        !           767:        STRDUP_FATAL(dst);
        !           768:        /* WARNING: Be careful about the format string! Don't 
        !           769:           ever pass in something that a user can modify!!! */
        !           770:        snprintf (buf, sizeof(buf), format, src, dst);
        !           771:        racoon_free (src);
        !           772:        racoon_free (dst);
        !           773: 
        !           774:        return buf;
        !           775: }
        !           776: 
        !           777: char *
        !           778: saddr2str_fromto(format, saddr, daddr)
        !           779:        const char *format;
        !           780:        const struct sockaddr *saddr;
        !           781:        const struct sockaddr *daddr;
        !           782: {
        !           783:        static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100];
        !           784:        char *src, *dst;
        !           785: 
        !           786:        src = racoon_strdup(saddr2str(saddr));
        !           787:        dst = racoon_strdup(saddr2str(daddr));
        !           788:        STRDUP_FATAL(src);
        !           789:        STRDUP_FATAL(dst);
        !           790:        /* WARNING: Be careful about the format string! Don't 
        !           791:           ever pass in something that a user can modify!!! */
        !           792:        snprintf (buf, sizeof(buf), format, src, dst);
        !           793:        racoon_free (src);
        !           794:        racoon_free (dst);
        !           795: 
        !           796:        return buf;
        !           797: }
        !           798: 
        !           799: struct sockaddr *
        !           800: str2saddr(host, port)
        !           801:        char *host;
        !           802:        char *port;
        !           803: {
        !           804:        struct addrinfo hints, *res;
        !           805:        struct sockaddr *saddr;
        !           806:        int error;
        !           807: 
        !           808:        memset(&hints, 0, sizeof(hints));
        !           809:        hints.ai_family = PF_UNSPEC;
        !           810:        hints.ai_socktype = SOCK_DGRAM;
        !           811:        hints.ai_flags = AI_NUMERICHOST;
        !           812:        error = getaddrinfo(host, port, &hints, &res);
        !           813:        if (error != 0) {
        !           814:                plog(LLV_ERROR, LOCATION, NULL,
        !           815:                        "getaddrinfo(%s%s%s): %s\n",
        !           816:                        host, port ? "," : "", port ? port : "",
        !           817:                        gai_strerror(error));
        !           818:                return NULL;
        !           819:        }
        !           820:        if (res->ai_next != NULL) {
        !           821:                plog(LLV_WARNING, LOCATION, NULL,
        !           822:                        "getaddrinfo(%s%s%s): "
        !           823:                        "resolved to multiple address, "
        !           824:                        "taking the first one\n",
        !           825:                        host, port ? "," : "", port ? port : "");
        !           826:        }
        !           827:        saddr = racoon_malloc(res->ai_addrlen);
        !           828:        if (saddr == NULL) {
        !           829:                plog(LLV_ERROR, LOCATION, NULL,
        !           830:                        "failed to allocate buffer.\n");
        !           831:                freeaddrinfo(res);
        !           832:                return NULL;
        !           833:        }
        !           834:        memcpy(saddr, res->ai_addr, res->ai_addrlen);
        !           835:        freeaddrinfo(res);
        !           836: 
        !           837:        return saddr;
        !           838: }
        !           839: 
        !           840: void
        !           841: mask_sockaddr(a, b, l)
        !           842:        struct sockaddr *a;
        !           843:        const struct sockaddr *b;
        !           844:        size_t l;
        !           845: {
        !           846:        size_t i;
        !           847:        u_int8_t *p, alen;
        !           848: 
        !           849:        switch (b->sa_family) {
        !           850:        case AF_INET:
        !           851:                alen = sizeof(struct in_addr);
        !           852:                p = (u_int8_t *)&((struct sockaddr_in *)a)->sin_addr;
        !           853:                break;
        !           854: #ifdef INET6
        !           855:        case AF_INET6:
        !           856:                alen = sizeof(struct in6_addr);
        !           857:                p = (u_int8_t *)&((struct sockaddr_in6 *)a)->sin6_addr;
        !           858:                break;
        !           859: #endif
        !           860:        default:
        !           861:                plog(LLV_ERROR, LOCATION, NULL,
        !           862:                        "invalid family: %d\n", b->sa_family);
        !           863:                exit(1);
        !           864:        }
        !           865: 
        !           866:        if ((alen << 3) < l) {
        !           867:                plog(LLV_ERROR, LOCATION, NULL,
        !           868:                        "unexpected inconsistency: %d %zu\n", b->sa_family, l);
        !           869:                exit(1);
        !           870:        }
        !           871: 
        !           872:        memcpy(a, b, sysdep_sa_len(b));
        !           873:        p[l / 8] &= (0xff00 >> (l % 8)) & 0xff;
        !           874:        for (i = l / 8 + 1; i < alen; i++)
        !           875:                p[i] = 0x00;
        !           876: }
        !           877: 
        !           878: /* Compute a score describing how "accurate" a netaddr is for a given sockaddr.
        !           879:  * Examples:
        !           880:  *     Return values for address 10.20.30.40 [port 500] and given netaddresses...
        !           881:  *             10.10.0.0/16    => -1   ... doesn't match
        !           882:  *             0.0.0.0/0       => 0    ... matches, but only 0 bits.
        !           883:  *             10.20.0.0/16    => 16   ... 16 bits match
        !           884:  *             10.20.30.0/24   => 24   ... guess what ;-)
        !           885:  *             10.20.30.40/32  => 32   ... whole address match
        !           886:  *             10.20.30.40:500 => 33   ... both address and port match
        !           887:  *             10.20.30.40:501 => -1   ... port doesn't match and isn't 0 (=any)
        !           888:  */
        !           889: int
        !           890: naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr)
        !           891: {
        !           892:        static const struct netaddr naddr_any;  /* initialized to all-zeros */
        !           893:        struct sockaddr sa;
        !           894:        u_int16_t naddr_port, saddr_port;
        !           895:        int port_score;
        !           896: 
        !           897:        if (!naddr || !saddr) {
        !           898:                plog(LLV_ERROR, LOCATION, NULL,
        !           899:                     "Call with null args: naddr=%p, saddr=%p\n",
        !           900:                     naddr, saddr);
        !           901:                return -1;
        !           902:        }
        !           903: 
        !           904:        /* Wildcard address matches, but only 0 bits. */
        !           905:        if (memcmp(naddr, &naddr_any, sizeof(naddr_any)) == 0)
        !           906:                return 0;
        !           907: 
        !           908:        /* If families don't match we really can't do much... */
        !           909:        if (naddr->sa.sa.sa_family != saddr->sa_family)
        !           910:                return -1;
        !           911:        
        !           912:        /* If port check fail don't bother to check addresses. */
        !           913:        naddr_port = extract_port(&naddr->sa.sa);
        !           914:        saddr_port = extract_port(saddr);
        !           915:        if (naddr_port == 0 || saddr_port == 0) /* wildcard match */
        !           916:                port_score = 0;
        !           917:        else if (naddr_port == saddr_port)      /* exact match */
        !           918:                port_score = 1;
        !           919:        else                                    /* mismatch :-) */
        !           920:                return -1;
        !           921: 
        !           922:        /* Here it comes - compare network addresses. */
        !           923:        mask_sockaddr(&sa, saddr, naddr->prefix);
        !           924:        if (loglevel >= LLV_DEBUG) {    /* debug only */
        !           925:                char *a1, *a2, *a3;
        !           926:                a1 = racoon_strdup(naddrwop2str(naddr));
        !           927:                a2 = racoon_strdup(saddrwop2str(saddr));
        !           928:                a3 = racoon_strdup(saddrwop2str(&sa));
        !           929:                STRDUP_FATAL(a1);
        !           930:                STRDUP_FATAL(a2);
        !           931:                STRDUP_FATAL(a3);
        !           932:                plog(LLV_DEBUG, LOCATION, NULL,
        !           933:                     "naddr=%s, saddr=%s (masked=%s)\n",
        !           934:                     a1, a2, a3);
        !           935:                free(a1);
        !           936:                free(a2);
        !           937:                free(a3);
        !           938:        }
        !           939:        if (cmpsaddr(&sa, &naddr->sa.sa) <= CMPSADDR_WOP_MATCH)
        !           940:                return naddr->prefix + port_score;
        !           941: 
        !           942:        return -1;
        !           943: }
        !           944: 
        !           945: /* Some useful functions for sockaddr port manipulations. */
        !           946: u_int16_t
        !           947: extract_port (const struct sockaddr *addr)
        !           948: {
        !           949:   u_int16_t port = 0;
        !           950:   
        !           951:   if (!addr)
        !           952:     return port;
        !           953: 
        !           954:   switch (addr->sa_family) {
        !           955:     case AF_UNSPEC:
        !           956:       break;
        !           957:     case AF_INET:
        !           958:       port = ((struct sockaddr_in *)addr)->sin_port;
        !           959:       break;
        !           960:     case AF_INET6:
        !           961:       port = ((struct sockaddr_in6 *)addr)->sin6_port;
        !           962:       break;
        !           963:     default:
        !           964:       plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family);
        !           965:       break;
        !           966:   }
        !           967: 
        !           968:   return ntohs(port);
        !           969: }
        !           970: 
        !           971: u_int16_t *
        !           972: get_port_ptr (struct sockaddr *addr)
        !           973: {
        !           974:   u_int16_t *port_ptr;
        !           975: 
        !           976:   if (!addr)
        !           977:     return NULL;
        !           978: 
        !           979:   switch (addr->sa_family) {
        !           980:     case AF_INET:
        !           981:       port_ptr = &(((struct sockaddr_in *)addr)->sin_port);
        !           982:       break;
        !           983:     case AF_INET6:
        !           984:       port_ptr = &(((struct sockaddr_in6 *)addr)->sin6_port);
        !           985:       break;
        !           986:     default:
        !           987:       plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family);
        !           988:       return NULL;
        !           989:       break;
        !           990:   }
        !           991: 
        !           992:   return port_ptr;
        !           993: }
        !           994: 
        !           995: u_int16_t *
        !           996: set_port (struct sockaddr *addr, u_int16_t new_port)
        !           997: {
        !           998:   u_int16_t *port_ptr;
        !           999: 
        !          1000:   port_ptr = get_port_ptr (addr);
        !          1001: 
        !          1002:   if (port_ptr)
        !          1003:     *port_ptr = htons(new_port);
        !          1004: 
        !          1005:   return port_ptr;
        !          1006: }

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