1 |
|
|
/* $OpenBSD: policy.c,v 1.42 2016/06/01 11:16:41 patrick Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> |
5 |
|
|
* Copyright (c) 2001 Daniel Hartmeier |
6 |
|
|
* |
7 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
8 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
9 |
|
|
* copyright notice and this permission notice appear in all copies. |
10 |
|
|
* |
11 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
#include <sys/queue.h> |
21 |
|
|
#include <sys/socket.h> |
22 |
|
|
#include <sys/uio.h> |
23 |
|
|
#include <sys/tree.h> |
24 |
|
|
|
25 |
|
|
#include <stdio.h> |
26 |
|
|
#include <stdlib.h> |
27 |
|
|
#include <unistd.h> |
28 |
|
|
#include <string.h> |
29 |
|
|
#include <errno.h> |
30 |
|
|
#include <fcntl.h> |
31 |
|
|
#include <event.h> |
32 |
|
|
|
33 |
|
|
#include "iked.h" |
34 |
|
|
#include "ikev2.h" |
35 |
|
|
|
36 |
|
|
static __inline int |
37 |
|
|
sa_cmp(struct iked_sa *, struct iked_sa *); |
38 |
|
|
static __inline int |
39 |
|
|
user_cmp(struct iked_user *, struct iked_user *); |
40 |
|
|
static __inline int |
41 |
|
|
childsa_cmp(struct iked_childsa *, struct iked_childsa *); |
42 |
|
|
static __inline int |
43 |
|
|
flow_cmp(struct iked_flow *, struct iked_flow *); |
44 |
|
|
|
45 |
|
|
|
46 |
|
|
void |
47 |
|
|
policy_init(struct iked *env) |
48 |
|
|
{ |
49 |
|
|
TAILQ_INIT(&env->sc_policies); |
50 |
|
|
TAILQ_INIT(&env->sc_ocsp); |
51 |
|
|
RB_INIT(&env->sc_users); |
52 |
|
|
RB_INIT(&env->sc_sas); |
53 |
|
|
RB_INIT(&env->sc_activesas); |
54 |
|
|
RB_INIT(&env->sc_activeflows); |
55 |
|
|
} |
56 |
|
|
|
57 |
|
|
int |
58 |
|
|
policy_lookup(struct iked *env, struct iked_message *msg) |
59 |
|
|
{ |
60 |
|
|
struct iked_policy pol; |
61 |
|
|
char *s, idstr[IKED_ID_SIZE]; |
62 |
|
|
|
63 |
|
|
|
64 |
|
|
if (msg->msg_sa != NULL && msg->msg_sa->sa_policy != NULL) { |
65 |
|
|
/* Existing SA with policy */ |
66 |
|
|
msg->msg_policy = msg->msg_sa->sa_policy; |
67 |
|
|
goto found; |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
bzero(&pol, sizeof(pol)); |
71 |
|
|
pol.pol_af = msg->msg_peer.ss_family; |
72 |
|
|
memcpy(&pol.pol_peer.addr, &msg->msg_peer, sizeof(msg->msg_peer)); |
73 |
|
|
memcpy(&pol.pol_local.addr, &msg->msg_local, sizeof(msg->msg_local)); |
74 |
|
|
if (msg->msg_id.id_type && |
75 |
|
|
ikev2_print_id(&msg->msg_id, idstr, IKED_ID_SIZE) == 0 && |
76 |
|
|
(s = strchr(idstr, '/')) != NULL) { |
77 |
|
|
pol.pol_peerid.id_type = msg->msg_id.id_type; |
78 |
|
|
pol.pol_peerid.id_length = strlen(s+1); |
79 |
|
|
strlcpy(pol.pol_peerid.id_data, s+1, |
80 |
|
|
sizeof(pol.pol_peerid.id_data)); |
81 |
|
|
log_debug("%s: peerid '%s'", __func__, s+1); |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
/* Try to find a matching policy for this message */ |
85 |
|
|
if ((msg->msg_policy = policy_test(env, &pol)) != NULL) |
86 |
|
|
goto found; |
87 |
|
|
|
88 |
|
|
/* No matching policy found, try the default */ |
89 |
|
|
if ((msg->msg_policy = env->sc_defaultcon) != NULL) |
90 |
|
|
goto found; |
91 |
|
|
|
92 |
|
|
/* No policy found */ |
93 |
|
|
return (-1); |
94 |
|
|
|
95 |
|
|
found: |
96 |
|
|
return (0); |
97 |
|
|
} |
98 |
|
|
|
99 |
|
|
struct iked_policy * |
100 |
|
|
policy_test(struct iked *env, struct iked_policy *key) |
101 |
|
|
{ |
102 |
|
|
struct iked_policy *p = NULL, *pol = NULL; |
103 |
|
|
struct iked_flow *flow = NULL, *flowkey; |
104 |
|
|
unsigned int cnt = 0; |
105 |
|
|
|
106 |
|
|
p = TAILQ_FIRST(&env->sc_policies); |
107 |
|
|
while (p != NULL) { |
108 |
|
|
cnt++; |
109 |
|
|
if (p->pol_flags & IKED_POLICY_SKIP) |
110 |
|
|
p = p->pol_skip[IKED_SKIP_FLAGS]; |
111 |
|
|
else if (key->pol_af && p->pol_af && |
112 |
|
|
key->pol_af != p->pol_af) |
113 |
|
|
p = p->pol_skip[IKED_SKIP_AF]; |
114 |
|
|
else if (key->pol_ipproto && p->pol_ipproto && |
115 |
|
|
key->pol_ipproto != p->pol_ipproto) |
116 |
|
|
p = p->pol_skip[IKED_SKIP_PROTO]; |
117 |
|
|
else if (sockaddr_cmp((struct sockaddr *)&key->pol_peer.addr, |
118 |
|
|
(struct sockaddr *)&p->pol_peer.addr, |
119 |
|
|
p->pol_peer.addr_mask) != 0) |
120 |
|
|
p = p->pol_skip[IKED_SKIP_DST_ADDR]; |
121 |
|
|
else if (sockaddr_cmp((struct sockaddr *)&key->pol_local.addr, |
122 |
|
|
(struct sockaddr *)&p->pol_local.addr, |
123 |
|
|
p->pol_local.addr_mask) != 0) |
124 |
|
|
p = p->pol_skip[IKED_SKIP_SRC_ADDR]; |
125 |
|
|
else { |
126 |
|
|
/* |
127 |
|
|
* Check if a specific flow is requested |
128 |
|
|
* (eg. for acquire messages from the kernel) |
129 |
|
|
* and find a matching flow. |
130 |
|
|
*/ |
131 |
|
|
if (key->pol_nflows && |
132 |
|
|
(flowkey = RB_MIN(iked_flows, |
133 |
|
|
&key->pol_flows)) != NULL && |
134 |
|
|
(flow = RB_FIND(iked_flows, &p->pol_flows, |
135 |
|
|
flowkey)) == NULL) { |
136 |
|
|
p = TAILQ_NEXT(p, pol_entry); |
137 |
|
|
continue; |
138 |
|
|
} |
139 |
|
|
/* make sure the peer ID matches */ |
140 |
|
|
if (key->pol_peerid.id_type && |
141 |
|
|
(key->pol_peerid.id_type != p->pol_peerid.id_type || |
142 |
|
|
memcmp(key->pol_peerid.id_data, |
143 |
|
|
p->pol_peerid.id_data, |
144 |
|
|
sizeof(key->pol_peerid.id_data)) != 0)) { |
145 |
|
|
p = TAILQ_NEXT(p, pol_entry); |
146 |
|
|
continue; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
/* Policy matched */ |
150 |
|
|
pol = p; |
151 |
|
|
|
152 |
|
|
if (pol->pol_flags & IKED_POLICY_QUICK) |
153 |
|
|
break; |
154 |
|
|
|
155 |
|
|
/* Continue to find last matching policy */ |
156 |
|
|
p = TAILQ_NEXT(p, pol_entry); |
157 |
|
|
} |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
return (pol); |
161 |
|
|
} |
162 |
|
|
|
163 |
|
|
#define IKED_SET_SKIP_STEPS(i) \ |
164 |
|
|
do { \ |
165 |
|
|
while (head[i] != cur) { \ |
166 |
|
|
head[i]->pol_skip[i] = cur; \ |
167 |
|
|
head[i] = TAILQ_NEXT(head[i], pol_entry); \ |
168 |
|
|
} \ |
169 |
|
|
} while (0) |
170 |
|
|
|
171 |
|
|
/* This code is derived from pf_calc_skip_steps() from pf.c */ |
172 |
|
|
void |
173 |
|
|
policy_calc_skip_steps(struct iked_policies *policies) |
174 |
|
|
{ |
175 |
|
|
struct iked_policy *head[IKED_SKIP_COUNT], *cur, *prev; |
176 |
|
|
int i; |
177 |
|
|
|
178 |
|
|
cur = TAILQ_FIRST(policies); |
179 |
|
|
prev = cur; |
180 |
|
|
for (i = 0; i < IKED_SKIP_COUNT; ++i) |
181 |
|
|
head[i] = cur; |
182 |
|
|
while (cur != NULL) { |
183 |
|
|
if (cur->pol_flags & IKED_POLICY_SKIP) |
184 |
|
|
IKED_SET_SKIP_STEPS(IKED_SKIP_FLAGS); |
185 |
|
|
else if (cur->pol_af != AF_UNSPEC && |
186 |
|
|
prev->pol_af != AF_UNSPEC && |
187 |
|
|
cur->pol_af != prev->pol_af) |
188 |
|
|
IKED_SET_SKIP_STEPS(IKED_SKIP_AF); |
189 |
|
|
else if (cur->pol_ipproto && prev->pol_ipproto && |
190 |
|
|
cur->pol_ipproto != prev->pol_ipproto) |
191 |
|
|
IKED_SET_SKIP_STEPS(IKED_SKIP_PROTO); |
192 |
|
|
else if (IKED_ADDR_NEQ(&cur->pol_peer, &prev->pol_peer)) |
193 |
|
|
IKED_SET_SKIP_STEPS(IKED_SKIP_DST_ADDR); |
194 |
|
|
else if (IKED_ADDR_NEQ(&cur->pol_local, &prev->pol_local)) |
195 |
|
|
IKED_SET_SKIP_STEPS(IKED_SKIP_SRC_ADDR); |
196 |
|
|
|
197 |
|
|
prev = cur; |
198 |
|
|
cur = TAILQ_NEXT(cur, pol_entry); |
199 |
|
|
} |
200 |
|
|
for (i = 0; i < IKED_SKIP_COUNT; ++i) |
201 |
|
|
IKED_SET_SKIP_STEPS(i); |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
void |
205 |
|
|
policy_ref(struct iked *env, struct iked_policy *pol) |
206 |
|
|
{ |
207 |
|
|
pol->pol_refcnt++; |
208 |
|
|
pol->pol_flags |= IKED_POLICY_REFCNT; |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
void |
212 |
|
|
policy_unref(struct iked *env, struct iked_policy *pol) |
213 |
|
|
{ |
214 |
|
|
if (pol == NULL || (pol->pol_flags & IKED_POLICY_REFCNT) == 0) |
215 |
|
|
return; |
216 |
|
|
if (--(pol->pol_refcnt) <= 0) |
217 |
|
|
config_free_policy(env, pol); |
218 |
|
|
else { |
219 |
|
|
struct iked_sa *tmp; |
220 |
|
|
int count = 0; |
221 |
|
|
|
222 |
|
|
TAILQ_FOREACH(tmp, &pol->pol_sapeers, sa_peer_entry) |
223 |
|
|
count++; |
224 |
|
|
if (count != pol->pol_refcnt) |
225 |
|
|
log_warnx("%s: ERROR pol %p pol_refcnt %d != count %d", |
226 |
|
|
__func__, pol, pol->pol_refcnt, count); |
227 |
|
|
} |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
void |
231 |
|
|
sa_state(struct iked *env, struct iked_sa *sa, int state) |
232 |
|
|
{ |
233 |
|
|
const char *a; |
234 |
|
|
const char *b; |
235 |
|
|
int ostate = sa->sa_state; |
236 |
|
|
|
237 |
|
|
a = print_map(ostate, ikev2_state_map); |
238 |
|
|
b = print_map(state, ikev2_state_map); |
239 |
|
|
|
240 |
|
|
sa->sa_state = state; |
241 |
|
|
if (ostate != IKEV2_STATE_INIT && |
242 |
|
|
!sa_stateok(sa, state)) { |
243 |
|
|
log_debug("%s: cannot switch: %s -> %s", __func__, a, b); |
244 |
|
|
sa->sa_state = ostate; |
245 |
|
|
} else if (ostate != sa->sa_state) { |
246 |
|
|
switch (state) { |
247 |
|
|
case IKEV2_STATE_ESTABLISHED: |
248 |
|
|
case IKEV2_STATE_CLOSED: |
249 |
|
|
log_info("%s: %s -> %s from %s to %s policy '%s'", |
250 |
|
|
__func__, a, b, |
251 |
|
|
print_host((struct sockaddr *)&sa->sa_peer.addr, |
252 |
|
|
NULL, 0), |
253 |
|
|
print_host((struct sockaddr *)&sa->sa_local.addr, |
254 |
|
|
NULL, 0), |
255 |
|
|
sa->sa_policy ? sa->sa_policy->pol_name : |
256 |
|
|
"<unknown>"); |
257 |
|
|
break; |
258 |
|
|
default: |
259 |
|
|
log_debug("%s: %s -> %s", __func__, a, b); |
260 |
|
|
break; |
261 |
|
|
} |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
} |
265 |
|
|
|
266 |
|
|
void |
267 |
|
|
sa_stateflags(struct iked_sa *sa, unsigned int flags) |
268 |
|
|
{ |
269 |
|
|
unsigned int require; |
270 |
|
|
|
271 |
|
|
if (sa->sa_state > IKEV2_STATE_SA_INIT) |
272 |
|
|
require = sa->sa_statevalid; |
273 |
|
|
else |
274 |
|
|
require = sa->sa_stateinit; |
275 |
|
|
|
276 |
|
|
log_debug("%s: 0x%04x -> 0x%04x %s (required 0x%04x %s)", __func__, |
277 |
|
|
sa->sa_stateflags, sa->sa_stateflags | flags, |
278 |
|
|
print_bits(sa->sa_stateflags | flags, IKED_REQ_BITS), require, |
279 |
|
|
print_bits(require, IKED_REQ_BITS)); |
280 |
|
|
|
281 |
|
|
sa->sa_stateflags |= flags; |
282 |
|
|
} |
283 |
|
|
|
284 |
|
|
int |
285 |
|
|
sa_stateok(struct iked_sa *sa, int state) |
286 |
|
|
{ |
287 |
|
|
unsigned int require; |
288 |
|
|
|
289 |
|
|
if (sa->sa_state < state) |
290 |
|
|
return (0); |
291 |
|
|
|
292 |
|
|
if (state == IKEV2_STATE_SA_INIT) |
293 |
|
|
require = sa->sa_stateinit; |
294 |
|
|
else |
295 |
|
|
require = sa->sa_statevalid; |
296 |
|
|
|
297 |
|
|
if (state == IKEV2_STATE_SA_INIT || |
298 |
|
|
state == IKEV2_STATE_VALID || |
299 |
|
|
state == IKEV2_STATE_EAP_VALID) { |
300 |
|
|
log_debug("%s: %s flags 0x%04x, require 0x%04x %s", __func__, |
301 |
|
|
print_map(state, ikev2_state_map), |
302 |
|
|
(sa->sa_stateflags & require), require, |
303 |
|
|
print_bits(require, IKED_REQ_BITS)); |
304 |
|
|
|
305 |
|
|
if ((sa->sa_stateflags & require) != require) |
306 |
|
|
return (0); /* not ready, ignore */ |
307 |
|
|
} |
308 |
|
|
return (1); |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
struct iked_sa * |
312 |
|
|
sa_new(struct iked *env, uint64_t ispi, uint64_t rspi, |
313 |
|
|
unsigned int initiator, struct iked_policy *pol) |
314 |
|
|
{ |
315 |
|
|
struct iked_sa *sa; |
316 |
|
|
struct iked_sa *old; |
317 |
|
|
struct iked_id *localid; |
318 |
|
|
unsigned int diff; |
319 |
|
|
|
320 |
|
|
if ((ispi == 0 && rspi == 0) || |
321 |
|
|
(sa = sa_lookup(env, ispi, rspi, initiator)) == NULL) { |
322 |
|
|
/* Create new SA */ |
323 |
|
|
if (!initiator && ispi == 0) { |
324 |
|
|
log_debug("%s: cannot create responder IKE SA w/o ispi", |
325 |
|
|
__func__); |
326 |
|
|
return (NULL); |
327 |
|
|
} |
328 |
|
|
sa = config_new_sa(env, initiator); |
329 |
|
|
if (sa == NULL) { |
330 |
|
|
log_debug("%s: failed to allocate IKE SA", __func__); |
331 |
|
|
return (NULL); |
332 |
|
|
} |
333 |
|
|
if (!initiator) |
334 |
|
|
sa->sa_hdr.sh_ispi = ispi; |
335 |
|
|
old = RB_INSERT(iked_sas, &env->sc_sas, sa); |
336 |
|
|
if (old && old != sa) { |
337 |
|
|
log_warnx("%s: duplicate IKE SA", __func__); |
338 |
|
|
config_free_sa(env, sa); |
339 |
|
|
return (NULL); |
340 |
|
|
} |
341 |
|
|
} |
342 |
|
|
/* Update rspi in the initator case */ |
343 |
|
|
if (initiator && sa->sa_hdr.sh_rspi == 0 && rspi) |
344 |
|
|
sa->sa_hdr.sh_rspi = rspi; |
345 |
|
|
|
346 |
|
|
if (sa->sa_policy == NULL) { |
347 |
|
|
sa->sa_policy = pol; |
348 |
|
|
TAILQ_INSERT_TAIL(&pol->pol_sapeers, sa, sa_peer_entry); |
349 |
|
|
} else |
350 |
|
|
pol = sa->sa_policy; |
351 |
|
|
|
352 |
|
|
sa->sa_statevalid = IKED_REQ_AUTH|IKED_REQ_AUTHVALID|IKED_REQ_SA; |
353 |
|
|
if (pol != NULL && pol->pol_auth.auth_eap) { |
354 |
|
|
sa->sa_statevalid |= IKED_REQ_CERT|IKED_REQ_EAPVALID; |
355 |
|
|
} else if (pol != NULL && pol->pol_auth.auth_method != |
356 |
|
|
IKEV2_AUTH_SHARED_KEY_MIC) { |
357 |
|
|
sa->sa_statevalid |= IKED_REQ_CERTVALID|IKED_REQ_CERT; |
358 |
|
|
} |
359 |
|
|
|
360 |
|
|
if (initiator) { |
361 |
|
|
localid = &sa->sa_iid; |
362 |
|
|
diff = IKED_REQ_CERTVALID|IKED_REQ_AUTHVALID|IKED_REQ_SA| |
363 |
|
|
IKED_REQ_EAPVALID; |
364 |
|
|
sa->sa_stateinit = sa->sa_statevalid & ~diff; |
365 |
|
|
sa->sa_statevalid = sa->sa_statevalid & diff; |
366 |
|
|
} else |
367 |
|
|
localid = &sa->sa_rid; |
368 |
|
|
|
369 |
|
|
if (!ibuf_length(localid->id_buf) && pol != NULL && |
370 |
|
|
ikev2_policy2id(&pol->pol_localid, localid, 1) != 0) { |
371 |
|
|
log_debug("%s: failed to get local id", __func__); |
372 |
|
|
sa_free(env, sa); |
373 |
|
|
return (NULL); |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
return (sa); |
377 |
|
|
} |
378 |
|
|
|
379 |
|
|
void |
380 |
|
|
sa_free(struct iked *env, struct iked_sa *sa) |
381 |
|
|
{ |
382 |
|
|
log_debug("%s: ispi %s rspi %s", __func__, |
383 |
|
|
print_spi(sa->sa_hdr.sh_ispi, 8), |
384 |
|
|
print_spi(sa->sa_hdr.sh_rspi, 8)); |
385 |
|
|
|
386 |
|
|
/* IKE rekeying running? */ |
387 |
|
|
if (sa->sa_next) { |
388 |
|
|
RB_REMOVE(iked_sas, &env->sc_sas, sa->sa_next); |
389 |
|
|
config_free_sa(env, sa->sa_next); |
390 |
|
|
} |
391 |
|
|
RB_REMOVE(iked_sas, &env->sc_sas, sa); |
392 |
|
|
config_free_sa(env, sa); |
393 |
|
|
} |
394 |
|
|
|
395 |
|
|
void |
396 |
|
|
sa_free_flows(struct iked *env, struct iked_saflows *head) |
397 |
|
|
{ |
398 |
|
|
struct iked_flow *flow, *next; |
399 |
|
|
|
400 |
|
|
for (flow = TAILQ_FIRST(head); flow != NULL; flow = next) { |
401 |
|
|
next = TAILQ_NEXT(flow, flow_entry); |
402 |
|
|
|
403 |
|
|
log_debug("%s: free %p", __func__, flow); |
404 |
|
|
|
405 |
|
|
if (flow->flow_loaded) |
406 |
|
|
RB_REMOVE(iked_flows, &env->sc_activeflows, flow); |
407 |
|
|
TAILQ_REMOVE(head, flow, flow_entry); |
408 |
|
|
(void)pfkey_flow_delete(env->sc_pfkey, flow); |
409 |
|
|
flow_free(flow); |
410 |
|
|
} |
411 |
|
|
} |
412 |
|
|
|
413 |
|
|
|
414 |
|
|
int |
415 |
|
|
sa_address(struct iked_sa *sa, struct iked_addr *addr, |
416 |
|
|
struct sockaddr_storage *peer) |
417 |
|
|
{ |
418 |
|
|
bzero(addr, sizeof(*addr)); |
419 |
|
|
addr->addr_af = peer->ss_family; |
420 |
|
|
addr->addr_port = htons(socket_getport((struct sockaddr *)peer)); |
421 |
|
|
memcpy(&addr->addr, peer, sizeof(*peer)); |
422 |
|
|
if (socket_af((struct sockaddr *)&addr->addr, addr->addr_port) == -1) { |
423 |
|
|
log_debug("%s: invalid address", __func__); |
424 |
|
|
return (-1); |
425 |
|
|
} |
426 |
|
|
return (0); |
427 |
|
|
} |
428 |
|
|
|
429 |
|
|
void |
430 |
|
|
childsa_free(struct iked_childsa *csa) |
431 |
|
|
{ |
432 |
|
|
if (csa->csa_children) { |
433 |
|
|
/* XXX should not happen */ |
434 |
|
|
log_warnx("%s: trying to remove CSA %p children %u", |
435 |
|
|
__func__, csa, csa->csa_children); |
436 |
|
|
return; |
437 |
|
|
} |
438 |
|
|
if (csa->csa_parent) |
439 |
|
|
csa->csa_parent->csa_children--; |
440 |
|
|
ibuf_release(csa->csa_encrkey); |
441 |
|
|
ibuf_release(csa->csa_integrkey); |
442 |
|
|
free(csa); |
443 |
|
|
} |
444 |
|
|
|
445 |
|
|
struct iked_childsa * |
446 |
|
|
childsa_lookup(struct iked_sa *sa, uint64_t spi, uint8_t protoid) |
447 |
|
|
{ |
448 |
|
|
struct iked_childsa *csa; |
449 |
|
|
|
450 |
|
|
if (sa == NULL || spi == 0 || protoid == 0) |
451 |
|
|
return (NULL); |
452 |
|
|
|
453 |
|
|
TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { |
454 |
|
|
if (csa->csa_spi.spi_protoid == protoid && |
455 |
|
|
(csa->csa_spi.spi == spi)) |
456 |
|
|
break; |
457 |
|
|
} |
458 |
|
|
return (csa); |
459 |
|
|
} |
460 |
|
|
|
461 |
|
|
void |
462 |
|
|
flow_free(struct iked_flow *flow) |
463 |
|
|
{ |
464 |
|
|
free(flow); |
465 |
|
|
} |
466 |
|
|
|
467 |
|
|
struct iked_sa * |
468 |
|
|
sa_lookup(struct iked *env, uint64_t ispi, uint64_t rspi, |
469 |
|
|
unsigned int initiator) |
470 |
|
|
{ |
471 |
|
|
struct iked_sa *sa, key; |
472 |
|
|
|
473 |
|
|
key.sa_hdr.sh_ispi = ispi; |
474 |
|
|
/* key.sa_hdr.sh_rspi = rspi; */ |
475 |
|
|
key.sa_hdr.sh_initiator = initiator; |
476 |
|
|
|
477 |
|
|
if ((sa = RB_FIND(iked_sas, &env->sc_sas, &key)) != NULL) { |
478 |
|
|
gettimeofday(&sa->sa_timeused, NULL); |
479 |
|
|
|
480 |
|
|
/* Validate if SPIr matches */ |
481 |
|
|
if ((sa->sa_hdr.sh_rspi != 0) && |
482 |
|
|
(rspi != 0) && |
483 |
|
|
(sa->sa_hdr.sh_rspi != rspi)) |
484 |
|
|
return (NULL); |
485 |
|
|
} |
486 |
|
|
|
487 |
|
|
return (sa); |
488 |
|
|
} |
489 |
|
|
|
490 |
|
|
static __inline int |
491 |
|
|
sa_cmp(struct iked_sa *a, struct iked_sa *b) |
492 |
|
|
{ |
493 |
|
|
if (a->sa_hdr.sh_initiator > b->sa_hdr.sh_initiator) |
494 |
|
|
return (-1); |
495 |
|
|
if (a->sa_hdr.sh_initiator < b->sa_hdr.sh_initiator) |
496 |
|
|
return (1); |
497 |
|
|
|
498 |
|
|
if (a->sa_hdr.sh_ispi > b->sa_hdr.sh_ispi) |
499 |
|
|
return (-1); |
500 |
|
|
if (a->sa_hdr.sh_ispi < b->sa_hdr.sh_ispi) |
501 |
|
|
return (1); |
502 |
|
|
|
503 |
|
|
#if 0 |
504 |
|
|
/* Responder SPI is not yet set in the local IKE SADB */ |
505 |
|
|
if ((b->sa_type == IKED_SATYPE_LOCAL && b->sa_hdr.sh_rspi == 0) || |
506 |
|
|
(a->sa_type == IKED_SATYPE_LOCAL && a->sa_hdr.sh_rspi == 0)) |
507 |
|
|
return (0); |
508 |
|
|
|
509 |
|
|
if (a->sa_hdr.sh_rspi > b->sa_hdr.sh_rspi) |
510 |
|
|
return (-1); |
511 |
|
|
if (a->sa_hdr.sh_rspi < b->sa_hdr.sh_rspi) |
512 |
|
|
return (1); |
513 |
|
|
#endif |
514 |
|
|
|
515 |
|
|
return (0); |
516 |
|
|
} |
517 |
|
|
|
518 |
|
|
static __inline int |
519 |
|
|
sa_addrpool_cmp(struct iked_sa *a, struct iked_sa *b) |
520 |
|
|
{ |
521 |
|
|
return (sockaddr_cmp((struct sockaddr *)&a->sa_addrpool->addr, |
522 |
|
|
(struct sockaddr *)&b->sa_addrpool->addr, -1)); |
523 |
|
|
} |
524 |
|
|
|
525 |
|
|
static __inline int |
526 |
|
|
sa_addrpool6_cmp(struct iked_sa *a, struct iked_sa *b) |
527 |
|
|
{ |
528 |
|
|
return (sockaddr_cmp((struct sockaddr *)&a->sa_addrpool6->addr, |
529 |
|
|
(struct sockaddr *)&b->sa_addrpool6->addr, -1)); |
530 |
|
|
} |
531 |
|
|
|
532 |
|
|
struct iked_user * |
533 |
|
|
user_lookup(struct iked *env, const char *user) |
534 |
|
|
{ |
535 |
|
|
struct iked_user key; |
536 |
|
|
|
537 |
|
|
if (strlcpy(key.usr_name, user, |
538 |
|
|
sizeof(key.usr_name)) >= sizeof(key.usr_name)) |
539 |
|
|
return (NULL); |
540 |
|
|
|
541 |
|
|
return (RB_FIND(iked_users, &env->sc_users, &key)); |
542 |
|
|
} |
543 |
|
|
|
544 |
|
|
static __inline int |
545 |
|
|
user_cmp(struct iked_user *a, struct iked_user *b) |
546 |
|
|
{ |
547 |
|
|
return (strcmp(a->usr_name, b->usr_name)); |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
static __inline int |
551 |
|
|
childsa_cmp(struct iked_childsa *a, struct iked_childsa *b) |
552 |
|
|
{ |
553 |
|
|
if (a->csa_spi.spi > b->csa_spi.spi) |
554 |
|
|
return (1); |
555 |
|
|
if (a->csa_spi.spi < b->csa_spi.spi) |
556 |
|
|
return (-1); |
557 |
|
|
return (0); |
558 |
|
|
} |
559 |
|
|
|
560 |
|
|
static __inline int |
561 |
|
|
addr_cmp(struct iked_addr *a, struct iked_addr *b, int useports) |
562 |
|
|
{ |
563 |
|
|
int diff = 0; |
564 |
|
|
|
565 |
|
|
diff = sockaddr_cmp((struct sockaddr *)&a->addr, |
566 |
|
|
(struct sockaddr *)&b->addr, 128); |
567 |
|
|
if (!diff) |
568 |
|
|
diff = (int)a->addr_mask - (int)b->addr_mask; |
569 |
|
|
if (!diff && useports) |
570 |
|
|
diff = a->addr_port - b->addr_port; |
571 |
|
|
|
572 |
|
|
return (diff); |
573 |
|
|
} |
574 |
|
|
|
575 |
|
|
static __inline int |
576 |
|
|
flow_cmp(struct iked_flow *a, struct iked_flow *b) |
577 |
|
|
{ |
578 |
|
|
int diff = 0; |
579 |
|
|
|
580 |
|
|
if (a->flow_peer && b->flow_peer) |
581 |
|
|
diff = addr_cmp(a->flow_peer, b->flow_peer, 0); |
582 |
|
|
if (!diff) |
583 |
|
|
diff = addr_cmp(&a->flow_dst, &b->flow_dst, 1); |
584 |
|
|
if (!diff) |
585 |
|
|
diff = addr_cmp(&a->flow_src, &b->flow_src, 1); |
586 |
|
|
if (!diff && a->flow_dir && b->flow_dir) |
587 |
|
|
diff = (int)a->flow_dir - (int)b->flow_dir; |
588 |
|
|
|
589 |
|
|
return (diff); |
590 |
|
|
} |
591 |
|
|
|
592 |
|
|
RB_GENERATE(iked_sas, iked_sa, sa_entry, sa_cmp); |
593 |
|
|
RB_GENERATE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); |
594 |
|
|
RB_GENERATE(iked_addrpool6, iked_sa, sa_addrpool6_entry, sa_addrpool6_cmp); |
595 |
|
|
RB_GENERATE(iked_users, iked_user, usr_entry, user_cmp); |
596 |
|
|
RB_GENERATE(iked_activesas, iked_childsa, csa_node, childsa_cmp); |
597 |
|
|
RB_GENERATE(iked_flows, iked_flow, flow_node, flow_cmp); |