1 /*
   2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  *
   5  * Copyright 2017 Joyent, Inc.
   6  */
   7 
   8 /* Portions of the following are... */
   9 /*
  10  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  11  * All rights reserved.
  12  *
  13  * Redistribution and use in source and binary forms, with or without
  14  * modification, are permitted provided that the following conditions
  15  * are met:
  16  * 1. Redistributions of source code must retain the above copyright
  17  *    notice, this list of conditions and the following disclaimer.
  18  * 2. Redistributions in binary form must reproduce the above copyright
  19  *    notice, this list of conditions and the following disclaimer in the
  20  *    documentation and/or other materials provided with the distribution.
  21  * 3. Neither the name of the project nor the names of its contributors
  22  *    may be used to endorse or promote products derived from this software
  23  *    without specific prior written permission.
  24  *
  25  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35  * SUCH DAMAGE.
  36  */
  37 
  38 /*
  39  * These functions provide an easy way to receive a packet with FULL address
  40  * information, and send one using precise addresses.
  41  */
  42 #ifdef lint
  43 /* We use X/Open style sockets */
  44 #define _XOPEN_SOURCE 600
  45 #endif
  46 
  47 #include <sys/types.h>
  48 #include <sys/socket.h>
  49 #include <sys/int_fmtio.h>
  50 #include <sys/debug.h>
  51 #include <net/if.h>
  52 #include <netinet/in.h>
  53 #include <arpa/inet.h>
  54 #include <stdlib.h>
  55 #include <stdio.h>
  56 #include <string.h>
  57 #include <errno.h>
  58 #include "defs.h"
  59 #include "fromto.h"
  60 #include "ike.h"
  61 
  62 /* BEGIN CSTYLED */
  63 /* cstyle doesn't deal with ## __VA_ARGS__ well */
  64 #define SOCKLOG(level, log, msg, sock, from, to, ...)   \
  65         NETLOG(level, log, msg, from, to,               \
  66         BUNYAN_T_INT32, "socket", (int32_t)(sock),      \
  67         ## __VA_ARGS__,                                 \
  68         BUNYAN_T_END)
  69 /* END CSTYLED */
  70 
  71 /*
  72  * Receive packet, with src/dst information.  It is assumed that necessary
  73  * setsockopt()s (e.g. IP_SEC_OPT(NEVER)) have already performed on socket.
  74  */
  75 ssize_t
  76 recvfromto(int s, uchar_t *buf, size_t buflen, int flags,
  77     struct sockaddr_storage *from, socklen_t *fromlen,
  78     struct sockaddr_storage *to, socklen_t *tolen)
  79 {
  80         int otolen;
  81         ssize_t len;
  82         socklen_t sslen;
  83         struct sockaddr_storage ss;
  84         struct msghdr m;
  85         struct iovec iov[2] = { 0 };
  86         uint32_t cmsgbuf[64] = { 0 };
  87         struct cmsghdr *cm = (struct cmsghdr *)cmsgbuf;
  88         struct in6_pktinfo *pi;
  89         struct sockaddr_in6 *sin6;
  90         struct sockaddr_in *sin;
  91 
  92         sslen = sizeof (ss);
  93         if (getsockname(s, (struct sockaddr *)&ss, &sslen) < 0) {
  94                 STDERR(error, log, "getsockname() failed",
  95                     BUNYAN_T_INT32, "socket", (int32_t)s);
  96                 return (-1);
  97         }
  98 
  99         /* Quick hack -- snapshot the current socket's port, at least. */
 100         (void) memcpy(to, &ss, sslen < *tolen ? sslen : *tolen);
 101 
 102         m.msg_name = (caddr_t)from;
 103         m.msg_namelen = *fromlen;
 104         iov[0].iov_base = buf;
 105         iov[0].iov_len = buflen;
 106         m.msg_iov = iov;
 107         m.msg_iovlen = 1;
 108         m.msg_control = (caddr_t)cm;
 109         m.msg_controllen = sizeof (cmsgbuf);
 110         if ((len = recvmsg(s, &m, flags)) < 0) {
 111                 SOCKLOG(error, log, "recvmsg() failed", s, from, to,
 112                     BUNYAN_T_STRING, "err", strerror(errno),
 113                     BUNYAN_T_INT32, "errno", (int32_t)errno);
 114                 return (-1);
 115         }
 116         if (len > buflen) {
 117                 /*
 118                  * size_t and ssize_t should always be "long", but not in 32-
 119                  * bit apps for some bizarre reason.
 120                  */
 121                 SOCKLOG(warn, log, "Received oversized message", s, from, to,
 122                     BUNYAN_T_UINT32, "msglen", (uint32_t)len,
 123                     BUNYAN_T_UINT32, "buflen", (uint32_t)buflen);
 124 
 125                 errno = E2BIG;  /* Not returned from normal recvmsg()... */
 126                 return (-1);
 127         }
 128 
 129         if (len < sizeof (ike_header_t)) {
 130                 SOCKLOG(warn, log, "Received undersized message", s, from, to,
 131                     BUNYAN_T_UINT32, "msglen", (uint32_t)len);
 132                 return (-1);
 133         }
 134 
 135         *fromlen = m.msg_namelen;
 136 
 137         otolen = *tolen;
 138         *tolen = 0;
 139         for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
 140             m.msg_controllen != 0 && cm;
 141             cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
 142                 if (ss.ss_family == AF_INET6 &&
 143                     cm->cmsg_level == IPPROTO_IPV6 &&
 144                     cm->cmsg_type == IPV6_PKTINFO &&
 145                     otolen >= sizeof (*sin6)) {
 146                         /* LINTED */
 147                         pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
 148                         *tolen = sizeof (*sin6);
 149                         sin6 = (struct sockaddr_in6 *)to;
 150                         (void) memset(sin6, 0, sizeof (*sin6));
 151                         sin6->sin6_family = AF_INET6;
 152                         sin6->sin6_addr = pi->ipi6_addr;
 153                         /* XXX other cases, such as site-local? */
 154                         if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
 155                                 sin6->sin6_scope_id = pi->ipi6_ifindex;
 156                         else
 157                                 sin6->sin6_scope_id = 0;
 158                         sin6->sin6_port =
 159                             ((struct sockaddr_in6 *)&ss)->sin6_port;
 160                         otolen = -1;    /* "to" already set */
 161                         continue;
 162                 }
 163 
 164                 if (ss.ss_family == AF_INET && cm->cmsg_level == IPPROTO_IP &&
 165                     cm->cmsg_type == IP_RECVDSTADDR &&
 166                     otolen >= (int)sizeof (struct sockaddr_in)) {
 167                         *tolen = sizeof (*sin);
 168                         sin = (struct sockaddr_in *)to;
 169                         (void) memset(sin, 0, sizeof (*sin));
 170                         sin->sin_family = AF_INET;
 171                         (void) memcpy(&sin->sin_addr, CMSG_DATA(cm),
 172                             sizeof (sin->sin_addr));
 173                         sin->sin_port = ((struct sockaddr_in *)&ss)->sin_port;
 174                         otolen = -1;    /* "to" already set */
 175                         continue;
 176                 }
 177         }
 178 
 179         SOCKLOG(debug, log, "Received datagram", s, from, to,
 180             BUNYAN_T_UINT32, "msglen", (uint32_t)len);
 181 
 182         return (len);
 183 }
 184 
 185 /* send packet, with fixing src/dst address pair. */
 186 ssize_t
 187 sendfromto(int s, const uchar_t *buf, size_t buflen,
 188     struct sockaddr_storage *src, struct sockaddr_storage *dst)
 189 {
 190         uint32_t cmsgbuf[64] = { 0 };
 191         struct msghdr m = { 0 };
 192         struct iovec iov[2];
 193         struct cmsghdr *cm = (struct cmsghdr *)&cmsgbuf;
 194         struct in6_pktinfo *pi6;
 195         struct in_pktinfo *pi;
 196         ssize_t n;
 197 
 198         if (src->ss_family != AF_INET && src->ss_family != AF_INET6) {
 199                 (void) bunyan_error(log, "Unsupported address family",
 200                     BUNYAN_T_STRING, "func", __func__,
 201                     BUNYAN_T_STRING, "file", __FILE__,
 202                     BUNYAN_T_INT32, "line", __LINE__,
 203                     BUNYAN_T_UINT32, "af", (uint32_t)src->ss_family,
 204                     BUNYAN_T_END);
 205                 errno = EAFNOSUPPORT;
 206                 return (-1);
 207         }
 208 
 209         if (src->ss_family != dst->ss_family) {
 210                 SOCKLOG(error, log, "Address family mismatch",
 211                     s, src, dst,
 212                     BUNYAN_T_UINT32, "srcaf", (uint32_t)src->ss_family,
 213                     BUNYAN_T_UINT32, "destaf", (uint32_t)src->ss_family);
 214 
 215                 errno = EADDRNOTAVAIL;  /* XXX KEBE ASKS - Better ideas? */
 216                 return (-1);
 217         }
 218 
 219         SOCKLOG(debug, log, "Sending datagram", s, src, dst,
 220             BUNYAN_T_UINT32, "msglen", buflen);
 221 
 222         m.msg_name = (caddr_t)dst;
 223         iov[0].iov_base = (caddr_t)buf;
 224         iov[0].iov_len = buflen;
 225         m.msg_iov = iov;
 226         m.msg_iovlen = 1;
 227         m.msg_control = (caddr_t)cm;
 228         if (src->ss_family == AF_INET6) {
 229                 /* v6 setup */
 230                 struct sockaddr_in6 *src6;
 231 
 232                 src6 = (struct sockaddr_in6 *)src;
 233                 m.msg_namelen = sizeof (*src6);
 234                 m.msg_controllen = CMSG_SPACE(sizeof (*pi6));
 235                 cm->cmsg_len = CMSG_LEN(sizeof (*pi6));
 236                 cm->cmsg_level = IPPROTO_IPV6;
 237                 cm->cmsg_type = IPV6_PKTINFO;
 238                 /* LINTED */
 239                 pi6 = (struct in6_pktinfo *)CMSG_DATA(cm);
 240                 pi6->ipi6_addr = src6->sin6_addr;
 241                 if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr) ||
 242                     IN6_IS_ADDR_MULTICAST(&src6->sin6_addr)) {
 243                         pi6->ipi6_ifindex = src6->sin6_scope_id;
 244                 } else {
 245                         pi6->ipi6_ifindex = 0;
 246                 }
 247         } else if (src->ss_family == AF_INET) {
 248                 /* v4 setup */
 249                 struct sockaddr_in *src4;
 250 
 251                 src4 = (struct sockaddr_in *)src;
 252                 m.msg_namelen = sizeof (*src4);
 253                 m.msg_controllen = CMSG_SPACE(sizeof (*pi));
 254                 cm->cmsg_len = CMSG_LEN(sizeof (*pi));
 255                 cm->cmsg_level = IPPROTO_IP;
 256                 cm->cmsg_type = IP_PKTINFO;
 257                 /* LINTED */
 258                 pi = (struct in_pktinfo *)CMSG_DATA(cm);
 259                 pi->ipi_addr = src4->sin_addr;
 260                 /* Zero out the other fields for IPv4. */
 261                 pi->ipi_spec_dst.s_addr = 0;
 262                 pi->ipi_ifindex = 0;
 263         } else {
 264                 /*NOTREACHED*/
 265                 INVALID("src->ss_family");
 266         }
 267 
 268         n = sendmsg(s, &m, 0);
 269         if (n < 0)
 270                 SOCKLOG(error, log, "sendmsg() failed", s, src, dst,
 271                     BUNYAN_T_STRING, "err", strerror(errno),
 272                     BUNYAN_T_UINT32, "errno", (int32_t)errno);
 273 
 274         return (n);
 275 }