1 /* $KAME: keysock.c,v 1.25 2001/08/13 20:07:41 itojun Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-3-Clause
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 "opt_ipsec.h"
35
36 /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/domain.h>
41 #include <sys/errno.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/mutex.h>
47 #include <sys/priv.h>
48 #include <sys/protosw.h>
49 #include <sys/signalvar.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/sysctl.h>
53 #include <sys/systm.h>
54
55 #include <net/if.h>
56 #include <net/vnet.h>
57
58 #include <netinet/in.h>
59
60 #include <net/pfkeyv2.h>
61 #include <netipsec/key.h>
62 #include <netipsec/keysock.h>
63 #include <netipsec/key_debug.h>
64 #include <netipsec/ipsec.h>
65
66 #include <machine/stdarg.h>
67
68 static struct mtx keysock_mtx;
69 MTX_SYSINIT(keysock, &keysock_mtx, "key socket pcb list", MTX_DEF);
70
71 #define KEYSOCK_LOCK() mtx_lock(&keysock_mtx)
72 #define KEYSOCK_UNLOCK() mtx_unlock(&keysock_mtx)
73
74 VNET_DEFINE_STATIC(LIST_HEAD(, keycb), keycb_list) =
75 LIST_HEAD_INITIALIZER(keycb_list);
76 #define V_keycb_list VNET(keycb_list)
77
78 static struct sockaddr key_src = { 2, PF_KEY, };
79
80 static int key_sendup0(struct keycb *, struct mbuf *, int);
81
82 VNET_PCPUSTAT_DEFINE(struct pfkeystat, pfkeystat);
83 VNET_PCPUSTAT_SYSINIT(pfkeystat);
84
85 #ifdef VIMAGE
86 VNET_PCPUSTAT_SYSUNINIT(pfkeystat);
87 #endif /* VIMAGE */
88
89 static int
key_send(struct socket * so,int flags,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct thread * td)90 key_send(struct socket *so, int flags, struct mbuf *m,
91 struct sockaddr *nam, struct mbuf *control, struct thread *td)
92 {
93 struct sadb_msg *msg;
94 int len, error = 0;
95
96 if ((flags & PRUS_OOB) || control != NULL) {
97 m_freem(m);
98 if (control != NULL)
99 m_freem(control);
100 return (EOPNOTSUPP);
101 }
102
103 PFKEYSTAT_INC(out_total);
104 PFKEYSTAT_ADD(out_bytes, m->m_pkthdr.len);
105
106 len = m->m_pkthdr.len;
107 if (len < sizeof(struct sadb_msg)) {
108 PFKEYSTAT_INC(out_tooshort);
109 error = EINVAL;
110 goto end;
111 }
112
113 if (m->m_len < sizeof(struct sadb_msg)) {
114 if ((m = m_pullup(m, sizeof(struct sadb_msg))) == NULL) {
115 PFKEYSTAT_INC(out_nomem);
116 error = ENOBUFS;
117 goto end;
118 }
119 }
120
121 M_ASSERTPKTHDR(m);
122
123 KEYDBG(KEY_DUMP, kdebug_mbuf(m));
124
125 msg = mtod(m, struct sadb_msg *);
126 PFKEYSTAT_INC(out_msgtype[msg->sadb_msg_type]);
127 if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
128 PFKEYSTAT_INC(out_invlen);
129 error = EINVAL;
130 goto end;
131 }
132
133 error = key_parse(m, so);
134 m = NULL;
135 end:
136 if (m != NULL)
137 m_freem(m);
138 return (error);
139 }
140
141 /*
142 * send message to the socket.
143 */
144 static int
key_sendup0(struct keycb * kp,struct mbuf * m,int promisc)145 key_sendup0(struct keycb *kp, struct mbuf *m, int promisc)
146 {
147
148 if (promisc) {
149 struct sadb_msg *pmsg;
150
151 M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT);
152 if (m == NULL) {
153 PFKEYSTAT_INC(in_nomem);
154 return (ENOBUFS);
155 }
156 pmsg = mtod(m, struct sadb_msg *);
157 bzero(pmsg, sizeof(*pmsg));
158 pmsg->sadb_msg_version = PF_KEY_V2;
159 pmsg->sadb_msg_type = SADB_X_PROMISC;
160 pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
161 /* pid and seq? */
162
163 PFKEYSTAT_INC(in_msgtype[pmsg->sadb_msg_type]);
164 }
165
166 if (!sbappendaddr(&kp->kp_socket->so_rcv, &key_src, m, NULL)) {
167 PFKEYSTAT_INC(in_nomem);
168 m_freem(m);
169 soroverflow(kp->kp_socket);
170 return (ENOBUFS);
171 }
172
173 sorwakeup(kp->kp_socket);
174 return (0);
175 }
176
177 /* so can be NULL if target != KEY_SENDUP_ONE */
178 int
key_sendup_mbuf(struct socket * so,struct mbuf * m,int target)179 key_sendup_mbuf(struct socket *so, struct mbuf *m, int target)
180 {
181 struct mbuf *n;
182 struct keycb *kp;
183 int error = 0;
184
185 KASSERT(m != NULL, ("NULL mbuf pointer was passed."));
186 KASSERT(so != NULL || target != KEY_SENDUP_ONE,
187 ("NULL socket pointer was passed."));
188 KASSERT(target == KEY_SENDUP_ONE || target == KEY_SENDUP_ALL ||
189 target == KEY_SENDUP_REGISTERED, ("Wrong target %d", target));
190
191 PFKEYSTAT_INC(in_total);
192 PFKEYSTAT_ADD(in_bytes, m->m_pkthdr.len);
193 if (m->m_len < sizeof(struct sadb_msg)) {
194 m = m_pullup(m, sizeof(struct sadb_msg));
195 if (m == NULL) {
196 PFKEYSTAT_INC(in_nomem);
197 return (ENOBUFS);
198 }
199 }
200 if (m->m_len >= sizeof(struct sadb_msg)) {
201 struct sadb_msg *msg;
202 msg = mtod(m, struct sadb_msg *);
203 PFKEYSTAT_INC(in_msgtype[msg->sadb_msg_type]);
204 }
205 KEYSOCK_LOCK();
206 LIST_FOREACH(kp, &V_keycb_list, kp_next) {
207 /*
208 * If you are in promiscuous mode, and when you get broadcasted
209 * reply, you'll get two PF_KEY messages.
210 * (based on pf_key@inner.net message on 14 Oct 1998)
211 */
212 if (kp->kp_promisc) {
213 n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
214 if (n != NULL)
215 key_sendup0(kp, n, 1);
216 else
217 PFKEYSTAT_INC(in_nomem);
218 }
219
220 /* the exact target will be processed later */
221 if (so != NULL && so->so_pcb == kp)
222 continue;
223
224 if (target == KEY_SENDUP_ONE || (target ==
225 KEY_SENDUP_REGISTERED && kp->kp_registered == 0))
226 continue;
227
228 /* KEY_SENDUP_ALL + KEY_SENDUP_REGISTERED */
229 n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
230 if (n == NULL) {
231 PFKEYSTAT_INC(in_nomem);
232 /* Try send to another socket */
233 continue;
234 }
235
236 if (key_sendup0(kp, n, 0) == 0)
237 PFKEYSTAT_INC(in_msgtarget[target]);
238 }
239
240 if (so) { /* KEY_SENDUP_ONE */
241 error = key_sendup0(so->so_pcb, m, 0);
242 if (error == 0)
243 PFKEYSTAT_INC(in_msgtarget[KEY_SENDUP_ONE]);
244 } else {
245 error = 0;
246 m_freem(m);
247 }
248 KEYSOCK_UNLOCK();
249 return (error);
250 }
251
252 static u_long key_sendspace = 8192;
253 SYSCTL_ULONG(_net_key, OID_AUTO, sendspace, CTLFLAG_RW, &key_sendspace, 0,
254 "Default key socket send space");
255 static u_long key_recvspace = 8192;
256 SYSCTL_ULONG(_net_key, OID_AUTO, recvspace, CTLFLAG_RW, &key_recvspace, 0,
257 "Default key socket receive space");
258
259 static int
key_attach(struct socket * so,int proto,struct thread * td)260 key_attach(struct socket *so, int proto, struct thread *td)
261 {
262 struct keycb *kp;
263 int error;
264
265 KASSERT(so->so_pcb == NULL, ("key_attach: so_pcb != NULL"));
266
267 if (td != NULL) {
268 error = priv_check(td, PRIV_NET_RAW);
269 if (error != 0)
270 return (error);
271 }
272
273 error = soreserve(so, key_sendspace, key_recvspace);
274 if (error != 0)
275 return (error);
276
277 kp = malloc(sizeof(*kp), M_PCB, M_WAITOK);
278 kp->kp_socket = so;
279 kp->kp_promisc = kp->kp_registered = 0;
280
281 so->so_pcb = kp;
282 so->so_options |= SO_USELOOPBACK;
283
284 KEYSOCK_LOCK();
285 LIST_INSERT_HEAD(&V_keycb_list, kp, kp_next);
286 KEYSOCK_UNLOCK();
287 soisconnected(so);
288
289 return (0);
290 }
291
292 static void
key_close(struct socket * so)293 key_close(struct socket *so)
294 {
295
296 soisdisconnected(so);
297 }
298
299 static void
key_detach(struct socket * so)300 key_detach(struct socket *so)
301 {
302 struct keycb *kp = so->so_pcb;
303
304 key_freereg(so);
305 KEYSOCK_LOCK();
306 LIST_REMOVE(kp, kp_next);
307 KEYSOCK_UNLOCK();
308 free(kp, M_PCB);
309 so->so_pcb = NULL;
310 }
311
312 static int
key_shutdown(struct socket * so,enum shutdown_how how)313 key_shutdown(struct socket *so, enum shutdown_how how)
314 {
315 /*
316 * Note: key socket marks itself as connected through its lifetime.
317 */
318 switch (how) {
319 case SHUT_RD:
320 socantrcvmore(so);
321 sbrelease(so, SO_RCV);
322 break;
323 case SHUT_RDWR:
324 socantrcvmore(so);
325 sbrelease(so, SO_RCV);
326 /* FALLTHROUGH */
327 case SHUT_WR:
328 socantsendmore(so);
329 }
330
331 return (0);
332 }
333
334 SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
335 "Key Family");
336
337 static struct protosw keysw = {
338 .pr_type = SOCK_RAW,
339 .pr_protocol = PF_KEY_V2,
340 .pr_flags = PR_ATOMIC | PR_ADDR,
341 .pr_abort = key_close,
342 .pr_attach = key_attach,
343 .pr_detach = key_detach,
344 .pr_send = key_send,
345 .pr_shutdown = key_shutdown,
346 .pr_close = key_close,
347 };
348
349 static struct domain keydomain = {
350 .dom_family = PF_KEY,
351 .dom_name = "key",
352 .dom_nprotosw = 1,
353 .dom_protosw = { &keysw },
354 };
355 DOMAIN_SET(key);
356