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