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 }