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