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

55-freebsd-126-freebsd-12
Last change on this file since ff36f5e was ff36f5e, checked in by Christian Mauderer <christian.mauderer@…>, on 05/30/18 at 12:27:35

Import ipsec-tools 0.8.2.

Import unchanged ipsec-tools sources in the release version 0.8.2. The
homepage of ipsec-tools is http://ipsec-tools.sourceforge.net/. The
sources can be obtained from there.

  • Property mode set to 100644
File size: 24.3 KB
Line 
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
80const 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 */
88int
89cmpsaddr(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. */
146struct sockaddr *
147getlocaladdr(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 */
197int
198recvfromto(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. */
339int
340sendfromto(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
596int
597setsockopt_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
660struct sockaddr *
661newsaddr(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
681out:
682        return new;
683}
684
685struct sockaddr *
686dupsaddr(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
703char *
704saddr2str(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
723char *
724saddrwop2str(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
739char *
740naddrwop2str(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
757char *
758naddrwop2str_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
777char *
778saddr2str_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
799struct sockaddr *
800str2saddr(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
840void
841mask_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 */
889int
890naddr_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. */
946u_int16_t
947extract_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
971u_int16_t *
972get_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
995u_int16_t *
996set_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}
Note: See TracBrowser for help on using the repository browser.