mywiki:linux:ipsec
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| mywiki:linux:ipsec [2015/12/10 10:18] – [Terms] super | mywiki:linux:ipsec [2019/09/15 18:55] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| **IPSec Implementation in Linux** | **IPSec Implementation in Linux** | ||
| + | |||
| + | | Reference | {{: | ||
| ====== IPSEC Basic ====== | ====== IPSEC Basic ====== | ||
| Line 30: | Line 32: | ||
| | XFRM_MSG_GETPOLICY | To get a new policy to SPD | | | XFRM_MSG_GETPOLICY | To get a new policy to SPD | | ||
| | XFRM_MSG_FLUSHPOLICY | To flush SPD | | | XFRM_MSG_FLUSHPOLICY | To flush SPD | | ||
| + | |||
| + | ===== IPSec framework in kernel ===== | ||
| + | | ESP Protocol | net/ | ||
| + | | AH Protocol | net/ | ||
| + | | XFRM framework | net/ | ||
| + | | XFRM initialization | xfrm4_init() and xfrm6_init(). | | ||
| + | |||
| + | |||
| + | ===== Kernel Terms ===== | ||
| + | | aalg | **Authentication** algo pointer | | ||
| + | | ealg | **Encryption** algo pointer | | ||
| + | | calg | **Compression** algo pointer | | ||
| + | | aead | **Authentication Encryption** with Associated Data pointer | Note: if (aead == NULL); then only authentication without any encryption | | ||
| + | | encap | Data for **encapsulator**, | ||
| + | |||
| + | |||
| + | ===== Kernel cryptography ===== | ||
| + | |||
| + | | acrypto | asynchronous crypto | | ||
| + | | cryptd | | ||
| + | | pcrypto | for multicore environment | | ||
| + | |||
| + | Algo: DES, 3DES, AES, RC5, IDEA, 3-IDEA, CAST, BLOWFISH etc... | ||
| + | |||
| + | two IPSec stacks: | ||
| + | | native netkey stack | syncronous | | ||
| + | | traditional KLIPS stack | asynchronous | | ||
| + | |||
| + | To start with, the core object of **xfrm** is the ' | ||
| + | |||
| + | Data structures | ||
| + | <file > | ||
| + | The building block of SPD (Policy Database) is struct xfrm_policy. | ||
| + | |||
| + | /* ################################################# | ||
| + | |||
| + | struct xfrm_policy { | ||
| + | |||
| + | #ifdef CONFIG_NET_NS | ||
| + | struct net *xp_net; | ||
| + | #endif | ||
| + | struct hlist_node | ||
| + | struct hlist_node | ||
| + | /* This lock only affects elements except for entry. */ | ||
| + | rwlock_t | ||
| + | atomic_t | ||
| + | struct timer_list | ||
| + | struct flow_cache_object flo; | ||
| + | atomic_t | ||
| + | u32 | ||
| + | u32 | ||
| + | struct xfrm_mark | ||
| + | struct xfrm_selector | ||
| + | struct xfrm_lifetime_cfg lft; | ||
| + | struct xfrm_lifetime_cur curlft; | ||
| + | struct xfrm_policy_walk_entry walk; | ||
| + | struct xfrm_policy_queue polq; | ||
| + | u8 type; | ||
| + | u8 | ||
| + | u8 | ||
| + | u8 | ||
| + | u16 | ||
| + | struct xfrm_sec_ctx | ||
| + | struct xfrm_tmpl | ||
| + | }; | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | Important Fields: | ||
| + | |||
| + | - refcnt is to hold the reference to the policy. | ||
| + | |||
| + | - which embedded xfrm_selector object to hold the source and destination IP addresses, source and destination ports, protocol, interface index etc. xfrm_selector_match() API checks if the given packet matches with the XFRM selector. | ||
| + | |||
| + | - lft: is the policy lifetime | ||
| + | |||
| + | - timer: to handle the policy expiry | ||
| + | |||
| + | - polq: is a queue to push the packets when there are no states associated with this policy. | ||
| + | |||
| + | - action: this field decides the fate of the traffic. (XFRM_POLICY_ALLOW and XFRM_POLICY_BLOCK) | ||
| + | |||
| + | - family (v4 or v6, as mentioned this structure is common for all protocols) | ||
| + | </ | ||
| + | |||
| + | The building block of SAD (Association Database) is struct xfrm_state | ||
| + | |||
| + | < | ||
| + | /* Full description of state of transformer. */ | ||
| + | |||
| + | struct xfrm_state { | ||
| + | |||
| + | #ifdef CONFIG_NET_NS | ||
| + | struct net *xs_net; | ||
| + | #endif | ||
| + | union { | ||
| + | struct hlist_node | ||
| + | struct hlist_node | ||
| + | }; | ||
| + | struct hlist_node | ||
| + | struct hlist_node | ||
| + | atomic_t | ||
| + | spinlock_t | ||
| + | struct xfrm_id | ||
| + | struct xfrm_selector | ||
| + | |||
| + | /* Key manager bits */ | ||
| + | |||
| + | struct xfrm_state_walk km; | ||
| + | |||
| + | /* Parameters of this state. */ | ||
| + | |||
| + | struct { | ||
| + | u32 | ||
| + | u8 mode; | ||
| + | u8 | ||
| + | u8 | ||
| + | u8 | ||
| + | u16 | ||
| + | xfrm_address_t | ||
| + | int | ||
| + | int | ||
| + | u32 | ||
| + | } props; | ||
| + | |||
| + | struct xfrm_lifetime_cfg lft; | ||
| + | |||
| + | /* Data for transformer */ | ||
| + | struct xfrm_algo_auth | ||
| + | struct xfrm_algo | ||
| + | struct xfrm_algo | ||
| + | struct xfrm_algo_aead | ||
| + | |||
| + | /* Data for encapsulator */ | ||
| + | |||
| + | struct xfrm_encap_tmpl | ||
| + | |||
| + | -------------- | ||
| + | |||
| + | | ||
| + | |||
| + | /* data for replay detection */ | ||
| + | |||
| + | struct xfrm_replay_state replay; | ||
| + | |||
| + | struct xfrm_replay_state_esn *replay_esn; | ||
| + | |||
| + | struct xfrm_replay_state preplay; | ||
| + | |||
| + | struct xfrm_replay_state_esn *preplay_esn; | ||
| + | |||
| + | struct xfrm_replay | ||
| + | |||
| + | u32 | ||
| + | |||
| + | u32 | ||
| + | |||
| + | struct timer_list | ||
| + | |||
| + | /* Statistics */ | ||
| + | |||
| + | struct xfrm_stats | ||
| + | |||
| + | struct xfrm_lifetime_cur curlft; | ||
| + | |||
| + | struct tasklet_hrtimer | ||
| + | |||
| + | /* Last used time */ | ||
| + | |||
| + | unsigned long lastused; | ||
| + | |||
| + | --------------------------- | ||
| + | |||
| + | ---------------------------- | ||
| + | |||
| + | /* Private data of this transformer, | ||
| + | |||
| + | * interpreted by xfrm_type methods. */ | ||
| + | void | ||
| + | |||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | ===== IPSec kernel | ||
| + | | Xfrm_lookup() | xfrm lookup(SPD and SAD) method | | ||
| + | | Xfrm_input() | xfrm processing for an ingress packet | | ||
| + | | Xfrm_output() | xfrm processing for an egress packet | | ||
| + | | Xfrm4_rcv() | IPv4 specific Rx method | | ||
| + | | Xfrm6_rcv() | IPv6 specific Rx method | | ||
| + | | Esp_input() | ESP processing for an ingress packet | | ||
| + | | Esp_output() | ESP processing for an egress packet | | ||
| + | | Ah_input() | AH processing for an ingress packet | | ||
| + | | Ah_output() | AH processing for an egress packet | | ||
| + | | xfrm_policy_alloc() | allocates an SPD object | | ||
| + | | Xfrm_policy_destroy() | frees an SPD object | | ||
| + | | xfrm_ policy_lookup | SPD lookup | | ||
| + | | xfrm_policy_byid() | SPD lookup based on id | | ||
| + | | Xfrm_policy_insert() | Add an entry to SPD | | ||
| + | | Xfrm_Policy_delete() | remove an entry from SPD | | ||
| + | | Xfrm_bundle_create() | creates a xfrm bundle | | ||
| + | | Xfrm_policy_delete() | releases the resources of a policy object | | ||
| + | | Xfrm_state_add() | add an entry to SAD | | ||
| + | | Xfrm_state_delete() | free and SAD object | | ||
| + | | xfrm_state_alloc() | allocate an SAD object | | ||
| + | | xfrm_state_lookup_byaddr() | src address based SAD lookup | | ||
| + | | xfrm_state_find() | SAD look up based on dst | | ||
| + | | xfrm_state_lookup() | SAD lookup based on spi | | ||
| + | |||
| + | ===== IPSec SA initialize ===== | ||
| + | It is initialized by API: **static int esp_init_state(struct xfrm_state *x)**, which is defined in file: | ||
| + | * net/ | ||
| + | * net/ | ||
| + | ===== IPSec Tx steps ===== | ||
| + | < | ||
| + | For better understanding I have divided the IPSec transmission process in 7 stepes as below | ||
| + | |||
| + | Step-1: Transport_layer_sendmsg() | ||
| + | |||
| + | Does TCP/UDP specific jobs are done here before going for route lookup | ||
| + | |||
| + | Step-2: ip_route_output_slow() | ||
| + | |||
| + | Xfrm_lookup() | ||
| + | |||
| + | Step-3: ip_local_output() | ||
| + | |||
| + | Step-4: ip_local_out() | ||
| + | |||
| + | | ||
| + | |||
| + | Calls skb-> | ||
| + | |||
| + | Step-5: xfrm4_output/ | ||
| + | |||
| + | Step-6: esp_output()/ | ||
| + | |||
| + | Step-7: ip_output() | ||
| + | |||
| + | Step-8: dev_queue_xmit() | ||
| + | |||
| + | Egress QoS comes here. | ||
| + | |||
| + | Step-9: dev-> | ||
| + | </ | ||
| + | ===== IPSec Rx steps ===== | ||
| + | < | ||
| + | For better understanding I have divided the IPSec reception process in 7 stepes, they are below | ||
| + | |||
| + | Step-1: netif_receive_skb() | ||
| + | |||
| + | Step-2: ip_rcv() | ||
| + | |||
| + | Netfilter PRE_ROUTING applies here. | ||
| + | |||
| + | Step-3: ip_receive_finish | ||
| + | |||
| + | Calls ip_route_input_noref(). Which finds the route entry and set dst-> | ||
| + | |||
| + | Step-4: ip_local_deliver | ||
| + | |||
| + | LOCAL_IN Netfilter part here. | ||
| + | |||
| + | Step-5: ip_local_deliver_finish() | ||
| + | |||
| + | Based on the protocol field of ip header (IPPROTO_AH, | ||
| + | |||
| + | Step-6: | ||
| + | |||
| + | Step-7: xfrm_input() | ||
| + | |||
| + | Calls xfrm_state_lookup() | ||
| + | |||
| + | calls esp_input()/ | ||
| + | |||
| + | Once again applies the PRE_ROUTING Netfilter, but now for the decapsulated packet | ||
| + | |||
| + | Step-8: xfrm4_rcv_encap_finish() | ||
| + | |||
| + | Will do the route lookup again for the decapsulated packet using ip_route_input_noref(). Again route lookup should decide for local_delivery. | ||
| + | |||
| + | Step-9: ip_local_delivery() | ||
| + | |||
| + | again the LOCAL_IN Netfilter for decapsulated packet | ||
| + | |||
| + | now the protocol field will be TCP/UDP and the packet flows in the native reception methods of TCP/UDP and delivers to the socket | ||
| + | |||
| + | Step-10: transport_layer_rcvmsg() | ||
| + | |||
| + | -to userspace | ||
| + | </ | ||
mywiki/linux/ipsec.1449713905.txt.gz · Last modified: (external edit)
