1/* 2 * Copyright (C) 2012 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Simple ISAKMP transparent proxy for in-kernel use. For use with the NAT 7 * code. 8 * 9 * $Id$ 10 * 11 */ 12#define IPF_IPSEC_PROXY 13 14 15/* 16 * IPSec proxy 17 */ 18typedef struct ipf_ipsec_softc_s { 19 frentry_t ipsec_fr; 20 int ipsec_proxy_init; 21 int ipsec_proxy_ttl; 22 ipftq_t *ipsec_nat_tqe; 23 ipftq_t *ipsec_state_tqe; 24 char ipsec_buffer[1500]; 25} ipf_ipsec_softc_t; 26 27 28void *ipf_p_ipsec_soft_create __P((ipf_main_softc_t *)); 29void ipf_p_ipsec_soft_destroy __P((ipf_main_softc_t *, void *)); 30int ipf_p_ipsec_soft_init __P((ipf_main_softc_t *, void *)); 31void ipf_p_ipsec_soft_fini __P((ipf_main_softc_t *, void *)); 32int ipf_p_ipsec_init __P((void)); 33void ipf_p_ipsec_fini __P((void)); 34int ipf_p_ipsec_new __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 35void ipf_p_ipsec_del __P((ipf_main_softc_t *, ap_session_t *)); 36int ipf_p_ipsec_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 37int ipf_p_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *)); 38 39 40/* 41 * IPSec application proxy initialization. 42 */ 43void * 44ipf_p_ipsec_soft_create(softc) 45 ipf_main_softc_t *softc; 46{ 47 ipf_ipsec_softc_t *softi; 48 49 KMALLOC(softi, ipf_ipsec_softc_t *); 50 if (softi == NULL) 51 return NULL; 52 53 bzero((char *)softi, sizeof(*softi)); 54 softi->ipsec_fr.fr_ref = 1; 55 softi->ipsec_fr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 56 MUTEX_INIT(&softi->ipsec_fr.fr_lock, "IPsec proxy rule lock"); 57 softi->ipsec_proxy_init = 1; 58 softi->ipsec_proxy_ttl = 60; 59 60 return softi; 61} 62 63 64int 65ipf_p_ipsec_soft_init(softc, arg) 66 ipf_main_softc_t *softc; 67 void *arg; 68{ 69 ipf_ipsec_softc_t *softi = arg; 70 71 softi->ipsec_nat_tqe = ipf_state_add_tq(softc, softi->ipsec_proxy_ttl); 72 if (softi->ipsec_nat_tqe == NULL) 73 return -1; 74 softi->ipsec_state_tqe = ipf_nat_add_tq(softc, softi->ipsec_proxy_ttl); 75 if (softi->ipsec_state_tqe == NULL) { 76 if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0) 77 ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe); 78 softi->ipsec_nat_tqe = NULL; 79 return -1; 80 } 81 82 softi->ipsec_nat_tqe->ifq_flags |= IFQF_PROXY; 83 softi->ipsec_state_tqe->ifq_flags |= IFQF_PROXY; 84 softi->ipsec_fr.fr_age[0] = softi->ipsec_proxy_ttl; 85 softi->ipsec_fr.fr_age[1] = softi->ipsec_proxy_ttl; 86 return 0; 87} 88 89 90void 91ipf_p_ipsec_soft_fini(softc, arg) 92 ipf_main_softc_t *softc; 93 void *arg; 94{ 95 ipf_ipsec_softc_t *softi = arg; 96 97 if (arg == NULL) 98 return; 99 100 if (softi->ipsec_nat_tqe != NULL) { 101 if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0) 102 ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe); 103 } 104 softi->ipsec_nat_tqe = NULL; 105 if (softi->ipsec_state_tqe != NULL) { 106 if (ipf_deletetimeoutqueue(softi->ipsec_state_tqe) == 0) 107 ipf_freetimeoutqueue(softc, softi->ipsec_state_tqe); 108 } 109 softi->ipsec_state_tqe = NULL; 110} 111 112 113void 114ipf_p_ipsec_soft_destroy(softc, arg) 115 ipf_main_softc_t *softc; 116 void *arg; 117{ 118 ipf_ipsec_softc_t *softi = arg; 119 120 if (softi->ipsec_proxy_init == 1) { 121 MUTEX_DESTROY(&softi->ipsec_fr.fr_lock); 122 softi->ipsec_proxy_init = 0; 123 } 124 125 KFREE(softi); 126} 127 128 129/* 130 * Setup for a new IPSEC proxy. 131 */ 132int 133ipf_p_ipsec_new(arg, fin, aps, nat) 134 void *arg; 135 fr_info_t *fin; 136 ap_session_t *aps; 137 nat_t *nat; 138{ 139 ipf_ipsec_softc_t *softi = arg; 140 ipf_main_softc_t *softc = fin->fin_main_soft; 141#ifdef USE_MUTEXES 142 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 143#endif 144 int p, off, dlen, ttl; 145 ipsec_pxy_t *ipsec; 146 ipnat_t *ipn, *np; 147 fr_info_t fi; 148 char *ptr; 149 int size; 150 ip_t *ip; 151 mb_t *m; 152 153 if (fin->fin_v != 4) 154 return -1; 155 156 off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff; 157 bzero(softi->ipsec_buffer, sizeof(softi->ipsec_buffer)); 158 ip = fin->fin_ip; 159 m = fin->fin_m; 160 161 dlen = M_LEN(m) - off; 162 if (dlen < 16) 163 return -1; 164 COPYDATA(m, off, MIN(sizeof(softi->ipsec_buffer), dlen), 165 softi->ipsec_buffer); 166 167 if (ipf_nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_nsrcip, 168 ip->ip_dst) != NULL) 169 return -1; 170 171 np = nat->nat_ptr; 172 size = np->in_size; 173 KMALLOC(ipsec, ipsec_pxy_t *); 174 if (ipsec == NULL) 175 return -1; 176 177 KMALLOCS(ipn, ipnat_t *, size); 178 if (ipn == NULL) { 179 KFREE(ipsec); 180 return -1; 181 } 182 183 aps->aps_data = ipsec; 184 aps->aps_psiz = sizeof(*ipsec); 185 bzero((char *)ipsec, sizeof(*ipsec)); 186 bzero((char *)ipn, size); 187 ipsec->ipsc_rule = ipn; 188 189 /* 190 * Create NAT rule against which the tunnel/transport mapping is 191 * created. This is required because the current NAT rule does not 192 * describe ESP but UDP instead. 193 */ 194 ipn->in_size = size; 195 ttl = IPF_TTLVAL(softi->ipsec_nat_tqe->ifq_ttl); 196 ipn->in_tqehead[0] = ipf_nat_add_tq(softc, ttl); 197 ipn->in_tqehead[1] = ipf_nat_add_tq(softc, ttl); 198 ipn->in_ifps[0] = fin->fin_ifp; 199 ipn->in_apr = NULL; 200 ipn->in_use = 1; 201 ipn->in_hits = 1; 202 ipn->in_snip = ntohl(nat->nat_nsrcaddr); 203 ipn->in_ippip = 1; 204 ipn->in_osrcip = nat->nat_osrcip; 205 ipn->in_osrcmsk = 0xffffffff; 206 ipn->in_nsrcip = nat->nat_nsrcip; 207 ipn->in_nsrcmsk = 0xffffffff; 208 ipn->in_odstip = nat->nat_odstip; 209 ipn->in_odstmsk = 0xffffffff; 210 ipn->in_ndstip = nat->nat_ndstip; 211 ipn->in_ndstmsk = 0xffffffff; 212 ipn->in_redir = NAT_MAP; 213 ipn->in_pr[0] = IPPROTO_ESP; 214 ipn->in_pr[1] = IPPROTO_ESP; 215 ipn->in_flags = (np->in_flags | IPN_PROXYRULE); 216 MUTEX_INIT(&ipn->in_lock, "IPSec proxy NAT rule"); 217 218 ipn->in_namelen = np->in_namelen; 219 bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen); 220 ipn->in_ifnames[0] = np->in_ifnames[0]; 221 ipn->in_ifnames[1] = np->in_ifnames[1]; 222 223 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 224 fi.fin_fi.fi_p = IPPROTO_ESP; 225 fi.fin_fr = &softi->ipsec_fr; 226 fi.fin_data[0] = 0; 227 fi.fin_data[1] = 0; 228 p = ip->ip_p; 229 ip->ip_p = IPPROTO_ESP; 230 fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); 231 fi.fin_flx |= FI_IGNORE; 232 233 ptr = softi->ipsec_buffer; 234 bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t)); 235 ptr += sizeof(ipsec_cookie_t); 236 bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t)); 237 /* 238 * The responder cookie should only be non-zero if the initiator 239 * cookie is non-zero. Therefore, it is safe to assume(!) that the 240 * cookies are both set after copying if the responder is non-zero. 241 */ 242 if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0) 243 ipsec->ipsc_rckset = 1; 244 245 MUTEX_ENTER(&softn->ipf_nat_new); 246 ipsec->ipsc_nat = ipf_nat_add(&fi, ipn, &ipsec->ipsc_nat, 247 NAT_SLAVE|SI_WILDP, NAT_OUTBOUND); 248 MUTEX_EXIT(&softn->ipf_nat_new); 249 if (ipsec->ipsc_nat != NULL) { 250 (void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0); 251 MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock); 252 ipf_nat_update(&fi, ipsec->ipsc_nat); 253 MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock); 254 255 fi.fin_data[0] = 0; 256 fi.fin_data[1] = 0; 257 (void) ipf_state_add(softc, &fi, &ipsec->ipsc_state, SI_WILDP); 258 } 259 ip->ip_p = p & 0xff; 260 return 0; 261} 262 263 264/* 265 * For outgoing IKE packets. refresh timeouts for NAT & state entries, if 266 * we can. If they have disappeared, recreate them. 267 */ 268int 269ipf_p_ipsec_inout(arg, fin, aps, nat) 270 void *arg; 271 fr_info_t *fin; 272 ap_session_t *aps; 273 nat_t *nat; 274{ 275 ipf_ipsec_softc_t *softi = arg; 276 ipf_main_softc_t *softc = fin->fin_main_soft; 277 ipsec_pxy_t *ipsec; 278 fr_info_t fi; 279 ip_t *ip; 280 int p; 281 282 if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) 283 return 0; 284 285 if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) 286 return 0; 287 288 ipsec = aps->aps_data; 289 290 if (ipsec != NULL) { 291 ip = fin->fin_ip; 292 p = ip->ip_p; 293 294 if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) { 295 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 296 fi.fin_fi.fi_p = IPPROTO_ESP; 297 fi.fin_fr = &softi->ipsec_fr; 298 fi.fin_data[0] = 0; 299 fi.fin_data[1] = 0; 300 ip->ip_p = IPPROTO_ESP; 301 fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); 302 fi.fin_flx |= FI_IGNORE; 303 } 304 305 /* 306 * Update NAT timeout/create NAT if missing. 307 */ 308 if (ipsec->ipsc_nat != NULL) 309 ipf_queueback(softc->ipf_ticks, 310 &ipsec->ipsc_nat->nat_tqe); 311 else { 312#ifdef USE_MUTEXES 313 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 314#endif 315 316 MUTEX_ENTER(&softn->ipf_nat_new); 317 ipsec->ipsc_nat = ipf_nat_add(&fi, ipsec->ipsc_rule, 318 &ipsec->ipsc_nat, 319 NAT_SLAVE|SI_WILDP, 320 nat->nat_dir); 321 MUTEX_EXIT(&softn->ipf_nat_new); 322 if (ipsec->ipsc_nat != NULL) { 323 (void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0); 324 MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock); 325 ipf_nat_update(&fi, ipsec->ipsc_nat); 326 MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock); 327 } 328 } 329 330 /* 331 * Update state timeout/create state if missing. 332 */ 333 READ_ENTER(&softc->ipf_state); 334 if (ipsec->ipsc_state != NULL) { 335 ipf_queueback(softc->ipf_ticks, 336 &ipsec->ipsc_state->is_sti); 337 ipsec->ipsc_state->is_die = nat->nat_age; 338 RWLOCK_EXIT(&softc->ipf_state); 339 } else { 340 RWLOCK_EXIT(&softc->ipf_state); 341 fi.fin_data[0] = 0; 342 fi.fin_data[1] = 0; 343 (void) ipf_state_add(softc, &fi, &ipsec->ipsc_state, 344 SI_WILDP); 345 } 346 ip->ip_p = p; 347 } 348 return 0; 349} 350 351 352/* 353 * This extends the NAT matching to be based on the cookies associated with 354 * a session and found at the front of IKE packets. The cookies are always 355 * in the same order (not reversed depending on packet flow direction as with 356 * UDP/TCP port numbers). 357 */ 358int 359ipf_p_ipsec_match(fin, aps, nat) 360 fr_info_t *fin; 361 ap_session_t *aps; 362 nat_t *nat; 363{ 364 ipsec_pxy_t *ipsec; 365 u_32_t cookies[4]; 366 mb_t *m; 367 int off; 368 369 nat = nat; /* LINT */ 370 371 if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG)) 372 return -1; 373 374 off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff; 375 ipsec = aps->aps_data; 376 m = fin->fin_m; 377 COPYDATA(m, off, sizeof(cookies), (char *)cookies); 378 379 if ((cookies[0] != ipsec->ipsc_icookie[0]) || 380 (cookies[1] != ipsec->ipsc_icookie[1])) 381 return -1; 382 383 if (ipsec->ipsc_rckset == 0) { 384 if ((cookies[2]|cookies[3]) == 0) { 385 return 0; 386 } 387 ipsec->ipsc_rckset = 1; 388 ipsec->ipsc_rcookie[0] = cookies[2]; 389 ipsec->ipsc_rcookie[1] = cookies[3]; 390 return 0; 391 } 392 393 if ((cookies[2] != ipsec->ipsc_rcookie[0]) || 394 (cookies[3] != ipsec->ipsc_rcookie[1])) 395 return -1; 396 return 0; 397} 398 399 400/* 401 * clean up after ourselves. 402 */ 403void 404ipf_p_ipsec_del(softc, aps) 405 ipf_main_softc_t *softc; 406 ap_session_t *aps; 407{ 408 ipsec_pxy_t *ipsec; 409 410 ipsec = aps->aps_data; 411 412 if (ipsec != NULL) { 413 /* 414 * Don't bother changing any of the NAT structure details, 415 * *_del() is on a callback from aps_free(), from nat_delete() 416 */ 417 418 READ_ENTER(&softc->ipf_state); 419 if (ipsec->ipsc_state != NULL) { 420 ipsec->ipsc_state->is_die = softc->ipf_ticks + 1; 421 ipsec->ipsc_state->is_me = NULL; 422 ipf_queuefront(&ipsec->ipsc_state->is_sti); 423 } 424 RWLOCK_EXIT(&softc->ipf_state); 425 426 ipsec->ipsc_state = NULL; 427 ipsec->ipsc_nat = NULL; 428 ipsec->ipsc_rule->in_flags |= IPN_DELETE; 429 ipf_nat_rule_deref(softc, &ipsec->ipsc_rule); 430 } 431} 432