source: rtems-libbsd/ipsec-tools/src/racoon/sockmisc.c @ b376ae1

55-freebsd-126-freebsd-12
Last change on this file since b376ae1 was b376ae1, checked in by Christian Mauderer <christian.mauderer@…>, on 05/03/18 at 12:15:11

ipsec-tools: Port libipsec, setkey and racoon.

Note that this replaces the libipsec from FreeBSD with the one provided
by ipsec-tools.

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