1 /*- 2 * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include "opt_inet.h" 29 #include "opt_inet6.h" 30 #include "opt_ipsec.h" 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/lock.h> 36 #include <sys/mbuf.h> 37 #include <sys/protosw.h> 38 #include <sys/socket.h> 39 #include <sys/sockopt.h> 40 #include <sys/sysctl.h> 41 42 #include <netinet/in.h> 43 #include <netinet/in_pcb.h> 44 #include <netinet/in_systm.h> 45 #include <netinet/ip.h> 46 #include <netinet/ip6.h> 47 #include <netinet/ip_var.h> 48 #include <netinet/tcp.h> 49 #include <netinet/udp.h> 50 #include <netinet/udp_var.h> 51 52 #include <netinet6/ip6_var.h> 53 54 #include <net/vnet.h> 55 56 #include <netipsec/ipsec.h> 57 #include <netipsec/esp.h> 58 #include <netipsec/esp_var.h> 59 #include <netipsec/xform.h> 60 61 #include <netipsec/key.h> 62 #include <netipsec/key_debug.h> 63 #include <netipsec/ipsec_support.h> 64 #include <machine/in_cksum.h> 65 66 /* 67 * Handle UDP_ENCAP socket option. Always return with released INP_WLOCK. 68 */ 69 int 70 udp_ipsec_pcbctl(struct inpcb *inp, struct sockopt *sopt) 71 { 72 struct udpcb *up; 73 int error, optval; 74 75 INP_WLOCK_ASSERT(inp); 76 if (sopt->sopt_name != UDP_ENCAP) { 77 INP_WUNLOCK(inp); 78 return (ENOPROTOOPT); 79 } 80 81 up = intoudpcb(inp); 82 if (sopt->sopt_dir == SOPT_GET) { 83 if (up->u_flags & UF_ESPINUDP) 84 optval = UDP_ENCAP_ESPINUDP; 85 else 86 optval = 0; 87 INP_WUNLOCK(inp); 88 return (sooptcopyout(sopt, &optval, sizeof(optval))); 89 } 90 INP_WUNLOCK(inp); 91 92 error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); 93 if (error != 0) 94 return (error); 95 96 INP_WLOCK(inp); 97 switch (optval) { 98 case 0: 99 up->u_flags &= ~UF_ESPINUDP; 100 break; 101 case UDP_ENCAP_ESPINUDP: 102 up->u_flags |= UF_ESPINUDP; 103 break; 104 default: 105 error = EINVAL; 106 } 107 INP_WUNLOCK(inp); 108 return (error); 109 } 110 111 /* 112 * Potentially decap ESP in UDP frame. Check for an ESP header. 113 * If present, strip the UDP header and push the result through IPSec. 114 * 115 * Returns error if mbuf consumed and/or processed, otherwise 0. 116 */ 117 int 118 udp_ipsec_input(struct mbuf *m, int off, int af) 119 { 120 union sockaddr_union dst; 121 struct secasvar *sav; 122 struct udphdr *udp; 123 uint32_t spi; 124 int hlen; 125 126 /* 127 * Just return if packet doesn't have enough data. 128 * We need at least [IP header + UDP header + ESP header]. 129 * NAT-Keepalive packet has only one byte of payload, so it 130 * by default will not be processed. 131 */ 132 if (m->m_pkthdr.len < off + sizeof(struct esp)) 133 return (0); 134 135 m_copydata(m, off, sizeof(uint32_t), (caddr_t)&spi); 136 if (spi == 0) /* Non-ESP marker. */ 137 return (0); 138 139 /* 140 * Find SA and check that it is configured for UDP 141 * encapsulation. 142 */ 143 bzero(&dst, sizeof(dst)); 144 dst.sa.sa_family = af; 145 switch (af) { 146 #ifdef INET 147 case AF_INET: { 148 struct ip *ip; 149 150 dst.sin.sin_len = sizeof(struct sockaddr_in); 151 ip = mtod(m, struct ip *); 152 ip->ip_p = IPPROTO_ESP; 153 off = offsetof(struct ip, ip_p); 154 hlen = ip->ip_hl << 2; 155 dst.sin.sin_addr = ip->ip_dst; 156 break; 157 } 158 #endif 159 #ifdef INET6 160 case AF_INET6: { 161 struct ip6_hdr *ip6; 162 163 dst.sin6.sin6_len = sizeof(struct sockaddr_in6); 164 ip6 = mtod(m, struct ip6_hdr *); 165 ip6->ip6_nxt = IPPROTO_ESP; 166 off = offsetof(struct ip6_hdr, ip6_nxt); 167 hlen = sizeof(struct ip6_hdr); 168 dst.sin6.sin6_addr = ip6->ip6_dst; 169 break; 170 } 171 #endif 172 default: 173 ESPSTAT_INC(esps_nopf); 174 m_freem(m); 175 return (EPFNOSUPPORT); 176 } 177 178 sav = key_allocsa(&dst, IPPROTO_ESP, spi); 179 if (sav == NULL) { 180 ESPSTAT_INC(esps_notdb); 181 m_freem(m); 182 return (ENOENT); 183 } 184 udp = mtodo(m, hlen); 185 if (sav->natt == NULL || 186 sav->natt->sport != udp->uh_sport || 187 sav->natt->dport != udp->uh_dport) { 188 /* XXXAE: should we check source address? */ 189 ESPSTAT_INC(esps_notdb); 190 key_freesav(&sav); 191 m_freem(m); 192 return (ENOENT); 193 } 194 /* 195 * Remove the UDP header 196 * Before: 197 * <--- off ---> 198 * +----+------+-----+ 199 * | IP | UDP | ESP | 200 * +----+------+-----+ 201 * <-skip-> 202 * After: 203 * +----+-----+ 204 * | IP | ESP | 205 * +----+-----+ 206 * <-skip-> 207 */ 208 m_striphdr(m, hlen, sizeof(*udp)); 209 210 /* 211 * We cannot yet update the cksums so clear any h/w cksum flags 212 * as they are no longer valid. 213 */ 214 switch (af) { 215 #ifdef INET 216 case AF_INET: 217 if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) 218 m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 219 break; 220 #endif /* INET */ 221 #ifdef INET6 222 case AF_INET6: 223 if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) 224 m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR); 225 break; 226 #endif /* INET6 */ 227 default: 228 ESPSTAT_INC(esps_nopf); 229 m_freem(m); 230 return (EPFNOSUPPORT); 231 } 232 233 /* 234 * We can update ip_len and ip_sum here, but ipsec4_input_cb() 235 * will do this anyway, so don't touch them here. 236 */ 237 ESPSTAT_INC(esps_input); 238 (*sav->tdb_xform->xf_input)(m, sav, hlen, off); 239 return (EINPROGRESS); /* Consumed by IPsec. */ 240 } 241 242 int 243 udp_ipsec_output(struct mbuf *m, struct secasvar *sav) 244 { 245 struct udphdr *udp; 246 struct mbuf *n; 247 int hlen, off; 248 249 IPSEC_ASSERT(sav->natt != NULL, ("UDP encapsulation isn't required.")); 250 251 switch (sav->sah->saidx.dst.sa.sa_family) { 252 #ifdef INET 253 case AF_INET: { 254 struct ip *ip; 255 ip = mtod(m, struct ip *); 256 hlen = ip->ip_hl << 2; 257 break; 258 } 259 #endif 260 #ifdef INET6 261 case AF_INET6: 262 hlen = sizeof(struct ip6_hdr); 263 break; 264 #endif 265 default: 266 ESPSTAT_INC(esps_nopf); 267 return (EAFNOSUPPORT); 268 } 269 270 n = m_makespace(m, hlen, sizeof(*udp), &off); 271 if (n == NULL) { 272 DPRINTF(("%s: m_makespace for udphdr failed\n", __func__)); 273 return (ENOBUFS); 274 } 275 276 udp = mtodo(n, off); 277 udp->uh_dport = sav->natt->dport; 278 udp->uh_sport = sav->natt->sport; 279 udp->uh_sum = 0; 280 udp->uh_ulen = htons(m->m_pkthdr.len - hlen); 281 282 switch (sav->sah->saidx.dst.sa.sa_family) { 283 #ifdef INET 284 case AF_INET: { 285 struct ip *ip; 286 287 ip = mtod(m, struct ip *); 288 ip->ip_len = htons(m->m_pkthdr.len); 289 ip->ip_p = IPPROTO_UDP; 290 break; 291 } 292 #endif 293 #ifdef INET6 294 case AF_INET6: { 295 struct ip6_hdr *ip6; 296 297 ip6 = mtod(m, struct ip6_hdr *); 298 KASSERT(ip6->ip6_nxt == IPPROTO_ESP, 299 ("unexpected next header type %d", ip6->ip6_nxt)); 300 ip6->ip6_plen = htons(m->m_pkthdr.len); 301 ip6->ip6_nxt = IPPROTO_UDP; 302 udp->uh_sum = in6_cksum_pseudo(ip6, 303 m->m_pkthdr.len - hlen, ip6->ip6_nxt, 0); 304 m->m_pkthdr.csum_flags = CSUM_UDP_IPV6; 305 m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); 306 break; 307 } 308 #endif 309 default: 310 ESPSTAT_INC(esps_nopf); 311 return (EAFNOSUPPORT); 312 } 313 314 return (0); 315 } 316 317 void 318 udp_ipsec_adjust_cksum(struct mbuf *m, struct secasvar *sav, int proto, 319 int skip) 320 { 321 uint16_t cksum, off; 322 323 IPSEC_ASSERT(sav->natt != NULL, ("NAT-T isn't required")); 324 IPSEC_ASSERT(proto == IPPROTO_UDP || proto == IPPROTO_TCP, 325 ("unexpected protocol %u", proto)); 326 327 if (proto == IPPROTO_UDP) 328 off = offsetof(struct udphdr, uh_sum); 329 else 330 off = offsetof(struct tcphdr, th_sum); 331 332 if (V_natt_cksum_policy == 0) { /* auto */ 333 if (sav->natt->cksum != 0) { 334 /* Incrementally recompute. */ 335 m_copydata(m, skip + off, sizeof(cksum), 336 (caddr_t)&cksum); 337 /* Do not adjust UDP checksum if it is zero. */ 338 if (proto == IPPROTO_UDP && cksum == 0) 339 return; 340 cksum = in_addword(cksum, sav->natt->cksum); 341 } else { 342 /* No OA from IKEd. */ 343 if (proto == IPPROTO_TCP) { 344 /* Ignore for TCP. */ 345 m->m_pkthdr.csum_data = 0xffff; 346 switch (sav->sah->saidx.dst.sa.sa_family) { 347 #ifdef INET 348 case AF_INET: 349 m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID | 350 CSUM_PSEUDO_HDR); 351 break; 352 #endif 353 #ifdef INET6 354 case AF_INET6: 355 m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID_IPV6 | 356 CSUM_PSEUDO_HDR); 357 break; 358 #endif 359 default: 360 break; 361 } 362 return; 363 } 364 cksum = 0; /* Reset for UDP. */ 365 } 366 m_copyback(m, skip + off, sizeof(cksum), (caddr_t)&cksum); 367 } else { /* Fully recompute */ 368 switch (sav->sah->saidx.dst.sa.sa_family) { 369 #ifdef INET 370 case AF_INET: { 371 struct ip *ip; 372 373 ip = mtod(m, struct ip *); 374 cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 375 htons(m->m_pkthdr.len - skip + proto)); 376 m_copyback(m, skip + off, sizeof(cksum), 377 (caddr_t)&cksum); 378 m->m_pkthdr.csum_flags = 379 (proto == IPPROTO_UDP) ? CSUM_UDP : CSUM_TCP; 380 m->m_pkthdr.csum_data = off; 381 in_delayed_cksum(m); 382 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 383 break; 384 } 385 #endif 386 #ifdef INET6 387 case AF_INET6: { 388 struct ip6_hdr *ip6; 389 390 ip6 = mtod(m, struct ip6_hdr *); 391 cksum = in6_cksum_pseudo(ip6, m->m_pkthdr.len - skip, 392 proto, 0); 393 m_copyback(m, skip + off, sizeof(cksum), 394 (caddr_t)&cksum); 395 m->m_pkthdr.csum_flags = 396 (proto == IPPROTO_UDP) ? CSUM_UDP_IPV6 : CSUM_TCP_IPV6; 397 m->m_pkthdr.csum_data = off; 398 in6_delayed_cksum(m, 399 m->m_pkthdr.len - sizeof(struct ip6_hdr), 400 sizeof(struct ip6_hdr)); 401 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; 402 break; 403 } 404 #endif 405 default: 406 break; 407 } 408 } 409 } 410