| @@ -1,734 +1,746 @@ | | | @@ -1,734 +1,746 @@ |
1 | /* $NetBSD: ipsec_output.c,v 1.35 2011/06/07 15:54:57 drochner Exp $ */ | | 1 | /* $NetBSD: ipsec_output.c,v 1.36 2011/06/09 21:04:37 drochner Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting | | 4 | * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | * | | 27 | * |
28 | * $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $ | | 28 | * $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $ |
29 | */ | | 29 | */ |
30 | | | 30 | |
31 | #include <sys/cdefs.h> | | 31 | #include <sys/cdefs.h> |
32 | __KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.35 2011/06/07 15:54:57 drochner Exp $"); | | 32 | __KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.36 2011/06/09 21:04:37 drochner Exp $"); |
33 | | | 33 | |
34 | /* | | 34 | /* |
35 | * IPsec output processing. | | 35 | * IPsec output processing. |
36 | */ | | 36 | */ |
37 | #include "opt_inet.h" | | 37 | #include "opt_inet.h" |
38 | #ifdef __FreeBSD__ | | 38 | #ifdef __FreeBSD__ |
39 | #include "opt_inet6.h" | | 39 | #include "opt_inet6.h" |
40 | #endif | | 40 | #endif |
41 | #include "opt_ipsec.h" | | 41 | #include "opt_ipsec.h" |
42 | | | 42 | |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <sys/systm.h> | | 44 | #include <sys/systm.h> |
45 | #include <sys/mbuf.h> | | 45 | #include <sys/mbuf.h> |
46 | #include <sys/domain.h> | | 46 | #include <sys/domain.h> |
47 | #include <sys/protosw.h> | | 47 | #include <sys/protosw.h> |
48 | #include <sys/socket.h> | | 48 | #include <sys/socket.h> |
49 | #include <sys/errno.h> | | 49 | #include <sys/errno.h> |
50 | #include <sys/syslog.h> | | 50 | #include <sys/syslog.h> |
51 | | | 51 | |
52 | #include <net/if.h> | | 52 | #include <net/if.h> |
53 | #include <net/route.h> | | 53 | #include <net/route.h> |
54 | | | 54 | |
55 | #include <netinet/in.h> | | 55 | #include <netinet/in.h> |
56 | #include <netinet/in_systm.h> | | 56 | #include <netinet/in_systm.h> |
57 | #include <netinet/ip.h> | | 57 | #include <netinet/ip.h> |
58 | #include <netinet/ip_var.h> | | 58 | #include <netinet/ip_var.h> |
59 | #include <netinet/in_var.h> | | 59 | #include <netinet/in_var.h> |
60 | #include <netinet/ip_ecn.h> | | 60 | #include <netinet/ip_ecn.h> |
61 | #ifdef INET6 | | 61 | #ifdef INET6 |
62 | # ifdef __FreeBSD__ | | 62 | # ifdef __FreeBSD__ |
63 | # include <netinet6/ip6_ecn.h> | | 63 | # include <netinet6/ip6_ecn.h> |
64 | # endif | | 64 | # endif |
65 | #endif | | 65 | #endif |
66 | | | 66 | |
67 | #include <netinet/ip6.h> | | 67 | #include <netinet/ip6.h> |
68 | #ifdef INET6 | | 68 | #ifdef INET6 |
69 | #include <netinet6/ip6_var.h> | | 69 | #include <netinet6/ip6_var.h> |
70 | #endif | | 70 | #endif |
71 | #include <netinet/in_pcb.h> | | 71 | #include <netinet/in_pcb.h> |
72 | #ifdef INET6 | | 72 | #ifdef INET6 |
73 | #include <netinet/icmp6.h> | | 73 | #include <netinet/icmp6.h> |
74 | #endif | | 74 | #endif |
75 | #ifdef IPSEC_NAT_T | | 75 | #ifdef IPSEC_NAT_T |
76 | #include <netinet/udp.h> | | 76 | #include <netinet/udp.h> |
77 | #endif | | 77 | #endif |
78 | | | 78 | |
79 | #include <netipsec/ipsec.h> | | 79 | #include <netipsec/ipsec.h> |
80 | #include <netipsec/ipsec_var.h> | | 80 | #include <netipsec/ipsec_var.h> |
81 | #include <netipsec/ipsec_private.h> | | 81 | #include <netipsec/ipsec_private.h> |
82 | #ifdef INET6 | | 82 | #ifdef INET6 |
83 | #include <netipsec/ipsec6.h> | | 83 | #include <netipsec/ipsec6.h> |
84 | #endif | | 84 | #endif |
85 | #include <netipsec/ah_var.h> | | 85 | #include <netipsec/ah_var.h> |
86 | #include <netipsec/esp_var.h> | | 86 | #include <netipsec/esp_var.h> |
87 | #include <netipsec/ipcomp_var.h> | | 87 | #include <netipsec/ipcomp_var.h> |
88 | | | 88 | |
89 | #include <netipsec/xform.h> | | 89 | #include <netipsec/xform.h> |
90 | | | 90 | |
91 | #include <netipsec/key.h> | | 91 | #include <netipsec/key.h> |
92 | #include <netipsec/keydb.h> | | 92 | #include <netipsec/keydb.h> |
93 | #include <netipsec/key_debug.h> | | 93 | #include <netipsec/key_debug.h> |
94 | #include <netipsec/ipsec_osdep.h> | | 94 | #include <netipsec/ipsec_osdep.h> |
95 | | | 95 | |
96 | #include <net/net_osdep.h> /* ovbcopy() in ipsec6_encapsulate() */ | | 96 | #include <net/net_osdep.h> /* ovbcopy() in ipsec6_encapsulate() */ |
97 | | | 97 | |
98 | | | 98 | |
99 | /* | | 99 | /* |
100 | * Add a IPSEC_OUT_DONE tag to mark that we have finished the ipsec processing | | 100 | * Add a IPSEC_OUT_DONE tag to mark that we have finished the ipsec processing |
101 | * It will be used by ip{,6}_output to check if we have already or not | | 101 | * It will be used by ip{,6}_output to check if we have already or not |
102 | * processed this packet. | | 102 | * processed this packet. |
103 | */ | | 103 | */ |
104 | static int | | 104 | static int |
105 | ipsec_register_done(struct mbuf *m, int * error) | | 105 | ipsec_register_done(struct mbuf *m, int * error) |
106 | { | | 106 | { |
107 | struct m_tag *mtag; | | 107 | struct m_tag *mtag; |
108 | | | 108 | |
109 | mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 0, M_NOWAIT); | | 109 | mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 0, M_NOWAIT); |
110 | if (mtag == NULL) { | | 110 | if (mtag == NULL) { |
111 | DPRINTF(("ipsec_register_done: could not get packet tag\n")); | | 111 | DPRINTF(("ipsec_register_done: could not get packet tag\n")); |
112 | *error = ENOMEM; | | 112 | *error = ENOMEM; |
113 | return -1; | | 113 | return -1; |
114 | } | | 114 | } |
115 | | | 115 | |
116 | m_tag_prepend(m, mtag); | | 116 | m_tag_prepend(m, mtag); |
117 | return 0; | | 117 | return 0; |
118 | } | | 118 | } |
119 | | | 119 | |
120 | static int | | 120 | static int |
121 | ipsec_reinject_ipstack(struct mbuf *m, int af) | | 121 | ipsec_reinject_ipstack(struct mbuf *m, int af) |
122 | { | | 122 | { |
123 | #ifdef INET | | 123 | #ifdef INET |
124 | struct ip * ip; | | 124 | struct ip * ip; |
125 | #endif /* INET */ | | 125 | #endif /* INET */ |
126 | #if defined(INET) || defined(INET6) | | 126 | #if defined(INET) || defined(INET6) |
127 | int rv; | | 127 | int rv; |
128 | #endif | | 128 | #endif |
129 | | | 129 | |
130 | switch (af) { | | 130 | switch (af) { |
131 | #ifdef INET | | 131 | #ifdef INET |
132 | case AF_INET: | | 132 | case AF_INET: |
133 | ip = mtod(m, struct ip *); | | 133 | ip = mtod(m, struct ip *); |
134 | #ifdef __FreeBSD__ | | 134 | #ifdef __FreeBSD__ |
135 | /* FreeBSD ip_output() expects ip_len, ip_off in host endian */ | | 135 | /* FreeBSD ip_output() expects ip_len, ip_off in host endian */ |
136 | ip->ip_len = ntohs(ip->ip_len); | | 136 | ip->ip_len = ntohs(ip->ip_len); |
137 | ip->ip_off = ntohs(ip->ip_off); | | 137 | ip->ip_off = ntohs(ip->ip_off); |
138 | #endif /* __FreeBSD_ */ | | 138 | #endif /* __FreeBSD_ */ |
139 | KERNEL_LOCK(1, NULL); | | 139 | KERNEL_LOCK(1, NULL); |
140 | rv = ip_output(m, NULL, NULL, IP_RAWOUTPUT|IP_NOIPNEWID, | | 140 | rv = ip_output(m, NULL, NULL, IP_RAWOUTPUT|IP_NOIPNEWID, |
141 | (struct ip_moptions *)NULL, (struct socket *)NULL); | | 141 | (struct ip_moptions *)NULL, (struct socket *)NULL); |
142 | KERNEL_UNLOCK_ONE(NULL); | | 142 | KERNEL_UNLOCK_ONE(NULL); |
143 | return rv; | | 143 | return rv; |
144 | | | 144 | |
145 | #endif /* INET */ | | 145 | #endif /* INET */ |
146 | #ifdef INET6 | | 146 | #ifdef INET6 |
147 | case AF_INET6: | | 147 | case AF_INET6: |
148 | /* | | 148 | /* |
149 | * We don't need massage, IPv6 header fields are always in | | 149 | * We don't need massage, IPv6 header fields are always in |
150 | * net endian. | | 150 | * net endian. |
151 | */ | | 151 | */ |
152 | KERNEL_LOCK(1, NULL); | | 152 | KERNEL_LOCK(1, NULL); |
153 | rv = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); | | 153 | rv = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); |
154 | KERNEL_UNLOCK_ONE(NULL); | | 154 | KERNEL_UNLOCK_ONE(NULL); |
155 | return rv; | | 155 | return rv; |
156 | #endif /* INET6 */ | | 156 | #endif /* INET6 */ |
157 | } | | 157 | } |
158 | | | 158 | |
159 | panic("ipsec_reinject_ipstack : iunknown protocol family %u\n", af); | | 159 | panic("ipsec_reinject_ipstack : iunknown protocol family %u\n", af); |
160 | return -1; /* NOTREACHED */ | | 160 | return -1; /* NOTREACHED */ |
161 | } | | 161 | } |
162 | | | 162 | |
163 | int | | 163 | int |
164 | ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) | | 164 | ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) |
165 | { | | 165 | { |
166 | struct secasvar *sav; | | 166 | struct secasvar *sav; |
167 | struct secasindex *saidx; | | 167 | struct secasindex *saidx; |
168 | int error; | | 168 | int error; |
169 | #ifdef INET | | 169 | #ifdef INET |
170 | struct ip * ip; | | 170 | struct ip * ip; |
171 | #endif /* INET */ | | 171 | #endif /* INET */ |
172 | #ifdef INET6 | | 172 | #ifdef INET6 |
173 | struct ip6_hdr * ip6; | | 173 | struct ip6_hdr * ip6; |
174 | #endif /* INET6 */ | | 174 | #endif /* INET6 */ |
175 | #ifdef IPSEC_NAT_T | | 175 | #ifdef IPSEC_NAT_T |
176 | struct mbuf * mo; | | 176 | struct mbuf * mo; |
177 | struct udphdr *udp = NULL; | | 177 | struct udphdr *udp = NULL; |
178 | uint64_t * data = NULL; | | 178 | uint64_t * data = NULL; |
179 | int hlen, roff; | | 179 | int hlen, roff; |
180 | #endif /* IPSEC_NAT_T */ | | 180 | #endif /* IPSEC_NAT_T */ |
181 | | | 181 | |
182 | IPSEC_SPLASSERT_SOFTNET("ipsec_process_done"); | | 182 | IPSEC_SPLASSERT_SOFTNET("ipsec_process_done"); |
183 | | | 183 | |
184 | IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf")); | | 184 | IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf")); |
185 | IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR")); | | 185 | IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR")); |
186 | sav = isr->sav; | | 186 | sav = isr->sav; |
187 | IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA")); | | 187 | IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA")); |
188 | IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH")); | | 188 | IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH")); |
189 | | | 189 | |
190 | saidx = &sav->sah->saidx; | | 190 | saidx = &sav->sah->saidx; |
191 | | | 191 | |
192 | #ifdef IPSEC_NAT_T | | 192 | #ifdef IPSEC_NAT_T |
193 | if(sav->natt_type != 0) { | | 193 | if(sav->natt_type != 0) { |
194 | ip = mtod(m, struct ip *); | | 194 | ip = mtod(m, struct ip *); |
195 | | | 195 | |
196 | hlen = sizeof(struct udphdr); | | 196 | hlen = sizeof(struct udphdr); |
197 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) | | 197 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) |
198 | hlen += sizeof(uint64_t); | | 198 | hlen += sizeof(uint64_t); |
199 | | | 199 | |
200 | mo = m_makespace(m, sizeof(struct ip), hlen, &roff); | | 200 | mo = m_makespace(m, sizeof(struct ip), hlen, &roff); |
201 | if (mo == NULL) { | | 201 | if (mo == NULL) { |
202 | DPRINTF(("ipsec_process_done : failed to inject" | | 202 | DPRINTF(("ipsec_process_done : failed to inject" |
203 | "%u byte UDP for SA %s/%08lx\n", | | 203 | "%u byte UDP for SA %s/%08lx\n", |
204 | hlen, ipsec_address(&saidx->dst), | | 204 | hlen, ipsec_address(&saidx->dst), |
205 | (u_long) ntohl(sav->spi))); | | 205 | (u_long) ntohl(sav->spi))); |
206 | error = ENOBUFS; | | 206 | error = ENOBUFS; |
207 | goto bad; | | 207 | goto bad; |
208 | } | | 208 | } |
209 | | | 209 | |
210 | udp = (struct udphdr*) (mtod(mo, char*) + roff); | | 210 | udp = (struct udphdr*) (mtod(mo, char*) + roff); |
211 | data = (uint64_t*) (udp + 1); | | 211 | data = (uint64_t*) (udp + 1); |
212 | | | 212 | |
213 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) | | 213 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) |
214 | *data = 0; /* NON-IKE Marker */ | | 214 | *data = 0; /* NON-IKE Marker */ |
215 | | | 215 | |
216 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) | | 216 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) |
217 | udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT); | | 217 | udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT); |
218 | else | | 218 | else |
219 | udp->uh_sport = key_portfromsaddr(&saidx->src); | | 219 | udp->uh_sport = key_portfromsaddr(&saidx->src); |
220 | | | 220 | |
221 | udp->uh_dport = key_portfromsaddr(&saidx->dst); | | 221 | udp->uh_dport = key_portfromsaddr(&saidx->dst); |
222 | udp->uh_sum = 0; | | 222 | udp->uh_sum = 0; |
223 | udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2)); | | 223 | udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2)); |
224 | } | | 224 | } |
225 | #endif /* IPSEC_NAT_T */ | | 225 | #endif /* IPSEC_NAT_T */ |
226 | | | 226 | |
227 | switch (saidx->dst.sa.sa_family) { | | 227 | switch (saidx->dst.sa.sa_family) { |
228 | #ifdef INET | | 228 | #ifdef INET |
229 | case AF_INET: | | 229 | case AF_INET: |
230 | /* Fix the header length, for AH processing. */ | | 230 | /* Fix the header length, for AH processing. */ |
231 | ip = mtod(m, struct ip *); | | 231 | ip = mtod(m, struct ip *); |
232 | ip->ip_len = htons(m->m_pkthdr.len); | | 232 | ip->ip_len = htons(m->m_pkthdr.len); |
233 | #ifdef IPSEC_NAT_T | | 233 | #ifdef IPSEC_NAT_T |
234 | if (sav->natt_type != 0) | | 234 | if (sav->natt_type != 0) |
235 | ip->ip_p = IPPROTO_UDP; | | 235 | ip->ip_p = IPPROTO_UDP; |
236 | #endif /* IPSEC_NAT_T */ | | 236 | #endif /* IPSEC_NAT_T */ |
237 | break; | | 237 | break; |
238 | #endif /* INET */ | | 238 | #endif /* INET */ |
239 | #ifdef INET6 | | 239 | #ifdef INET6 |
240 | case AF_INET6: | | 240 | case AF_INET6: |
241 | /* Fix the header length, for AH processing. */ | | 241 | /* Fix the header length, for AH processing. */ |
242 | if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) { | | 242 | if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) { |
243 | error = ENXIO; | | 243 | error = ENXIO; |
244 | goto bad; | | 244 | goto bad; |
245 | } | | 245 | } |
246 | if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) { | | 246 | if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) { |
247 | /* No jumbogram support. */ | | 247 | /* No jumbogram support. */ |
248 | error = ENXIO; /*?*/ | | 248 | error = ENXIO; /*?*/ |
249 | goto bad; | | 249 | goto bad; |
250 | } | | 250 | } |
251 | ip6 = mtod(m, struct ip6_hdr *); | | 251 | ip6 = mtod(m, struct ip6_hdr *); |
252 | ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); | | 252 | ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); |
253 | #ifdef IPSEC_NAT_T | | 253 | #ifdef IPSEC_NAT_T |
254 | if (sav->natt_type != 0) | | 254 | if (sav->natt_type != 0) |
255 | ip6->ip6_nxt = IPPROTO_UDP; | | 255 | ip6->ip6_nxt = IPPROTO_UDP; |
256 | #endif /* IPSEC_NAT_T */ | | 256 | #endif /* IPSEC_NAT_T */ |
257 | break; | | 257 | break; |
258 | #endif /* INET6 */ | | 258 | #endif /* INET6 */ |
259 | default: | | 259 | default: |
260 | DPRINTF(("ipsec_process_done: unknown protocol family %u\n", | | 260 | DPRINTF(("ipsec_process_done: unknown protocol family %u\n", |
261 | saidx->dst.sa.sa_family)); | | 261 | saidx->dst.sa.sa_family)); |
262 | error = ENXIO; | | 262 | error = ENXIO; |
263 | goto bad; | | 263 | goto bad; |
264 | } | | 264 | } |
265 | | | 265 | |
266 | key_sa_recordxfer(sav, m); | | 266 | key_sa_recordxfer(sav, m); |
267 | | | 267 | |
268 | /* | | 268 | /* |
269 | * If there's another (bundled) SA to apply, do so. | | 269 | * If there's another (bundled) SA to apply, do so. |
270 | * Note that this puts a burden on the kernel stack size. | | 270 | * Note that this puts a burden on the kernel stack size. |
271 | * If this is a problem we'll need to introduce a queue | | 271 | * If this is a problem we'll need to introduce a queue |
272 | * to set the packet on so we can unwind the stack before | | 272 | * to set the packet on so we can unwind the stack before |
273 | * doing further processing. | | 273 | * doing further processing. |
274 | */ | | 274 | */ |
275 | if (isr->next) { | | 275 | if (isr->next) { |
276 | IPSEC_STATINC(IPSEC_STAT_OUT_BUNDLESA); | | 276 | IPSEC_STATINC(IPSEC_STAT_OUT_BUNDLESA); |
277 | switch ( saidx->dst.sa.sa_family ) { | | 277 | switch ( saidx->dst.sa.sa_family ) { |
278 | #ifdef INET | | 278 | #ifdef INET |
279 | case AF_INET: | | 279 | case AF_INET: |
280 | return ipsec4_process_packet(m, isr->next, 0,0); | | 280 | return ipsec4_process_packet(m, isr->next, 0,0); |
281 | #endif /* INET */ | | 281 | #endif /* INET */ |
282 | #ifdef INET6 | | 282 | #ifdef INET6 |
283 | case AF_INET6: | | 283 | case AF_INET6: |
284 | return ipsec6_process_packet(m,isr->next); | | 284 | return ipsec6_process_packet(m,isr->next); |
285 | #endif /* INET6 */ | | 285 | #endif /* INET6 */ |
286 | default : | | 286 | default : |
287 | DPRINTF(("ipsec_process_done: unknown protocol family %u\n", | | 287 | DPRINTF(("ipsec_process_done: unknown protocol family %u\n", |
288 | saidx->dst.sa.sa_family)); | | 288 | saidx->dst.sa.sa_family)); |
289 | error = ENXIO; | | 289 | error = ENXIO; |
290 | goto bad; | | 290 | goto bad; |
291 | } | | 291 | } |
292 | } | | 292 | } |
293 | | | 293 | |
294 | /* | | 294 | /* |
295 | * We're done with IPsec processing, | | 295 | * We're done with IPsec processing, |
296 | * mark that we have already processed the packet | | 296 | * mark that we have already processed the packet |
297 | * transmit it packet using the appropriate network protocol (IP or IPv6). | | 297 | * transmit it packet using the appropriate network protocol (IP or IPv6). |
298 | */ | | 298 | */ |
299 | | | 299 | |
300 | if (ipsec_register_done(m, &error) < 0) | | 300 | if (ipsec_register_done(m, &error) < 0) |
301 | goto bad; | | 301 | goto bad; |
302 | | | 302 | |
303 | return ipsec_reinject_ipstack(m, saidx->dst.sa.sa_family); | | 303 | return ipsec_reinject_ipstack(m, saidx->dst.sa.sa_family); |
304 | bad: | | 304 | bad: |
305 | m_freem(m); | | 305 | m_freem(m); |
306 | KEY_FREESAV(&sav); | | 306 | KEY_FREESAV(&sav); |
307 | return (error); | | 307 | return (error); |
308 | } | | 308 | } |
309 | | | 309 | |
310 | /* | | 310 | /* |
311 | * ipsec_nextisr can return : | | 311 | * ipsec_nextisr can return : |
312 | * - isr == NULL and error != 0 => something is bad : the packet must be | | 312 | * - isr == NULL and error != 0 => something is bad : the packet must be |
313 | * discarded | | 313 | * discarded |
314 | * - isr == NULL and error == 0 => no more rules to apply, ipsec processing | | 314 | * - isr == NULL and error == 0 => no more rules to apply, ipsec processing |
315 | * is done, reinject it in ip stack | | 315 | * is done, reinject it in ip stack |
316 | * - isr != NULL (error == 0) => we need to apply one rule to the packet | | 316 | * - isr != NULL (error == 0) => we need to apply one rule to the packet |
317 | */ | | 317 | */ |
318 | static struct ipsecrequest * | | 318 | static struct ipsecrequest * |
319 | ipsec_nextisr( | | 319 | ipsec_nextisr( |
320 | struct mbuf *m, | | 320 | struct mbuf *m, |
321 | struct ipsecrequest *isr, | | 321 | struct ipsecrequest *isr, |
322 | int af, | | 322 | int af, |
323 | struct secasindex *saidx, | | 323 | struct secasindex *saidx, |
324 | int *error | | 324 | int *error |
325 | ) | | 325 | ) |
326 | { | | 326 | { |
327 | #define IPSEC_OSTAT(x, y, z) \ | | 327 | #define IPSEC_OSTAT(x, y, z) \ |
328 | do { \ | | 328 | do { \ |
329 | switch (isr->saidx.proto) { \ | | 329 | switch (isr->saidx.proto) { \ |
330 | case IPPROTO_ESP: \ | | 330 | case IPPROTO_ESP: \ |
331 | ESP_STATINC(x); \ | | 331 | ESP_STATINC(x); \ |
332 | break; \ | | 332 | break; \ |
333 | case IPPROTO_AH: \ | | 333 | case IPPROTO_AH: \ |
334 | AH_STATINC(y); \ | | 334 | AH_STATINC(y); \ |
335 | break; \ | | 335 | break; \ |
336 | default: \ | | 336 | default: \ |
337 | IPCOMP_STATINC(z); \ | | 337 | IPCOMP_STATINC(z); \ |
338 | break; \ | | 338 | break; \ |
339 | } \ | | 339 | } \ |
340 | } while (/*CONSTCOND*/0) | | 340 | } while (/*CONSTCOND*/0) |
341 | | | 341 | |
342 | struct secasvar *sav; | | 342 | struct secasvar *sav; |
343 | | | 343 | |
344 | IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr"); | | 344 | IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr"); |
345 | IPSEC_ASSERT(af == AF_INET || af == AF_INET6, | | 345 | IPSEC_ASSERT(af == AF_INET || af == AF_INET6, |
346 | ("ipsec_nextisr: invalid address family %u", af)); | | 346 | ("ipsec_nextisr: invalid address family %u", af)); |
347 | again: | | 347 | again: |
348 | /* | | 348 | /* |
349 | * Craft SA index to search for proper SA. Note that | | 349 | * Craft SA index to search for proper SA. Note that |
350 | * we only fillin unspecified SA peers for transport | | 350 | * we only fillin unspecified SA peers for transport |
351 | * mode; for tunnel mode they must already be filled in. | | 351 | * mode; for tunnel mode they must already be filled in. |
352 | */ | | 352 | */ |
353 | *saidx = isr->saidx; | | 353 | *saidx = isr->saidx; |
354 | if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { | | 354 | if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { |
355 | /* Fillin unspecified SA peers only for transport mode */ | | 355 | /* Fillin unspecified SA peers only for transport mode */ |
356 | if (af == AF_INET) { | | 356 | if (af == AF_INET) { |
357 | struct sockaddr_in *sin; | | 357 | struct sockaddr_in *sin; |
358 | struct ip *ip = mtod(m, struct ip *); | | 358 | struct ip *ip = mtod(m, struct ip *); |
359 | | | 359 | |
360 | if (saidx->src.sa.sa_len == 0) { | | 360 | if (saidx->src.sa.sa_len == 0) { |
361 | sin = &saidx->src.sin; | | 361 | sin = &saidx->src.sin; |
362 | sin->sin_len = sizeof(*sin); | | 362 | sin->sin_len = sizeof(*sin); |
363 | sin->sin_family = AF_INET; | | 363 | sin->sin_family = AF_INET; |
364 | sin->sin_port = IPSEC_PORT_ANY; | | 364 | sin->sin_port = IPSEC_PORT_ANY; |
365 | sin->sin_addr = ip->ip_src; | | 365 | sin->sin_addr = ip->ip_src; |
366 | } | | 366 | } |
367 | if (saidx->dst.sa.sa_len == 0) { | | 367 | if (saidx->dst.sa.sa_len == 0) { |
368 | sin = &saidx->dst.sin; | | 368 | sin = &saidx->dst.sin; |
369 | sin->sin_len = sizeof(*sin); | | 369 | sin->sin_len = sizeof(*sin); |
370 | sin->sin_family = AF_INET; | | 370 | sin->sin_family = AF_INET; |
371 | sin->sin_port = IPSEC_PORT_ANY; | | 371 | sin->sin_port = IPSEC_PORT_ANY; |
372 | sin->sin_addr = ip->ip_dst; | | 372 | sin->sin_addr = ip->ip_dst; |
373 | } | | 373 | } |
374 | } else { | | 374 | } else { |
375 | struct sockaddr_in6 *sin6; | | 375 | struct sockaddr_in6 *sin6; |
376 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | | 376 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
377 | | | 377 | |
378 | if (saidx->src.sin6.sin6_len == 0) { | | 378 | if (saidx->src.sin6.sin6_len == 0) { |
379 | sin6 = (struct sockaddr_in6 *)&saidx->src; | | 379 | sin6 = (struct sockaddr_in6 *)&saidx->src; |
380 | sin6->sin6_len = sizeof(*sin6); | | 380 | sin6->sin6_len = sizeof(*sin6); |
381 | sin6->sin6_family = AF_INET6; | | 381 | sin6->sin6_family = AF_INET6; |
382 | sin6->sin6_port = IPSEC_PORT_ANY; | | 382 | sin6->sin6_port = IPSEC_PORT_ANY; |
383 | sin6->sin6_addr = ip6->ip6_src; | | 383 | sin6->sin6_addr = ip6->ip6_src; |
384 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { | | 384 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { |
385 | /* fix scope id for comparing SPD */ | | 385 | /* fix scope id for comparing SPD */ |
386 | sin6->sin6_addr.s6_addr16[1] = 0; | | 386 | sin6->sin6_addr.s6_addr16[1] = 0; |
387 | sin6->sin6_scope_id = | | 387 | sin6->sin6_scope_id = |
388 | ntohs(ip6->ip6_src.s6_addr16[1]); | | 388 | ntohs(ip6->ip6_src.s6_addr16[1]); |
389 | } | | 389 | } |
390 | } | | 390 | } |
391 | if (saidx->dst.sin6.sin6_len == 0) { | | 391 | if (saidx->dst.sin6.sin6_len == 0) { |
392 | sin6 = (struct sockaddr_in6 *)&saidx->dst; | | 392 | sin6 = (struct sockaddr_in6 *)&saidx->dst; |
393 | sin6->sin6_len = sizeof(*sin6); | | 393 | sin6->sin6_len = sizeof(*sin6); |
394 | sin6->sin6_family = AF_INET6; | | 394 | sin6->sin6_family = AF_INET6; |
395 | sin6->sin6_port = IPSEC_PORT_ANY; | | 395 | sin6->sin6_port = IPSEC_PORT_ANY; |
396 | sin6->sin6_addr = ip6->ip6_dst; | | 396 | sin6->sin6_addr = ip6->ip6_dst; |
397 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { | | 397 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { |
398 | /* fix scope id for comparing SPD */ | | 398 | /* fix scope id for comparing SPD */ |
399 | sin6->sin6_addr.s6_addr16[1] = 0; | | 399 | sin6->sin6_addr.s6_addr16[1] = 0; |
400 | sin6->sin6_scope_id = | | 400 | sin6->sin6_scope_id = |
401 | ntohs(ip6->ip6_dst.s6_addr16[1]); | | 401 | ntohs(ip6->ip6_dst.s6_addr16[1]); |
402 | } | | 402 | } |
403 | } | | 403 | } |
404 | } | | 404 | } |
405 | } | | 405 | } |
406 | | | 406 | |
407 | /* | | 407 | /* |
408 | * Lookup SA and validate it. | | 408 | * Lookup SA and validate it. |
409 | */ | | 409 | */ |
410 | *error = key_checkrequest(isr, saidx); | | 410 | *error = key_checkrequest(isr, saidx); |
411 | if (*error != 0) { | | 411 | if (*error != 0) { |
412 | /* | | 412 | /* |
413 | * IPsec processing is required, but no SA found. | | 413 | * IPsec processing is required, but no SA found. |
414 | * I assume that key_acquire() had been called | | 414 | * I assume that key_acquire() had been called |
415 | * to get/establish the SA. Here I discard | | 415 | * to get/establish the SA. Here I discard |
416 | * this packet because it is responsibility for | | 416 | * this packet because it is responsibility for |
417 | * upper layer to retransmit the packet. | | 417 | * upper layer to retransmit the packet. |
418 | */ | | 418 | */ |
419 | IPSEC_STATINC(IPSEC_STAT_OUT_NOSA); | | 419 | IPSEC_STATINC(IPSEC_STAT_OUT_NOSA); |
420 | goto bad; | | 420 | goto bad; |
421 | } | | 421 | } |
422 | sav = isr->sav; | | 422 | sav = isr->sav; |
423 | /* sav may be NULL here if we have an USE rule */ | | 423 | /* sav may be NULL here if we have an USE rule */ |
424 | if (sav == NULL) { | | 424 | if (sav == NULL) { |
425 | IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE, | | 425 | IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE, |
426 | ("ipsec_nextisr: no SA found, but required; level %u", | | 426 | ("ipsec_nextisr: no SA found, but required; level %u", |
427 | ipsec_get_reqlevel(isr))); | | 427 | ipsec_get_reqlevel(isr))); |
428 | isr = isr->next; | | 428 | isr = isr->next; |
429 | /* | | 429 | /* |
430 | * No more rules to apply, return NULL isr and no error | | 430 | * No more rules to apply, return NULL isr and no error |
431 | * It can happen when the last rules are USE rules | | 431 | * It can happen when the last rules are USE rules |
432 | * */ | | 432 | * */ |
433 | if (isr == NULL) { | | 433 | if (isr == NULL) { |
434 | *error = 0; | | 434 | *error = 0; |
435 | return isr; | | 435 | return isr; |
436 | } | | 436 | } |
437 | goto again; | | 437 | goto again; |
438 | } | | 438 | } |
439 | | | 439 | |
440 | /* | | 440 | /* |
441 | * Check system global policy controls. | | 441 | * Check system global policy controls. |
442 | */ | | 442 | */ |
443 | if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) || | | 443 | if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) || |
444 | (isr->saidx.proto == IPPROTO_AH && !ah_enable) || | | 444 | (isr->saidx.proto == IPPROTO_AH && !ah_enable) || |
445 | (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) { | | 445 | (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) { |
446 | DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due" | | 446 | DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due" |
447 | " to policy (check your sysctls)\n")); | | 447 | " to policy (check your sysctls)\n")); |
448 | IPSEC_OSTAT(ESP_STAT_PDROPS, AH_STAT_PDROPS, | | 448 | IPSEC_OSTAT(ESP_STAT_PDROPS, AH_STAT_PDROPS, |
449 | IPCOMP_STAT_PDROPS); | | 449 | IPCOMP_STAT_PDROPS); |
450 | *error = EHOSTUNREACH; | | 450 | *error = EHOSTUNREACH; |
451 | goto bad; | | 451 | goto bad; |
452 | } | | 452 | } |
453 | | | 453 | |
454 | /* | | 454 | /* |
455 | * Sanity check the SA contents for the caller | | 455 | * Sanity check the SA contents for the caller |
456 | * before they invoke the xform output method. | | 456 | * before they invoke the xform output method. |
457 | */ | | 457 | */ |
458 | if (sav->tdb_xform == NULL) { | | 458 | if (sav->tdb_xform == NULL) { |
459 | DPRINTF(("ipsec_nextisr: no transform for SA\n")); | | 459 | DPRINTF(("ipsec_nextisr: no transform for SA\n")); |
460 | IPSEC_OSTAT(ESP_STAT_NOXFORM, AH_STAT_NOXFORM, | | 460 | IPSEC_OSTAT(ESP_STAT_NOXFORM, AH_STAT_NOXFORM, |
461 | IPCOMP_STAT_NOXFORM); | | 461 | IPCOMP_STAT_NOXFORM); |
462 | *error = EHOSTUNREACH; | | 462 | *error = EHOSTUNREACH; |
463 | goto bad; | | 463 | goto bad; |
464 | } | | 464 | } |
465 | return isr; | | 465 | return isr; |
466 | bad: | | 466 | bad: |
467 | IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code")); | | 467 | IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code")); |
468 | return NULL; | | 468 | return NULL; |
469 | #undef IPSEC_OSTAT | | 469 | #undef IPSEC_OSTAT |
470 | } | | 470 | } |
471 | | | 471 | |
472 | #ifdef INET | | 472 | #ifdef INET |
473 | /* | | 473 | /* |
474 | * IPsec output logic for IPv4. | | 474 | * IPsec output logic for IPv4. |
475 | */ | | 475 | */ |
476 | int | | 476 | int |
477 | ipsec4_process_packet( | | 477 | ipsec4_process_packet( |
478 | struct mbuf *m, | | 478 | struct mbuf *m, |
479 | struct ipsecrequest *isr, | | 479 | struct ipsecrequest *isr, |
480 | int flags, | | 480 | int flags, |
481 | int tunalready | | 481 | int tunalready |
482 | ) | | 482 | ) |
483 | { | | 483 | { |
484 | struct secasindex saidx; | | 484 | struct secasindex saidx; |
485 | struct secasvar *sav; | | 485 | struct secasvar *sav; |
486 | struct ip *ip; | | 486 | struct ip *ip; |
487 | int s, error, i, off; | | 487 | int s, error, i, off; |
488 | | | 488 | |
489 | IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf")); | | 489 | IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf")); |
490 | IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr")); | | 490 | IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr")); |
491 | | | 491 | |
492 | s = splsoftnet(); /* insure SA contents don't change */ | | 492 | s = splsoftnet(); /* insure SA contents don't change */ |
493 | | | 493 | |
494 | isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); | | 494 | isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); |
495 | if (isr == NULL) { | | 495 | if (isr == NULL) { |
496 | if (error != 0) { | | 496 | if (error != 0) { |
497 | goto bad; | | 497 | goto bad; |
498 | } else { | | 498 | } else { |
499 | if (ipsec_register_done(m, &error) < 0) | | 499 | if (ipsec_register_done(m, &error) < 0) |
500 | goto bad; | | 500 | goto bad; |
501 | | | 501 | |
502 | splx(s); | | 502 | splx(s); |
503 | return ipsec_reinject_ipstack(m, AF_INET); | | 503 | return ipsec_reinject_ipstack(m, AF_INET); |
504 | } | | 504 | } |
505 | } | | 505 | } |
506 | | | 506 | |
507 | sav = isr->sav; | | 507 | sav = isr->sav; |
508 | if (!tunalready) { | | 508 | if (!tunalready) { |
509 | union sockaddr_union *dst = &sav->sah->saidx.dst; | | 509 | union sockaddr_union *dst = &sav->sah->saidx.dst; |
510 | int setdf; | | 510 | int setdf; |
511 | | | 511 | |
512 | /* | | 512 | /* |
513 | * Collect IP_DF state from the outer header. | | 513 | * Collect IP_DF state from the outer header. |
514 | */ | | 514 | */ |
515 | if (dst->sa.sa_family == AF_INET) { | | 515 | if (dst->sa.sa_family == AF_INET) { |
516 | if (m->m_len < sizeof (struct ip) && | | 516 | if (m->m_len < sizeof (struct ip) && |
517 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { | | 517 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { |
518 | error = ENOBUFS; | | 518 | error = ENOBUFS; |
519 | goto bad; | | 519 | goto bad; |
520 | } | | 520 | } |
521 | ip = mtod(m, struct ip *); | | 521 | ip = mtod(m, struct ip *); |
522 | /* Honor system-wide control of how to handle IP_DF */ | | 522 | /* Honor system-wide control of how to handle IP_DF */ |
523 | switch (ip4_ipsec_dfbit) { | | 523 | switch (ip4_ipsec_dfbit) { |
524 | case 0: /* clear in outer header */ | | 524 | case 0: /* clear in outer header */ |
525 | case 1: /* set in outer header */ | | 525 | case 1: /* set in outer header */ |
526 | setdf = ip4_ipsec_dfbit; | | 526 | setdf = ip4_ipsec_dfbit; |
527 | break; | | 527 | break; |
528 | default: /* propagate to outer header */ | | 528 | default: /* propagate to outer header */ |
529 | setdf = ip->ip_off; | | 529 | setdf = ip->ip_off; |
530 | #ifndef __FreeBSD__ | | 530 | #ifndef __FreeBSD__ |
531 | /* On FreeBSD, ip_off and ip_len assumed in host endian. */ | | 531 | /* On FreeBSD, ip_off and ip_len assumed in host endian. */ |
532 | setdf = ntohs(setdf); | | 532 | setdf = ntohs(setdf); |
533 | #endif | | 533 | #endif |
534 | setdf = htons(setdf & IP_DF); | | 534 | setdf = htons(setdf & IP_DF); |
535 | break; | | 535 | break; |
536 | } | | 536 | } |
537 | } else { | | 537 | } else { |
538 | ip = NULL; /* keep compiler happy */ | | 538 | ip = NULL; /* keep compiler happy */ |
539 | setdf = 0; | | 539 | setdf = 0; |
540 | } | | 540 | } |
541 | /* Do the appropriate encapsulation, if necessary */ | | 541 | /* Do the appropriate encapsulation, if necessary */ |
542 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ | | 542 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ |
543 | dst->sa.sa_family != AF_INET || /* PF mismatch */ | | 543 | dst->sa.sa_family != AF_INET || /* PF mismatch */ |
544 | #if 0 | | 544 | #if 0 |
545 | (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */ | | 545 | (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */ |
546 | sav->tdb_xform->xf_type == XF_IP4 || /* ditto */ | | 546 | sav->tdb_xform->xf_type == XF_IP4 || /* ditto */ |
547 | #endif | | 547 | #endif |
548 | (dst->sa.sa_family == AF_INET && /* Proxy */ | | 548 | (dst->sa.sa_family == AF_INET && /* Proxy */ |
549 | dst->sin.sin_addr.s_addr != INADDR_ANY && | | 549 | dst->sin.sin_addr.s_addr != INADDR_ANY && |
550 | dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { | | 550 | dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { |
551 | struct mbuf *mp; | | 551 | struct mbuf *mp; |
552 | | | 552 | |
553 | /* Fix IPv4 header checksum and length */ | | 553 | /* Fix IPv4 header checksum and length */ |
554 | if (m->m_len < sizeof (struct ip) && | | 554 | if (m->m_len < sizeof (struct ip) && |
555 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { | | 555 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { |
556 | error = ENOBUFS; | | 556 | error = ENOBUFS; |
557 | goto bad; | | 557 | goto bad; |
558 | } | | 558 | } |
559 | ip = mtod(m, struct ip *); | | 559 | ip = mtod(m, struct ip *); |
560 | ip->ip_len = htons(m->m_pkthdr.len); | | 560 | ip->ip_len = htons(m->m_pkthdr.len); |
561 | ip->ip_sum = 0; | | 561 | ip->ip_sum = 0; |
562 | ip->ip_sum = in_cksum(m, ip->ip_hl << 2); | | 562 | ip->ip_sum = in_cksum(m, ip->ip_hl << 2); |
563 | | | 563 | |
564 | /* Encapsulate the packet */ | | 564 | /* Encapsulate the packet */ |
565 | error = ipip_output(m, isr, &mp, 0, 0); | | 565 | error = ipip_output(m, isr, &mp, 0, 0); |
566 | if (mp == NULL && !error) { | | 566 | if (mp == NULL && !error) { |
567 | /* Should never happen. */ | | 567 | /* Should never happen. */ |
568 | DPRINTF(("ipsec4_process_packet: ipip_output " | | 568 | DPRINTF(("ipsec4_process_packet: ipip_output " |
569 | "returns no mbuf and no error!")); | | 569 | "returns no mbuf and no error!")); |
570 | error = EFAULT; | | 570 | error = EFAULT; |
571 | } | | 571 | } |
572 | if (error) { | | 572 | if (error) { |
573 | if (mp) { | | 573 | if (mp) { |
574 | /* XXX: Should never happen! */ | | 574 | /* XXX: Should never happen! */ |
575 | m_freem(mp); | | 575 | m_freem(mp); |
576 | } | | 576 | } |
577 | m = NULL; /* ipip_output() already freed it */ | | 577 | m = NULL; /* ipip_output() already freed it */ |
578 | goto bad; | | 578 | goto bad; |
579 | } | | 579 | } |
580 | m = mp, mp = NULL; | | 580 | m = mp, mp = NULL; |
581 | /* | | 581 | /* |
582 | * ipip_output clears IP_DF in the new header. If | | 582 | * ipip_output clears IP_DF in the new header. If |
583 | * we need to propagate IP_DF from the outer header, | | 583 | * we need to propagate IP_DF from the outer header, |
584 | * then we have to do it here. | | 584 | * then we have to do it here. |
585 | * | | 585 | * |
586 | * XXX shouldn't assume what ipip_output does. | | 586 | * XXX shouldn't assume what ipip_output does. |
587 | */ | | 587 | */ |
588 | if (dst->sa.sa_family == AF_INET && setdf) { | | 588 | if (dst->sa.sa_family == AF_INET && setdf) { |
589 | if (m->m_len < sizeof (struct ip) && | | 589 | if (m->m_len < sizeof (struct ip) && |
590 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { | | 590 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { |
591 | error = ENOBUFS; | | 591 | error = ENOBUFS; |
592 | goto bad; | | 592 | goto bad; |
593 | } | | 593 | } |
594 | ip = mtod(m, struct ip *); | | 594 | ip = mtod(m, struct ip *); |
595 | ip->ip_off |= IP_OFF_CONVERT(IP_DF); | | 595 | ip->ip_off |= IP_OFF_CONVERT(IP_DF); |
596 | } | | 596 | } |
597 | } | | 597 | } |
598 | } | | 598 | } |
599 | | | 599 | |
600 | /* | | 600 | /* |
601 | * Dispatch to the appropriate IPsec transform logic. The | | 601 | * Dispatch to the appropriate IPsec transform logic. The |
602 | * packet will be returned for transmission after crypto | | 602 | * packet will be returned for transmission after crypto |
603 | * processing, etc. are completed. For encapsulation we | | 603 | * processing, etc. are completed. For encapsulation we |
604 | * bypass this call because of the explicit call done above | | 604 | * bypass this call because of the explicit call done above |
605 | * (necessary to deal with IP_DF handling for IPv4). | | 605 | * (necessary to deal with IP_DF handling for IPv4). |
606 | * | | 606 | * |
607 | * NB: m & sav are ``passed to caller'' who's reponsible for | | 607 | * NB: m & sav are ``passed to caller'' who's reponsible for |
608 | * for reclaiming their resources. | | 608 | * for reclaiming their resources. |
609 | */ | | 609 | */ |
610 | if (sav->tdb_xform->xf_type != XF_IP4) { | | 610 | if (sav->tdb_xform->xf_type != XF_IP4) { |
611 | union sockaddr_union *dst = &sav->sah->saidx.dst; | | 611 | union sockaddr_union *dst = &sav->sah->saidx.dst; |
612 | if (dst->sa.sa_family == AF_INET) { | | 612 | if (dst->sa.sa_family == AF_INET) { |
613 | ip = mtod(m, struct ip *); | | 613 | ip = mtod(m, struct ip *); |
614 | i = ip->ip_hl << 2; | | 614 | i = ip->ip_hl << 2; |
615 | off = offsetof(struct ip, ip_p); | | 615 | off = offsetof(struct ip, ip_p); |
616 | } else { | | 616 | } else { |
617 | i = sizeof(struct ip6_hdr); | | 617 | i = sizeof(struct ip6_hdr); |
618 | off = offsetof(struct ip6_hdr, ip6_nxt); | | 618 | off = offsetof(struct ip6_hdr, ip6_nxt); |
619 | } | | 619 | } |
620 | error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); | | 620 | error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); |
621 | } else { | | 621 | } else { |
622 | error = ipsec_process_done(m, isr); | | 622 | error = ipsec_process_done(m, isr); |
623 | } | | 623 | } |
624 | splx(s); | | 624 | splx(s); |
625 | return error; | | 625 | return error; |
626 | bad: | | 626 | bad: |
627 | splx(s); | | 627 | splx(s); |
628 | if (m) | | 628 | if (m) |
629 | m_freem(m); | | 629 | m_freem(m); |
630 | return error; | | 630 | return error; |
631 | } | | 631 | } |
632 | #endif | | 632 | #endif |
633 | | | 633 | |
634 | #ifdef INET6 | | 634 | #ifdef INET6 |
| | | 635 | static int |
| | | 636 | in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia) |
| | | 637 | { |
| | | 638 | struct in6_addr ia2; |
| | | 639 | |
| | | 640 | memcpy(&ia2, &sa->sin6_addr, sizeof(ia2)); |
| | | 641 | if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr)) |
| | | 642 | ia2.s6_addr16[1] = htons(sa->sin6_scope_id); |
| | | 643 | |
| | | 644 | return IN6_ARE_ADDR_EQUAL(ia, &ia2); |
| | | 645 | } |
| | | 646 | |
635 | int | | 647 | int |
636 | ipsec6_process_packet( | | 648 | ipsec6_process_packet( |
637 | struct mbuf *m, | | 649 | struct mbuf *m, |
638 | struct ipsecrequest *isr | | 650 | struct ipsecrequest *isr |
639 | ) | | 651 | ) |
640 | { | | 652 | { |
641 | struct secasindex saidx; | | 653 | struct secasindex saidx; |
642 | struct secasvar *sav; | | 654 | struct secasvar *sav; |
643 | struct ip6_hdr *ip6; | | 655 | struct ip6_hdr *ip6; |
644 | int s, error, i, off; | | 656 | int s, error, i, off; |
645 | union sockaddr_union *dst; | | 657 | union sockaddr_union *dst; |
646 | | | 658 | |
647 | IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf")); | | 659 | IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf")); |
648 | IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr")); | | 660 | IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr")); |
649 | | | 661 | |
650 | s = splsoftnet(); /* insure SA contents don't change */ | | 662 | s = splsoftnet(); /* insure SA contents don't change */ |
651 | | | 663 | |
652 | isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); | | 664 | isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); |
653 | if (isr == NULL) { | | 665 | if (isr == NULL) { |
654 | if (error != 0) { | | 666 | if (error != 0) { |
655 | /* XXX Should we send a notification ? */ | | 667 | /* XXX Should we send a notification ? */ |
656 | goto bad; | | 668 | goto bad; |
657 | } else { | | 669 | } else { |
658 | if (ipsec_register_done(m, &error) < 0) | | 670 | if (ipsec_register_done(m, &error) < 0) |
659 | goto bad; | | 671 | goto bad; |
660 | | | 672 | |
661 | splx(s); | | 673 | splx(s); |
662 | return ipsec_reinject_ipstack(m, AF_INET6); | | 674 | return ipsec_reinject_ipstack(m, AF_INET6); |
663 | } | | 675 | } |
664 | } | | 676 | } |
665 | | | 677 | |
666 | sav = isr->sav; | | 678 | sav = isr->sav; |
667 | dst = &sav->sah->saidx.dst; | | 679 | dst = &sav->sah->saidx.dst; |
668 | | | 680 | |
669 | ip6 = mtod(m, struct ip6_hdr *); /* XXX */ | | 681 | ip6 = mtod(m, struct ip6_hdr *); /* XXX */ |
670 | | | 682 | |
671 | /* Do the appropriate encapsulation, if necessary */ | | 683 | /* Do the appropriate encapsulation, if necessary */ |
672 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ | | 684 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ |
673 | dst->sa.sa_family != AF_INET6 || /* PF mismatch */ | | 685 | dst->sa.sa_family != AF_INET6 || /* PF mismatch */ |
674 | ((dst->sa.sa_family == AF_INET6) && | | 686 | ((dst->sa.sa_family == AF_INET6) && |
675 | (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && | | 687 | (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && |
676 | (!IN6_ARE_ADDR_EQUAL(&dst->sin6.sin6_addr, | | 688 | (!in6_sa_equal_addrwithscope(&dst->sin6, |
677 | &ip6->ip6_dst)))) { | | 689 | &ip6->ip6_dst)))) { |
678 | struct mbuf *mp; | | 690 | struct mbuf *mp; |
679 | | | 691 | |
680 | /* Fix IPv6 header payload length. */ | | 692 | /* Fix IPv6 header payload length. */ |
681 | if (m->m_len < sizeof(struct ip6_hdr)) | | 693 | if (m->m_len < sizeof(struct ip6_hdr)) |
682 | if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) | | 694 | if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) |
683 | return ENOBUFS; | | 695 | return ENOBUFS; |
684 | | | 696 | |
685 | if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { | | 697 | if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { |
686 | /* No jumbogram support. */ | | 698 | /* No jumbogram support. */ |
687 | m_freem(m); | | 699 | m_freem(m); |
688 | return ENXIO; /*XXX*/ | | 700 | return ENXIO; /*XXX*/ |
689 | } | | 701 | } |
690 | | | 702 | |
691 | ip6 = mtod(m, struct ip6_hdr *); | | 703 | ip6 = mtod(m, struct ip6_hdr *); |
692 | ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); | | 704 | ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); |
693 | | | 705 | |
694 | /* Encapsulate the packet */ | | 706 | /* Encapsulate the packet */ |
695 | error = ipip_output(m, isr, &mp, 0, 0); | | 707 | error = ipip_output(m, isr, &mp, 0, 0); |
696 | if (mp == NULL && !error) { | | 708 | if (mp == NULL && !error) { |
697 | /* Should never happen. */ | | 709 | /* Should never happen. */ |
698 | DPRINTF(("ipsec6_process_packet: ipip_output " | | 710 | DPRINTF(("ipsec6_process_packet: ipip_output " |
699 | "returns no mbuf and no error!")); | | 711 | "returns no mbuf and no error!")); |
700 | error = EFAULT; | | 712 | error = EFAULT; |
701 | } | | 713 | } |
702 | | | 714 | |
703 | if (error) { | | 715 | if (error) { |
704 | if (mp) { | | 716 | if (mp) { |
705 | /* XXX: Should never happen! */ | | 717 | /* XXX: Should never happen! */ |
706 | m_freem(mp); | | 718 | m_freem(mp); |
707 | } | | 719 | } |
708 | m = NULL; /* ipip_output() already freed it */ | | 720 | m = NULL; /* ipip_output() already freed it */ |
709 | goto bad; | | 721 | goto bad; |
710 | } | | 722 | } |
711 | | | 723 | |
712 | m = mp; | | 724 | m = mp; |
713 | mp = NULL; | | 725 | mp = NULL; |
714 | } | | 726 | } |
715 | | | 727 | |
716 | if (dst->sa.sa_family == AF_INET) { | | 728 | if (dst->sa.sa_family == AF_INET) { |
717 | struct ip *ip; | | 729 | struct ip *ip; |
718 | ip = mtod(m, struct ip *); | | 730 | ip = mtod(m, struct ip *); |
719 | i = ip->ip_hl << 2; | | 731 | i = ip->ip_hl << 2; |
720 | off = offsetof(struct ip, ip_p); | | 732 | off = offsetof(struct ip, ip_p); |
721 | } else { | | 733 | } else { |
722 | i = sizeof(struct ip6_hdr); | | 734 | i = sizeof(struct ip6_hdr); |
723 | off = offsetof(struct ip6_hdr, ip6_nxt); | | 735 | off = offsetof(struct ip6_hdr, ip6_nxt); |
724 | } | | 736 | } |
725 | error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); | | 737 | error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); |
726 | splx(s); | | 738 | splx(s); |
727 | return error; | | 739 | return error; |
728 | bad: | | 740 | bad: |
729 | splx(s); | | 741 | splx(s); |
730 | if (m) | | 742 | if (m) |
731 | m_freem(m); | | 743 | m_freem(m); |
732 | return error; | | 744 | return error; |
733 | } | | 745 | } |
734 | #endif /*INET6*/ | | 746 | #endif /*INET6*/ |