| @@ -1,2226 +1,2226 @@ | | | @@ -1,2226 +1,2226 @@ |
1 | /* $NetBSD: ipsec.c,v 1.53 2011/06/05 01:45:37 christos Exp $ */ | | 1 | /* $NetBSD: ipsec.c,v 1.54 2011/06/08 16:24:50 dyoung Exp $ */ |
2 | /* $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/netipsec/ipsec.c,v 1.2.2.2 2003/07/01 01:38:13 sam Exp $ */ | | 2 | /* $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/netipsec/ipsec.c,v 1.2.2.2 2003/07/01 01:38:13 sam Exp $ */ |
3 | /* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ | | 3 | /* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ |
4 | | | 4 | |
5 | /* | | 5 | /* |
6 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | | 6 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
7 | * All rights reserved. | | 7 | * All rights reserved. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. Neither the name of the project nor the names of its contributors | | 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 | | 18 | * may be used to endorse or promote products derived from this software |
19 | * without specific prior written permission. | | 19 | * without specific prior written permission. |
20 | * | | 20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | | 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 | | 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | | 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | * SUCH DAMAGE. | | 31 | * SUCH DAMAGE. |
32 | */ | | 32 | */ |
33 | | | 33 | |
34 | #include <sys/cdefs.h> | | 34 | #include <sys/cdefs.h> |
35 | __KERNEL_RCSID(0, "$NetBSD: ipsec.c,v 1.53 2011/06/05 01:45:37 christos Exp $"); | | 35 | __KERNEL_RCSID(0, "$NetBSD: ipsec.c,v 1.54 2011/06/08 16:24:50 dyoung Exp $"); |
36 | | | 36 | |
37 | /* | | 37 | /* |
38 | * IPsec controller part. | | 38 | * IPsec controller part. |
39 | */ | | 39 | */ |
40 | | | 40 | |
41 | #include "opt_inet.h" | | 41 | #include "opt_inet.h" |
42 | #ifdef __FreeBSD__ | | 42 | #ifdef __FreeBSD__ |
43 | #include "opt_inet6.h" | | 43 | #include "opt_inet6.h" |
44 | #endif | | 44 | #endif |
45 | #include "opt_ipsec.h" | | 45 | #include "opt_ipsec.h" |
46 | | | 46 | |
47 | #include <sys/param.h> | | 47 | #include <sys/param.h> |
48 | #include <sys/systm.h> | | 48 | #include <sys/systm.h> |
49 | #include <sys/malloc.h> | | 49 | #include <sys/malloc.h> |
50 | #include <sys/mbuf.h> | | 50 | #include <sys/mbuf.h> |
51 | #include <sys/domain.h> | | 51 | #include <sys/domain.h> |
52 | #include <sys/protosw.h> | | 52 | #include <sys/protosw.h> |
53 | #include <sys/socket.h> | | 53 | #include <sys/socket.h> |
54 | #include <sys/socketvar.h> | | 54 | #include <sys/socketvar.h> |
55 | #include <sys/errno.h> | | 55 | #include <sys/errno.h> |
56 | #include <sys/time.h> | | 56 | #include <sys/time.h> |
57 | #include <sys/kernel.h> | | 57 | #include <sys/kernel.h> |
58 | #include <sys/syslog.h> | | 58 | #include <sys/syslog.h> |
59 | #include <sys/sysctl.h> | | 59 | #include <sys/sysctl.h> |
60 | #include <sys/proc.h> | | 60 | #include <sys/proc.h> |
61 | #include <sys/kauth.h> | | 61 | #include <sys/kauth.h> |
62 | | | 62 | |
63 | #include <net/if.h> | | 63 | #include <net/if.h> |
64 | #include <net/route.h> | | 64 | #include <net/route.h> |
65 | | | 65 | |
66 | #include <netinet/in.h> | | 66 | #include <netinet/in.h> |
67 | #include <netinet/in_systm.h> | | 67 | #include <netinet/in_systm.h> |
68 | #include <netinet/ip.h> | | 68 | #include <netinet/ip.h> |
69 | #include <netinet/ip_var.h> | | 69 | #include <netinet/ip_var.h> |
70 | #include <netinet/in_var.h> | | 70 | #include <netinet/in_var.h> |
71 | #include <netinet/udp.h> | | 71 | #include <netinet/udp.h> |
72 | #include <netinet/udp_var.h> | | 72 | #include <netinet/udp_var.h> |
73 | #include <netinet/tcp.h> | | 73 | #include <netinet/tcp.h> |
74 | #include <netinet/udp.h> | | 74 | #include <netinet/udp.h> |
75 | #include <netinet/ip_icmp.h> | | 75 | #include <netinet/ip_icmp.h> |
76 | | | 76 | |
77 | #include <netinet/ip6.h> | | 77 | #include <netinet/ip6.h> |
78 | #ifdef INET6 | | 78 | #ifdef INET6 |
79 | #include <netinet6/ip6_var.h> | | 79 | #include <netinet6/ip6_var.h> |
80 | #endif | | 80 | #endif |
81 | #include <netinet/in_pcb.h> | | 81 | #include <netinet/in_pcb.h> |
82 | #ifdef INET6 | | 82 | #ifdef INET6 |
83 | #include <netinet6/in6_pcb.h> | | 83 | #include <netinet6/in6_pcb.h> |
84 | #include <netinet/icmp6.h> | | 84 | #include <netinet/icmp6.h> |
85 | #endif | | 85 | #endif |
86 | | | 86 | |
87 | #include <netipsec/ipsec.h> | | 87 | #include <netipsec/ipsec.h> |
88 | #include <netipsec/ipsec_var.h> | | 88 | #include <netipsec/ipsec_var.h> |
89 | #include <netipsec/ipsec_private.h> | | 89 | #include <netipsec/ipsec_private.h> |
90 | #ifdef INET6 | | 90 | #ifdef INET6 |
91 | #include <netipsec/ipsec6.h> | | 91 | #include <netipsec/ipsec6.h> |
92 | #endif | | 92 | #endif |
93 | #include <netipsec/ah_var.h> | | 93 | #include <netipsec/ah_var.h> |
94 | #include <netipsec/esp_var.h> | | 94 | #include <netipsec/esp_var.h> |
95 | #include <netipsec/ipcomp.h> /*XXX*/ | | 95 | #include <netipsec/ipcomp.h> /*XXX*/ |
96 | #include <netipsec/ipcomp_var.h> | | 96 | #include <netipsec/ipcomp_var.h> |
97 | | | 97 | |
98 | #include <netipsec/key.h> | | 98 | #include <netipsec/key.h> |
99 | #include <netipsec/keydb.h> | | 99 | #include <netipsec/keydb.h> |
100 | #include <netipsec/key_debug.h> | | 100 | #include <netipsec/key_debug.h> |
101 | | | 101 | |
102 | #include <netipsec/xform.h> | | 102 | #include <netipsec/xform.h> |
103 | | | 103 | |
104 | #include <netipsec/ipsec_osdep.h> | | 104 | #include <netipsec/ipsec_osdep.h> |
105 | | | 105 | |
106 | #include <net/net_osdep.h> | | 106 | #include <net/net_osdep.h> |
107 | | | 107 | |
108 | #ifdef IPSEC_DEBUG | | 108 | #ifdef IPSEC_DEBUG |
109 | int ipsec_debug = 1; | | 109 | int ipsec_debug = 1; |
110 | | | 110 | |
111 | /* | | 111 | /* |
112 | * When set to 1, IPsec will send packets with the same sequence number. | | 112 | * When set to 1, IPsec will send packets with the same sequence number. |
113 | * This allows to verify if the other side has proper replay attacks detection. | | 113 | * This allows to verify if the other side has proper replay attacks detection. |
114 | */ | | 114 | */ |
115 | int ipsec_replay = 0; | | 115 | int ipsec_replay = 0; |
116 | | | 116 | |
117 | /* | | 117 | /* |
118 | * When set 1, IPsec will send packets with corrupted HMAC. | | 118 | * When set 1, IPsec will send packets with corrupted HMAC. |
119 | * This allows to verify if the other side properly detects modified packets. | | 119 | * This allows to verify if the other side properly detects modified packets. |
120 | */ | | 120 | */ |
121 | int ipsec_integrity = 0; | | 121 | int ipsec_integrity = 0; |
122 | #else | | 122 | #else |
123 | int ipsec_debug = 0; | | 123 | int ipsec_debug = 0; |
124 | #endif | | 124 | #endif |
125 | | | 125 | |
126 | percpu_t *ipsecstat_percpu; | | 126 | percpu_t *ipsecstat_percpu; |
127 | int ip4_ah_offsetmask = 0; /* maybe IP_DF? */ | | 127 | int ip4_ah_offsetmask = 0; /* maybe IP_DF? */ |
128 | int ip4_ipsec_dfbit = 2; /* DF bit on encap. 0: clear 1: set 2: copy */ | | 128 | int ip4_ipsec_dfbit = 2; /* DF bit on encap. 0: clear 1: set 2: copy */ |
129 | int ip4_esp_trans_deflev = IPSEC_LEVEL_USE; | | 129 | int ip4_esp_trans_deflev = IPSEC_LEVEL_USE; |
130 | int ip4_esp_net_deflev = IPSEC_LEVEL_USE; | | 130 | int ip4_esp_net_deflev = IPSEC_LEVEL_USE; |
131 | int ip4_ah_trans_deflev = IPSEC_LEVEL_USE; | | 131 | int ip4_ah_trans_deflev = IPSEC_LEVEL_USE; |
132 | int ip4_ah_net_deflev = IPSEC_LEVEL_USE; | | 132 | int ip4_ah_net_deflev = IPSEC_LEVEL_USE; |
133 | struct secpolicy ip4_def_policy; | | 133 | struct secpolicy ip4_def_policy; |
134 | int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ | | 134 | int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ |
135 | int ip4_esp_randpad = -1; | | 135 | int ip4_esp_randpad = -1; |
136 | | | 136 | |
137 | #ifdef __NetBSD__ | | 137 | #ifdef __NetBSD__ |
138 | u_int ipsec_spdgen = 1; /* SPD generation # */ | | 138 | u_int ipsec_spdgen = 1; /* SPD generation # */ |
139 | | | 139 | |
140 | static struct secpolicy *ipsec_checkpcbcache (struct mbuf *, | | 140 | static struct secpolicy *ipsec_checkpcbcache (struct mbuf *, |
141 | struct inpcbpolicy *, int); | | 141 | struct inpcbpolicy *, int); |
142 | static int ipsec_fillpcbcache (struct inpcbpolicy *, struct mbuf *, | | 142 | static int ipsec_fillpcbcache (struct inpcbpolicy *, struct mbuf *, |
143 | struct secpolicy *, int); | | 143 | struct secpolicy *, int); |
144 | static int ipsec_invalpcbcache (struct inpcbpolicy *, int); | | 144 | static int ipsec_invalpcbcache (struct inpcbpolicy *, int); |
145 | #endif /* __NetBSD__ */ | | 145 | #endif /* __NetBSD__ */ |
146 | | | 146 | |
147 | /* | | 147 | /* |
148 | * Crypto support requirements: | | 148 | * Crypto support requirements: |
149 | * | | 149 | * |
150 | * 1 require hardware support | | 150 | * 1 require hardware support |
151 | * -1 require software support | | 151 | * -1 require software support |
152 | * 0 take anything | | 152 | * 0 take anything |
153 | */ | | 153 | */ |
154 | int crypto_support = 0; | | 154 | int crypto_support = 0; |
155 | | | 155 | |
156 | static struct secpolicy *ipsec_getpolicybysock(struct mbuf *, u_int, | | 156 | static struct secpolicy *ipsec_getpolicybysock(struct mbuf *, u_int, |
157 | PCB_T *, int *); | | 157 | PCB_T *, int *); |
158 | | | 158 | |
159 | #ifdef __FreeBSD__ | | 159 | #ifdef __FreeBSD__ |
160 | SYSCTL_DECL(_net_inet_ipsec); | | 160 | SYSCTL_DECL(_net_inet_ipsec); |
161 | | | 161 | |
162 | /* net.inet.ipsec */ | | 162 | /* net.inet.ipsec */ |
163 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, | | 163 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, |
164 | def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); | | 164 | def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); |
165 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, | | 165 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, |
166 | CTLFLAG_RW, &ip4_esp_trans_deflev, 0, ""); | | 166 | CTLFLAG_RW, &ip4_esp_trans_deflev, 0, ""); |
167 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, | | 167 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, |
168 | CTLFLAG_RW, &ip4_esp_net_deflev, 0, ""); | | 168 | CTLFLAG_RW, &ip4_esp_net_deflev, 0, ""); |
169 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, | | 169 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, |
170 | CTLFLAG_RW, &ip4_ah_trans_deflev, 0, ""); | | 170 | CTLFLAG_RW, &ip4_ah_trans_deflev, 0, ""); |
171 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, | | 171 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, |
172 | CTLFLAG_RW, &ip4_ah_net_deflev, 0, ""); | | 172 | CTLFLAG_RW, &ip4_ah_net_deflev, 0, ""); |
173 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, | | 173 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, |
174 | ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, ""); | | 174 | ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, ""); |
175 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, | | 175 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, |
176 | ah_offsetmask, CTLFLAG_RW, &ip4_ah_offsetmask, 0, ""); | | 176 | ah_offsetmask, CTLFLAG_RW, &ip4_ah_offsetmask, 0, ""); |
177 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, | | 177 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, |
178 | dfbit, CTLFLAG_RW, &ip4_ipsec_dfbit, 0, ""); | | 178 | dfbit, CTLFLAG_RW, &ip4_ipsec_dfbit, 0, ""); |
179 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, | | 179 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, |
180 | ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, ""); | | 180 | ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, ""); |
181 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, | | 181 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, |
182 | debug, CTLFLAG_RW, &ipsec_debug, 0, ""); | | 182 | debug, CTLFLAG_RW, &ipsec_debug, 0, ""); |
183 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, | | 183 | SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, |
184 | esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, ""); | | 184 | esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, ""); |
185 | SYSCTL_INT(_net_inet_ipsec, OID_AUTO, | | 185 | SYSCTL_INT(_net_inet_ipsec, OID_AUTO, |
186 | crypto_support, CTLFLAG_RW, &crypto_support,0, ""); | | 186 | crypto_support, CTLFLAG_RW, &crypto_support,0, ""); |
187 | SYSCTL_STRUCT(_net_inet_ipsec, OID_AUTO, | | 187 | SYSCTL_STRUCT(_net_inet_ipsec, OID_AUTO, |
188 | ipsecstats, CTLFLAG_RD, &newipsecstat, newipsecstat, ""); | | 188 | ipsecstats, CTLFLAG_RD, &newipsecstat, newipsecstat, ""); |
189 | SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_replay, CTLFLAG_RW, &ipsec_replay, 0, | | 189 | SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_replay, CTLFLAG_RW, &ipsec_replay, 0, |
190 | "Emulate replay attack"); | | 190 | "Emulate replay attack"); |
191 | SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity, CTLFLAG_RW, | | 191 | SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity, CTLFLAG_RW, |
192 | &ipsec_integrity, 0, "Emulate man-in-the-middle attack"); | | 192 | &ipsec_integrity, 0, "Emulate man-in-the-middle attack"); |
193 | #endif /* __FreeBSD__ */ | | 193 | #endif /* __FreeBSD__ */ |
194 | | | 194 | |
195 | #ifdef INET6 | | 195 | #ifdef INET6 |
196 | int ip6_esp_trans_deflev = IPSEC_LEVEL_USE; | | 196 | int ip6_esp_trans_deflev = IPSEC_LEVEL_USE; |
197 | int ip6_esp_net_deflev = IPSEC_LEVEL_USE; | | 197 | int ip6_esp_net_deflev = IPSEC_LEVEL_USE; |
198 | int ip6_ah_trans_deflev = IPSEC_LEVEL_USE; | | 198 | int ip6_ah_trans_deflev = IPSEC_LEVEL_USE; |
199 | int ip6_ah_net_deflev = IPSEC_LEVEL_USE; | | 199 | int ip6_ah_net_deflev = IPSEC_LEVEL_USE; |
200 | struct secpolicy ip6_def_policy; | | 200 | struct secpolicy ip6_def_policy; |
201 | int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ | | 201 | int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ |
202 | int ip6_esp_randpad = -1; | | 202 | int ip6_esp_randpad = -1; |
203 | | | 203 | |
204 | | | 204 | |
205 | #ifdef __FreeBSD__ | | 205 | #ifdef __FreeBSD__ |
206 | SYSCTL_DECL(_net_inet6_ipsec6); | | 206 | SYSCTL_DECL(_net_inet6_ipsec6); |
207 | | | 207 | |
208 | /* net.inet6.ipsec6 */ | | 208 | /* net.inet6.ipsec6 */ |
209 | #ifdef COMPAT_KAME | | 209 | #ifdef COMPAT_KAME |
210 | SYSCTL_OID(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD, | | 210 | SYSCTL_OID(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD, |
211 | 0,0, compat_ipsecstats_sysctl, "S", ""); | | 211 | 0,0, compat_ipsecstats_sysctl, "S", ""); |
212 | #endif /* COMPAT_KAME */ | | 212 | #endif /* COMPAT_KAME */ |
213 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, | | 213 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, |
214 | def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); | | 214 | def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); |
215 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, | | 215 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, |
216 | CTLFLAG_RW, &ip6_esp_trans_deflev, 0, ""); | | 216 | CTLFLAG_RW, &ip6_esp_trans_deflev, 0, ""); |
217 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, | | 217 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, |
218 | CTLFLAG_RW, &ip6_esp_net_deflev, 0, ""); | | 218 | CTLFLAG_RW, &ip6_esp_net_deflev, 0, ""); |
219 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, | | 219 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, |
220 | CTLFLAG_RW, &ip6_ah_trans_deflev, 0, ""); | | 220 | CTLFLAG_RW, &ip6_ah_trans_deflev, 0, ""); |
221 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, | | 221 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, |
222 | CTLFLAG_RW, &ip6_ah_net_deflev, 0, ""); | | 222 | CTLFLAG_RW, &ip6_ah_net_deflev, 0, ""); |
223 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, | | 223 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, |
224 | ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); | | 224 | ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); |
225 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, | | 225 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, |
226 | debug, CTLFLAG_RW, &ipsec_debug, 0, ""); | | 226 | debug, CTLFLAG_RW, &ipsec_debug, 0, ""); |
227 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, | | 227 | SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, |
228 | esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); | | 228 | esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); |
229 | #endif /* INET6 */ | | 229 | #endif /* INET6 */ |
230 | #endif /* __FreeBSD__ */ | | 230 | #endif /* __FreeBSD__ */ |
231 | | | 231 | |
232 | static int ipsec4_setspidx_inpcb (struct mbuf *, struct inpcb *); | | 232 | static int ipsec4_setspidx_inpcb (struct mbuf *, struct inpcb *); |
233 | #ifdef INET6 | | 233 | #ifdef INET6 |
234 | static int ipsec6_setspidx_in6pcb (struct mbuf *, struct in6pcb *); | | 234 | static int ipsec6_setspidx_in6pcb (struct mbuf *, struct in6pcb *); |
235 | #endif | | 235 | #endif |
236 | static int ipsec_setspidx (struct mbuf *, struct secpolicyindex *, int); | | 236 | static int ipsec_setspidx (struct mbuf *, struct secpolicyindex *, int); |
237 | static void ipsec4_get_ulp (struct mbuf *m, struct secpolicyindex *, int); | | 237 | static void ipsec4_get_ulp (struct mbuf *m, struct secpolicyindex *, int); |
238 | static int ipsec4_setspidx_ipaddr (struct mbuf *, struct secpolicyindex *); | | 238 | static int ipsec4_setspidx_ipaddr (struct mbuf *, struct secpolicyindex *); |
239 | #ifdef INET6 | | 239 | #ifdef INET6 |
240 | static void ipsec6_get_ulp (struct mbuf *m, struct secpolicyindex *, int); | | 240 | static void ipsec6_get_ulp (struct mbuf *m, struct secpolicyindex *, int); |
241 | static int ipsec6_setspidx_ipaddr (struct mbuf *, struct secpolicyindex *); | | 241 | static int ipsec6_setspidx_ipaddr (struct mbuf *, struct secpolicyindex *); |
242 | #endif | | 242 | #endif |
243 | static void ipsec_delpcbpolicy (struct inpcbpolicy *); | | 243 | static void ipsec_delpcbpolicy (struct inpcbpolicy *); |
244 | static struct secpolicy *ipsec_deepcopy_policy (const struct secpolicy *); | | 244 | static struct secpolicy *ipsec_deepcopy_policy (const struct secpolicy *); |
245 | static int ipsec_set_policy (struct secpolicy **,int , void *, size_t , | | 245 | static int ipsec_set_policy (struct secpolicy **,int , void *, size_t , |
246 | kauth_cred_t ); | | 246 | kauth_cred_t ); |
247 | static int ipsec_get_policy (struct secpolicy *, struct mbuf **); | | 247 | static int ipsec_get_policy (struct secpolicy *, struct mbuf **); |
248 | static void vshiftl (unsigned char *, int, int); | | 248 | static void vshiftl (unsigned char *, int, int); |
249 | static size_t ipsec_hdrsiz (struct secpolicy *); | | 249 | static size_t ipsec_hdrsiz (struct secpolicy *); |
250 | | | 250 | |
251 | #ifdef __NetBSD__ | | 251 | #ifdef __NetBSD__ |
252 | /* | | 252 | /* |
253 | * Try to validate and use cached policy on a PCB. | | 253 | * Try to validate and use cached policy on a PCB. |
254 | */ | | 254 | */ |
255 | static struct secpolicy * | | 255 | static struct secpolicy * |
256 | ipsec_checkpcbcache(struct mbuf *m, struct inpcbpolicy *pcbsp, int dir) | | 256 | ipsec_checkpcbcache(struct mbuf *m, struct inpcbpolicy *pcbsp, int dir) |
257 | { | | 257 | { |
258 | struct secpolicyindex spidx; | | 258 | struct secpolicyindex spidx; |
259 | | | 259 | |
260 | switch (dir) { | | 260 | switch (dir) { |
261 | case IPSEC_DIR_INBOUND: | | 261 | case IPSEC_DIR_INBOUND: |
262 | case IPSEC_DIR_OUTBOUND: | | 262 | case IPSEC_DIR_OUTBOUND: |
263 | case IPSEC_DIR_ANY: | | 263 | case IPSEC_DIR_ANY: |
264 | break; | | 264 | break; |
265 | default: | | 265 | default: |
266 | return NULL; | | 266 | return NULL; |
267 | } | | 267 | } |
268 | #ifdef DIAGNOSTIC | | 268 | #ifdef DIAGNOSTIC |
269 | if (pcbsp == NULL) { | | 269 | if (pcbsp == NULL) { |
270 | printf("ipsec_checkpcbcache: NULL pcbsp\n"); | | 270 | printf("ipsec_checkpcbcache: NULL pcbsp\n"); |
271 | /* XXX panic? */ | | 271 | /* XXX panic? */ |
272 | return NULL; | | 272 | return NULL; |
273 | } | | 273 | } |
274 | #endif | | 274 | #endif |
275 | | | 275 | |
276 | #ifdef DIAGNOSTIC | | 276 | #ifdef DIAGNOSTIC |
277 | if (dir >= sizeof(pcbsp->sp_cache)/sizeof(pcbsp->sp_cache[0])) | | 277 | if (dir >= sizeof(pcbsp->sp_cache)/sizeof(pcbsp->sp_cache[0])) |
278 | panic("dir too big in ipsec_checkpcbcache"); | | 278 | panic("dir too big in ipsec_checkpcbcache"); |
279 | #endif | | 279 | #endif |
280 | /* SPD table change invalidate all the caches. */ | | 280 | /* SPD table change invalidate all the caches. */ |
281 | if (ipsec_spdgen != pcbsp->sp_cache[dir].cachegen) { | | 281 | if (ipsec_spdgen != pcbsp->sp_cache[dir].cachegen) { |
282 | ipsec_invalpcbcache(pcbsp, dir); | | 282 | ipsec_invalpcbcache(pcbsp, dir); |
283 | return NULL; | | 283 | return NULL; |
284 | } | | 284 | } |
285 | if (!pcbsp->sp_cache[dir].cachesp) | | 285 | if (!pcbsp->sp_cache[dir].cachesp) |
286 | return NULL; | | 286 | return NULL; |
287 | if (pcbsp->sp_cache[dir].cachesp->state != IPSEC_SPSTATE_ALIVE) { | | 287 | if (pcbsp->sp_cache[dir].cachesp->state != IPSEC_SPSTATE_ALIVE) { |
288 | ipsec_invalpcbcache(pcbsp, dir); | | 288 | ipsec_invalpcbcache(pcbsp, dir); |
289 | return NULL; | | 289 | return NULL; |
290 | } | | 290 | } |
291 | if ((pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) == 0) { | | 291 | if ((pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) == 0) { |
292 | if (!pcbsp->sp_cache[dir].cachesp) | | 292 | if (!pcbsp->sp_cache[dir].cachesp) |
293 | return NULL; | | 293 | return NULL; |
294 | if (ipsec_setspidx(m, &spidx, 1) != 0) | | 294 | if (ipsec_setspidx(m, &spidx, 1) != 0) |
295 | return NULL; | | 295 | return NULL; |
296 | | | 296 | |
297 | /* | | 297 | /* |
298 | * We have to make an exact match here since the cached rule | | 298 | * We have to make an exact match here since the cached rule |
299 | * might have lower priority than a rule that would otherwise | | 299 | * might have lower priority than a rule that would otherwise |
300 | * have matched the packet. | | 300 | * have matched the packet. |
301 | */ | | 301 | */ |
302 | | | 302 | |
303 | if (memcmp(&pcbsp->sp_cache[dir].cacheidx, &spidx, sizeof(spidx))) | | 303 | if (memcmp(&pcbsp->sp_cache[dir].cacheidx, &spidx, sizeof(spidx))) |
304 | return NULL; | | 304 | return NULL; |
305 | | | 305 | |
306 | } else { | | 306 | } else { |
307 | /* | | 307 | /* |
308 | * The pcb is connected, and the L4 code is sure that: | | 308 | * The pcb is connected, and the L4 code is sure that: |
309 | * - outgoing side uses inp_[lf]addr | | 309 | * - outgoing side uses inp_[lf]addr |
310 | * - incoming side looks up policy after inpcb lookup | | 310 | * - incoming side looks up policy after inpcb lookup |
311 | * and address pair is know to be stable. We do not need | | 311 | * and address pair is know to be stable. We do not need |
312 | * to generate spidx again, nor check the address match again. | | 312 | * to generate spidx again, nor check the address match again. |
313 | * | | 313 | * |
314 | * For IPv4/v6 SOCK_STREAM sockets, this assumptions holds | | 314 | * For IPv4/v6 SOCK_STREAM sockets, this assumptions holds |
315 | * and there are calls to ipsec_pcbconn() from in_pcbconnect(). | | 315 | * and there are calls to ipsec_pcbconn() from in_pcbconnect(). |
316 | */ | | 316 | */ |
317 | } | | 317 | } |
318 | | | 318 | |
319 | pcbsp->sp_cache[dir].cachesp->lastused = time_second; | | 319 | pcbsp->sp_cache[dir].cachesp->lastused = time_second; |
320 | pcbsp->sp_cache[dir].cachesp->refcnt++; | | 320 | pcbsp->sp_cache[dir].cachesp->refcnt++; |
321 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, | | 321 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
322 | printf("DP ipsec_checkpcbcache cause refcnt++:%d SP:%p\n", | | 322 | printf("DP ipsec_checkpcbcache cause refcnt++:%d SP:%p\n", |
323 | pcbsp->sp_cache[dir].cachesp->refcnt, | | 323 | pcbsp->sp_cache[dir].cachesp->refcnt, |
324 | pcbsp->sp_cache[dir].cachesp)); | | 324 | pcbsp->sp_cache[dir].cachesp)); |
325 | return pcbsp->sp_cache[dir].cachesp; | | 325 | return pcbsp->sp_cache[dir].cachesp; |
326 | } | | 326 | } |
327 | | | 327 | |
328 | static int | | 328 | static int |
329 | ipsec_fillpcbcache(struct inpcbpolicy *pcbsp, struct mbuf *m, | | 329 | ipsec_fillpcbcache(struct inpcbpolicy *pcbsp, struct mbuf *m, |
330 | struct secpolicy *sp, int dir) | | 330 | struct secpolicy *sp, int dir) |
331 | { | | 331 | { |
332 | | | 332 | |
333 | switch (dir) { | | 333 | switch (dir) { |
334 | case IPSEC_DIR_INBOUND: | | 334 | case IPSEC_DIR_INBOUND: |
335 | case IPSEC_DIR_OUTBOUND: | | 335 | case IPSEC_DIR_OUTBOUND: |
336 | break; | | 336 | break; |
337 | default: | | 337 | default: |
338 | return EINVAL; | | 338 | return EINVAL; |
339 | } | | 339 | } |
340 | #ifdef DIAGNOSTIC | | 340 | #ifdef DIAGNOSTIC |
341 | if (dir >= sizeof(pcbsp->sp_cache)/sizeof(pcbsp->sp_cache[0])) | | 341 | if (dir >= sizeof(pcbsp->sp_cache)/sizeof(pcbsp->sp_cache[0])) |
342 | panic("dir too big in ipsec_fillpcbcache"); | | 342 | panic("dir too big in ipsec_fillpcbcache"); |
343 | #endif | | 343 | #endif |
344 | | | 344 | |
345 | if (pcbsp->sp_cache[dir].cachesp) | | 345 | if (pcbsp->sp_cache[dir].cachesp) |
346 | KEY_FREESP(&pcbsp->sp_cache[dir].cachesp); | | 346 | KEY_FREESP(&pcbsp->sp_cache[dir].cachesp); |
347 | pcbsp->sp_cache[dir].cachesp = NULL; | | 347 | pcbsp->sp_cache[dir].cachesp = NULL; |
348 | pcbsp->sp_cache[dir].cachehint = IPSEC_PCBHINT_MAYBE; | | 348 | pcbsp->sp_cache[dir].cachehint = IPSEC_PCBHINT_MAYBE; |
349 | if (ipsec_setspidx(m, &pcbsp->sp_cache[dir].cacheidx, 1) != 0) { | | 349 | if (ipsec_setspidx(m, &pcbsp->sp_cache[dir].cacheidx, 1) != 0) { |
350 | return EINVAL; | | 350 | return EINVAL; |
351 | } | | 351 | } |
352 | pcbsp->sp_cache[dir].cachesp = sp; | | 352 | pcbsp->sp_cache[dir].cachesp = sp; |
353 | if (pcbsp->sp_cache[dir].cachesp) { | | 353 | if (pcbsp->sp_cache[dir].cachesp) { |
354 | pcbsp->sp_cache[dir].cachesp->refcnt++; | | 354 | pcbsp->sp_cache[dir].cachesp->refcnt++; |
355 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, | | 355 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
356 | printf("DP ipsec_fillpcbcache cause refcnt++:%d SP:%p\n", | | 356 | printf("DP ipsec_fillpcbcache cause refcnt++:%d SP:%p\n", |
357 | pcbsp->sp_cache[dir].cachesp->refcnt, | | 357 | pcbsp->sp_cache[dir].cachesp->refcnt, |
358 | pcbsp->sp_cache[dir].cachesp)); | | 358 | pcbsp->sp_cache[dir].cachesp)); |
359 | | | 359 | |
360 | /* | | 360 | /* |
361 | * If the PCB is connected, we can remember a hint to | | 361 | * If the PCB is connected, we can remember a hint to |
362 | * possibly short-circuit IPsec processing in other places. | | 362 | * possibly short-circuit IPsec processing in other places. |
363 | */ | | 363 | */ |
364 | if (pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) { | | 364 | if (pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) { |
365 | switch (pcbsp->sp_cache[dir].cachesp->policy) { | | 365 | switch (pcbsp->sp_cache[dir].cachesp->policy) { |
366 | case IPSEC_POLICY_NONE: | | 366 | case IPSEC_POLICY_NONE: |
367 | case IPSEC_POLICY_BYPASS: | | 367 | case IPSEC_POLICY_BYPASS: |
368 | pcbsp->sp_cache[dir].cachehint = | | 368 | pcbsp->sp_cache[dir].cachehint = |
369 | IPSEC_PCBHINT_NO; | | 369 | IPSEC_PCBHINT_NO; |
370 | break; | | 370 | break; |
371 | default: | | 371 | default: |
372 | pcbsp->sp_cache[dir].cachehint = | | 372 | pcbsp->sp_cache[dir].cachehint = |
373 | IPSEC_PCBHINT_YES; | | 373 | IPSEC_PCBHINT_YES; |
374 | } | | 374 | } |
375 | } | | 375 | } |
376 | } | | 376 | } |
377 | pcbsp->sp_cache[dir].cachegen = ipsec_spdgen; | | 377 | pcbsp->sp_cache[dir].cachegen = ipsec_spdgen; |
378 | | | 378 | |
379 | return 0; | | 379 | return 0; |
380 | } | | 380 | } |
381 | | | 381 | |
382 | static int | | 382 | static int |
383 | ipsec_invalpcbcache(struct inpcbpolicy *pcbsp, int dir) | | 383 | ipsec_invalpcbcache(struct inpcbpolicy *pcbsp, int dir) |
384 | { | | 384 | { |
385 | int i; | | 385 | int i; |
386 | | | 386 | |
387 | for (i = IPSEC_DIR_INBOUND; i <= IPSEC_DIR_OUTBOUND; i++) { | | 387 | for (i = IPSEC_DIR_INBOUND; i <= IPSEC_DIR_OUTBOUND; i++) { |
388 | if (dir != IPSEC_DIR_ANY && i != dir) | | 388 | if (dir != IPSEC_DIR_ANY && i != dir) |
389 | continue; | | 389 | continue; |
390 | if (pcbsp->sp_cache[i].cachesp) | | 390 | if (pcbsp->sp_cache[i].cachesp) |
391 | KEY_FREESP(&pcbsp->sp_cache[i].cachesp); | | 391 | KEY_FREESP(&pcbsp->sp_cache[i].cachesp); |
392 | pcbsp->sp_cache[i].cachesp = NULL; | | 392 | pcbsp->sp_cache[i].cachesp = NULL; |
393 | pcbsp->sp_cache[i].cachehint = IPSEC_PCBHINT_MAYBE; | | 393 | pcbsp->sp_cache[i].cachehint = IPSEC_PCBHINT_MAYBE; |
394 | pcbsp->sp_cache[i].cachegen = 0; | | 394 | pcbsp->sp_cache[i].cachegen = 0; |
395 | memset(&pcbsp->sp_cache[i].cacheidx, 0, | | 395 | memset(&pcbsp->sp_cache[i].cacheidx, 0, |
396 | sizeof(pcbsp->sp_cache[i].cacheidx)); | | 396 | sizeof(pcbsp->sp_cache[i].cacheidx)); |
397 | } | | 397 | } |
398 | return 0; | | 398 | return 0; |
399 | } | | 399 | } |
400 | | | 400 | |
401 | void | | 401 | void |
402 | ipsec_pcbconn(struct inpcbpolicy *pcbsp) | | 402 | ipsec_pcbconn(struct inpcbpolicy *pcbsp) |
403 | { | | 403 | { |
404 | | | 404 | |
405 | pcbsp->sp_cacheflags |= IPSEC_PCBSP_CONNECTED; | | 405 | pcbsp->sp_cacheflags |= IPSEC_PCBSP_CONNECTED; |
406 | ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY); | | 406 | ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY); |
407 | } | | 407 | } |
408 | | | 408 | |
409 | void | | 409 | void |
410 | ipsec_pcbdisconn(struct inpcbpolicy *pcbsp) | | 410 | ipsec_pcbdisconn(struct inpcbpolicy *pcbsp) |
411 | { | | 411 | { |
412 | | | 412 | |
413 | pcbsp->sp_cacheflags &= ~IPSEC_PCBSP_CONNECTED; | | 413 | pcbsp->sp_cacheflags &= ~IPSEC_PCBSP_CONNECTED; |
414 | ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY); | | 414 | ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY); |
415 | } | | 415 | } |
416 | | | 416 | |
417 | void | | 417 | void |
418 | ipsec_invalpcbcacheall(void) | | 418 | ipsec_invalpcbcacheall(void) |
419 | { | | 419 | { |
420 | | | 420 | |
421 | if (ipsec_spdgen == UINT_MAX) | | 421 | if (ipsec_spdgen == UINT_MAX) |
422 | ipsec_spdgen = 1; | | 422 | ipsec_spdgen = 1; |
423 | else | | 423 | else |
424 | ipsec_spdgen++; | | 424 | ipsec_spdgen++; |
425 | } | | 425 | } |
426 | #endif /* __NetBSD__ */ | | 426 | #endif /* __NetBSD__ */ |
427 | | | 427 | |
428 | /* | | 428 | /* |
429 | * Return a held reference to the default SP. | | 429 | * Return a held reference to the default SP. |
430 | */ | | 430 | */ |
431 | static struct secpolicy * | | 431 | static struct secpolicy * |
432 | key_allocsp_default(int af, const char *where, int tag) | | 432 | key_allocsp_default(int af, const char *where, int tag) |
433 | { | | 433 | { |
434 | struct secpolicy *sp; | | 434 | struct secpolicy *sp; |
435 | | | 435 | |
436 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, | | 436 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
437 | printf("DP key_allocsp_default from %s:%u\n", where, tag)); | | 437 | printf("DP key_allocsp_default from %s:%u\n", where, tag)); |
438 | | | 438 | |
439 | switch(af) { | | 439 | switch(af) { |
440 | case AF_INET: | | 440 | case AF_INET: |
441 | sp = &ip4_def_policy; | | 441 | sp = &ip4_def_policy; |
442 | break; | | 442 | break; |
443 | #ifdef INET6 | | 443 | #ifdef INET6 |
444 | case AF_INET6: | | 444 | case AF_INET6: |
445 | sp = &ip6_def_policy; | | 445 | sp = &ip6_def_policy; |
446 | break; | | 446 | break; |
447 | #endif | | 447 | #endif |
448 | default: | | 448 | default: |
449 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, | | 449 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
450 | printf("key_allocsp_default : unexpected protocol family %u\n", | | 450 | printf("key_allocsp_default : unexpected protocol family %u\n", |
451 | af)); | | 451 | af)); |
452 | return NULL; | | 452 | return NULL; |
453 | } | | 453 | } |
454 | | | 454 | |
455 | if (sp->policy != IPSEC_POLICY_DISCARD && | | 455 | if (sp->policy != IPSEC_POLICY_DISCARD && |
456 | sp->policy != IPSEC_POLICY_NONE) { | | 456 | sp->policy != IPSEC_POLICY_NONE) { |
457 | ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", | | 457 | ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", |
458 | sp->policy, IPSEC_POLICY_NONE)); | | 458 | sp->policy, IPSEC_POLICY_NONE)); |
459 | sp->policy = IPSEC_POLICY_NONE; | | 459 | sp->policy = IPSEC_POLICY_NONE; |
460 | } | | 460 | } |
461 | sp->refcnt++; | | 461 | sp->refcnt++; |
462 | | | 462 | |
463 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, | | 463 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
464 | printf("DP key_allocsp_default returns SP:%p (%u)\n", | | 464 | printf("DP key_allocsp_default returns SP:%p (%u)\n", |
465 | sp, sp->refcnt)); | | 465 | sp, sp->refcnt)); |
466 | return sp; | | 466 | return sp; |
467 | } | | 467 | } |
468 | #define KEY_ALLOCSP_DEFAULT(af) \ | | 468 | #define KEY_ALLOCSP_DEFAULT(af) \ |
469 | key_allocsp_default((af),__FILE__, __LINE__) | | 469 | key_allocsp_default((af),__FILE__, __LINE__) |
470 | | | 470 | |
471 | /* | | 471 | /* |
472 | * For OUTBOUND packet having a socket. Searching SPD for packet, | | 472 | * For OUTBOUND packet having a socket. Searching SPD for packet, |
473 | * and return a pointer to SP. | | 473 | * and return a pointer to SP. |
474 | * OUT: NULL: no apropreate SP found, the following value is set to error. | | 474 | * OUT: NULL: no apropreate SP found, the following value is set to error. |
475 | * 0 : bypass | | 475 | * 0 : bypass |
476 | * EACCES : discard packet. | | 476 | * EACCES : discard packet. |
477 | * ENOENT : ipsec_acquire() in progress, maybe. | | 477 | * ENOENT : ipsec_acquire() in progress, maybe. |
478 | * others : error occurred. | | 478 | * others : error occurred. |
479 | * others: a pointer to SP | | 479 | * others: a pointer to SP |
480 | * | | 480 | * |
481 | * NOTE: IPv6 mapped address concern is implemented here. | | 481 | * NOTE: IPv6 mapped address concern is implemented here. |
482 | */ | | 482 | */ |
483 | struct secpolicy * | | 483 | struct secpolicy * |
484 | ipsec_getpolicy(struct tdb_ident *tdbi, u_int dir) | | 484 | ipsec_getpolicy(struct tdb_ident *tdbi, u_int dir) |
485 | { | | 485 | { |
486 | struct secpolicy *sp; | | 486 | struct secpolicy *sp; |
487 | | | 487 | |
488 | IPSEC_ASSERT(tdbi != NULL, ("ipsec_getpolicy: null tdbi")); | | 488 | IPSEC_ASSERT(tdbi != NULL, ("ipsec_getpolicy: null tdbi")); |
489 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, | | 489 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, |
490 | ("ipsec_getpolicy: invalid direction %u", dir)); | | 490 | ("ipsec_getpolicy: invalid direction %u", dir)); |
491 | | | 491 | |
492 | sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir); | | 492 | sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir); |
493 | if (sp == NULL) /*XXX????*/ | | 493 | if (sp == NULL) /*XXX????*/ |
494 | sp = KEY_ALLOCSP_DEFAULT(tdbi->dst.sa.sa_family); | | 494 | sp = KEY_ALLOCSP_DEFAULT(tdbi->dst.sa.sa_family); |
495 | IPSEC_ASSERT(sp != NULL, ("ipsec_getpolicy: null SP")); | | 495 | IPSEC_ASSERT(sp != NULL, ("ipsec_getpolicy: null SP")); |
496 | return sp; | | 496 | return sp; |
497 | } | | 497 | } |
498 | | | 498 | |
499 | /* | | 499 | /* |
500 | * For OUTBOUND packet having a socket. Searching SPD for packet, | | 500 | * For OUTBOUND packet having a socket. Searching SPD for packet, |
501 | * and return a pointer to SP. | | 501 | * and return a pointer to SP. |
502 | * OUT: NULL: no apropreate SP found, the following value is set to error. | | 502 | * OUT: NULL: no apropreate SP found, the following value is set to error. |
503 | * 0 : bypass | | 503 | * 0 : bypass |
504 | * EACCES : discard packet. | | 504 | * EACCES : discard packet. |
505 | * ENOENT : ipsec_acquire() in progress, maybe. | | 505 | * ENOENT : ipsec_acquire() in progress, maybe. |
506 | * others : error occurred. | | 506 | * others : error occurred. |
507 | * others: a pointer to SP | | 507 | * others: a pointer to SP |
508 | * | | 508 | * |
509 | * NOTE: IPv6 mapped address concern is implemented here. | | 509 | * NOTE: IPv6 mapped address concern is implemented here. |
510 | */ | | 510 | */ |
511 | static struct secpolicy * | | 511 | static struct secpolicy * |
512 | ipsec_getpolicybysock(struct mbuf *m, u_int dir, PCB_T *inp, int *error) | | 512 | ipsec_getpolicybysock(struct mbuf *m, u_int dir, PCB_T *inp, int *error) |
513 | { | | 513 | { |
514 | struct inpcbpolicy *pcbsp = NULL; | | 514 | struct inpcbpolicy *pcbsp = NULL; |
515 | struct secpolicy *currsp = NULL; /* policy on socket */ | | 515 | struct secpolicy *currsp = NULL; /* policy on socket */ |
516 | struct secpolicy *sp; | | 516 | struct secpolicy *sp; |
517 | int af; | | 517 | int af; |
518 | | | 518 | |
519 | IPSEC_ASSERT(m != NULL, ("ipsec_getpolicybysock: null mbuf")); | | 519 | IPSEC_ASSERT(m != NULL, ("ipsec_getpolicybysock: null mbuf")); |
520 | IPSEC_ASSERT(inp != NULL, ("ipsec_getpolicybysock: null inpcb")); | | 520 | IPSEC_ASSERT(inp != NULL, ("ipsec_getpolicybysock: null inpcb")); |
521 | IPSEC_ASSERT(error != NULL, ("ipsec_getpolicybysock: null error")); | | 521 | IPSEC_ASSERT(error != NULL, ("ipsec_getpolicybysock: null error")); |
522 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, | | 522 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, |
523 | ("ipsec_getpolicybysock: invalid direction %u", dir)); | | 523 | ("ipsec_getpolicybysock: invalid direction %u", dir)); |
524 | | | 524 | |
525 | IPSEC_ASSERT(PCB_SOCKET(inp) != NULL, | | 525 | IPSEC_ASSERT(PCB_SOCKET(inp) != NULL, |
526 | ("ipsec_getppolicybysock: null socket\n")); | | 526 | ("ipsec_getppolicybysock: null socket\n")); |
527 | | | 527 | |
528 | /* XXX FIXME inpcb/in6pcb vs socket*/ | | 528 | /* XXX FIXME inpcb/in6pcb vs socket*/ |
529 | af = PCB_FAMILY(inp); | | 529 | af = PCB_FAMILY(inp); |
530 | IPSEC_ASSERT(af == AF_INET || af == AF_INET6, | | 530 | IPSEC_ASSERT(af == AF_INET || af == AF_INET6, |
531 | ("ipsec_getpolicybysock: unexpected protocol family %u", af)); | | 531 | ("ipsec_getpolicybysock: unexpected protocol family %u", af)); |
532 | | | 532 | |
533 | #ifdef __NetBSD__ | | 533 | #ifdef __NetBSD__ |
534 | IPSEC_ASSERT(inp->inph_sp != NULL, ("null PCB policy cache")); | | 534 | IPSEC_ASSERT(inp->inph_sp != NULL, ("null PCB policy cache")); |
535 | /* If we have a cached entry, and if it is still valid, use it. */ | | 535 | /* If we have a cached entry, and if it is still valid, use it. */ |
536 | IPSEC_STATINC(IPSEC_STAT_SPDCACHELOOKUP); | | 536 | IPSEC_STATINC(IPSEC_STAT_SPDCACHELOOKUP); |
537 | currsp = ipsec_checkpcbcache(m, /*inpcb_hdr*/inp->inph_sp, dir); | | 537 | currsp = ipsec_checkpcbcache(m, /*inpcb_hdr*/inp->inph_sp, dir); |
538 | if (currsp) { | | 538 | if (currsp) { |
539 | *error = 0; | | 539 | *error = 0; |
540 | return currsp; | | 540 | return currsp; |
541 | } | | 541 | } |
542 | IPSEC_STATINC(IPSEC_STAT_SPDCACHEMISS); | | 542 | IPSEC_STATINC(IPSEC_STAT_SPDCACHEMISS); |
543 | #endif /* __NetBSD__ */ | | 543 | #endif /* __NetBSD__ */ |
544 | | | 544 | |
545 | switch (af) { | | 545 | switch (af) { |
546 | case AF_INET: { | | 546 | case AF_INET: { |
547 | struct inpcb *in4p = PCB_TO_IN4PCB(inp); | | 547 | struct inpcb *in4p = PCB_TO_IN4PCB(inp); |
548 | /* set spidx in pcb */ | | 548 | /* set spidx in pcb */ |
549 | *error = ipsec4_setspidx_inpcb(m, in4p); | | 549 | *error = ipsec4_setspidx_inpcb(m, in4p); |
550 | pcbsp = in4p->inp_sp; | | 550 | pcbsp = in4p->inp_sp; |
551 | break; | | 551 | break; |
552 | } | | 552 | } |
553 | | | 553 | |
554 | #if defined(INET6) | | 554 | #if defined(INET6) |
555 | case AF_INET6: { | | 555 | case AF_INET6: { |
556 | struct in6pcb *in6p = PCB_TO_IN6PCB(inp); | | 556 | struct in6pcb *in6p = PCB_TO_IN6PCB(inp); |
557 | /* set spidx in pcb */ | | 557 | /* set spidx in pcb */ |
558 | *error = ipsec6_setspidx_in6pcb(m, in6p); | | 558 | *error = ipsec6_setspidx_in6pcb(m, in6p); |
559 | pcbsp = in6p->in6p_sp; | | 559 | pcbsp = in6p->in6p_sp; |
560 | break; | | 560 | break; |
561 | } | | 561 | } |
562 | #endif | | 562 | #endif |
563 | default: | | 563 | default: |
564 | *error = EPFNOSUPPORT; | | 564 | *error = EPFNOSUPPORT; |
565 | break; | | 565 | break; |
566 | } | | 566 | } |
567 | if (*error) | | 567 | if (*error) |
568 | return NULL; | | 568 | return NULL; |
569 | | | 569 | |
570 | IPSEC_ASSERT(pcbsp != NULL, ("ipsec_getpolicybysock: null pcbsp")); | | 570 | IPSEC_ASSERT(pcbsp != NULL, ("ipsec_getpolicybysock: null pcbsp")); |
571 | switch (dir) { | | 571 | switch (dir) { |
572 | case IPSEC_DIR_INBOUND: | | 572 | case IPSEC_DIR_INBOUND: |
573 | currsp = pcbsp->sp_in; | | 573 | currsp = pcbsp->sp_in; |
574 | break; | | 574 | break; |
575 | case IPSEC_DIR_OUTBOUND: | | 575 | case IPSEC_DIR_OUTBOUND: |
576 | currsp = pcbsp->sp_out; | | 576 | currsp = pcbsp->sp_out; |
577 | break; | | 577 | break; |
578 | } | | 578 | } |
579 | IPSEC_ASSERT(currsp != NULL, ("ipsec_getpolicybysock: null currsp")); | | 579 | IPSEC_ASSERT(currsp != NULL, ("ipsec_getpolicybysock: null currsp")); |
580 | | | 580 | |
581 | if (pcbsp->priv) { /* when privilieged socket */ | | 581 | if (pcbsp->priv) { /* when privilieged socket */ |
582 | switch (currsp->policy) { | | 582 | switch (currsp->policy) { |
583 | case IPSEC_POLICY_BYPASS: | | 583 | case IPSEC_POLICY_BYPASS: |
584 | case IPSEC_POLICY_IPSEC: | | 584 | case IPSEC_POLICY_IPSEC: |
585 | currsp->refcnt++; | | 585 | currsp->refcnt++; |
586 | sp = currsp; | | 586 | sp = currsp; |
587 | break; | | 587 | break; |
588 | | | 588 | |
589 | case IPSEC_POLICY_ENTRUST: | | 589 | case IPSEC_POLICY_ENTRUST: |
590 | /* look for a policy in SPD */ | | 590 | /* look for a policy in SPD */ |
591 | sp = KEY_ALLOCSP(&currsp->spidx, dir); | | 591 | sp = KEY_ALLOCSP(&currsp->spidx, dir); |
592 | if (sp == NULL) /* no SP found */ | | 592 | if (sp == NULL) /* no SP found */ |
593 | sp = KEY_ALLOCSP_DEFAULT(af); | | 593 | sp = KEY_ALLOCSP_DEFAULT(af); |
594 | break; | | 594 | break; |
595 | | | 595 | |
596 | default: | | 596 | default: |
597 | ipseclog((LOG_ERR, "ipsec_getpolicybysock: " | | 597 | ipseclog((LOG_ERR, "ipsec_getpolicybysock: " |
598 | "Invalid policy for PCB %d\n", currsp->policy)); | | 598 | "Invalid policy for PCB %d\n", currsp->policy)); |
599 | *error = EINVAL; | | 599 | *error = EINVAL; |
600 | return NULL; | | 600 | return NULL; |
601 | } | | 601 | } |
602 | } else { /* unpriv, SPD has policy */ | | 602 | } else { /* unpriv, SPD has policy */ |
603 | sp = KEY_ALLOCSP(&currsp->spidx, dir); | | 603 | sp = KEY_ALLOCSP(&currsp->spidx, dir); |
604 | if (sp == NULL) { /* no SP found */ | | 604 | if (sp == NULL) { /* no SP found */ |
605 | switch (currsp->policy) { | | 605 | switch (currsp->policy) { |
606 | case IPSEC_POLICY_BYPASS: | | 606 | case IPSEC_POLICY_BYPASS: |
607 | ipseclog((LOG_ERR, "ipsec_getpolicybysock: " | | 607 | ipseclog((LOG_ERR, "ipsec_getpolicybysock: " |
608 | "Illegal policy for non-priviliged defined %d\n", | | 608 | "Illegal policy for non-priviliged defined %d\n", |
609 | currsp->policy)); | | 609 | currsp->policy)); |
610 | *error = EINVAL; | | 610 | *error = EINVAL; |
611 | return NULL; | | 611 | return NULL; |
612 | | | 612 | |
613 | case IPSEC_POLICY_ENTRUST: | | 613 | case IPSEC_POLICY_ENTRUST: |
614 | sp = KEY_ALLOCSP_DEFAULT(af); | | 614 | sp = KEY_ALLOCSP_DEFAULT(af); |
615 | break; | | 615 | break; |
616 | | | 616 | |
617 | case IPSEC_POLICY_IPSEC: | | 617 | case IPSEC_POLICY_IPSEC: |
618 | currsp->refcnt++; | | 618 | currsp->refcnt++; |
619 | sp = currsp; | | 619 | sp = currsp; |
620 | break; | | 620 | break; |
621 | | | 621 | |
622 | default: | | 622 | default: |
623 | ipseclog((LOG_ERR, "ipsec_getpolicybysock: " | | 623 | ipseclog((LOG_ERR, "ipsec_getpolicybysock: " |
624 | "Invalid policy for PCB %d\n", currsp->policy)); | | 624 | "Invalid policy for PCB %d\n", currsp->policy)); |
625 | *error = EINVAL; | | 625 | *error = EINVAL; |
626 | return NULL; | | 626 | return NULL; |
627 | } | | 627 | } |
628 | } | | 628 | } |
629 | } | | 629 | } |
630 | IPSEC_ASSERT(sp != NULL, | | 630 | IPSEC_ASSERT(sp != NULL, |
631 | ("ipsec_getpolicybysock: null SP (priv %u policy %u", | | 631 | ("ipsec_getpolicybysock: null SP (priv %u policy %u", |
632 | pcbsp->priv, currsp->policy)); | | 632 | pcbsp->priv, currsp->policy)); |
633 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, | | 633 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
634 | printf("DP ipsec_getpolicybysock (priv %u policy %u) allocates " | | 634 | printf("DP ipsec_getpolicybysock (priv %u policy %u) allocates " |
635 | "SP:%p (refcnt %u)\n", pcbsp->priv, currsp->policy, | | 635 | "SP:%p (refcnt %u)\n", pcbsp->priv, currsp->policy, |
636 | sp, sp->refcnt)); | | 636 | sp, sp->refcnt)); |
637 | #ifdef __NetBSD__ | | 637 | #ifdef __NetBSD__ |
638 | ipsec_fillpcbcache(pcbsp, m, sp, dir); | | 638 | ipsec_fillpcbcache(pcbsp, m, sp, dir); |
639 | #endif /* __NetBSD__ */ | | 639 | #endif /* __NetBSD__ */ |
640 | return sp; | | 640 | return sp; |
641 | } | | 641 | } |
642 | | | 642 | |
643 | /* | | 643 | /* |
644 | * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, | | 644 | * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, |
645 | * and return a pointer to SP. | | 645 | * and return a pointer to SP. |
646 | * OUT: positive: a pointer to the entry for security policy leaf matched. | | 646 | * OUT: positive: a pointer to the entry for security policy leaf matched. |
647 | * NULL: no apropreate SP found, the following value is set to error. | | 647 | * NULL: no apropreate SP found, the following value is set to error. |
648 | * 0 : bypass | | 648 | * 0 : bypass |
649 | * EACCES : discard packet. | | 649 | * EACCES : discard packet. |
650 | * ENOENT : ipsec_acquire() in progress, maybe. | | 650 | * ENOENT : ipsec_acquire() in progress, maybe. |
651 | * others : error occurred. | | 651 | * others : error occurred. |
652 | */ | | 652 | */ |
653 | struct secpolicy * | | 653 | struct secpolicy * |
654 | ipsec_getpolicybyaddr(struct mbuf *m, u_int dir, int flag, int *error) | | 654 | ipsec_getpolicybyaddr(struct mbuf *m, u_int dir, int flag, int *error) |
655 | { | | 655 | { |
656 | struct secpolicyindex spidx; | | 656 | struct secpolicyindex spidx; |
657 | struct secpolicy *sp; | | 657 | struct secpolicy *sp; |
658 | | | 658 | |
659 | IPSEC_ASSERT(m != NULL, ("ipsec_getpolicybyaddr: null mbuf")); | | 659 | IPSEC_ASSERT(m != NULL, ("ipsec_getpolicybyaddr: null mbuf")); |
660 | IPSEC_ASSERT(error != NULL, ("ipsec_getpolicybyaddr: null error")); | | 660 | IPSEC_ASSERT(error != NULL, ("ipsec_getpolicybyaddr: null error")); |
661 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, | | 661 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, |
662 | ("ipsec4_getpolicybaddr: invalid direction %u", dir)); | | 662 | ("ipsec4_getpolicybaddr: invalid direction %u", dir)); |
663 | | | 663 | |
664 | sp = NULL; | | 664 | sp = NULL; |
665 | | | 665 | |
666 | /* Make an index to look for a policy. */ | | 666 | /* Make an index to look for a policy. */ |
667 | *error = ipsec_setspidx(m, &spidx, (flag & IP_FORWARDING) ? 0 : 1); | | 667 | *error = ipsec_setspidx(m, &spidx, (flag & IP_FORWARDING) ? 0 : 1); |
668 | if (*error != 0) { | | 668 | if (*error != 0) { |
669 | DPRINTF(("ipsec_getpolicybyaddr: setpidx failed," | | 669 | DPRINTF(("ipsec_getpolicybyaddr: setpidx failed," |
670 | " dir %u flag %u\n", dir, flag)); | | 670 | " dir %u flag %u\n", dir, flag)); |
671 | memset(&spidx, 0, sizeof (spidx)); | | 671 | memset(&spidx, 0, sizeof (spidx)); |
672 | return NULL; | | 672 | return NULL; |
673 | } | | 673 | } |
674 | | | 674 | |
675 | spidx.dir = dir; | | 675 | spidx.dir = dir; |
676 | | | 676 | |
677 | if (key_havesp(dir)) { | | 677 | if (key_havesp(dir)) { |
678 | sp = KEY_ALLOCSP(&spidx, dir); | | 678 | sp = KEY_ALLOCSP(&spidx, dir); |
679 | } | | 679 | } |
680 | | | 680 | |
681 | if (sp == NULL) /* no SP found, use system default */ | | 681 | if (sp == NULL) /* no SP found, use system default */ |
682 | sp = KEY_ALLOCSP_DEFAULT(spidx.dst.sa.sa_family); | | 682 | sp = KEY_ALLOCSP_DEFAULT(spidx.dst.sa.sa_family); |
683 | IPSEC_ASSERT(sp != NULL, ("ipsec_getpolicybyaddr: null SP")); | | 683 | IPSEC_ASSERT(sp != NULL, ("ipsec_getpolicybyaddr: null SP")); |
684 | return sp; | | 684 | return sp; |
685 | } | | 685 | } |
686 | | | 686 | |
687 | struct secpolicy * | | 687 | struct secpolicy * |
688 | ipsec4_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error, | | 688 | ipsec4_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error, |
689 | struct inpcb *inp) | | 689 | struct inpcb *inp) |
690 | { | | 690 | { |
691 | struct secpolicy *sp; | | 691 | struct secpolicy *sp; |
692 | | | 692 | |
693 | *error = 0; | | 693 | *error = 0; |
694 | | | 694 | |
695 | | | 695 | |
696 | /* XXX KAME IPv6 calls us with non-null inp but bogus inp_socket? */ | | 696 | /* XXX KAME IPv6 calls us with non-null inp but bogus inp_socket? */ |
697 | if (inp == NULL || inp->inp_socket == NULL) { | | 697 | if (inp == NULL || inp->inp_socket == NULL) { |
698 | sp = ipsec_getpolicybyaddr(m, dir, flag, error); | | 698 | sp = ipsec_getpolicybyaddr(m, dir, flag, error); |
699 | } else | | 699 | } else |
700 | sp = ipsec_getpolicybysock(m, dir, IN4PCB_TO_PCB(inp), error); | | 700 | sp = ipsec_getpolicybysock(m, dir, IN4PCB_TO_PCB(inp), error); |
701 | if (sp == NULL) { | | 701 | if (sp == NULL) { |
702 | IPSEC_ASSERT(*error != 0, | | 702 | IPSEC_ASSERT(*error != 0, |
703 | ("ipsec4_checkpolicy: getpolicy failed w/o error")); | | 703 | ("ipsec4_checkpolicy: getpolicy failed w/o error")); |
704 | IPSEC_STATINC(IPSEC_STAT_OUT_INVAL); | | 704 | IPSEC_STATINC(IPSEC_STAT_OUT_INVAL); |
705 | return NULL; | | 705 | return NULL; |
706 | } | | 706 | } |
707 | IPSEC_ASSERT(*error == 0, | | 707 | IPSEC_ASSERT(*error == 0, |
708 | ("ipsec4_checkpolicy: sp w/ error set to %u", *error)); | | 708 | ("ipsec4_checkpolicy: sp w/ error set to %u", *error)); |
709 | switch (sp->policy) { | | 709 | switch (sp->policy) { |
710 | case IPSEC_POLICY_ENTRUST: | | 710 | case IPSEC_POLICY_ENTRUST: |
711 | default: | | 711 | default: |
712 | printf("ipsec4_checkpolicy: invalid policy %u\n", sp->policy); | | 712 | printf("ipsec4_checkpolicy: invalid policy %u\n", sp->policy); |
713 | /* fall thru... */ | | 713 | /* fall thru... */ |
714 | case IPSEC_POLICY_DISCARD: | | 714 | case IPSEC_POLICY_DISCARD: |
715 | IPSEC_STATINC(IPSEC_STAT_OUT_POLVIO); | | 715 | IPSEC_STATINC(IPSEC_STAT_OUT_POLVIO); |
716 | *error = -EINVAL; /* packet is discarded by caller */ | | 716 | *error = -EINVAL; /* packet is discarded by caller */ |
717 | break; | | 717 | break; |
718 | case IPSEC_POLICY_BYPASS: | | 718 | case IPSEC_POLICY_BYPASS: |
719 | case IPSEC_POLICY_NONE: | | 719 | case IPSEC_POLICY_NONE: |
720 | KEY_FREESP(&sp); | | 720 | KEY_FREESP(&sp); |
721 | sp = NULL; /* NB: force NULL result */ | | 721 | sp = NULL; /* NB: force NULL result */ |
722 | break; | | 722 | break; |
723 | case IPSEC_POLICY_IPSEC: | | 723 | case IPSEC_POLICY_IPSEC: |
724 | if (sp->req == NULL) /* acquire an SA */ | | 724 | if (sp->req == NULL) /* acquire an SA */ |
725 | *error = key_spdacquire(sp); | | 725 | *error = key_spdacquire(sp); |
726 | break; | | 726 | break; |
727 | } | | 727 | } |
728 | if (*error != 0) { | | 728 | if (*error != 0) { |
729 | KEY_FREESP(&sp); | | 729 | KEY_FREESP(&sp); |
730 | sp = NULL; | | 730 | sp = NULL; |
731 | DPRINTF(("%s: done, error %d\n", __func__, *error)); | | 731 | DPRINTF(("%s: done, error %d\n", __func__, *error)); |
732 | } | | 732 | } |
733 | return sp; | | 733 | return sp; |
734 | } | | 734 | } |
735 | | | 735 | |
736 | #ifdef INET6 | | 736 | #ifdef INET6 |
737 | struct secpolicy * | | 737 | struct secpolicy * |
738 | ipsec6_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error, | | 738 | ipsec6_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error, |
739 | struct in6pcb *in6p) | | 739 | struct in6pcb *in6p) |
740 | { | | 740 | { |
741 | struct secpolicy *sp; | | 741 | struct secpolicy *sp; |
742 | | | 742 | |
743 | *error = 0; | | 743 | *error = 0; |
744 | | | 744 | |
745 | | | 745 | |
746 | /* XXX KAME IPv6 calls us with non-null inp but bogus inp_socket? */ | | 746 | /* XXX KAME IPv6 calls us with non-null inp but bogus inp_socket? */ |
747 | if (in6p == NULL || in6p->in6p_socket == NULL) { | | 747 | if (in6p == NULL || in6p->in6p_socket == NULL) { |
748 | sp = ipsec_getpolicybyaddr(m, dir, flag, error); | | 748 | sp = ipsec_getpolicybyaddr(m, dir, flag, error); |
749 | } else | | 749 | } else |
750 | sp = ipsec_getpolicybysock(m, dir, IN6PCB_TO_PCB(in6p), error); | | 750 | sp = ipsec_getpolicybysock(m, dir, IN6PCB_TO_PCB(in6p), error); |
751 | if (sp == NULL) { | | 751 | if (sp == NULL) { |
752 | IPSEC_ASSERT(*error != 0, | | 752 | IPSEC_ASSERT(*error != 0, |
753 | ("ipsec6_checkpolicy: getpolicy failed w/o error")); | | 753 | ("ipsec6_checkpolicy: getpolicy failed w/o error")); |
754 | IPSEC_STATINC(IPSEC_STAT_OUT_INVAL); | | 754 | IPSEC_STATINC(IPSEC_STAT_OUT_INVAL); |
755 | return NULL; | | 755 | return NULL; |
756 | } | | 756 | } |
757 | IPSEC_ASSERT(*error == 0, | | 757 | IPSEC_ASSERT(*error == 0, |
758 | ("ipsec6_checkpolicy: sp w/ error set to %u", *error)); | | 758 | ("ipsec6_checkpolicy: sp w/ error set to %u", *error)); |
759 | switch (sp->policy) { | | 759 | switch (sp->policy) { |
760 | case IPSEC_POLICY_ENTRUST: | | 760 | case IPSEC_POLICY_ENTRUST: |
761 | default: | | 761 | default: |
762 | printf("ipsec6_checkpolicy: invalid policy %u\n", sp->policy); | | 762 | printf("ipsec6_checkpolicy: invalid policy %u\n", sp->policy); |
763 | /* fall thru... */ | | 763 | /* fall thru... */ |
764 | case IPSEC_POLICY_DISCARD: | | 764 | case IPSEC_POLICY_DISCARD: |
765 | IPSEC_STATINC(IPSEC_STAT_OUT_POLVIO); | | 765 | IPSEC_STATINC(IPSEC_STAT_OUT_POLVIO); |
766 | *error = -EINVAL; /* packet is discarded by caller */ | | 766 | *error = -EINVAL; /* packet is discarded by caller */ |
767 | break; | | 767 | break; |
768 | case IPSEC_POLICY_BYPASS: | | 768 | case IPSEC_POLICY_BYPASS: |
769 | case IPSEC_POLICY_NONE: | | 769 | case IPSEC_POLICY_NONE: |
770 | KEY_FREESP(&sp); | | 770 | KEY_FREESP(&sp); |
771 | sp = NULL; /* NB: force NULL result */ | | 771 | sp = NULL; /* NB: force NULL result */ |
772 | break; | | 772 | break; |
773 | case IPSEC_POLICY_IPSEC: | | 773 | case IPSEC_POLICY_IPSEC: |
774 | if (sp->req == NULL) /* acquire an SA */ | | 774 | if (sp->req == NULL) /* acquire an SA */ |
775 | *error = key_spdacquire(sp); | | 775 | *error = key_spdacquire(sp); |
776 | break; | | 776 | break; |
777 | } | | 777 | } |
778 | if (*error != 0) { | | 778 | if (*error != 0) { |
779 | KEY_FREESP(&sp); | | 779 | KEY_FREESP(&sp); |
780 | sp = NULL; | | 780 | sp = NULL; |
781 | DPRINTF(("%s: done, error %d\n", __func__, *error)); | | 781 | DPRINTF(("%s: done, error %d\n", __func__, *error)); |
782 | } | | 782 | } |
783 | return sp; | | 783 | return sp; |
784 | } | | 784 | } |
785 | #endif /* INET6 */ | | 785 | #endif /* INET6 */ |
786 | | | 786 | |
787 | static int | | 787 | static int |
788 | ipsec4_setspidx_inpcb(struct mbuf *m ,struct inpcb *pcb) | | 788 | ipsec4_setspidx_inpcb(struct mbuf *m ,struct inpcb *pcb) |
789 | { | | 789 | { |
790 | int error; | | 790 | int error; |
791 | | | 791 | |
792 | IPSEC_ASSERT(pcb != NULL, ("ipsec4_setspidx_inpcb: null pcb")); | | 792 | IPSEC_ASSERT(pcb != NULL, ("ipsec4_setspidx_inpcb: null pcb")); |
793 | IPSEC_ASSERT(pcb->inp_sp != NULL, ("ipsec4_setspidx_inpcb: null inp_sp")); | | 793 | IPSEC_ASSERT(pcb->inp_sp != NULL, ("ipsec4_setspidx_inpcb: null inp_sp")); |
794 | IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL, | | 794 | IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL, |
795 | ("ipsec4_setspidx_inpcb: null sp_in || sp_out")); | | 795 | ("ipsec4_setspidx_inpcb: null sp_in || sp_out")); |
796 | | | 796 | |
797 | error = ipsec_setspidx(m, &pcb->inp_sp->sp_in->spidx, 1); | | 797 | error = ipsec_setspidx(m, &pcb->inp_sp->sp_in->spidx, 1); |
798 | if (error == 0) { | | 798 | if (error == 0) { |
799 | pcb->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; | | 799 | pcb->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; |
800 | pcb->inp_sp->sp_out->spidx = pcb->inp_sp->sp_in->spidx; | | 800 | pcb->inp_sp->sp_out->spidx = pcb->inp_sp->sp_in->spidx; |
801 | pcb->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; | | 801 | pcb->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; |
802 | } else { | | 802 | } else { |
803 | memset(&pcb->inp_sp->sp_in->spidx, 0, | | 803 | memset(&pcb->inp_sp->sp_in->spidx, 0, |
804 | sizeof (pcb->inp_sp->sp_in->spidx)); | | 804 | sizeof (pcb->inp_sp->sp_in->spidx)); |
805 | memset(&pcb->inp_sp->sp_out->spidx, 0, | | 805 | memset(&pcb->inp_sp->sp_out->spidx, 0, |
806 | sizeof (pcb->inp_sp->sp_in->spidx)); | | 806 | sizeof (pcb->inp_sp->sp_in->spidx)); |
807 | } | | 807 | } |
808 | return error; | | 808 | return error; |
809 | } | | 809 | } |
810 | | | 810 | |
811 | #ifdef INET6 | | 811 | #ifdef INET6 |
812 | static int | | 812 | static int |
813 | ipsec6_setspidx_in6pcb(struct mbuf *m, struct in6pcb *pcb) | | 813 | ipsec6_setspidx_in6pcb(struct mbuf *m, struct in6pcb *pcb) |
814 | { | | 814 | { |
815 | struct secpolicyindex *spidx; | | 815 | struct secpolicyindex *spidx; |
816 | int error; | | 816 | int error; |
817 | | | 817 | |
818 | IPSEC_ASSERT(pcb != NULL, ("ipsec6_setspidx_in6pcb: null pcb")); | | 818 | IPSEC_ASSERT(pcb != NULL, ("ipsec6_setspidx_in6pcb: null pcb")); |
819 | IPSEC_ASSERT(pcb->in6p_sp != NULL, ("ipsec6_setspidx_in6pcb: null inp_sp")); | | 819 | IPSEC_ASSERT(pcb->in6p_sp != NULL, ("ipsec6_setspidx_in6pcb: null inp_sp")); |
820 | IPSEC_ASSERT(pcb->in6p_sp->sp_out != NULL && pcb->in6p_sp->sp_in != NULL, | | 820 | IPSEC_ASSERT(pcb->in6p_sp->sp_out != NULL && pcb->in6p_sp->sp_in != NULL, |
821 | ("ipsec6_setspidx_in6pcb: null sp_in || sp_out")); | | 821 | ("ipsec6_setspidx_in6pcb: null sp_in || sp_out")); |
822 | | | 822 | |
823 | memset(&pcb->in6p_sp->sp_in->spidx, 0, sizeof(*spidx)); | | 823 | memset(&pcb->in6p_sp->sp_in->spidx, 0, sizeof(*spidx)); |
824 | memset(&pcb->in6p_sp->sp_out->spidx, 0, sizeof(*spidx)); | | 824 | memset(&pcb->in6p_sp->sp_out->spidx, 0, sizeof(*spidx)); |
825 | | | 825 | |
826 | spidx = &pcb->in6p_sp->sp_in->spidx; | | 826 | spidx = &pcb->in6p_sp->sp_in->spidx; |
827 | error = ipsec_setspidx(m, spidx, 1); | | 827 | error = ipsec_setspidx(m, spidx, 1); |
828 | if (error) | | 828 | if (error) |
829 | goto bad; | | 829 | goto bad; |
830 | spidx->dir = IPSEC_DIR_INBOUND; | | 830 | spidx->dir = IPSEC_DIR_INBOUND; |
831 | | | 831 | |
832 | spidx = &pcb->in6p_sp->sp_out->spidx; | | 832 | spidx = &pcb->in6p_sp->sp_out->spidx; |
833 | error = ipsec_setspidx(m, spidx, 1); | | 833 | error = ipsec_setspidx(m, spidx, 1); |
834 | if (error) | | 834 | if (error) |
835 | goto bad; | | 835 | goto bad; |
836 | spidx->dir = IPSEC_DIR_OUTBOUND; | | 836 | spidx->dir = IPSEC_DIR_OUTBOUND; |
837 | | | 837 | |
838 | return 0; | | 838 | return 0; |
839 | | | 839 | |
840 | bad: | | 840 | bad: |
841 | memset(&pcb->in6p_sp->sp_in->spidx, 0, sizeof(*spidx)); | | 841 | memset(&pcb->in6p_sp->sp_in->spidx, 0, sizeof(*spidx)); |
842 | memset(&pcb->in6p_sp->sp_out->spidx, 0, sizeof(*spidx)); | | 842 | memset(&pcb->in6p_sp->sp_out->spidx, 0, sizeof(*spidx)); |
843 | return error; | | 843 | return error; |
844 | } | | 844 | } |
845 | #endif | | 845 | #endif |
846 | | | 846 | |
847 | /* | | 847 | /* |
848 | * configure security policy index (src/dst/proto/sport/dport) | | 848 | * configure security policy index (src/dst/proto/sport/dport) |
849 | * by looking at the content of mbuf. | | 849 | * by looking at the content of mbuf. |
850 | * the caller is responsible for error recovery (like clearing up spidx). | | 850 | * the caller is responsible for error recovery (like clearing up spidx). |
851 | */ | | 851 | */ |
852 | static int | | 852 | static int |
853 | ipsec_setspidx(struct mbuf *m, struct secpolicyindex *spidx, int needport) | | 853 | ipsec_setspidx(struct mbuf *m, struct secpolicyindex *spidx, int needport) |
854 | { | | 854 | { |
855 | struct ip *ip = NULL; | | 855 | struct ip *ip = NULL; |
856 | struct ip ipbuf; | | 856 | struct ip ipbuf; |
857 | u_int v; | | 857 | u_int v; |
858 | struct mbuf *n; | | 858 | struct mbuf *n; |
859 | int len; | | 859 | int len; |
860 | int error; | | 860 | int error; |
861 | | | 861 | |
862 | IPSEC_ASSERT(m != NULL, ("ipsec_setspidx: null mbuf")); | | 862 | IPSEC_ASSERT(m != NULL, ("ipsec_setspidx: null mbuf")); |
863 | | | 863 | |
864 | /* | | 864 | /* |
865 | * validate m->m_pkthdr.len. we see incorrect length if we | | 865 | * validate m->m_pkthdr.len. we see incorrect length if we |
866 | * mistakenly call this function with inconsistent mbuf chain | | 866 | * mistakenly call this function with inconsistent mbuf chain |
867 | * (like 4.4BSD tcp/udp processing). XXX should we panic here? | | 867 | * (like 4.4BSD tcp/udp processing). XXX should we panic here? |
868 | */ | | 868 | */ |
869 | len = 0; | | 869 | len = 0; |
870 | for (n = m; n; n = n->m_next) | | 870 | for (n = m; n; n = n->m_next) |
871 | len += n->m_len; | | 871 | len += n->m_len; |
872 | if (m->m_pkthdr.len != len) { | | 872 | if (m->m_pkthdr.len != len) { |
873 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 873 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
874 | printf("ipsec_setspidx: " | | 874 | printf("ipsec_setspidx: " |
875 | "total of m_len(%d) != pkthdr.len(%d), " | | 875 | "total of m_len(%d) != pkthdr.len(%d), " |
876 | "ignored.\n", | | 876 | "ignored.\n", |
877 | len, m->m_pkthdr.len)); | | 877 | len, m->m_pkthdr.len)); |
878 | return EINVAL; | | 878 | return EINVAL; |
879 | } | | 879 | } |
880 | | | 880 | |
881 | if (m->m_pkthdr.len < sizeof(struct ip)) { | | 881 | if (m->m_pkthdr.len < sizeof(struct ip)) { |
882 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 882 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
883 | printf("ipsec_setspidx: " | | 883 | printf("ipsec_setspidx: " |
884 | "pkthdr.len(%d) < sizeof(struct ip), ignored.\n", | | 884 | "pkthdr.len(%d) < sizeof(struct ip), ignored.\n", |
885 | m->m_pkthdr.len)); | | 885 | m->m_pkthdr.len)); |
886 | return EINVAL; | | 886 | return EINVAL; |
887 | } | | 887 | } |
888 | | | 888 | |
889 | if (m->m_len >= sizeof(*ip)) | | 889 | if (m->m_len >= sizeof(*ip)) |
890 | ip = mtod(m, struct ip *); | | 890 | ip = mtod(m, struct ip *); |
891 | else { | | 891 | else { |
892 | m_copydata(m, 0, sizeof(ipbuf), &ipbuf); | | 892 | m_copydata(m, 0, sizeof(ipbuf), &ipbuf); |
893 | ip = &ipbuf; | | 893 | ip = &ipbuf; |
894 | } | | 894 | } |
895 | v = ip->ip_v; | | 895 | v = ip->ip_v; |
896 | switch (v) { | | 896 | switch (v) { |
897 | case 4: | | 897 | case 4: |
898 | error = ipsec4_setspidx_ipaddr(m, spidx); | | 898 | error = ipsec4_setspidx_ipaddr(m, spidx); |
899 | if (error) | | 899 | if (error) |
900 | return error; | | 900 | return error; |
901 | ipsec4_get_ulp(m, spidx, needport); | | 901 | ipsec4_get_ulp(m, spidx, needport); |
902 | return 0; | | 902 | return 0; |
903 | #ifdef INET6 | | 903 | #ifdef INET6 |
904 | case 6: | | 904 | case 6: |
905 | if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { | | 905 | if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { |
906 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 906 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
907 | printf("ipsec_setspidx: " | | 907 | printf("ipsec_setspidx: " |
908 | "pkthdr.len(%d) < sizeof(struct ip6_hdr), " | | 908 | "pkthdr.len(%d) < sizeof(struct ip6_hdr), " |
909 | "ignored.\n", m->m_pkthdr.len)); | | 909 | "ignored.\n", m->m_pkthdr.len)); |
910 | return EINVAL; | | 910 | return EINVAL; |
911 | } | | 911 | } |
912 | error = ipsec6_setspidx_ipaddr(m, spidx); | | 912 | error = ipsec6_setspidx_ipaddr(m, spidx); |
913 | if (error) | | 913 | if (error) |
914 | return error; | | 914 | return error; |
915 | ipsec6_get_ulp(m, spidx, needport); | | 915 | ipsec6_get_ulp(m, spidx, needport); |
916 | return 0; | | 916 | return 0; |
917 | #endif | | 917 | #endif |
918 | default: | | 918 | default: |
919 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 919 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
920 | printf("ipsec_setspidx: " | | 920 | printf("ipsec_setspidx: " |
921 | "unknown IP version %u, ignored.\n", v)); | | 921 | "unknown IP version %u, ignored.\n", v)); |
922 | return EINVAL; | | 922 | return EINVAL; |
923 | } | | 923 | } |
924 | } | | 924 | } |
925 | | | 925 | |
926 | static void | | 926 | static void |
927 | ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) | | 927 | ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) |
928 | { | | 928 | { |
929 | u_int8_t nxt; | | 929 | u_int8_t nxt; |
930 | int off; | | 930 | int off; |
931 | | | 931 | |
932 | /* sanity check */ | | 932 | /* sanity check */ |
933 | IPSEC_ASSERT(m != NULL, ("ipsec4_get_ulp: null mbuf")); | | 933 | IPSEC_ASSERT(m != NULL, ("ipsec4_get_ulp: null mbuf")); |
934 | IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip), | | 934 | IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip), |
935 | ("ipsec4_get_ulp: packet too short")); | | 935 | ("ipsec4_get_ulp: packet too short")); |
936 | | | 936 | |
937 | /* NB: ip_input() flips it into host endian XXX need more checking */ | | 937 | /* NB: ip_input() flips it into host endian XXX need more checking */ |
938 | if (m->m_len >= sizeof(struct ip)) { | | 938 | if (m->m_len >= sizeof(struct ip)) { |
939 | struct ip *ip = mtod(m, struct ip *); | | 939 | struct ip *ip = mtod(m, struct ip *); |
940 | if (ip->ip_off & IP_OFF_CONVERT(IP_MF | IP_OFFMASK)) | | 940 | if (ip->ip_off & IP_OFF_CONVERT(IP_MF | IP_OFFMASK)) |
941 | goto done; | | 941 | goto done; |
942 | off = ip->ip_hl << 2; | | 942 | off = ip->ip_hl << 2; |
943 | nxt = ip->ip_p; | | 943 | nxt = ip->ip_p; |
944 | } else { | | 944 | } else { |
945 | struct ip ih; | | 945 | struct ip ih; |
946 | | | 946 | |
947 | m_copydata(m, 0, sizeof (struct ip), &ih); | | 947 | m_copydata(m, 0, sizeof (struct ip), &ih); |
948 | if (ih.ip_off & IP_OFF_CONVERT(IP_MF | IP_OFFMASK)) | | 948 | if (ih.ip_off & IP_OFF_CONVERT(IP_MF | IP_OFFMASK)) |
949 | goto done; | | 949 | goto done; |
950 | off = ih.ip_hl << 2; | | 950 | off = ih.ip_hl << 2; |
951 | nxt = ih.ip_p; | | 951 | nxt = ih.ip_p; |
952 | } | | 952 | } |
953 | | | 953 | |
954 | while (off < m->m_pkthdr.len) { | | 954 | while (off < m->m_pkthdr.len) { |
955 | struct ip6_ext ip6e; | | 955 | struct ip6_ext ip6e; |
956 | struct tcphdr th; | | 956 | struct tcphdr th; |
957 | struct udphdr uh; | | 957 | struct udphdr uh; |
958 | struct icmp icmph; | | 958 | struct icmp icmph; |
959 | | | 959 | |
960 | switch (nxt) { | | 960 | switch (nxt) { |
961 | case IPPROTO_TCP: | | 961 | case IPPROTO_TCP: |
962 | spidx->ul_proto = nxt; | | 962 | spidx->ul_proto = nxt; |
963 | if (!needport) | | 963 | if (!needport) |
964 | goto done_proto; | | 964 | goto done_proto; |
965 | if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) | | 965 | if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) |
966 | goto done; | | 966 | goto done; |
967 | m_copydata(m, off, sizeof (th), &th); | | 967 | m_copydata(m, off, sizeof (th), &th); |
968 | spidx->src.sin.sin_port = th.th_sport; | | 968 | spidx->src.sin.sin_port = th.th_sport; |
969 | spidx->dst.sin.sin_port = th.th_dport; | | 969 | spidx->dst.sin.sin_port = th.th_dport; |
970 | return; | | 970 | return; |
971 | case IPPROTO_UDP: | | 971 | case IPPROTO_UDP: |
972 | spidx->ul_proto = nxt; | | 972 | spidx->ul_proto = nxt; |
973 | if (!needport) | | 973 | if (!needport) |
974 | goto done_proto; | | 974 | goto done_proto; |
975 | if (off + sizeof(struct udphdr) > m->m_pkthdr.len) | | 975 | if (off + sizeof(struct udphdr) > m->m_pkthdr.len) |
976 | goto done; | | 976 | goto done; |
977 | m_copydata(m, off, sizeof (uh), &uh); | | 977 | m_copydata(m, off, sizeof (uh), &uh); |
978 | spidx->src.sin.sin_port = uh.uh_sport; | | 978 | spidx->src.sin.sin_port = uh.uh_sport; |
979 | spidx->dst.sin.sin_port = uh.uh_dport; | | 979 | spidx->dst.sin.sin_port = uh.uh_dport; |
980 | return; | | 980 | return; |
981 | case IPPROTO_AH: | | 981 | case IPPROTO_AH: |
982 | if (m->m_pkthdr.len > off + sizeof(ip6e)) | | 982 | if (m->m_pkthdr.len > off + sizeof(ip6e)) |
983 | goto done; | | 983 | goto done; |
984 | /* XXX sigh, this works but is totally bogus */ | | 984 | /* XXX sigh, this works but is totally bogus */ |
985 | m_copydata(m, off, sizeof(ip6e), &ip6e); | | 985 | m_copydata(m, off, sizeof(ip6e), &ip6e); |
986 | off += (ip6e.ip6e_len + 2) << 2; | | 986 | off += (ip6e.ip6e_len + 2) << 2; |
987 | nxt = ip6e.ip6e_nxt; | | 987 | nxt = ip6e.ip6e_nxt; |
988 | break; | | 988 | break; |
989 | case IPPROTO_ICMP: | | 989 | case IPPROTO_ICMP: |
990 | spidx->ul_proto = nxt; | | 990 | spidx->ul_proto = nxt; |
991 | if (off + sizeof(struct icmp) > m->m_pkthdr.len) | | 991 | if (off + sizeof(struct icmp) > m->m_pkthdr.len) |
992 | return; | | 992 | return; |
993 | m_copydata(m, off, sizeof(icmph), &icmph); | | 993 | m_copydata(m, off, sizeof(icmph), &icmph); |
994 | ((struct sockaddr_in *)&spidx->src)->sin_port = | | 994 | ((struct sockaddr_in *)&spidx->src)->sin_port = |
995 | htons((uint16_t)icmph.icmp_type); | | 995 | htons((uint16_t)icmph.icmp_type); |
996 | ((struct sockaddr_in *)&spidx->dst)->sin_port = | | 996 | ((struct sockaddr_in *)&spidx->dst)->sin_port = |
997 | htons((uint16_t)icmph.icmp_code); | | 997 | htons((uint16_t)icmph.icmp_code); |
998 | return; | | 998 | return; |
999 | default: | | 999 | default: |
1000 | /* XXX intermediate headers??? */ | | 1000 | /* XXX intermediate headers??? */ |
1001 | spidx->ul_proto = nxt; | | 1001 | spidx->ul_proto = nxt; |
1002 | goto done_proto; | | 1002 | goto done_proto; |
1003 | } | | 1003 | } |
1004 | } | | 1004 | } |
1005 | done: | | 1005 | done: |
1006 | spidx->ul_proto = IPSEC_ULPROTO_ANY; | | 1006 | spidx->ul_proto = IPSEC_ULPROTO_ANY; |
1007 | done_proto: | | 1007 | done_proto: |
1008 | spidx->src.sin.sin_port = IPSEC_PORT_ANY; | | 1008 | spidx->src.sin.sin_port = IPSEC_PORT_ANY; |
1009 | spidx->dst.sin.sin_port = IPSEC_PORT_ANY; | | 1009 | spidx->dst.sin.sin_port = IPSEC_PORT_ANY; |
1010 | } | | 1010 | } |
1011 | | | 1011 | |
1012 | /* assumes that m is sane */ | | 1012 | /* assumes that m is sane */ |
1013 | static int | | 1013 | static int |
1014 | ipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) | | 1014 | ipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) |
1015 | { | | 1015 | { |
1016 | static const struct sockaddr_in template = { | | 1016 | static const struct sockaddr_in template = { |
1017 | sizeof (struct sockaddr_in), | | 1017 | sizeof (struct sockaddr_in), |
1018 | AF_INET, | | 1018 | AF_INET, |
1019 | 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } | | 1019 | 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } |
1020 | }; | | 1020 | }; |
1021 | | | 1021 | |
1022 | spidx->src.sin = template; | | 1022 | spidx->src.sin = template; |
1023 | spidx->dst.sin = template; | | 1023 | spidx->dst.sin = template; |
1024 | | | 1024 | |
1025 | if (m->m_len < sizeof (struct ip)) { | | 1025 | if (m->m_len < sizeof (struct ip)) { |
1026 | m_copydata(m, offsetof(struct ip, ip_src), | | 1026 | m_copydata(m, offsetof(struct ip, ip_src), |
1027 | sizeof (struct in_addr), | | 1027 | sizeof (struct in_addr), |
1028 | &spidx->src.sin.sin_addr); | | 1028 | &spidx->src.sin.sin_addr); |
1029 | m_copydata(m, offsetof(struct ip, ip_dst), | | 1029 | m_copydata(m, offsetof(struct ip, ip_dst), |
1030 | sizeof (struct in_addr), | | 1030 | sizeof (struct in_addr), |
1031 | &spidx->dst.sin.sin_addr); | | 1031 | &spidx->dst.sin.sin_addr); |
1032 | } else { | | 1032 | } else { |
1033 | struct ip *ip = mtod(m, struct ip *); | | 1033 | struct ip *ip = mtod(m, struct ip *); |
1034 | spidx->src.sin.sin_addr = ip->ip_src; | | 1034 | spidx->src.sin.sin_addr = ip->ip_src; |
1035 | spidx->dst.sin.sin_addr = ip->ip_dst; | | 1035 | spidx->dst.sin.sin_addr = ip->ip_dst; |
1036 | } | | 1036 | } |
1037 | | | 1037 | |
1038 | spidx->prefs = sizeof(struct in_addr) << 3; | | 1038 | spidx->prefs = sizeof(struct in_addr) << 3; |
1039 | spidx->prefd = sizeof(struct in_addr) << 3; | | 1039 | spidx->prefd = sizeof(struct in_addr) << 3; |
1040 | | | 1040 | |
1041 | return 0; | | 1041 | return 0; |
1042 | } | | 1042 | } |
1043 | | | 1043 | |
1044 | #ifdef INET6 | | 1044 | #ifdef INET6 |
1045 | static void | | 1045 | static void |
1046 | ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, | | 1046 | ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, |
1047 | int needport) | | 1047 | int needport) |
1048 | { | | 1048 | { |
1049 | int off, nxt; | | 1049 | int off, nxt; |
1050 | struct tcphdr th; | | 1050 | struct tcphdr th; |
1051 | struct udphdr uh; | | 1051 | struct udphdr uh; |
1052 | struct icmp6_hdr icmph; | | 1052 | struct icmp6_hdr icmph; |
1053 | | | 1053 | |
1054 | /* sanity check */ | | 1054 | /* sanity check */ |
1055 | if (m == NULL) | | 1055 | if (m == NULL) |
1056 | panic("ipsec6_get_ulp: NULL pointer was passed"); | | 1056 | panic("ipsec6_get_ulp: NULL pointer was passed"); |
1057 | | | 1057 | |
1058 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 1058 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
1059 | printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); | | 1059 | printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); |
1060 | | | 1060 | |
1061 | /* set default */ | | 1061 | /* set default */ |
1062 | spidx->ul_proto = IPSEC_ULPROTO_ANY; | | 1062 | spidx->ul_proto = IPSEC_ULPROTO_ANY; |
1063 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; | | 1063 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; |
1064 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; | | 1064 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; |
1065 | | | 1065 | |
1066 | nxt = -1; | | 1066 | nxt = -1; |
1067 | off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); | | 1067 | off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); |
1068 | if (off < 0 || m->m_pkthdr.len < off) | | 1068 | if (off < 0 || m->m_pkthdr.len < off) |
1069 | return; | | 1069 | return; |
1070 | | | 1070 | |
1071 | switch (nxt) { | | 1071 | switch (nxt) { |
1072 | case IPPROTO_TCP: | | 1072 | case IPPROTO_TCP: |
1073 | spidx->ul_proto = nxt; | | 1073 | spidx->ul_proto = nxt; |
1074 | if (!needport) | | 1074 | if (!needport) |
1075 | break; | | 1075 | break; |
1076 | if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) | | 1076 | if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) |
1077 | break; | | 1077 | break; |
1078 | m_copydata(m, off, sizeof(th), &th); | | 1078 | m_copydata(m, off, sizeof(th), &th); |
1079 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; | | 1079 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; |
1080 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; | | 1080 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; |
1081 | break; | | 1081 | break; |
1082 | case IPPROTO_UDP: | | 1082 | case IPPROTO_UDP: |
1083 | spidx->ul_proto = nxt; | | 1083 | spidx->ul_proto = nxt; |
1084 | if (!needport) | | 1084 | if (!needport) |
1085 | break; | | 1085 | break; |
1086 | if (off + sizeof(struct udphdr) > m->m_pkthdr.len) | | 1086 | if (off + sizeof(struct udphdr) > m->m_pkthdr.len) |
1087 | break; | | 1087 | break; |
1088 | m_copydata(m, off, sizeof(uh), &uh); | | 1088 | m_copydata(m, off, sizeof(uh), &uh); |
1089 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; | | 1089 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; |
1090 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; | | 1090 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; |
1091 | break; | | 1091 | break; |
1092 | case IPPROTO_ICMPV6: | | 1092 | case IPPROTO_ICMPV6: |
1093 | spidx->ul_proto = nxt; | | 1093 | spidx->ul_proto = nxt; |
1094 | if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) | | 1094 | if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) |
1095 | break; | | 1095 | break; |
1096 | m_copydata(m, off, sizeof(icmph), &icmph); | | 1096 | m_copydata(m, off, sizeof(icmph), &icmph); |
1097 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = | | 1097 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = |
1098 | htons((uint16_t)icmph.icmp6_type); | | 1098 | htons((uint16_t)icmph.icmp6_type); |
1099 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = | | 1099 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = |
1100 | htons((uint16_t)icmph.icmp6_code); | | 1100 | htons((uint16_t)icmph.icmp6_code); |
1101 | break; | | 1101 | break; |
1102 | default: | | 1102 | default: |
1103 | /* XXX intermediate headers??? */ | | 1103 | /* XXX intermediate headers??? */ |
1104 | spidx->ul_proto = nxt; | | 1104 | spidx->ul_proto = nxt; |
1105 | break; | | 1105 | break; |
1106 | } | | 1106 | } |
1107 | } | | 1107 | } |
1108 | | | 1108 | |
1109 | /* assumes that m is sane */ | | 1109 | /* assumes that m is sane */ |
1110 | static int | | 1110 | static int |
1111 | ipsec6_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) | | 1111 | ipsec6_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) |
1112 | { | | 1112 | { |
1113 | struct ip6_hdr *ip6 = NULL; | | 1113 | struct ip6_hdr *ip6 = NULL; |
1114 | struct ip6_hdr ip6buf; | | 1114 | struct ip6_hdr ip6buf; |
1115 | struct sockaddr_in6 *sin6; | | 1115 | struct sockaddr_in6 *sin6; |
1116 | | | 1116 | |
1117 | if (m->m_len >= sizeof(*ip6)) | | 1117 | if (m->m_len >= sizeof(*ip6)) |
1118 | ip6 = mtod(m, struct ip6_hdr *); | | 1118 | ip6 = mtod(m, struct ip6_hdr *); |
1119 | else { | | 1119 | else { |
1120 | m_copydata(m, 0, sizeof(ip6buf), &ip6buf); | | 1120 | m_copydata(m, 0, sizeof(ip6buf), &ip6buf); |
1121 | ip6 = &ip6buf; | | 1121 | ip6 = &ip6buf; |
1122 | } | | 1122 | } |
1123 | | | 1123 | |
1124 | sin6 = (struct sockaddr_in6 *)&spidx->src; | | 1124 | sin6 = (struct sockaddr_in6 *)&spidx->src; |
1125 | memset(sin6, 0, sizeof(*sin6)); | | 1125 | memset(sin6, 0, sizeof(*sin6)); |
1126 | sin6->sin6_family = AF_INET6; | | 1126 | sin6->sin6_family = AF_INET6; |
1127 | sin6->sin6_len = sizeof(struct sockaddr_in6); | | 1127 | sin6->sin6_len = sizeof(struct sockaddr_in6); |
1128 | memcpy(&sin6->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)); | | 1128 | memcpy(&sin6->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)); |
1129 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { | | 1129 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { |
1130 | sin6->sin6_addr.s6_addr16[1] = 0; | | 1130 | sin6->sin6_addr.s6_addr16[1] = 0; |
1131 | sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); | | 1131 | sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); |
1132 | } | | 1132 | } |
1133 | spidx->prefs = sizeof(struct in6_addr) << 3; | | 1133 | spidx->prefs = sizeof(struct in6_addr) << 3; |
1134 | | | 1134 | |
1135 | sin6 = (struct sockaddr_in6 *)&spidx->dst; | | 1135 | sin6 = (struct sockaddr_in6 *)&spidx->dst; |
1136 | memset(sin6, 0, sizeof(*sin6)); | | 1136 | memset(sin6, 0, sizeof(*sin6)); |
1137 | sin6->sin6_family = AF_INET6; | | 1137 | sin6->sin6_family = AF_INET6; |
1138 | sin6->sin6_len = sizeof(struct sockaddr_in6); | | 1138 | sin6->sin6_len = sizeof(struct sockaddr_in6); |
1139 | memcpy(&sin6->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); | | 1139 | memcpy(&sin6->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); |
1140 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { | | 1140 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { |
1141 | sin6->sin6_addr.s6_addr16[1] = 0; | | 1141 | sin6->sin6_addr.s6_addr16[1] = 0; |
1142 | sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); | | 1142 | sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); |
1143 | } | | 1143 | } |
1144 | spidx->prefd = sizeof(struct in6_addr) << 3; | | 1144 | spidx->prefd = sizeof(struct in6_addr) << 3; |
1145 | | | 1145 | |
1146 | return 0; | | 1146 | return 0; |
1147 | } | | 1147 | } |
1148 | #endif | | 1148 | #endif |
1149 | | | 1149 | |
1150 | static void | | 1150 | static void |
1151 | ipsec_delpcbpolicy(struct inpcbpolicy *p) | | 1151 | ipsec_delpcbpolicy(struct inpcbpolicy *p) |
1152 | { | | 1152 | { |
1153 | free(p, M_SECA); | | 1153 | free(p, M_SECA); |
1154 | } | | 1154 | } |
1155 | | | 1155 | |
1156 | /* initialize policy in PCB */ | | 1156 | /* initialize policy in PCB */ |
1157 | int | | 1157 | int |
1158 | ipsec_init_policy(struct socket *so, struct inpcbpolicy **pcb_sp) | | 1158 | ipsec_init_policy(struct socket *so, struct inpcbpolicy **pcb_sp) |
1159 | { | | 1159 | { |
1160 | struct inpcbpolicy *new; | | 1160 | struct inpcbpolicy *new; |
1161 | | | 1161 | |
1162 | /* sanity check. */ | | 1162 | /* sanity check. */ |
1163 | if (so == NULL || pcb_sp == NULL) | | 1163 | if (so == NULL || pcb_sp == NULL) |
1164 | panic("ipsec_init_policy: NULL pointer was passed"); | | 1164 | panic("ipsec_init_policy: NULL pointer was passed"); |
1165 | | | 1165 | |
1166 | new = malloc(sizeof(*new), M_SECA, M_NOWAIT|M_ZERO); | | 1166 | new = malloc(sizeof(*new), M_SECA, M_NOWAIT|M_ZERO); |
1167 | if (new == NULL) { | | 1167 | if (new == NULL) { |
1168 | ipseclog((LOG_DEBUG, "ipsec_init_policy: No more memory.\n")); | | 1168 | ipseclog((LOG_DEBUG, "ipsec_init_policy: No more memory.\n")); |
1169 | return ENOBUFS; | | 1169 | return ENOBUFS; |
1170 | } | | 1170 | } |
1171 | | | 1171 | |
1172 | if (IPSEC_PRIVILEGED_SO(so)) | | 1172 | if (IPSEC_PRIVILEGED_SO(so)) |
1173 | new->priv = 1; | | 1173 | new->priv = 1; |
1174 | else | | 1174 | else |
1175 | new->priv = 0; | | 1175 | new->priv = 0; |
1176 | | | 1176 | |
1177 | if ((new->sp_in = KEY_NEWSP()) == NULL) { | | 1177 | if ((new->sp_in = KEY_NEWSP()) == NULL) { |
1178 | ipsec_delpcbpolicy(new); | | 1178 | ipsec_delpcbpolicy(new); |
1179 | return ENOBUFS; | | 1179 | return ENOBUFS; |
1180 | } | | 1180 | } |
1181 | new->sp_in->state = IPSEC_SPSTATE_ALIVE; | | 1181 | new->sp_in->state = IPSEC_SPSTATE_ALIVE; |
1182 | new->sp_in->policy = IPSEC_POLICY_ENTRUST; | | 1182 | new->sp_in->policy = IPSEC_POLICY_ENTRUST; |
1183 | | | 1183 | |
1184 | if ((new->sp_out = KEY_NEWSP()) == NULL) { | | 1184 | if ((new->sp_out = KEY_NEWSP()) == NULL) { |
1185 | KEY_FREESP(&new->sp_in); | | 1185 | KEY_FREESP(&new->sp_in); |
1186 | ipsec_delpcbpolicy(new); | | 1186 | ipsec_delpcbpolicy(new); |
1187 | return ENOBUFS; | | 1187 | return ENOBUFS; |
1188 | } | | 1188 | } |
1189 | new->sp_out->state = IPSEC_SPSTATE_ALIVE; | | 1189 | new->sp_out->state = IPSEC_SPSTATE_ALIVE; |
1190 | new->sp_out->policy = IPSEC_POLICY_ENTRUST; | | 1190 | new->sp_out->policy = IPSEC_POLICY_ENTRUST; |
1191 | | | 1191 | |
1192 | *pcb_sp = new; | | 1192 | *pcb_sp = new; |
1193 | | | 1193 | |
1194 | return 0; | | 1194 | return 0; |
1195 | } | | 1195 | } |
1196 | | | 1196 | |
1197 | /* copy old ipsec policy into new */ | | 1197 | /* copy old ipsec policy into new */ |
1198 | int | | 1198 | int |
1199 | ipsec_copy_policy(const struct inpcbpolicy *old, struct inpcbpolicy *new) | | 1199 | ipsec_copy_policy(const struct inpcbpolicy *old, struct inpcbpolicy *new) |
1200 | { | | 1200 | { |
1201 | struct secpolicy *sp; | | 1201 | struct secpolicy *sp; |
1202 | | | 1202 | |
1203 | sp = ipsec_deepcopy_policy(old->sp_in); | | 1203 | sp = ipsec_deepcopy_policy(old->sp_in); |
1204 | if (sp) { | | 1204 | if (sp) { |
1205 | KEY_FREESP(&new->sp_in); | | 1205 | KEY_FREESP(&new->sp_in); |
1206 | new->sp_in = sp; | | 1206 | new->sp_in = sp; |
1207 | } else | | 1207 | } else |
1208 | return ENOBUFS; | | 1208 | return ENOBUFS; |
1209 | | | 1209 | |
1210 | sp = ipsec_deepcopy_policy(old->sp_out); | | 1210 | sp = ipsec_deepcopy_policy(old->sp_out); |
1211 | if (sp) { | | 1211 | if (sp) { |
1212 | KEY_FREESP(&new->sp_out); | | 1212 | KEY_FREESP(&new->sp_out); |
1213 | new->sp_out = sp; | | 1213 | new->sp_out = sp; |
1214 | } else | | 1214 | } else |
1215 | return ENOBUFS; | | 1215 | return ENOBUFS; |
1216 | | | 1216 | |
1217 | new->priv = old->priv; | | 1217 | new->priv = old->priv; |
1218 | | | 1218 | |
1219 | return 0; | | 1219 | return 0; |
1220 | } | | 1220 | } |
1221 | | | 1221 | |
1222 | /* deep-copy a policy in PCB */ | | 1222 | /* deep-copy a policy in PCB */ |
1223 | static struct secpolicy * | | 1223 | static struct secpolicy * |
1224 | ipsec_deepcopy_policy(const struct secpolicy *src) | | 1224 | ipsec_deepcopy_policy(const struct secpolicy *src) |
1225 | { | | 1225 | { |
1226 | struct ipsecrequest *newchain = NULL; | | 1226 | struct ipsecrequest *newchain = NULL; |
1227 | const struct ipsecrequest *p; | | 1227 | struct ipsecrequest *p; |
1228 | struct ipsecrequest **q; | | 1228 | struct ipsecrequest **q; |
1229 | struct ipsecrequest *r; | | 1229 | struct ipsecrequest *r; |
1230 | struct secpolicy *dst; | | 1230 | struct secpolicy *dst; |
1231 | | | 1231 | |
1232 | if (src == NULL) | | 1232 | if (src == NULL) |
1233 | return NULL; | | 1233 | return NULL; |
1234 | dst = KEY_NEWSP(); | | 1234 | dst = KEY_NEWSP(); |
1235 | if (dst == NULL) | | 1235 | if (dst == NULL) |
1236 | return NULL; | | 1236 | return NULL; |
1237 | | | 1237 | |
1238 | /* | | 1238 | /* |
1239 | * deep-copy IPsec request chain. This is required since struct | | 1239 | * deep-copy IPsec request chain. This is required since struct |
1240 | * ipsecrequest is not reference counted. | | 1240 | * ipsecrequest is not reference counted. |
1241 | */ | | 1241 | */ |
1242 | q = &newchain; | | 1242 | q = &newchain; |
1243 | for (p = src->req; p; p = p->next) { | | 1243 | for (p = src->req; p; p = p->next) { |
1244 | *q = malloc(sizeof(**q), M_SECA, M_NOWAIT|M_ZERO); | | 1244 | *q = malloc(sizeof(**q), M_SECA, M_NOWAIT|M_ZERO); |
1245 | if (*q == NULL) | | 1245 | if (*q == NULL) |
1246 | goto fail; | | 1246 | goto fail; |
1247 | (*q)->next = NULL; | | 1247 | (*q)->next = NULL; |
1248 | | | 1248 | |
1249 | (*q)->saidx.proto = p->saidx.proto; | | 1249 | (*q)->saidx.proto = p->saidx.proto; |
1250 | (*q)->saidx.mode = p->saidx.mode; | | 1250 | (*q)->saidx.mode = p->saidx.mode; |
1251 | (*q)->level = p->level; | | 1251 | (*q)->level = p->level; |
1252 | (*q)->saidx.reqid = p->saidx.reqid; | | 1252 | (*q)->saidx.reqid = p->saidx.reqid; |
1253 | | | 1253 | |
1254 | memcpy(&(*q)->saidx.src, &p->saidx.src, sizeof((*q)->saidx.src)); | | 1254 | memcpy(&(*q)->saidx.src, &p->saidx.src, sizeof((*q)->saidx.src)); |
1255 | memcpy(&(*q)->saidx.dst, &p->saidx.dst, sizeof((*q)->saidx.dst)); | | 1255 | memcpy(&(*q)->saidx.dst, &p->saidx.dst, sizeof((*q)->saidx.dst)); |
1256 | | | 1256 | |
1257 | (*q)->sav = NULL; | | 1257 | (*q)->sav = NULL; |
1258 | (*q)->sp = dst; | | 1258 | (*q)->sp = dst; |
1259 | | | 1259 | |
1260 | q = &((*q)->next); | | 1260 | q = &((*q)->next); |
1261 | } | | 1261 | } |
1262 | | | 1262 | |
1263 | dst->req = newchain; | | 1263 | dst->req = newchain; |
1264 | dst->state = src->state; | | 1264 | dst->state = src->state; |
1265 | dst->policy = src->policy; | | 1265 | dst->policy = src->policy; |
1266 | /* do not touch the refcnt fields */ | | 1266 | /* do not touch the refcnt fields */ |
1267 | | | 1267 | |
1268 | return dst; | | 1268 | return dst; |
1269 | | | 1269 | |
1270 | fail: | | 1270 | fail: |
1271 | for (p = newchain; p; p = r) { | | 1271 | for (p = newchain; p; p = r) { |
1272 | r = p->next; | | 1272 | r = p->next; |
1273 | free(p, M_SECA); | | 1273 | free(p, M_SECA); |
1274 | p = NULL; | | 1274 | p = NULL; |
1275 | } | | 1275 | } |
1276 | return NULL; | | 1276 | return NULL; |
1277 | } | | 1277 | } |
1278 | | | 1278 | |
1279 | /* set policy and ipsec request if present. */ | | 1279 | /* set policy and ipsec request if present. */ |
1280 | static int | | 1280 | static int |
1281 | ipsec_set_policy( | | 1281 | ipsec_set_policy( |
1282 | struct secpolicy **pcb_sp, | | 1282 | struct secpolicy **pcb_sp, |
1283 | int optname, | | 1283 | int optname, |
1284 | void *request, | | 1284 | void *request, |
1285 | size_t len, | | 1285 | size_t len, |
1286 | kauth_cred_t cred | | 1286 | kauth_cred_t cred |
1287 | ) | | 1287 | ) |
1288 | { | | 1288 | { |
1289 | struct sadb_x_policy *xpl; | | 1289 | struct sadb_x_policy *xpl; |
1290 | struct secpolicy *newsp = NULL; | | 1290 | struct secpolicy *newsp = NULL; |
1291 | int error; | | 1291 | int error; |
1292 | | | 1292 | |
1293 | /* sanity check. */ | | 1293 | /* sanity check. */ |
1294 | if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL) | | 1294 | if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL) |
1295 | return EINVAL; | | 1295 | return EINVAL; |
1296 | if (len < sizeof(*xpl)) | | 1296 | if (len < sizeof(*xpl)) |
1297 | return EINVAL; | | 1297 | return EINVAL; |
1298 | xpl = (struct sadb_x_policy *)request; | | 1298 | xpl = (struct sadb_x_policy *)request; |
1299 | | | 1299 | |
1300 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 1300 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
1301 | printf("ipsec_set_policy: passed policy\n"); | | 1301 | printf("ipsec_set_policy: passed policy\n"); |
1302 | kdebug_sadb_x_policy((struct sadb_ext *)xpl)); | | 1302 | kdebug_sadb_x_policy((struct sadb_ext *)xpl)); |
1303 | | | 1303 | |
1304 | /* check policy type */ | | 1304 | /* check policy type */ |
1305 | /* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */ | | 1305 | /* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */ |
1306 | if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD | | 1306 | if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD |
1307 | || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) | | 1307 | || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) |
1308 | return EINVAL; | | 1308 | return EINVAL; |
1309 | | | 1309 | |
1310 | /* check privileged socket */ | | 1310 | /* check privileged socket */ |
1311 | if (xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { | | 1311 | if (xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { |
1312 | error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, | | 1312 | error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, |
1313 | NULL); | | 1313 | NULL); |
1314 | if (error) | | 1314 | if (error) |
1315 | return (error); | | 1315 | return (error); |
1316 | } | | 1316 | } |
1317 | | | 1317 | |
1318 | /* allocation new SP entry */ | | 1318 | /* allocation new SP entry */ |
1319 | if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) | | 1319 | if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) |
1320 | return error; | | 1320 | return error; |
1321 | | | 1321 | |
1322 | newsp->state = IPSEC_SPSTATE_ALIVE; | | 1322 | newsp->state = IPSEC_SPSTATE_ALIVE; |
1323 | | | 1323 | |
1324 | /* clear old SP and set new SP */ | | 1324 | /* clear old SP and set new SP */ |
1325 | KEY_FREESP(pcb_sp); | | 1325 | KEY_FREESP(pcb_sp); |
1326 | *pcb_sp = newsp; | | 1326 | *pcb_sp = newsp; |
1327 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 1327 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
1328 | printf("ipsec_set_policy: new policy\n"); | | 1328 | printf("ipsec_set_policy: new policy\n"); |
1329 | kdebug_secpolicy(newsp)); | | 1329 | kdebug_secpolicy(newsp)); |
1330 | | | 1330 | |
1331 | return 0; | | 1331 | return 0; |
1332 | } | | 1332 | } |
1333 | | | 1333 | |
1334 | static int | | 1334 | static int |
1335 | ipsec_get_policy(struct secpolicy *pcb_sp, struct mbuf **mp) | | 1335 | ipsec_get_policy(struct secpolicy *pcb_sp, struct mbuf **mp) |
1336 | { | | 1336 | { |
1337 | | | 1337 | |
1338 | /* sanity check. */ | | 1338 | /* sanity check. */ |
1339 | if (pcb_sp == NULL || mp == NULL) | | 1339 | if (pcb_sp == NULL || mp == NULL) |
1340 | return EINVAL; | | 1340 | return EINVAL; |
1341 | | | 1341 | |
1342 | *mp = key_sp2msg(pcb_sp); | | 1342 | *mp = key_sp2msg(pcb_sp); |
1343 | if (!*mp) { | | 1343 | if (!*mp) { |
1344 | ipseclog((LOG_DEBUG, "ipsec_get_policy: No more memory.\n")); | | 1344 | ipseclog((LOG_DEBUG, "ipsec_get_policy: No more memory.\n")); |
1345 | return ENOBUFS; | | 1345 | return ENOBUFS; |
1346 | } | | 1346 | } |
1347 | | | 1347 | |
1348 | (*mp)->m_type = MT_DATA; | | 1348 | (*mp)->m_type = MT_DATA; |
1349 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 1349 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
1350 | printf("ipsec_get_policy:\n"); | | 1350 | printf("ipsec_get_policy:\n"); |
1351 | kdebug_mbuf(*mp)); | | 1351 | kdebug_mbuf(*mp)); |
1352 | | | 1352 | |
1353 | return 0; | | 1353 | return 0; |
1354 | } | | 1354 | } |
1355 | | | 1355 | |
1356 | int | | 1356 | int |
1357 | ipsec4_set_policy(struct inpcb *inp, int optname ,void *request, | | 1357 | ipsec4_set_policy(struct inpcb *inp, int optname ,void *request, |
1358 | size_t len, kauth_cred_t cred) | | 1358 | size_t len, kauth_cred_t cred) |
1359 | { | | 1359 | { |
1360 | struct sadb_x_policy *xpl; | | 1360 | struct sadb_x_policy *xpl; |
1361 | struct secpolicy **pcb_sp; | | 1361 | struct secpolicy **pcb_sp; |
1362 | | | 1362 | |
1363 | /* sanity check. */ | | 1363 | /* sanity check. */ |
1364 | if (inp == NULL || request == NULL) | | 1364 | if (inp == NULL || request == NULL) |
1365 | return EINVAL; | | 1365 | return EINVAL; |
1366 | if (len < sizeof(*xpl)) | | 1366 | if (len < sizeof(*xpl)) |
1367 | return EINVAL; | | 1367 | return EINVAL; |
1368 | xpl = (struct sadb_x_policy *)request; | | 1368 | xpl = (struct sadb_x_policy *)request; |
1369 | | | 1369 | |
1370 | IPSEC_ASSERT(inp->inp_sp != NULL, | | 1370 | IPSEC_ASSERT(inp->inp_sp != NULL, |
1371 | ("ipsec4_set_policy(): null inp->in_sp")); | | 1371 | ("ipsec4_set_policy(): null inp->in_sp")); |
1372 | | | 1372 | |
1373 | /* select direction */ | | 1373 | /* select direction */ |
1374 | switch (xpl->sadb_x_policy_dir) { | | 1374 | switch (xpl->sadb_x_policy_dir) { |
1375 | case IPSEC_DIR_INBOUND: | | 1375 | case IPSEC_DIR_INBOUND: |
1376 | pcb_sp = &inp->inp_sp->sp_in; | | 1376 | pcb_sp = &inp->inp_sp->sp_in; |
1377 | break; | | 1377 | break; |
1378 | case IPSEC_DIR_OUTBOUND: | | 1378 | case IPSEC_DIR_OUTBOUND: |
1379 | pcb_sp = &inp->inp_sp->sp_out; | | 1379 | pcb_sp = &inp->inp_sp->sp_out; |
1380 | break; | | 1380 | break; |
1381 | default: | | 1381 | default: |
1382 | ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n", | | 1382 | ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n", |
1383 | xpl->sadb_x_policy_dir)); | | 1383 | xpl->sadb_x_policy_dir)); |
1384 | return EINVAL; | | 1384 | return EINVAL; |
1385 | } | | 1385 | } |
1386 | | | 1386 | |
1387 | return ipsec_set_policy(pcb_sp, optname, request, len, cred); | | 1387 | return ipsec_set_policy(pcb_sp, optname, request, len, cred); |
1388 | } | | 1388 | } |
1389 | | | 1389 | |
1390 | int | | 1390 | int |
1391 | ipsec4_get_policy(struct inpcb *inp, void *request, size_t len, | | 1391 | ipsec4_get_policy(struct inpcb *inp, void *request, size_t len, |
1392 | struct mbuf **mp) | | 1392 | struct mbuf **mp) |
1393 | { | | 1393 | { |
1394 | struct sadb_x_policy *xpl; | | 1394 | struct sadb_x_policy *xpl; |
1395 | struct secpolicy *pcb_sp; | | 1395 | struct secpolicy *pcb_sp; |
1396 | | | 1396 | |
1397 | /* sanity check. */ | | 1397 | /* sanity check. */ |
1398 | if (inp == NULL || request == NULL || mp == NULL) | | 1398 | if (inp == NULL || request == NULL || mp == NULL) |
1399 | return EINVAL; | | 1399 | return EINVAL; |
1400 | IPSEC_ASSERT(inp->inp_sp != NULL, ("ipsec4_get_policy: null inp_sp")); | | 1400 | IPSEC_ASSERT(inp->inp_sp != NULL, ("ipsec4_get_policy: null inp_sp")); |
1401 | if (len < sizeof(*xpl)) | | 1401 | if (len < sizeof(*xpl)) |
1402 | return EINVAL; | | 1402 | return EINVAL; |
1403 | xpl = (struct sadb_x_policy *)request; | | 1403 | xpl = (struct sadb_x_policy *)request; |
1404 | | | 1404 | |
1405 | /* select direction */ | | 1405 | /* select direction */ |
1406 | switch (xpl->sadb_x_policy_dir) { | | 1406 | switch (xpl->sadb_x_policy_dir) { |
1407 | case IPSEC_DIR_INBOUND: | | 1407 | case IPSEC_DIR_INBOUND: |
1408 | pcb_sp = inp->inp_sp->sp_in; | | 1408 | pcb_sp = inp->inp_sp->sp_in; |
1409 | break; | | 1409 | break; |
1410 | case IPSEC_DIR_OUTBOUND: | | 1410 | case IPSEC_DIR_OUTBOUND: |
1411 | pcb_sp = inp->inp_sp->sp_out; | | 1411 | pcb_sp = inp->inp_sp->sp_out; |
1412 | break; | | 1412 | break; |
1413 | default: | | 1413 | default: |
1414 | ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n", | | 1414 | ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n", |
1415 | xpl->sadb_x_policy_dir)); | | 1415 | xpl->sadb_x_policy_dir)); |
1416 | return EINVAL; | | 1416 | return EINVAL; |
1417 | } | | 1417 | } |
1418 | | | 1418 | |
1419 | return ipsec_get_policy(pcb_sp, mp); | | 1419 | return ipsec_get_policy(pcb_sp, mp); |
1420 | } | | 1420 | } |
1421 | | | 1421 | |
1422 | /* delete policy in PCB */ | | 1422 | /* delete policy in PCB */ |
1423 | int | | 1423 | int |
1424 | ipsec4_delete_pcbpolicy(struct inpcb *inp) | | 1424 | ipsec4_delete_pcbpolicy(struct inpcb *inp) |
1425 | { | | 1425 | { |
1426 | IPSEC_ASSERT(inp != NULL, ("ipsec4_delete_pcbpolicy: null inp")); | | 1426 | IPSEC_ASSERT(inp != NULL, ("ipsec4_delete_pcbpolicy: null inp")); |
1427 | | | 1427 | |
1428 | if (inp->inp_sp == NULL) | | 1428 | if (inp->inp_sp == NULL) |
1429 | return 0; | | 1429 | return 0; |
1430 | | | 1430 | |
1431 | if (inp->inp_sp->sp_in != NULL) | | 1431 | if (inp->inp_sp->sp_in != NULL) |
1432 | KEY_FREESP(&inp->inp_sp->sp_in); | | 1432 | KEY_FREESP(&inp->inp_sp->sp_in); |
1433 | | | 1433 | |
1434 | if (inp->inp_sp->sp_out != NULL) | | 1434 | if (inp->inp_sp->sp_out != NULL) |
1435 | KEY_FREESP(&inp->inp_sp->sp_out); | | 1435 | KEY_FREESP(&inp->inp_sp->sp_out); |
1436 | | | 1436 | |
1437 | #ifdef __NetBSD__ | | 1437 | #ifdef __NetBSD__ |
1438 | ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY); | | 1438 | ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY); |
1439 | #endif | | 1439 | #endif |
1440 | | | 1440 | |
1441 | ipsec_delpcbpolicy(inp->inp_sp); | | 1441 | ipsec_delpcbpolicy(inp->inp_sp); |
1442 | inp->inp_sp = NULL; | | 1442 | inp->inp_sp = NULL; |
1443 | | | 1443 | |
1444 | return 0; | | 1444 | return 0; |
1445 | } | | 1445 | } |
1446 | | | 1446 | |
1447 | #ifdef INET6 | | 1447 | #ifdef INET6 |
1448 | int | | 1448 | int |
1449 | ipsec6_set_policy(struct in6pcb *in6p, int optname, void *request, | | 1449 | ipsec6_set_policy(struct in6pcb *in6p, int optname, void *request, |
1450 | size_t len, kauth_cred_t cred) | | 1450 | size_t len, kauth_cred_t cred) |
1451 | { | | 1451 | { |
1452 | struct sadb_x_policy *xpl; | | 1452 | struct sadb_x_policy *xpl; |
1453 | struct secpolicy **pcb_sp; | | 1453 | struct secpolicy **pcb_sp; |
1454 | | | 1454 | |
1455 | /* sanity check. */ | | 1455 | /* sanity check. */ |
1456 | if (in6p == NULL || request == NULL) | | 1456 | if (in6p == NULL || request == NULL) |
1457 | return EINVAL; | | 1457 | return EINVAL; |
1458 | if (len < sizeof(*xpl)) | | 1458 | if (len < sizeof(*xpl)) |
1459 | return EINVAL; | | 1459 | return EINVAL; |
1460 | xpl = (struct sadb_x_policy *)request; | | 1460 | xpl = (struct sadb_x_policy *)request; |
1461 | | | 1461 | |
1462 | /* select direction */ | | 1462 | /* select direction */ |
1463 | switch (xpl->sadb_x_policy_dir) { | | 1463 | switch (xpl->sadb_x_policy_dir) { |
1464 | case IPSEC_DIR_INBOUND: | | 1464 | case IPSEC_DIR_INBOUND: |
1465 | pcb_sp = &in6p->in6p_sp->sp_in; | | 1465 | pcb_sp = &in6p->in6p_sp->sp_in; |
1466 | break; | | 1466 | break; |
1467 | case IPSEC_DIR_OUTBOUND: | | 1467 | case IPSEC_DIR_OUTBOUND: |
1468 | pcb_sp = &in6p->in6p_sp->sp_out; | | 1468 | pcb_sp = &in6p->in6p_sp->sp_out; |
1469 | break; | | 1469 | break; |
1470 | default: | | 1470 | default: |
1471 | ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", | | 1471 | ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", |
1472 | xpl->sadb_x_policy_dir)); | | 1472 | xpl->sadb_x_policy_dir)); |
1473 | return EINVAL; | | 1473 | return EINVAL; |
1474 | } | | 1474 | } |
1475 | | | 1475 | |
1476 | return ipsec_set_policy(pcb_sp, optname, request, len, cred); | | 1476 | return ipsec_set_policy(pcb_sp, optname, request, len, cred); |
1477 | } | | 1477 | } |
1478 | | | 1478 | |
1479 | int | | 1479 | int |
1480 | ipsec6_get_policy(struct in6pcb *in6p, void *request, size_t len, | | 1480 | ipsec6_get_policy(struct in6pcb *in6p, void *request, size_t len, |
1481 | struct mbuf **mp) | | 1481 | struct mbuf **mp) |
1482 | { | | 1482 | { |
1483 | struct sadb_x_policy *xpl; | | 1483 | struct sadb_x_policy *xpl; |
1484 | struct secpolicy *pcb_sp; | | 1484 | struct secpolicy *pcb_sp; |
1485 | | | 1485 | |
1486 | /* sanity check. */ | | 1486 | /* sanity check. */ |
1487 | if (in6p == NULL || request == NULL || mp == NULL) | | 1487 | if (in6p == NULL || request == NULL || mp == NULL) |
1488 | return EINVAL; | | 1488 | return EINVAL; |
1489 | IPSEC_ASSERT(in6p->in6p_sp != NULL, ("ipsec6_get_policy: null in6p_sp")); | | 1489 | IPSEC_ASSERT(in6p->in6p_sp != NULL, ("ipsec6_get_policy: null in6p_sp")); |
1490 | if (len < sizeof(*xpl)) | | 1490 | if (len < sizeof(*xpl)) |
1491 | return EINVAL; | | 1491 | return EINVAL; |
1492 | xpl = (struct sadb_x_policy *)request; | | 1492 | xpl = (struct sadb_x_policy *)request; |
1493 | | | 1493 | |
1494 | /* select direction */ | | 1494 | /* select direction */ |
1495 | switch (xpl->sadb_x_policy_dir) { | | 1495 | switch (xpl->sadb_x_policy_dir) { |
1496 | case IPSEC_DIR_INBOUND: | | 1496 | case IPSEC_DIR_INBOUND: |
1497 | pcb_sp = in6p->in6p_sp->sp_in; | | 1497 | pcb_sp = in6p->in6p_sp->sp_in; |
1498 | break; | | 1498 | break; |
1499 | case IPSEC_DIR_OUTBOUND: | | 1499 | case IPSEC_DIR_OUTBOUND: |
1500 | pcb_sp = in6p->in6p_sp->sp_out; | | 1500 | pcb_sp = in6p->in6p_sp->sp_out; |
1501 | break; | | 1501 | break; |
1502 | default: | | 1502 | default: |
1503 | ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", | | 1503 | ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", |
1504 | xpl->sadb_x_policy_dir)); | | 1504 | xpl->sadb_x_policy_dir)); |
1505 | return EINVAL; | | 1505 | return EINVAL; |
1506 | } | | 1506 | } |
1507 | | | 1507 | |
1508 | return ipsec_get_policy(pcb_sp, mp); | | 1508 | return ipsec_get_policy(pcb_sp, mp); |
1509 | } | | 1509 | } |
1510 | | | 1510 | |
1511 | int | | 1511 | int |
1512 | ipsec6_delete_pcbpolicy(struct in6pcb *in6p) | | 1512 | ipsec6_delete_pcbpolicy(struct in6pcb *in6p) |
1513 | { | | 1513 | { |
1514 | IPSEC_ASSERT(in6p != NULL, ("ipsec6_delete_pcbpolicy: null in6p")); | | 1514 | IPSEC_ASSERT(in6p != NULL, ("ipsec6_delete_pcbpolicy: null in6p")); |
1515 | | | 1515 | |
1516 | if (in6p->in6p_sp == NULL) | | 1516 | if (in6p->in6p_sp == NULL) |
1517 | return 0; | | 1517 | return 0; |
1518 | | | 1518 | |
1519 | if (in6p->in6p_sp->sp_in != NULL) | | 1519 | if (in6p->in6p_sp->sp_in != NULL) |
1520 | KEY_FREESP(&in6p->in6p_sp->sp_in); | | 1520 | KEY_FREESP(&in6p->in6p_sp->sp_in); |
1521 | | | 1521 | |
1522 | if (in6p->in6p_sp->sp_out != NULL) | | 1522 | if (in6p->in6p_sp->sp_out != NULL) |
1523 | KEY_FREESP(&in6p->in6p_sp->sp_out); | | 1523 | KEY_FREESP(&in6p->in6p_sp->sp_out); |
1524 | | | 1524 | |
1525 | #ifdef __NetBSD | | 1525 | #ifdef __NetBSD |
1526 | ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY); | | 1526 | ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY); |
1527 | #endif | | 1527 | #endif |
1528 | | | 1528 | |
1529 | ipsec_delpcbpolicy(in6p->in6p_sp); | | 1529 | ipsec_delpcbpolicy(in6p->in6p_sp); |
1530 | in6p->in6p_sp = NULL; | | 1530 | in6p->in6p_sp = NULL; |
1531 | | | 1531 | |
1532 | return 0; | | 1532 | return 0; |
1533 | } | | 1533 | } |
1534 | #endif | | 1534 | #endif |
1535 | | | 1535 | |
1536 | /* | | 1536 | /* |
1537 | * return current level. | | 1537 | * return current level. |
1538 | * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. | | 1538 | * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. |
1539 | */ | | 1539 | */ |
1540 | u_int | | 1540 | u_int |
1541 | ipsec_get_reqlevel(const struct ipsecrequest *isr) | | 1541 | ipsec_get_reqlevel(const struct ipsecrequest *isr) |
1542 | { | | 1542 | { |
1543 | u_int level = 0; | | 1543 | u_int level = 0; |
1544 | u_int esp_trans_deflev, esp_net_deflev; | | 1544 | u_int esp_trans_deflev, esp_net_deflev; |
1545 | u_int ah_trans_deflev, ah_net_deflev; | | 1545 | u_int ah_trans_deflev, ah_net_deflev; |
1546 | | | 1546 | |
1547 | IPSEC_ASSERT(isr != NULL && isr->sp != NULL, | | 1547 | IPSEC_ASSERT(isr != NULL && isr->sp != NULL, |
1548 | ("ipsec_get_reqlevel: null argument")); | | 1548 | ("ipsec_get_reqlevel: null argument")); |
1549 | IPSEC_ASSERT(isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family, | | 1549 | IPSEC_ASSERT(isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family, |
1550 | ("ipsec_get_reqlevel: af family mismatch, src %u, dst %u", | | 1550 | ("ipsec_get_reqlevel: af family mismatch, src %u, dst %u", |
1551 | isr->sp->spidx.src.sa.sa_family, | | 1551 | isr->sp->spidx.src.sa.sa_family, |
1552 | isr->sp->spidx.dst.sa.sa_family)); | | 1552 | isr->sp->spidx.dst.sa.sa_family)); |
1553 | | | 1553 | |
1554 | /* XXX note that we have ipseclog() expanded here - code sync issue */ | | 1554 | /* XXX note that we have ipseclog() expanded here - code sync issue */ |
1555 | #define IPSEC_CHECK_DEFAULT(lev) \ | | 1555 | #define IPSEC_CHECK_DEFAULT(lev) \ |
1556 | (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ | | 1556 | (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ |
1557 | && (lev) != IPSEC_LEVEL_UNIQUE) \ | | 1557 | && (lev) != IPSEC_LEVEL_UNIQUE) \ |
1558 | ? (ipsec_debug \ | | 1558 | ? (ipsec_debug \ |
1559 | ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ | | 1559 | ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ |
1560 | (lev), IPSEC_LEVEL_REQUIRE) \ | | 1560 | (lev), IPSEC_LEVEL_REQUIRE) \ |
1561 | : 0), \ | | 1561 | : 0), \ |
1562 | (lev) = IPSEC_LEVEL_REQUIRE, \ | | 1562 | (lev) = IPSEC_LEVEL_REQUIRE, \ |
1563 | (lev) \ | | 1563 | (lev) \ |
1564 | : (lev)) | | 1564 | : (lev)) |
1565 | | | 1565 | |
1566 | /* set default level */ | | 1566 | /* set default level */ |
1567 | switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { | | 1567 | switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { |
1568 | #ifdef INET | | 1568 | #ifdef INET |
1569 | case AF_INET: | | 1569 | case AF_INET: |
1570 | esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_trans_deflev); | | 1570 | esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_trans_deflev); |
1571 | esp_net_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_net_deflev); | | 1571 | esp_net_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_net_deflev); |
1572 | ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_trans_deflev); | | 1572 | ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_trans_deflev); |
1573 | ah_net_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_net_deflev); | | 1573 | ah_net_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_net_deflev); |
1574 | break; | | 1574 | break; |
1575 | #endif | | 1575 | #endif |
1576 | #ifdef INET6 | | 1576 | #ifdef INET6 |
1577 | case AF_INET6: | | 1577 | case AF_INET6: |
1578 | esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_trans_deflev); | | 1578 | esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_trans_deflev); |
1579 | esp_net_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_net_deflev); | | 1579 | esp_net_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_net_deflev); |
1580 | ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_trans_deflev); | | 1580 | ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_trans_deflev); |
1581 | ah_net_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_net_deflev); | | 1581 | ah_net_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_net_deflev); |
1582 | break; | | 1582 | break; |
1583 | #endif /* INET6 */ | | 1583 | #endif /* INET6 */ |
1584 | default: | | 1584 | default: |
1585 | panic("key_get_reqlevel: unknown af %u", | | 1585 | panic("key_get_reqlevel: unknown af %u", |
1586 | isr->sp->spidx.src.sa.sa_family); | | 1586 | isr->sp->spidx.src.sa.sa_family); |
1587 | } | | 1587 | } |
1588 | | | 1588 | |
1589 | #undef IPSEC_CHECK_DEFAULT | | 1589 | #undef IPSEC_CHECK_DEFAULT |
1590 | | | 1590 | |
1591 | /* set level */ | | 1591 | /* set level */ |
1592 | switch (isr->level) { | | 1592 | switch (isr->level) { |
1593 | case IPSEC_LEVEL_DEFAULT: | | 1593 | case IPSEC_LEVEL_DEFAULT: |
1594 | switch (isr->saidx.proto) { | | 1594 | switch (isr->saidx.proto) { |
1595 | case IPPROTO_ESP: | | 1595 | case IPPROTO_ESP: |
1596 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) | | 1596 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) |
1597 | level = esp_net_deflev; | | 1597 | level = esp_net_deflev; |
1598 | else | | 1598 | else |
1599 | level = esp_trans_deflev; | | 1599 | level = esp_trans_deflev; |
1600 | break; | | 1600 | break; |
1601 | case IPPROTO_AH: | | 1601 | case IPPROTO_AH: |
1602 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) | | 1602 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) |
1603 | level = ah_net_deflev; | | 1603 | level = ah_net_deflev; |
1604 | else | | 1604 | else |
1605 | level = ah_trans_deflev; | | 1605 | level = ah_trans_deflev; |
1606 | break; | | 1606 | break; |
1607 | case IPPROTO_IPCOMP: | | 1607 | case IPPROTO_IPCOMP: |
1608 | /* | | 1608 | /* |
1609 | * we don't really care, as IPcomp document says that | | 1609 | * we don't really care, as IPcomp document says that |
1610 | * we shouldn't compress small packets | | 1610 | * we shouldn't compress small packets |
1611 | */ | | 1611 | */ |
1612 | level = IPSEC_LEVEL_USE; | | 1612 | level = IPSEC_LEVEL_USE; |
1613 | break; | | 1613 | break; |
1614 | default: | | 1614 | default: |
1615 | panic("ipsec_get_reqlevel: Illegal protocol defined %u", | | 1615 | panic("ipsec_get_reqlevel: Illegal protocol defined %u", |
1616 | isr->saidx.proto); | | 1616 | isr->saidx.proto); |
1617 | } | | 1617 | } |
1618 | break; | | 1618 | break; |
1619 | | | 1619 | |
1620 | case IPSEC_LEVEL_USE: | | 1620 | case IPSEC_LEVEL_USE: |
1621 | case IPSEC_LEVEL_REQUIRE: | | 1621 | case IPSEC_LEVEL_REQUIRE: |
1622 | level = isr->level; | | 1622 | level = isr->level; |
1623 | break; | | 1623 | break; |
1624 | case IPSEC_LEVEL_UNIQUE: | | 1624 | case IPSEC_LEVEL_UNIQUE: |
1625 | level = IPSEC_LEVEL_REQUIRE; | | 1625 | level = IPSEC_LEVEL_REQUIRE; |
1626 | break; | | 1626 | break; |
1627 | | | 1627 | |
1628 | default: | | 1628 | default: |
1629 | panic("ipsec_get_reqlevel: Illegal IPsec level %u", | | 1629 | panic("ipsec_get_reqlevel: Illegal IPsec level %u", |
1630 | isr->level); | | 1630 | isr->level); |
1631 | } | | 1631 | } |
1632 | | | 1632 | |
1633 | return level; | | 1633 | return level; |
1634 | } | | 1634 | } |
1635 | | | 1635 | |
1636 | /* | | 1636 | /* |
1637 | * Check security policy requirements against the actual | | 1637 | * Check security policy requirements against the actual |
1638 | * packet contents. Return one if the packet should be | | 1638 | * packet contents. Return one if the packet should be |
1639 | * reject as "invalid"; otherwiser return zero to have the | | 1639 | * reject as "invalid"; otherwiser return zero to have the |
1640 | * packet treated as "valid". | | 1640 | * packet treated as "valid". |
1641 | * | | 1641 | * |
1642 | * OUT: | | 1642 | * OUT: |
1643 | * 0: valid | | 1643 | * 0: valid |
1644 | * 1: invalid | | 1644 | * 1: invalid |
1645 | */ | | 1645 | */ |
1646 | int | | 1646 | int |
1647 | ipsec_in_reject(const struct secpolicy *sp, const struct mbuf *m) | | 1647 | ipsec_in_reject(const struct secpolicy *sp, const struct mbuf *m) |
1648 | { | | 1648 | { |
1649 | struct ipsecrequest *isr; | | 1649 | struct ipsecrequest *isr; |
1650 | int need_auth; | | 1650 | int need_auth; |
1651 | | | 1651 | |
1652 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, | | 1652 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, |
1653 | printf("ipsec_in_reject: using SP\n"); | | 1653 | printf("ipsec_in_reject: using SP\n"); |
1654 | kdebug_secpolicy(sp)); | | 1654 | kdebug_secpolicy(sp)); |
1655 | | | 1655 | |
1656 | /* check policy */ | | 1656 | /* check policy */ |
1657 | switch (sp->policy) { | | 1657 | switch (sp->policy) { |
1658 | case IPSEC_POLICY_DISCARD: | | 1658 | case IPSEC_POLICY_DISCARD: |
1659 | return 1; | | 1659 | return 1; |
1660 | case IPSEC_POLICY_BYPASS: | | 1660 | case IPSEC_POLICY_BYPASS: |
1661 | case IPSEC_POLICY_NONE: | | 1661 | case IPSEC_POLICY_NONE: |
1662 | return 0; | | 1662 | return 0; |
1663 | } | | 1663 | } |
1664 | | | 1664 | |
1665 | IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, | | 1665 | IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, |
1666 | ("ipsec_in_reject: invalid policy %u", sp->policy)); | | 1666 | ("ipsec_in_reject: invalid policy %u", sp->policy)); |
1667 | | | 1667 | |
1668 | /* XXX should compare policy against ipsec header history */ | | 1668 | /* XXX should compare policy against ipsec header history */ |
1669 | | | 1669 | |
1670 | need_auth = 0; | | 1670 | need_auth = 0; |
1671 | for (isr = sp->req; isr != NULL; isr = isr->next) { | | 1671 | for (isr = sp->req; isr != NULL; isr = isr->next) { |
1672 | if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE) | | 1672 | if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE) |
1673 | continue; | | 1673 | continue; |
1674 | switch (isr->saidx.proto) { | | 1674 | switch (isr->saidx.proto) { |
1675 | case IPPROTO_ESP: | | 1675 | case IPPROTO_ESP: |
1676 | if ((m->m_flags & M_DECRYPTED) == 0) { | | 1676 | if ((m->m_flags & M_DECRYPTED) == 0) { |
1677 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 1677 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
1678 | printf("ipsec_in_reject: ESP m_flags:%x\n", | | 1678 | printf("ipsec_in_reject: ESP m_flags:%x\n", |
1679 | m->m_flags)); | | 1679 | m->m_flags)); |
1680 | return 1; | | 1680 | return 1; |
1681 | } | | 1681 | } |
1682 | | | 1682 | |
1683 | if (!need_auth && | | 1683 | if (!need_auth && |
1684 | isr->sav != NULL && | | 1684 | isr->sav != NULL && |
1685 | isr->sav->tdb_authalgxform != NULL && | | 1685 | isr->sav->tdb_authalgxform != NULL && |
1686 | (m->m_flags & M_AUTHIPDGM) == 0) { | | 1686 | (m->m_flags & M_AUTHIPDGM) == 0) { |
1687 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 1687 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
1688 | printf("ipsec_in_reject: ESP/AH m_flags:%x\n", | | 1688 | printf("ipsec_in_reject: ESP/AH m_flags:%x\n", |
1689 | m->m_flags)); | | 1689 | m->m_flags)); |
1690 | return 1; | | 1690 | return 1; |
1691 | } | | 1691 | } |
1692 | break; | | 1692 | break; |
1693 | case IPPROTO_AH: | | 1693 | case IPPROTO_AH: |
1694 | need_auth = 1; | | 1694 | need_auth = 1; |
1695 | if ((m->m_flags & M_AUTHIPHDR) == 0) { | | 1695 | if ((m->m_flags & M_AUTHIPHDR) == 0) { |
1696 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, | | 1696 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
1697 | printf("ipsec_in_reject: AH m_flags:%x\n", | | 1697 | printf("ipsec_in_reject: AH m_flags:%x\n", |
1698 | m->m_flags)); | | 1698 | m->m_flags)); |
1699 | return 1; | | 1699 | return 1; |
1700 | } | | 1700 | } |
1701 | break; | | 1701 | break; |
1702 | case IPPROTO_IPCOMP: | | 1702 | case IPPROTO_IPCOMP: |
1703 | /* | | 1703 | /* |
1704 | * we don't really care, as IPcomp document | | 1704 | * we don't really care, as IPcomp document |
1705 | * says that we shouldn't compress small | | 1705 | * says that we shouldn't compress small |
1706 | * packets, IPComp policy should always be | | 1706 | * packets, IPComp policy should always be |
1707 | * treated as being in "use" level. | | 1707 | * treated as being in "use" level. |
1708 | */ | | 1708 | */ |
1709 | break; | | 1709 | break; |
1710 | } | | 1710 | } |
1711 | } | | 1711 | } |
1712 | return 0; /* valid */ | | 1712 | return 0; /* valid */ |
1713 | } | | 1713 | } |
1714 | | | 1714 | |
1715 | /* | | 1715 | /* |
1716 | * Check AH/ESP integrity. | | 1716 | * Check AH/ESP integrity. |
1717 | * This function is called from tcp_input(), udp_input(), | | 1717 | * This function is called from tcp_input(), udp_input(), |
1718 | * and {ah,esp}4_input for tunnel mode | | 1718 | * and {ah,esp}4_input for tunnel mode |
1719 | */ | | 1719 | */ |
1720 | int | | 1720 | int |
1721 | ipsec4_in_reject(struct mbuf *m, struct inpcb *inp) | | 1721 | ipsec4_in_reject(struct mbuf *m, struct inpcb *inp) |
1722 | { | | 1722 | { |
1723 | struct secpolicy *sp; | | 1723 | struct secpolicy *sp; |
1724 | int error; | | 1724 | int error; |
1725 | int result; | | 1725 | int result; |
1726 | | | 1726 | |
1727 | IPSEC_ASSERT(m != NULL, ("ipsec4_in_reject_so: null mbuf")); | | 1727 | IPSEC_ASSERT(m != NULL, ("ipsec4_in_reject_so: null mbuf")); |
1728 | | | 1728 | |
1729 | /* get SP for this packet. | | 1729 | /* get SP for this packet. |
1730 | * When we are called from ip_forward(), we call | | 1730 | * When we are called from ip_forward(), we call |
1731 | * ipsec_getpolicybyaddr() with IP_FORWARDING flag. | | 1731 | * ipsec_getpolicybyaddr() with IP_FORWARDING flag. |
1732 | */ | | 1732 | */ |
1733 | if (inp == NULL) | | 1733 | if (inp == NULL) |
1734 | sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); | | 1734 | sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); |
1735 | else | | 1735 | else |
1736 | sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, | | 1736 | sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, |
1737 | IN4PCB_TO_PCB(inp), &error); | | 1737 | IN4PCB_TO_PCB(inp), &error); |
1738 | | | 1738 | |
1739 | if (sp != NULL) { | | 1739 | if (sp != NULL) { |
1740 | result = ipsec_in_reject(sp, m); | | 1740 | result = ipsec_in_reject(sp, m); |
1741 | if (result) | | 1741 | if (result) |
1742 | IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); | | 1742 | IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); |
1743 | KEY_FREESP(&sp); | | 1743 | KEY_FREESP(&sp); |
1744 | } else { | | 1744 | } else { |
1745 | result = 0; /* XXX should be panic ? | | 1745 | result = 0; /* XXX should be panic ? |
1746 | * -> No, there may be error. */ | | 1746 | * -> No, there may be error. */ |
1747 | } | | 1747 | } |
1748 | return result; | | 1748 | return result; |
1749 | } | | 1749 | } |
1750 | | | 1750 | |
1751 | | | 1751 | |
1752 | #ifdef INET6 | | 1752 | #ifdef INET6 |
1753 | /* | | 1753 | /* |
1754 | * Check AH/ESP integrity. | | 1754 | * Check AH/ESP integrity. |
1755 | * This function is called from tcp6_input(), udp6_input(), | | 1755 | * This function is called from tcp6_input(), udp6_input(), |
1756 | * and {ah,esp}6_input for tunnel mode | | 1756 | * and {ah,esp}6_input for tunnel mode |
1757 | */ | | 1757 | */ |
1758 | int | | 1758 | int |
1759 | ipsec6_in_reject(struct mbuf *m, struct in6pcb *in6p) | | 1759 | ipsec6_in_reject(struct mbuf *m, struct in6pcb *in6p) |
1760 | { | | 1760 | { |
1761 | struct secpolicy *sp = NULL; | | 1761 | struct secpolicy *sp = NULL; |
1762 | int error; | | 1762 | int error; |
1763 | int result; | | 1763 | int result; |
1764 | | | 1764 | |
1765 | /* sanity check */ | | 1765 | /* sanity check */ |
1766 | if (m == NULL) | | 1766 | if (m == NULL) |
1767 | return 0; /* XXX should be panic ? */ | | 1767 | return 0; /* XXX should be panic ? */ |
1768 | | | 1768 | |
1769 | /* get SP for this packet. | | 1769 | /* get SP for this packet. |
1770 | * When we are called from ip_forward(), we call | | 1770 | * When we are called from ip_forward(), we call |
1771 | * ipsec_getpolicybyaddr() with IP_FORWARDING flag. | | 1771 | * ipsec_getpolicybyaddr() with IP_FORWARDING flag. |
1772 | */ | | 1772 | */ |
1773 | if (in6p == NULL) | | 1773 | if (in6p == NULL) |
1774 | sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); | | 1774 | sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); |
1775 | else | | 1775 | else |
1776 | sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, | | 1776 | sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, |
1777 | IN6PCB_TO_PCB(in6p), | | 1777 | IN6PCB_TO_PCB(in6p), |
1778 | &error); | | 1778 | &error); |
1779 | | | 1779 | |
1780 | if (sp != NULL) { | | 1780 | if (sp != NULL) { |
1781 | result = ipsec_in_reject(sp, m); | | 1781 | result = ipsec_in_reject(sp, m); |
1782 | if (result) | | 1782 | if (result) |
1783 | IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); | | 1783 | IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); |
1784 | KEY_FREESP(&sp); | | 1784 | KEY_FREESP(&sp); |
1785 | } else { | | 1785 | } else { |
1786 | result = 0; | | 1786 | result = 0; |
1787 | } | | 1787 | } |
1788 | return result; | | 1788 | return result; |
1789 | } | | 1789 | } |
1790 | #endif | | 1790 | #endif |
1791 | | | 1791 | |
1792 | /* | | 1792 | /* |
1793 | * compute the byte size to be occupied by IPsec header. | | 1793 | * compute the byte size to be occupied by IPsec header. |
1794 | * in case it is tunneled, it includes the size of outer IP header. | | 1794 | * in case it is tunneled, it includes the size of outer IP header. |
1795 | * NOTE: SP passed is free in this function. | | 1795 | * NOTE: SP passed is free in this function. |
1796 | */ | | 1796 | */ |
1797 | static size_t | | 1797 | static size_t |
1798 | ipsec_hdrsiz(struct secpolicy *sp) | | 1798 | ipsec_hdrsiz(struct secpolicy *sp) |
1799 | { | | 1799 | { |
1800 | struct ipsecrequest *isr; | | 1800 | struct ipsecrequest *isr; |
1801 | size_t siz; | | 1801 | size_t siz; |
1802 | | | 1802 | |
1803 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, | | 1803 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, |
1804 | printf("ipsec_hdrsiz: using SP\n"); | | 1804 | printf("ipsec_hdrsiz: using SP\n"); |
1805 | kdebug_secpolicy(sp)); | | 1805 | kdebug_secpolicy(sp)); |
1806 | | | 1806 | |
1807 | switch (sp->policy) { | | 1807 | switch (sp->policy) { |
1808 | case IPSEC_POLICY_DISCARD: | | 1808 | case IPSEC_POLICY_DISCARD: |
1809 | case IPSEC_POLICY_BYPASS: | | 1809 | case IPSEC_POLICY_BYPASS: |
1810 | case IPSEC_POLICY_NONE: | | 1810 | case IPSEC_POLICY_NONE: |
1811 | return 0; | | 1811 | return 0; |
1812 | } | | 1812 | } |
1813 | | | 1813 | |
1814 | IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, | | 1814 | IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, |
1815 | ("ipsec_hdrsiz: invalid policy %u", sp->policy)); | | 1815 | ("ipsec_hdrsiz: invalid policy %u", sp->policy)); |
1816 | | | 1816 | |
1817 | siz = 0; | | 1817 | siz = 0; |
1818 | for (isr = sp->req; isr != NULL; isr = isr->next) { | | 1818 | for (isr = sp->req; isr != NULL; isr = isr->next) { |
1819 | size_t clen = 0; | | 1819 | size_t clen = 0; |
1820 | | | 1820 | |
1821 | switch (isr->saidx.proto) { | | 1821 | switch (isr->saidx.proto) { |
1822 | case IPPROTO_ESP: | | 1822 | case IPPROTO_ESP: |
1823 | clen = esp_hdrsiz(isr->sav); | | 1823 | clen = esp_hdrsiz(isr->sav); |
1824 | break; | | 1824 | break; |
1825 | case IPPROTO_AH: | | 1825 | case IPPROTO_AH: |
1826 | clen = ah_hdrsiz(isr->sav); | | 1826 | clen = ah_hdrsiz(isr->sav); |
1827 | break; | | 1827 | break; |
1828 | case IPPROTO_IPCOMP: | | 1828 | case IPPROTO_IPCOMP: |
1829 | clen = sizeof(struct ipcomp); | | 1829 | clen = sizeof(struct ipcomp); |
1830 | break; | | 1830 | break; |
1831 | } | | 1831 | } |
1832 | | | 1832 | |
1833 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { | | 1833 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { |
1834 | switch (isr->saidx.dst.sa.sa_family) { | | 1834 | switch (isr->saidx.dst.sa.sa_family) { |
1835 | case AF_INET: | | 1835 | case AF_INET: |
1836 | clen += sizeof(struct ip); | | 1836 | clen += sizeof(struct ip); |
1837 | break; | | 1837 | break; |
1838 | #ifdef INET6 | | 1838 | #ifdef INET6 |
1839 | case AF_INET6: | | 1839 | case AF_INET6: |
1840 | clen += sizeof(struct ip6_hdr); | | 1840 | clen += sizeof(struct ip6_hdr); |
1841 | break; | | 1841 | break; |
1842 | #endif | | 1842 | #endif |
1843 | default: | | 1843 | default: |
1844 | ipseclog((LOG_ERR, "ipsec_hdrsiz: " | | 1844 | ipseclog((LOG_ERR, "ipsec_hdrsiz: " |
1845 | "unknown AF %d in IPsec tunnel SA\n", | | 1845 | "unknown AF %d in IPsec tunnel SA\n", |
1846 | ((struct sockaddr *)&isr->saidx.dst)->sa_family)); | | 1846 | ((struct sockaddr *)&isr->saidx.dst)->sa_family)); |
1847 | break; | | 1847 | break; |
1848 | } | | 1848 | } |
1849 | } | | 1849 | } |
1850 | siz += clen; | | 1850 | siz += clen; |
1851 | } | | 1851 | } |
1852 | | | 1852 | |
1853 | return siz; | | 1853 | return siz; |
1854 | } | | 1854 | } |
1855 | | | 1855 | |
1856 | /* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ | | 1856 | /* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ |
1857 | size_t | | 1857 | size_t |
1858 | ipsec4_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp) | | 1858 | ipsec4_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp) |
1859 | { | | 1859 | { |
1860 | struct secpolicy *sp; | | 1860 | struct secpolicy *sp; |
1861 | int error; | | 1861 | int error; |
1862 | size_t size; | | 1862 | size_t size; |
1863 | | | 1863 | |
1864 | IPSEC_ASSERT(m != NULL, ("ipsec4_hdrsiz: null mbuf")); | | 1864 | IPSEC_ASSERT(m != NULL, ("ipsec4_hdrsiz: null mbuf")); |
1865 | IPSEC_ASSERT(inp == NULL || inp->inp_socket != NULL, | | 1865 | IPSEC_ASSERT(inp == NULL || inp->inp_socket != NULL, |
1866 | ("ipsec4_hdrsize: socket w/o inpcb")); | | 1866 | ("ipsec4_hdrsize: socket w/o inpcb")); |
1867 | | | 1867 | |
1868 | /* get SP for this packet. | | 1868 | /* get SP for this packet. |
1869 | * When we are called from ip_forward(), we call | | 1869 | * When we are called from ip_forward(), we call |
1870 | * ipsec_getpolicybyaddr() with IP_FORWARDING flag. | | 1870 | * ipsec_getpolicybyaddr() with IP_FORWARDING flag. |
1871 | */ | | 1871 | */ |
1872 | if (inp == NULL) | | 1872 | if (inp == NULL) |
1873 | sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); | | 1873 | sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); |
1874 | else | | 1874 | else |
1875 | sp = ipsec_getpolicybysock(m, dir, | | 1875 | sp = ipsec_getpolicybysock(m, dir, |
1876 | IN4PCB_TO_PCB(inp), &error); | | 1876 | IN4PCB_TO_PCB(inp), &error); |
1877 | | | 1877 | |
1878 | if (sp != NULL) { | | 1878 | if (sp != NULL) { |
1879 | size = ipsec_hdrsiz(sp); | | 1879 | size = ipsec_hdrsiz(sp); |
1880 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, | | 1880 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, |
1881 | printf("ipsec4_hdrsiz: size:%lu.\n", | | 1881 | printf("ipsec4_hdrsiz: size:%lu.\n", |
1882 | (unsigned long)size)); | | 1882 | (unsigned long)size)); |
1883 | | | 1883 | |
1884 | KEY_FREESP(&sp); | | 1884 | KEY_FREESP(&sp); |
1885 | } else { | | 1885 | } else { |
1886 | size = 0; /* XXX should be panic ? */ | | 1886 | size = 0; /* XXX should be panic ? */ |
1887 | } | | 1887 | } |
1888 | return size; | | 1888 | return size; |
1889 | } | | 1889 | } |
1890 | | | 1890 | |
1891 | #ifdef INET6 | | 1891 | #ifdef INET6 |
1892 | /* This function is called from ipsec6_hdrsize_tcp(), | | 1892 | /* This function is called from ipsec6_hdrsize_tcp(), |
1893 | * and maybe from ip6_forward.() | | 1893 | * and maybe from ip6_forward.() |
1894 | */ | | 1894 | */ |
1895 | size_t | | 1895 | size_t |
1896 | ipsec6_hdrsiz(struct mbuf *m, u_int dir, struct in6pcb *in6p) | | 1896 | ipsec6_hdrsiz(struct mbuf *m, u_int dir, struct in6pcb *in6p) |
1897 | { | | 1897 | { |
1898 | struct secpolicy *sp; | | 1898 | struct secpolicy *sp; |
1899 | int error; | | 1899 | int error; |
1900 | size_t size; | | 1900 | size_t size; |
1901 | | | 1901 | |
1902 | IPSEC_ASSERT(m != NULL, ("ipsec6_hdrsiz: null mbuf")); | | 1902 | IPSEC_ASSERT(m != NULL, ("ipsec6_hdrsiz: null mbuf")); |
1903 | IPSEC_ASSERT(in6p == NULL || in6p->in6p_socket != NULL, | | 1903 | IPSEC_ASSERT(in6p == NULL || in6p->in6p_socket != NULL, |
1904 | ("ipsec6_hdrsize: socket w/o inpcb")); | | 1904 | ("ipsec6_hdrsize: socket w/o inpcb")); |
1905 | | | 1905 | |
1906 | /* get SP for this packet */ | | 1906 | /* get SP for this packet */ |
1907 | /* XXX Is it right to call with IP_FORWARDING. */ | | 1907 | /* XXX Is it right to call with IP_FORWARDING. */ |
1908 | if (in6p == NULL) | | 1908 | if (in6p == NULL) |
1909 | sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); | | 1909 | sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); |
1910 | else | | 1910 | else |
1911 | sp = ipsec_getpolicybysock(m, dir, | | 1911 | sp = ipsec_getpolicybysock(m, dir, |
1912 | IN6PCB_TO_PCB(in6p), | | 1912 | IN6PCB_TO_PCB(in6p), |
1913 | &error); | | 1913 | &error); |
1914 | | | 1914 | |
1915 | if (sp == NULL) | | 1915 | if (sp == NULL) |
1916 | return 0; | | 1916 | return 0; |
1917 | size = ipsec_hdrsiz(sp); | | 1917 | size = ipsec_hdrsiz(sp); |
1918 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, | | 1918 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, |
1919 | printf("ipsec6_hdrsiz: size:%lu.\n", (unsigned long)size)); | | 1919 | printf("ipsec6_hdrsiz: size:%lu.\n", (unsigned long)size)); |
1920 | KEY_FREESP(&sp); | | 1920 | KEY_FREESP(&sp); |
1921 | | | 1921 | |
1922 | return size; | | 1922 | return size; |
1923 | } | | 1923 | } |
1924 | #endif /*INET6*/ | | 1924 | #endif /*INET6*/ |
1925 | | | 1925 | |
1926 | /* | | 1926 | /* |
1927 | * Check the variable replay window. | | 1927 | * Check the variable replay window. |
1928 | * ipsec_chkreplay() performs replay check before ICV verification. | | 1928 | * ipsec_chkreplay() performs replay check before ICV verification. |
1929 | * ipsec_updatereplay() updates replay bitmap. This must be called after | | 1929 | * ipsec_updatereplay() updates replay bitmap. This must be called after |
1930 | * ICV verification (it also performs replay check, which is usually done | | 1930 | * ICV verification (it also performs replay check, which is usually done |
1931 | * beforehand). | | 1931 | * beforehand). |
1932 | * 0 (zero) is returned if packet disallowed, 1 if packet permitted. | | 1932 | * 0 (zero) is returned if packet disallowed, 1 if packet permitted. |
1933 | * | | 1933 | * |
1934 | * based on RFC 2401. | | 1934 | * based on RFC 2401. |
1935 | */ | | 1935 | */ |
1936 | int | | 1936 | int |
1937 | ipsec_chkreplay(u_int32_t seq, const struct secasvar *sav) | | 1937 | ipsec_chkreplay(u_int32_t seq, const struct secasvar *sav) |
1938 | { | | 1938 | { |
1939 | const struct secreplay *replay; | | 1939 | const struct secreplay *replay; |
1940 | u_int32_t diff; | | 1940 | u_int32_t diff; |
1941 | int fr; | | 1941 | int fr; |
1942 | u_int32_t wsizeb; /* constant: bits of window size */ | | 1942 | u_int32_t wsizeb; /* constant: bits of window size */ |
1943 | int frlast; /* constant: last frame */ | | 1943 | int frlast; /* constant: last frame */ |
1944 | | | 1944 | |
1945 | IPSEC_SPLASSERT_SOFTNET("ipsec_chkreplay"); | | 1945 | IPSEC_SPLASSERT_SOFTNET("ipsec_chkreplay"); |
1946 | | | 1946 | |
1947 | IPSEC_ASSERT(sav != NULL, ("ipsec_chkreplay: Null SA")); | | 1947 | IPSEC_ASSERT(sav != NULL, ("ipsec_chkreplay: Null SA")); |
1948 | IPSEC_ASSERT(sav->replay != NULL, ("ipsec_chkreplay: Null replay state")); | | 1948 | IPSEC_ASSERT(sav->replay != NULL, ("ipsec_chkreplay: Null replay state")); |
1949 | | | 1949 | |
1950 | replay = sav->replay; | | 1950 | replay = sav->replay; |
1951 | | | 1951 | |
1952 | if (replay->wsize == 0) | | 1952 | if (replay->wsize == 0) |
1953 | return 1; /* no need to check replay. */ | | 1953 | return 1; /* no need to check replay. */ |
1954 | | | 1954 | |
1955 | /* constant */ | | 1955 | /* constant */ |
1956 | frlast = replay->wsize - 1; | | 1956 | frlast = replay->wsize - 1; |
1957 | wsizeb = replay->wsize << 3; | | 1957 | wsizeb = replay->wsize << 3; |
1958 | | | 1958 | |
1959 | /* sequence number of 0 is invalid */ | | 1959 | /* sequence number of 0 is invalid */ |
1960 | if (seq == 0) | | 1960 | if (seq == 0) |
1961 | return 0; | | 1961 | return 0; |
1962 | | | 1962 | |
1963 | /* first time is always okay */ | | 1963 | /* first time is always okay */ |
1964 | if (replay->count == 0) | | 1964 | if (replay->count == 0) |
1965 | return 1; | | 1965 | return 1; |
1966 | | | 1966 | |
1967 | if (seq > replay->lastseq) { | | 1967 | if (seq > replay->lastseq) { |
1968 | /* larger sequences are okay */ | | 1968 | /* larger sequences are okay */ |
1969 | return 1; | | 1969 | return 1; |
1970 | } else { | | 1970 | } else { |
1971 | /* seq is equal or less than lastseq. */ | | 1971 | /* seq is equal or less than lastseq. */ |
1972 | diff = replay->lastseq - seq; | | 1972 | diff = replay->lastseq - seq; |
1973 | | | 1973 | |
1974 | /* over range to check, i.e. too old or wrapped */ | | 1974 | /* over range to check, i.e. too old or wrapped */ |
1975 | if (diff >= wsizeb) | | 1975 | if (diff >= wsizeb) |
1976 | return 0; | | 1976 | return 0; |
1977 | | | 1977 | |
1978 | fr = frlast - diff / 8; | | 1978 | fr = frlast - diff / 8; |
1979 | | | 1979 | |
1980 | /* this packet already seen ? */ | | 1980 | /* this packet already seen ? */ |
1981 | if ((replay->bitmap)[fr] & (1 << (diff % 8))) | | 1981 | if ((replay->bitmap)[fr] & (1 << (diff % 8))) |
1982 | return 0; | | 1982 | return 0; |
1983 | | | 1983 | |
1984 | /* out of order but good */ | | 1984 | /* out of order but good */ |
1985 | return 1; | | 1985 | return 1; |
1986 | } | | 1986 | } |
1987 | } | | 1987 | } |
1988 | | | 1988 | |
1989 | /* | | 1989 | /* |
1990 | * check replay counter whether to update or not. | | 1990 | * check replay counter whether to update or not. |
1991 | * OUT: 0: OK | | 1991 | * OUT: 0: OK |
1992 | * 1: NG | | 1992 | * 1: NG |
1993 | */ | | 1993 | */ |
1994 | int | | 1994 | int |
1995 | ipsec_updatereplay(u_int32_t seq, const struct secasvar *sav) | | 1995 | ipsec_updatereplay(u_int32_t seq, const struct secasvar *sav) |
1996 | { | | 1996 | { |
1997 | struct secreplay *replay; | | 1997 | struct secreplay *replay; |
1998 | u_int32_t diff; | | 1998 | u_int32_t diff; |
1999 | int fr; | | 1999 | int fr; |
2000 | u_int32_t wsizeb; /* constant: bits of window size */ | | 2000 | u_int32_t wsizeb; /* constant: bits of window size */ |
2001 | int frlast; /* constant: last frame */ | | 2001 | int frlast; /* constant: last frame */ |
2002 | | | 2002 | |
2003 | IPSEC_SPLASSERT_SOFTNET("ipsec_updatereplay"); | | 2003 | IPSEC_SPLASSERT_SOFTNET("ipsec_updatereplay"); |
2004 | | | 2004 | |
2005 | IPSEC_ASSERT(sav != NULL, ("ipsec_updatereplay: Null SA")); | | 2005 | IPSEC_ASSERT(sav != NULL, ("ipsec_updatereplay: Null SA")); |
2006 | IPSEC_ASSERT(sav->replay != NULL, ("ipsec_updatereplay: Null replay state")); | | 2006 | IPSEC_ASSERT(sav->replay != NULL, ("ipsec_updatereplay: Null replay state")); |
2007 | | | 2007 | |
2008 | replay = sav->replay; | | 2008 | replay = sav->replay; |
2009 | | | 2009 | |
2010 | if (replay->wsize == 0) | | 2010 | if (replay->wsize == 0) |
2011 | goto ok; /* no need to check replay. */ | | 2011 | goto ok; /* no need to check replay. */ |
2012 | | | 2012 | |
2013 | /* constant */ | | 2013 | /* constant */ |
2014 | frlast = replay->wsize - 1; | | 2014 | frlast = replay->wsize - 1; |
2015 | wsizeb = replay->wsize << 3; | | 2015 | wsizeb = replay->wsize << 3; |
2016 | | | 2016 | |
2017 | /* sequence number of 0 is invalid */ | | 2017 | /* sequence number of 0 is invalid */ |
2018 | if (seq == 0) | | 2018 | if (seq == 0) |
2019 | return 1; | | 2019 | return 1; |
2020 | | | 2020 | |
2021 | /* first time */ | | 2021 | /* first time */ |
2022 | if (replay->count == 0) { | | 2022 | if (replay->count == 0) { |
2023 | replay->lastseq = seq; | | 2023 | replay->lastseq = seq; |
2024 | memset(replay->bitmap, 0, replay->wsize); | | 2024 | memset(replay->bitmap, 0, replay->wsize); |
2025 | (replay->bitmap)[frlast] = 1; | | 2025 | (replay->bitmap)[frlast] = 1; |
2026 | goto ok; | | 2026 | goto ok; |
2027 | } | | 2027 | } |
2028 | | | 2028 | |
2029 | if (seq > replay->lastseq) { | | 2029 | if (seq > replay->lastseq) { |
2030 | /* seq is larger than lastseq. */ | | 2030 | /* seq is larger than lastseq. */ |
2031 | diff = seq - replay->lastseq; | | 2031 | diff = seq - replay->lastseq; |
2032 | | | 2032 | |
2033 | /* new larger sequence number */ | | 2033 | /* new larger sequence number */ |
2034 | if (diff < wsizeb) { | | 2034 | if (diff < wsizeb) { |
2035 | /* In window */ | | 2035 | /* In window */ |
2036 | /* set bit for this packet */ | | 2036 | /* set bit for this packet */ |
2037 | vshiftl(replay->bitmap, diff, replay->wsize); | | 2037 | vshiftl(replay->bitmap, diff, replay->wsize); |
2038 | (replay->bitmap)[frlast] |= 1; | | 2038 | (replay->bitmap)[frlast] |= 1; |
2039 | } else { | | 2039 | } else { |
2040 | /* this packet has a "way larger" */ | | 2040 | /* this packet has a "way larger" */ |
2041 | memset(replay->bitmap, 0, replay->wsize); | | 2041 | memset(replay->bitmap, 0, replay->wsize); |
2042 | (replay->bitmap)[frlast] = 1; | | 2042 | (replay->bitmap)[frlast] = 1; |
2043 | } | | 2043 | } |
2044 | replay->lastseq = seq; | | 2044 | replay->lastseq = seq; |
2045 | | | 2045 | |
2046 | /* larger is good */ | | 2046 | /* larger is good */ |
2047 | } else { | | 2047 | } else { |
2048 | /* seq is equal or less than lastseq. */ | | 2048 | /* seq is equal or less than lastseq. */ |
2049 | diff = replay->lastseq - seq; | | 2049 | diff = replay->lastseq - seq; |
2050 | | | 2050 | |
2051 | /* over range to check, i.e. too old or wrapped */ | | 2051 | /* over range to check, i.e. too old or wrapped */ |
2052 | if (diff >= wsizeb) | | 2052 | if (diff >= wsizeb) |
2053 | return 1; | | 2053 | return 1; |
2054 | | | 2054 | |
2055 | fr = frlast - diff / 8; | | 2055 | fr = frlast - diff / 8; |
2056 | | | 2056 | |
2057 | /* this packet already seen ? */ | | 2057 | /* this packet already seen ? */ |
2058 | if ((replay->bitmap)[fr] & (1 << (diff % 8))) | | 2058 | if ((replay->bitmap)[fr] & (1 << (diff % 8))) |
2059 | return 1; | | 2059 | return 1; |
2060 | | | 2060 | |
2061 | /* mark as seen */ | | 2061 | /* mark as seen */ |
2062 | (replay->bitmap)[fr] |= (1 << (diff % 8)); | | 2062 | (replay->bitmap)[fr] |= (1 << (diff % 8)); |
2063 | | | 2063 | |
2064 | /* out of order but good */ | | 2064 | /* out of order but good */ |
2065 | } | | 2065 | } |
2066 | | | 2066 | |
2067 | ok: | | 2067 | ok: |
2068 | if (replay->count == ~0) { | | 2068 | if (replay->count == ~0) { |
2069 | | | 2069 | |
2070 | /* set overflow flag */ | | 2070 | /* set overflow flag */ |
2071 | replay->overflow++; | | 2071 | replay->overflow++; |
2072 | | | 2072 | |
2073 | /* don't increment, no more packets accepted */ | | 2073 | /* don't increment, no more packets accepted */ |
2074 | if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) | | 2074 | if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) |
2075 | return 1; | | 2075 | return 1; |
2076 | | | 2076 | |
2077 | ipseclog((LOG_WARNING, "replay counter made %d cycle. %s\n", | | 2077 | ipseclog((LOG_WARNING, "replay counter made %d cycle. %s\n", |
2078 | replay->overflow, ipsec_logsastr(sav))); | | 2078 | replay->overflow, ipsec_logsastr(sav))); |
2079 | } | | 2079 | } |
2080 | | | 2080 | |
2081 | replay->count++; | | 2081 | replay->count++; |
2082 | | | 2082 | |
2083 | return 0; | | 2083 | return 0; |
2084 | } | | 2084 | } |
2085 | | | 2085 | |
2086 | /* | | 2086 | /* |
2087 | * shift variable length bunffer to left. | | 2087 | * shift variable length bunffer to left. |
2088 | * IN: bitmap: pointer to the buffer | | 2088 | * IN: bitmap: pointer to the buffer |
2089 | * nbit: the number of to shift. | | 2089 | * nbit: the number of to shift. |
2090 | * wsize: buffer size (bytes). | | 2090 | * wsize: buffer size (bytes). |
2091 | */ | | 2091 | */ |
2092 | static void | | 2092 | static void |
2093 | vshiftl(unsigned char *bitmap, int nbit, int wsize) | | 2093 | vshiftl(unsigned char *bitmap, int nbit, int wsize) |
2094 | { | | 2094 | { |
2095 | int s, j, i; | | 2095 | int s, j, i; |
2096 | unsigned char over; | | 2096 | unsigned char over; |
2097 | | | 2097 | |
2098 | for (j = 0; j < nbit; j += 8) { | | 2098 | for (j = 0; j < nbit; j += 8) { |
2099 | s = (nbit - j < 8) ? (nbit - j): 8; | | 2099 | s = (nbit - j < 8) ? (nbit - j): 8; |
2100 | bitmap[0] <<= s; | | 2100 | bitmap[0] <<= s; |
2101 | for (i = 1; i < wsize; i++) { | | 2101 | for (i = 1; i < wsize; i++) { |
2102 | over = (bitmap[i] >> (8 - s)); | | 2102 | over = (bitmap[i] >> (8 - s)); |
2103 | bitmap[i] <<= s; | | 2103 | bitmap[i] <<= s; |
2104 | bitmap[i-1] |= over; | | 2104 | bitmap[i-1] |= over; |
2105 | } | | 2105 | } |
2106 | } | | 2106 | } |
2107 | | | 2107 | |
2108 | return; | | 2108 | return; |
2109 | } | | 2109 | } |
2110 | | | 2110 | |
2111 | /* Return a printable string for the IPv4 address. */ | | 2111 | /* Return a printable string for the IPv4 address. */ |
2112 | static char * | | 2112 | static char * |
2113 | inet_ntoa4(struct in_addr ina) | | 2113 | inet_ntoa4(struct in_addr ina) |
2114 | { | | 2114 | { |
2115 | static char buf[4][4 * sizeof "123" + 4]; | | 2115 | static char buf[4][4 * sizeof "123" + 4]; |
2116 | unsigned char *ucp = (unsigned char *) &ina; | | 2116 | unsigned char *ucp = (unsigned char *) &ina; |
2117 | static int i = 3; | | 2117 | static int i = 3; |
2118 | | | 2118 | |
2119 | i = (i + 1) % 4; | | 2119 | i = (i + 1) % 4; |
2120 | snprintf(buf[i], sizeof(buf[i]), "%d.%d.%d.%d", | | 2120 | snprintf(buf[i], sizeof(buf[i]), "%d.%d.%d.%d", |
2121 | ucp[0] & 0xff, ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff); | | 2121 | ucp[0] & 0xff, ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff); |
2122 | return (buf[i]); | | 2122 | return (buf[i]); |
2123 | } | | 2123 | } |
2124 | | | 2124 | |
2125 | /* Return a printable string for the address. */ | | 2125 | /* Return a printable string for the address. */ |
2126 | const char * | | 2126 | const char * |
2127 | ipsec_address(const union sockaddr_union *sa) | | 2127 | ipsec_address(const union sockaddr_union *sa) |
2128 | { | | 2128 | { |
2129 | switch (sa->sa.sa_family) { | | 2129 | switch (sa->sa.sa_family) { |
2130 | #if INET | | 2130 | #if INET |
2131 | case AF_INET: | | 2131 | case AF_INET: |
2132 | return inet_ntoa4(sa->sin.sin_addr); | | 2132 | return inet_ntoa4(sa->sin.sin_addr); |
2133 | #endif /* INET */ | | 2133 | #endif /* INET */ |
2134 | | | 2134 | |
2135 | #if INET6 | | 2135 | #if INET6 |
2136 | case AF_INET6: | | 2136 | case AF_INET6: |
2137 | return ip6_sprintf(&sa->sin6.sin6_addr); | | 2137 | return ip6_sprintf(&sa->sin6.sin6_addr); |
2138 | #endif /* INET6 */ | | 2138 | #endif /* INET6 */ |
2139 | | | 2139 | |
2140 | default: | | 2140 | default: |
2141 | return "(unknown address family)"; | | 2141 | return "(unknown address family)"; |
2142 | } | | 2142 | } |
2143 | } | | 2143 | } |
2144 | | | 2144 | |
2145 | const char * | | 2145 | const char * |
2146 | ipsec_logsastr(const struct secasvar *sav) | | 2146 | ipsec_logsastr(const struct secasvar *sav) |
2147 | { | | 2147 | { |
2148 | static char buf[256]; | | 2148 | static char buf[256]; |
2149 | char *p; | | 2149 | char *p; |
2150 | const struct secasindex *saidx = &sav->sah->saidx; | | 2150 | const struct secasindex *saidx = &sav->sah->saidx; |
2151 | | | 2151 | |
2152 | IPSEC_ASSERT(saidx->src.sa.sa_family == saidx->dst.sa.sa_family, | | 2152 | IPSEC_ASSERT(saidx->src.sa.sa_family == saidx->dst.sa.sa_family, |
2153 | ("ipsec_logsastr: address family mismatch")); | | 2153 | ("ipsec_logsastr: address family mismatch")); |
2154 | | | 2154 | |
2155 | p = buf; | | 2155 | p = buf; |
2156 | snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); | | 2156 | snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); |
2157 | while (p && *p) | | 2157 | while (p && *p) |
2158 | p++; | | 2158 | p++; |
2159 | /* NB: only use ipsec_address on one address at a time */ | | 2159 | /* NB: only use ipsec_address on one address at a time */ |
2160 | snprintf(p, sizeof (buf) - (p - buf), "src=%s ", | | 2160 | snprintf(p, sizeof (buf) - (p - buf), "src=%s ", |
2161 | ipsec_address(&saidx->src)); | | 2161 | ipsec_address(&saidx->src)); |
2162 | while (p && *p) | | 2162 | while (p && *p) |
2163 | p++; | | 2163 | p++; |
2164 | snprintf(p, sizeof (buf) - (p - buf), "dst=%s)", | | 2164 | snprintf(p, sizeof (buf) - (p - buf), "dst=%s)", |
2165 | ipsec_address(&saidx->dst)); | | 2165 | ipsec_address(&saidx->dst)); |
2166 | | | 2166 | |
2167 | return buf; | | 2167 | return buf; |
2168 | } | | 2168 | } |
2169 | | | 2169 | |
2170 | void | | 2170 | void |
2171 | ipsec_dumpmbuf(struct mbuf *m) | | 2171 | ipsec_dumpmbuf(struct mbuf *m) |
2172 | { | | 2172 | { |
2173 | int totlen; | | 2173 | int totlen; |
2174 | int i; | | 2174 | int i; |
2175 | u_char *p; | | 2175 | u_char *p; |
2176 | | | 2176 | |
2177 | totlen = 0; | | 2177 | totlen = 0; |
2178 | printf("---\n"); | | 2178 | printf("---\n"); |
2179 | while (m) { | | 2179 | while (m) { |
2180 | p = mtod(m, u_char *); | | 2180 | p = mtod(m, u_char *); |
2181 | for (i = 0; i < m->m_len; i++) { | | 2181 | for (i = 0; i < m->m_len; i++) { |
2182 | printf("%02x ", p[i]); | | 2182 | printf("%02x ", p[i]); |
2183 | totlen++; | | 2183 | totlen++; |
2184 | if (totlen % 16 == 0) | | 2184 | if (totlen % 16 == 0) |
2185 | printf("\n"); | | 2185 | printf("\n"); |
2186 | } | | 2186 | } |
2187 | m = m->m_next; | | 2187 | m = m->m_next; |
2188 | } | | 2188 | } |
2189 | if (totlen % 16 != 0) | | 2189 | if (totlen % 16 != 0) |
2190 | printf("\n"); | | 2190 | printf("\n"); |
2191 | printf("---\n"); | | 2191 | printf("---\n"); |
2192 | } | | 2192 | } |
2193 | | | 2193 | |
2194 | #ifdef INET6 | | 2194 | #ifdef INET6 |
2195 | struct secpolicy * | | 2195 | struct secpolicy * |
2196 | ipsec6_check_policy(struct mbuf *m, const struct socket *so, | | 2196 | ipsec6_check_policy(struct mbuf *m, const struct socket *so, |
2197 | int flags, int *needipsecp, int *errorp) | | 2197 | int flags, int *needipsecp, int *errorp) |
2198 | { | | 2198 | { |
2199 | struct in6pcb *in6p = NULL; | | 2199 | struct in6pcb *in6p = NULL; |
2200 | struct secpolicy *sp = NULL; | | 2200 | struct secpolicy *sp = NULL; |
2201 | int s; | | 2201 | int s; |
2202 | int error = 0; | | 2202 | int error = 0; |
2203 | int needipsec = 0; | | 2203 | int needipsec = 0; |
2204 | | | 2204 | |
2205 | if (so != NULL && so->so_proto->pr_domain->dom_family == AF_INET6) | | 2205 | if (so != NULL && so->so_proto->pr_domain->dom_family == AF_INET6) |
2206 | in6p = sotoin6pcb(so); | | 2206 | in6p = sotoin6pcb(so); |
2207 | | | 2207 | |
2208 | if (!ipsec_outdone(m)) { | | 2208 | if (!ipsec_outdone(m)) { |
2209 | s = splsoftnet(); | | 2209 | s = splsoftnet(); |
2210 | if (in6p != NULL && | | 2210 | if (in6p != NULL && |
2211 | IPSEC_PCB_SKIP_IPSEC(in6p->in6p_sp, IPSEC_DIR_OUTBOUND)) { | | 2211 | IPSEC_PCB_SKIP_IPSEC(in6p->in6p_sp, IPSEC_DIR_OUTBOUND)) { |
2212 | splx(s); | | 2212 | splx(s); |
2213 | goto skippolicycheck; | | 2213 | goto skippolicycheck; |
2214 | } | | 2214 | } |
2215 | sp = ipsec6_checkpolicy(m, IPSEC_DIR_OUTBOUND, flags, &error,in6p); | | 2215 | sp = ipsec6_checkpolicy(m, IPSEC_DIR_OUTBOUND, flags, &error,in6p); |
2216 | | | 2216 | |
2217 | /* | | 2217 | /* |
2218 | * There are four return cases: | | 2218 | * There are four return cases: |
2219 | * sp != NULL apply IPsec policy | | 2219 | * sp != NULL apply IPsec policy |
2220 | * sp == NULL, error == 0 no IPsec handling needed | | 2220 | * sp == NULL, error == 0 no IPsec handling needed |
2221 | * sp == NULL, error == -EINVAL discard packet w/o error | | 2221 | * sp == NULL, error == -EINVAL discard packet w/o error |
2222 | * sp == NULL, error != 0 discard packet, report error | | 2222 | * sp == NULL, error != 0 discard packet, report error |
2223 | */ | | 2223 | */ |
2224 | | | 2224 | |
2225 | splx(s); | | 2225 | splx(s); |
2226 | if (sp == NULL) { | | 2226 | if (sp == NULL) { |