Openswan-NAT traversal Analysis

Source: Internet
Author: User

Conflict between IPsec and Nat

For packets sent from the NAT server to the Intranet, you must modify the source address and source port to the address and port (or other Nat mode) of the server before forwarding the packets. This modification damages the integrity of IPSec data and causes the receiver to fail verification. In addition, the port information of packets encapsulated by ESP has been encrypted and cannot be obtained by the NAT server, making Nat translation impossible. This is the conflict between IPsec and Nat.

The most common solution to this conflict is UDP encapsulation, that is, a layer of UDP header is encapsulated outside the IPsec packet, so that the NAT modification is limited to the inside of the UDP header, IPSec data is not damaged.

Openswan supports NAT traversal through UDP encapsulation:
The data transmission process depends on the policy SP to determine whether to perform traversal;
During the data receiving process, the kernel is patched to hook up the UDP processing process.
The following is a brief analysis.

NAT-T package Analysis
The secret of IPSec NAT traversal is to use UDP to wrap ESP and Ah protocol packets. Therefore, openswan must obtain necessary information such as the port before secure encapsulation. Otherwise, after ESP encapsulation, the port information will not be available.

Openswan obtains this information in ipsec_xmit_encap_bundle_2 and saves it to the ixs sending descriptor before calling ipsec_xmit_encap_once:
If (ixs-> ipsp-> ips_natt_type )&&(! Ixs-> natt_type) {if the NAT-T is enabled in the Policy
Ixs-> natt_type = ixs-> ipsp-> ips_natt_type;
Ixs-> natt_sport = ixs-> ipsp-> ips_natt_sport;
Ixs-> natt_dport = ixs-> ipsp-> ips_natt_dport;
Switch (ixs-> natt_type ){
Case espinudp_with_non_ike:
Ixs-> natt_head = sizeof (struct udphdr) + (2 * sizeof (_ u32 ));
Break;

Case espinudp_with_non_esp:
Ixs-> natt_head = sizeof (struct udphdr );
Break;

Default:
Klips_print (debug_tunnel & db_tn_crout
, "Klips_xmit: Invalid nat-T type % d"
, Ixs-> natt_type );
Bundle_stat = ipsec_xmit_espudp_badtype;
Goto cleanup;

Break;
}
Ixs-> tailroom + = ixs-> natt_head;
}

At this point, necessary information for encapsulating UDP has been obtained, and the next step is to process the IPSec Security Process (omitted). The final UDP encapsulation is performed at the end of the xmit function of the virtual NIC:
Int ipsec_tunnel_start_xmit (struct sk_buff * SKB, struct net_device * Dev ){
Struct ipsec_xmit_state * ixs = NULL;
Ixs = ipsec_xmit_state_new (); ixs-> Dev = dev; ixs-> SKB = SKB;
Stat = ipsec_xmit_sanity_check_dev (ixs); // check Dev and fill in ixs with the value
Stat = ipsec_xmit_sanity_check_skb (ixs); // check SKB and fill in ixs with the value
Stat = ipsec_tunnel_strip_hard_header (ixs); // obtain the length of the hardware header of the Data Packet

Stat = ipsec_tunnel_salookup (ixs); // find the SA. For details, refer to the sadb section below.
// Fill in ixs-> outgoing_said
Stat = ipsec_xmit_encap_bundle (ixs); // process according to SA and Policy
Stat = ipsec_nat_encap (ixs); // process the NAT-T (wrap the ESP packet with UDP)
Stat = ipsec_tunnel_restore_hard_header (ixs); // restore the hardware Header
Stat = ipsec_tunnel_send (ixs); // Replace the sent physical device, find the new route, and send the packets
// Ip_route_output, ip_send
Ipsec_xmit_cleanup (ixs); // clear the memory occupied by SKB.
Ipsec_xmit_state_delete (ixs); // return to the cache pool
}

Ipsec_nat_encap internal first determine whether the policy has enabled the NAT-T, if not enabled, then nothing will directly return success; if enabled, UDP encapsulation. The encapsulation process is relatively simple, that is, moving the ESP protocol data down from the IP header, leaving the UDP header Size Space, entering the UDP header information, and modifying the protocol field of the IP header to ipproto_udp, and re-calculate the IP header checksum.
(Why don't I move the IP address above the head, so there can be much less data to copy, who knows ?)

NAT-T patch code analysis in openswan (package analysis)

In the klips initialization function, add a hook point klips26_rcv_encap to the UDP kernel code to process the ESP protocol:
Int ipsec_klips_init (void ){
# If defined (net_26) & defined (config_ipsec_nat_traversal)
/* Register our ESP-UDP handler */
If (udp4_register_esp_rcvencap (klips26_rcv_encap, & klips_old_encap )! = 0 ){
Printk (kern_err "klips: Can not register klips_rcv_encap function/N ");
}
# Endif
}

The following is a patch in UDP. C:
Static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = NULL; // Hook Point
Int udp4_register_esp_rcvencap (xfrm4_rcv_encap_t func, xfrm4_rcv_encap_t * oldfunc ){
If (oldfunc! = NULL)
* Oldfunc = xfrm4_rcv_encap_func;
Xfrm4_rcv_encap_func = func;
Return 0;
}
Int udp4_unregister_esp_rcvencap (xfrm4_rcv_encap_t func ){
If (xfrm4_rcv_encap_func! = Func)
Return-1;
Xfrm4_rcv_encap_func = NULL;
Return 0;
}
Finally, the hook points xfrm4_rcv_encap_func = klips26_rcv_encap.

In the UDP kernel code, udp_lib_setsockopt overwrites up-> encap_rcv:
Case udp_encap_espinudp:
Case udp_encap_espinudp_non_ike:
# If defined (config_xfrm) | defined (config_ipsec_nat_traversal)
If (xfrm4_rcv_encap_func)
Up-> encap_rcv = xfrm4_udp_encap_rcv_wrapper;
Else
# Endif
Up-> encap_rcv = xfrm4_udp_encap_rcv;

The UDP receiving process in the kernel is as follows:
Int udp_rcv (struct sk_buff * SKB)
À _ udp4_lib_rcv (SKB, udp_hash, ipproto_udp );
À udp_queue_rcv_skb (SK, SKB );
À (* Up-> encap_rcv) (SK, SKB); // it may be an encapsulation of UDP, which needs to be unencapsulated first
À sock_queue_rcv_skb (SK, SKB); // unencapsulated UDP, submitted
À skb_queue_tail (& SK-> sk_receive_queue, SKB); // put it in the receiving queue of sock
À SK-> sk_data_ready (SK, skb_len); // The upstream notification data is ready.
In udp_queue_rcv_skb, first check udp_sock-> encap_type. If a UDP encapsulation is found, up-> encap_rcv is called for unencapsulation, which is called to xfrm4_udp_encap_rcv_wrapper.
Except for the original xfrm4_udp_encap_rcv in the kernel, the kernel removes the UDP header. The latter only calls the ESP engine ret = xfrm4_rcv_encap (SKB, ipproto_esp, 0, encap_type) in the kernel ), the former calls the hook function xfrm4_rcv_encap_func registered by openswan:
IPH-> protocol = ipproto_esp;/* modify the Protocol (It's ESP !) */
Ret = (* xfrm4_rcv_encap_func) (SKB, encap_type);/* process ESP */

In this way, the ESP hook klips26_rcv_encap in openswan is called, and this function calls the IPsec unpacket loop ipsec_rcv_decap (IRS ).

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.