📄 nat_traversal.c
字号:
__FILE__, __LINE__); return FALSE; } ip = &(st->st_localaddr); nat_np = (st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES ? ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS); if (!out_modify_previous_np(nat_np, outs)) { return FALSE; } memset(&natoa, 0, sizeof(natoa)); natoa.isanoa_np = np; switch (addrtypeof(ip)) { case AF_INET: ip_len = sizeof(ip->u.v4.sin_addr.s_addr); memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len); natoa.isanoa_idtype = ID_IPV4_ADDR; break; case AF_INET6: ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr); memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len); natoa.isanoa_idtype = ID_IPV6_ADDR; break; default: loglog(RC_LOG_SERIOUS, "NAT-Traversal: " "invalid addrtypeof()=%d", addrtypeof(ip)); return FALSE; } if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs)) return FALSE; if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA")) return FALSE; DBG(DBG_NATT, DBG_dump("NAT-OA (S):", ip_val, ip_len); ); close_output_pbs(&pbs); return TRUE;}void nat_traversal_show_result (u_int32_t nt, u_int16_t sport){ const char *mth = NULL, *rslt = NULL; switch (nt & NAT_TRAVERSAL_METHOD) { case LELEM(NAT_TRAVERSAL_IETF_00_01): mth = natt_type_bitnames[0]; break; case LELEM(NAT_TRAVERSAL_IETF_02_03): mth = natt_type_bitnames[1]; break; case LELEM(NAT_TRAVERSAL_OSX): mth = natt_type_bitnames[2]; break; case LELEM(NAT_TRAVERSAL_RFC): mth = natt_type_bitnames[3]; break; } switch (nt & NAT_T_DETECTED) { case 0: rslt = "no NAT detected"; break; case LELEM(NAT_TRAVERSAL_NAT_BHND_ME): rslt = "i am NATed"; break; case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER): rslt = "peer is NATed"; break; case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER): rslt = "both are NATed"; break; } loglog(RC_LOG_SERIOUS, "NAT-Traversal: Result using %s: %s", mth ? mth : "unknown method", rslt ? rslt : "unknown result" ); if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)) && (sport == IKE_UDP_PORT) && ((nt & NAT_T_WITH_PORT_FLOATING)==0)) { loglog(RC_LOG_SERIOUS, "Warning: peer is NATed but source port is still udp/%d. " "IPsec-passthrough NAT device suspected -- NAT-T may not work.", IKE_UDP_PORT ); }}int nat_traversal_espinudp_socket (int sk, const char *fam, u_int32_t type){ int r; r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type)); if ((r<0) && (errno == ENOPROTOOPT)) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: ESPINUDP(%d) not supported by kernel for family %s" , type, fam); disable_nat_traversal(type); } return r;}void nat_traversal_new_ka_event (void){ if (_ka_evt) return; /* Event already schedule */ event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL); _ka_evt = 1;}static void nat_traversal_send_ka (struct state *st){ static unsigned char ka_payload = 0xff; chunk_t sav; DBG(DBG_NATT|DBG_DPD, DBG_log("ka_event: send NAT-KA to %s:%d (state=#%lu)" , ip_str(&st->st_remoteaddr) , st->st_remoteport , st->st_serialno); ); /** save state chunk */ setchunk(sav, st->st_tpacket.ptr, st->st_tpacket.len); /** send keep alive */ setchunk(st->st_tpacket, &ka_payload, 1); send_packet(st, "NAT-T Keep Alive", FALSE); /** restore state chunk */ setchunk(st->st_tpacket, sav.ptr, sav.len);}/** * Find ISAKMP States with NAT-T and send keep-alive */static void nat_traversal_ka_event_state (struct state *st, void *data){ unsigned int *_kap_st = (unsigned int *)data; const struct connection *c = st->st_connection; if (!c) return; if ( ((st->st_state == STATE_MAIN_R3) || (st->st_state == STATE_MAIN_I4) || (st->st_state == STATE_AGGR_R2) || (st->st_state == STATE_AGGR_I2)) && (st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) && ((st->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || (_force_ka))) { /** * - ISAKMP established * - NAT-Traversal detected * - NAT-KeepAlive needed (we are NATed) */ if (c->newest_isakmp_sa != st->st_serialno) { /** * if newest is also valid, ignore this one, we will only use * newest. */ struct state *st_newest; st_newest = state_with_serialno(c->newest_isakmp_sa); if ((st_newest) && ((st_newest->st_state==STATE_MAIN_R3) || (st_newest->st_state==STATE_MAIN_I4)) && (st_newest->hidden_variables.st_nat_traversal & NAT_T_DETECTED) && ((st_newest->hidden_variables.st_nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || (_force_ka))) { return; } } set_cur_state(st); nat_traversal_send_ka(st); reset_cur_state(); (*_kap_st)++; }}void nat_traversal_ka_event (void){ unsigned int _kap_st = 0; _ka_evt = 0; /* ready to be reschedule */ for_each_state((void *)nat_traversal_ka_event_state, &_kap_st); if (_kap_st) { /** * If there are still states who needs Keep-Alive, schedule new event */ nat_traversal_new_ka_event(); }}struct _new_mapp_nfo { ip_address addr; u_int16_t sport, dport;};static void nat_traversal_find_new_mapp_state (struct state *st, void *data){ struct connection *c = st->st_connection; struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data; if ((c) && sameaddr(&st->st_remoteaddr, &(nfo->addr)) && (st->st_remoteport == nfo->sport)) { /** * Change host port */ st->st_remoteport = nfo->dport; if (IS_IPSEC_SA_ESTABLISHED(st->st_state) || IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) { if (!update_ipsec_sa(st)) { /** * If ipsec update failed, restore old port or we'll * not be able to update anymore. */ st->st_remoteport = nfo->sport; } } }}static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport, const ip_address *dst, u_int16_t dport){ char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF]; struct _new_mapp_nfo nfo; addrtot(src, 0, srca, ADDRTOT_BUF); addrtot(dst, 0, dsta, ADDRTOT_BUF); if (!sameaddr(src, dst)) { loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: " "address change currently not supported [%s:%d,%s:%d]", srca, sport, dsta, dport); return -1; } if (sport == dport) { /* no change */ return 0; } DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport); nfo.addr = *src; nfo.sport = sport; nfo.dport = dport; for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo); return 0;}void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st){ struct iface_port *i = NULL; if (st == NULL) { return; } if (md) { /** * If source port has changed, update (including other * states and established kernel SA) */ if (st->st_remoteport != md->sender_port) { nat_traversal_new_mapping(&st->st_remoteaddr , st->st_remoteport , &st->st_remoteaddr , md->sender_port); } /** * If interface type has changed, update local port (500/4500) */ if (md->iface->port != st->st_localport) { st->st_localport = md->iface->port; DBG(DBG_NATT, DBG_log("NAT-T: updating local port to %d" , st->st_localport)); } } /** * If we're initiator and NAT-T (with port floating) is detected, we * need to change port (MAIN_I3 or QUICK_I1) */ if (((st->st_state == STATE_MAIN_I3) || (st->st_state == STATE_QUICK_I1)) && (st->hidden_variables.st_nat_traversal & NAT_T_WITH_PORT_FLOATING) && (st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) && (st->st_localport != NAT_T_IKE_FLOAT_PORT)) { DBG(DBG_NATT , DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT)); st->st_localport = NAT_T_IKE_FLOAT_PORT; st->st_remoteport = NAT_T_IKE_FLOAT_PORT; /* * Also update pending connections or they will be deleted if * uniqueids option is set. * THIS does NOTHING as, both arguments are "st"! */ update_pending(st, st); } /** * Find valid interface according to local port (500/4500) */ if (!(sameaddr(&st->st_localaddr, &st->st_interface->ip_addr) && st->st_localport == st->st_interface->port)) { char b1[ADDRTOT_BUF], b2[ADDRTOT_BUF]; DBG(DBG_NATT, DBG_log("NAT-T connection has wrong interface definition %s:%u vs %s:%u" , (addrtot(&st->st_localaddr, 0, b1, sizeof(b1)),b1) , st->st_localport , (addrtot(&st->st_interface->ip_addr, 0, b2, sizeof(b2)),b2) , st->st_interface->port)); for (i = interfaces; i != NULL; i = i->next) { if ((sameaddr(&st->st_localaddr, &i->ip_addr)) && (st->st_localport == i->port)) { DBG(DBG_NATT, DBG_log("NAT-T: using interface %s:%d" , i->ip_dev->id_rname , i->port)); st->st_interface = i; break; } } }}struct _new_klips_mapp_nfo { struct sadb_sa *sa; ip_address src, dst; u_int16_t sport, dport;};static void nat_t_new_klips_mapp (struct state *st, void *data){ struct connection *c = st->st_connection; struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data; if ((c) && (st->st_esp.present) && sameaddr(&st->st_remoteaddr, &(nfo->src)) && (st->st_esp.our_spi == nfo->sa->sadb_sa_spi)) { nat_traversal_new_mapping(&st->st_remoteaddr , st->st_remoteport , &(nfo->dst), nfo->dport); }}void process_pfkey_nat_t_new_mapping( struct sadb_msg *msg __attribute__ ((unused)), struct sadb_ext *extensions[SADB_EXT_MAX + 1]){ struct _new_klips_mapp_nfo nfo; struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC]; struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST]; struct sockaddr *srca, *dsta; err_t ugh = NULL; nfo.sa = (void *) extensions[SADB_EXT_SA]; if ((!nfo.sa) || (!srcx) || (!dstx)) { openswan_log("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: " "got NULL params"); return; } srca = ((struct sockaddr *)(void *)&srcx[1]); dsta = ((struct sockaddr *)(void *)&dstx[1]); if ((srca->sa_family != AF_INET) || (dsta->sa_family != AF_INET)) { ugh = "only AF_INET supported"; } else { char text_said[SATOT_BUF]; char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF]; ip_said said; initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr, sizeof(((const struct sockaddr_in *)srca)->sin_addr), srca->sa_family, &(nfo.src)); nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port); initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr, sizeof(((const struct sockaddr_in *)dsta)->sin_addr), dsta->sa_family, &(nfo.dst)); nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port); DBG(DBG_NATT, initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said); satot(&said, 0, text_said, SATOT_BUF); addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF); addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF); DBG_log("new klips mapping %s %s:%d %s:%d", text_said, _srca, nfo.sport, _dsta, nfo.dport); ); for_each_state((void *)nat_t_new_klips_mapp, &nfo); } if (ugh != NULL) openswan_log("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh);}#endif/* * $Log: nat_traversal.c,v $ * Revision 1.26.2.6 2006/01/04 18:57:52 ken * Send 02_N too * * Revision 1.26.2.5 2005/11/24 05:30:37 ken * MCR's refactored natd_lookup function for multi-NAT-D Hash * * Revision 1.26.2.4 2005/09/27 04:30:20 paul * Backport of HEAD's patch, adopted from Peter Van der Beken's * (peterv@propagandism.org) MacOSX interop patch. * * Reported to Apple Developer Center (ADC) by Paul Wouters (paul@xelerance.com): * Problem ID: 4274347 * Title: IPsec NAT-T implementation is broken, breaking L2TP VPN's to non-apple servers * Created Date: 26-Sep-2005 06:36 PM * * Revision 1.26.2.3 2005/09/07 00:41:12 paul * Pull up mcr's nat-t detection for klips. * * Revision 1.26.2.2 2005/07/26 02:11:23 ken * Pullin from HEAD: * Split Aggressive mode into ikev1_aggr.c * Fix NAT-T that we broke in dr7 * Move dpd/pgp vendor id's to vendor.[ch] * * Revision 1.26.2.1 2005/07/26 01:20:14 ken * Pull in st -> c changes from HEAD * * Revision 1.27 2005/07/26 01:14:58 mcr * switch from i->interface to st->st_interface. * cleaned up some diagnostic, and canonicalized to "NAT-Traversal" * * Revision 1.26 2005/06/14 22:38:06 mcr * changed definition of interface such that we can now compare if * a NAT vs non-NAT interface are considered the "same" * * Revision 1.25 2005/05/08 13:25:48 paul * fixed typo * * Revision 1.24 2005/04/21 21:58:06 mcr * log correct address/port for NAT-KA. * * Revision 1.23 2005/04/20 15:30:28 mcr * additional debugging of NAT-KA and DPD messages. * * Revision 1.22 2005/04/08 18:29:52 mcr * use natt_defines.h to get definitions. * * Revision 1.21 2005/04/06 17:56:04 mcr * log where/who the DPD R_U_THERE sent to. * * Revision 1.20 2005/03/20 23:16:16 mcr * fixed typo in case. * * Revision 1.19 2005/02/14 18:27:27 mcr * additional debugging of when NAT-T is enabled, and when the * VID is actually being sent. * * Revision 1.18 2005/01/28 06:22:52 mcr * additional debugging of whether or not NAT-T vendor * IDs are inserted. * * Revision 1.17 2005/01/24 03:35:22 mcr * fixed selection of interface for various states * of NAT "floating" * * Revision 1.16 2005/01/23 19:16:15 mcr * moved nat varibales to "hidden_variables" * added for RFC3947 NAT code. * * Revision 1.15 2004/11/30 02:31:14 mcr * oops, function didn't match prototype. * * Revision 1.14 2004/11/30 02:26:59 mcr * additional debugging of port-floating enabling/disabling. * * Revision 1.13 2004/11/05 00:14:50 mcr * added log info. * * * $Id: nat_traversal.c,v 1.26.2.6 2006/01/04 18:57:52 ken Exp $ * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -