]>
git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/policy.c
1 /* $KAME: policy.c,v 1.46 2001/11/16 04:08:10 sakane Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/queue.h>
39 #include <netinet/in.h>
40 #ifdef HAVE_NETINET6_IPSEC
41 # include <netinet6/ipsec.h>
43 # include <netinet/ipsec.h>
59 #include "localconf.h"
60 #include "isakmp_var.h"
68 static TAILQ_HEAD(_sptree
, secpolicy
) sptree
;
70 /* perform exact match against security policy table. */
73 struct policyindex
*spidx
;
77 for (p
= TAILQ_FIRST(&sptree
); p
; p
= TAILQ_NEXT(p
, chain
)) {
78 if (!cmpspidxstrict(spidx
, &p
->spidx
))
86 * perform non-exact match against security policy table, only if this is
87 * transport mode SA negotiation. for example, 0.0.0.0/0 -> 0.0.0.0/0
88 * entry in policy.txt can be returned when we're negotiating transport
89 * mode SA. this is how the kernel works.
94 struct policyindex
*spidx
;
95 struct ph2handle
*iph2
;
98 int mismatched_outer_addr
= 0;
100 for (p
= TAILQ_FIRST(&sptree
); p
; p
= TAILQ_NEXT(p
, chain
)) {
101 if (!cmpspidxwild(spidx
, &p
->spidx
)) {
102 if (spidx
->dir
!= IPSEC_DIR_ANY
) {
103 struct ipsecrequest
*isr
;
104 for (isr
= p
->req
; isr
!= NULL
; isr
= isr
->next
) {
105 if (isr
->saidx
.mode
!= IPSEC_MODE_TUNNEL
) {
106 plog(LLV_DEBUG2
, LOCATION
, NULL
, "%s, skipping policy. dir %d, mode %d\n",
107 __FUNCTION__
, spidx
->dir
, isr
->saidx
.mode
);
111 // for tunnel mode: verify the outer ip addresses match the phase2's addresses
112 if (spidx
->dir
== IPSEC_DIR_INBOUND
) {
113 // TODO: look out for wildcards
114 if (!cmpsaddrwop(iph2
->dst
, (struct sockaddr
*)&isr
->saidx
.src
) &&
115 !cmpsaddrwop(iph2
->src
, (struct sockaddr
*)&isr
->saidx
.dst
)) {
116 plog(LLV_DEBUG2
, LOCATION
, NULL
, "%s, inbound policy outer addresses matched phase2's addresses\n",
120 mismatched_outer_addr
= 1;
122 } else if (spidx
->dir
== IPSEC_DIR_OUTBOUND
) {
123 // TODO: look out for wildcards
124 if (!cmpsaddrwop(iph2
->src
, (struct sockaddr
*)&isr
->saidx
.src
) &&
125 !cmpsaddrwop(iph2
->dst
, (struct sockaddr
*)&isr
->saidx
.dst
)) {
126 plog(LLV_DEBUG2
, LOCATION
, NULL
, "%s, outbound policy outer addresses matched phase2's addresses\n",
130 mismatched_outer_addr
= 1;
133 mismatched_outer_addr
= 1;
135 if (mismatched_outer_addr
) {
136 plog(LLV_DEBUG2
, LOCATION
, NULL
, "%s, policy outer addresses matched phase2's addresses: dir %d\n",
137 __FUNCTION__
, spidx
->dir
);
138 plog(LLV_DEBUG
, LOCATION
, NULL
, "src1: %s\n",
139 saddr2str(iph2
->src
));
140 plog(LLV_DEBUG
, LOCATION
, NULL
, "src2: %s\n",
141 saddr2str((struct sockaddr
*)&isr
->saidx
.src
));
142 plog(LLV_DEBUG
, LOCATION
, NULL
, "dst1: %s\n",
143 saddr2str(iph2
->dst
));
144 plog(LLV_DEBUG
, LOCATION
, NULL
, "dst2: %s\n",
145 saddr2str((struct sockaddr
*)&isr
->saidx
.dst
));
149 if (!mismatched_outer_addr
) {
160 struct policyindex
*spidx
;
161 struct ph2handle
*iph2
;
166 plog(LLV_DEBUG
, LOCATION
, NULL
, "checking for transport mode\n");
168 if (spidx
->src
.ss_family
!= spidx
->dst
.ss_family
) {
169 plog(LLV_ERROR
, LOCATION
, NULL
,
170 "address family mismatch, src:%d dst:%d\n",
171 spidx
->src
.ss_family
,
172 spidx
->dst
.ss_family
);
175 switch (spidx
->src
.ss_family
) {
177 prefixlen
= sizeof(struct in_addr
) << 3;
181 prefixlen
= sizeof(struct in6_addr
) << 3;
185 plog(LLV_ERROR
, LOCATION
, NULL
,
186 "invalid family: %d\n", spidx
->src
.ss_family
);
190 /* is it transport mode SA negotiation? */
191 plog(LLV_DEBUG
, LOCATION
, NULL
, "src1: %s\n",
192 saddr2str(iph2
->src
));
193 plog(LLV_DEBUG
, LOCATION
, NULL
, "src2: %s\n",
194 saddr2str((struct sockaddr
*)&spidx
->src
));
195 if (cmpsaddrwop(iph2
->src
, (struct sockaddr
*)&spidx
->src
)
196 || spidx
->prefs
!= prefixlen
)
199 plog(LLV_DEBUG
, LOCATION
, NULL
, "dst1: %s\n",
200 saddr2str(iph2
->dst
));
201 plog(LLV_DEBUG
, LOCATION
, NULL
, "dst2: %s\n",
202 saddr2str((struct sockaddr
*)&spidx
->dst
));
203 if (cmpsaddrwop(iph2
->dst
, (struct sockaddr
*)&spidx
->dst
)
204 || spidx
->prefd
!= prefixlen
)
207 plog(LLV_DEBUG
, LOCATION
, NULL
, "looks to be transport mode\n");
209 for (p
= TAILQ_FIRST(&sptree
); p
; p
= TAILQ_NEXT(p
, chain
)) {
210 if (!cmpspidx_wild(spidx
, &p
->spidx
))
224 for (p
= TAILQ_FIRST(&sptree
); p
; p
= TAILQ_NEXT(p
, chain
)) {
233 * compare policyindex.
240 struct policyindex
*a
, *b
;
242 plog(LLV_DEBUG
, LOCATION
, NULL
, "sub:%p: %s\n", a
, spidx2str(a
));
243 plog(LLV_DEBUG
, LOCATION
, NULL
, "db :%p: %s\n", b
, spidx2str(b
));
245 /* XXX don't check direction now, but it's to be checked carefully. */
247 || a
->prefs
!= b
->prefs
248 || a
->prefd
!= b
->prefd
249 || a
->ul_proto
!= b
->ul_proto
)
252 if (cmpsaddrstrict((struct sockaddr
*)&a
->src
,
253 (struct sockaddr
*)&b
->src
))
255 if (cmpsaddrstrict((struct sockaddr
*)&a
->dst
,
256 (struct sockaddr
*)&b
->dst
))
263 * compare policyindex, with wildcard address/protocol match.
264 * a: subject b: db, can contain wildcard things.
270 struct policyindex
*a
, *b
;
272 struct sockaddr_storage sa1
, sa2
;
274 plog(LLV_DEBUG
, LOCATION
, NULL
, "sub:%p: %s\n", a
, spidx2str(a
));
275 plog(LLV_DEBUG
, LOCATION
, NULL
, "db: %p: %s\n", b
, spidx2str(b
));
277 if (!(b
->dir
== IPSEC_DIR_ANY
|| a
->dir
== b
->dir
))
280 if (!(a
->ul_proto
== IPSEC_ULPROTO_ANY
||
281 b
->ul_proto
== IPSEC_ULPROTO_ANY
||
282 a
->ul_proto
== b
->ul_proto
))
285 if (a
->src
.ss_family
!= b
->src
.ss_family
)
287 if (a
->dst
.ss_family
!= b
->dst
.ss_family
)
291 /* compare src address */
292 if (sizeof(sa1
) < a
->src
.ss_len
|| sizeof(sa2
) < b
->src
.ss_len
) {
293 plog(LLV_ERROR
, LOCATION
, NULL
,
295 "src.ss_len:%d dst.ss_len:%d\n",
296 a
->src
.ss_len
, b
->src
.ss_len
);
300 mask_sockaddr((struct sockaddr
*)&sa1
, (struct sockaddr
*)&a
->src
,
302 mask_sockaddr((struct sockaddr
*)&sa2
, (struct sockaddr
*)&b
->src
,
304 plog(LLV_DEBUG
, LOCATION
, NULL
, "%p masked with /%d: %s\n",
305 a
, b
->prefs
, saddr2str((struct sockaddr
*)&sa1
));
306 plog(LLV_DEBUG
, LOCATION
, NULL
, "%p masked with /%d: %s\n",
307 b
, b
->prefs
, saddr2str((struct sockaddr
*)&sa2
));
308 if (cmpsaddrwild((struct sockaddr
*)&sa1
, (struct sockaddr
*)&sa2
))
312 /* compare dst address */
313 if (sizeof(sa1
) < a
->dst
.ss_len
|| sizeof(sa2
) < b
->dst
.ss_len
) {
314 plog(LLV_ERROR
, LOCATION
, NULL
, "unexpected error\n");
318 mask_sockaddr((struct sockaddr
*)&sa1
, (struct sockaddr
*)&a
->dst
,
320 mask_sockaddr((struct sockaddr
*)&sa2
, (struct sockaddr
*)&b
->dst
,
322 plog(LLV_DEBUG
, LOCATION
, NULL
, "%p masked with /%d: %s\n",
323 a
, b
->prefd
, saddr2str((struct sockaddr
*)&sa1
));
324 plog(LLV_DEBUG
, LOCATION
, NULL
, "%p masked with /%d: %s\n",
325 b
, b
->prefd
, saddr2str((struct sockaddr
*)&sa2
));
326 if (cmpsaddrwild((struct sockaddr
*)&sa1
, (struct sockaddr
*)&sa2
))
335 struct secpolicy
*new;
337 new = racoon_calloc(1, sizeof(*new));
346 struct secpolicy
*sp
;
348 struct ipsecrequest
*req
= NULL
, *next
;
350 for (req
= sp
->req
; req
; req
= next
) {
359 delsp_bothdir(spidx0
)
360 struct policyindex
*spidx0
;
362 struct policyindex spidx
;
363 struct secpolicy
*sp
;
364 struct sockaddr_storage src
, dst
;
365 u_int8_t prefs
, prefd
;
367 memcpy(&spidx
, spidx0
, sizeof(spidx
));
369 case IPSEC_DIR_INBOUND
:
370 #ifdef HAVE_POLICY_FWD
378 case IPSEC_DIR_OUTBOUND
:
392 spidx
.dir
= IPSEC_DIR_INBOUND
;
400 #ifdef HAVE_POLICY_FWD
401 spidx
.dir
= IPSEC_DIR_FWD
;
414 spidx
.dir
= IPSEC_DIR_OUTBOUND
;
425 struct secpolicy
*new;
427 #ifdef HAVE_PFKEY_POLICY_PRIORITY
430 TAILQ_FOREACH(p
, &sptree
, chain
) {
431 if (new->spidx
.priority
< p
->spidx
.priority
) {
432 TAILQ_INSERT_BEFORE(p
, new, chain
);
438 TAILQ_INSERT_HEAD(&sptree
, new, chain
);
446 struct secpolicy
*sp
;
448 TAILQ_REMOVE(&sptree
, sp
, chain
);
455 struct secpolicy
*p
, *next
;
457 for (p
= TAILQ_FIRST(&sptree
); p
; p
= next
) {
458 next
= TAILQ_NEXT(p
, chain
);
465 policies_installed(void)
467 if (TAILQ_EMPTY(&sptree
))
479 struct ipsecrequest
*
482 struct ipsecrequest
*new;
484 new = racoon_calloc(1, sizeof(*new));
493 const struct policyindex
*spidx
;
495 /* addr/pref[port] addr/pref[port] ul dir act */
496 static char buf
[256];
500 blen
= sizeof(buf
) - 1;
503 a
= saddr2str((const struct sockaddr
*)&spidx
->src
);
504 for (b
= a
; *b
!= '\0'; b
++)
510 i
= snprintf(p
, blen
, "%s/%d[%s ", a
, spidx
->prefs
, b
);
511 if (i
< 0 || i
>= blen
)
516 a
= saddr2str((const struct sockaddr
*)&spidx
->dst
);
517 for (b
= a
; *b
!= '\0'; b
++)
523 i
= snprintf(p
, blen
, "%s/%d[%s ", a
, spidx
->prefd
, b
);
524 if (i
< 0 || i
>= blen
)
529 snprintf(p
, blen
, "proto=%s dir=%s",
530 s_proto(spidx
->ul_proto
), s_direction(spidx
->dir
));