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>