Today I'll show you the input/output procedure of XFRM.
Output procedure
  Go through the code:
+xfrm4_output->
 +xfrm4_output_finish->
  -xfrm4_output_finish2
  In xfrm4_output_finish2, it applies a sa(take AH for example) by '.mode->output' and '.type->output'. Finally, it calls dst_output again and pass down the packet protected to the 'neighbour subsystem'.
Input procedure
  Go through the code:
 +xfrm4_rcv->
  +xfrm4_rcv_encap->
Monday, October 6, 2008
Sunday, September 28, 2008
XFRM policy_check
  Today's topic: __xfrm_policy_check.
  First, it extracts flowi's information from skb by _decode_session, and then checks skb->sp. skb->sp records the security path it has walked and you can read xfrm4_rcv to see how does skb->sp initiate(Here i give you a brief image, think about a encapsulation: IP+AH+ESP+L4, so the first security path is AH and next is ESP). While checking, if skb->sp exists, each xfrm_state's selector, which stores PROXY IP(see RFC2367), MUST match the current one IP.
  Secondly, it tries to find policy as possible as it could, if not, it will think the current path needs not to protect and treat the packet as a normal one.But there's an exception that if skb->sp exist at the same time, it should returns error.
  Thirdly, it checks xfrm_state in skb->sp with the corresponding policy.And if skb->sp is null, nothing to be really checked:
xfrm_policy_ok->xfrm_state_ok
  First, it extracts flowi's information from skb by _decode_session, and then checks skb->sp. skb->sp records the security path it has walked and you can read xfrm4_rcv to see how does skb->sp initiate(Here i give you a brief image, think about a encapsulation: IP+AH+ESP+L4, so the first security path is AH and next is ESP). While checking, if skb->sp exists, each xfrm_state's selector, which stores PROXY IP(see RFC2367), MUST match the current one IP.
  Secondly, it tries to find policy as possible as it could, if not, it will think the current path needs not to protect and treat the packet as a normal one.But there's an exception that if skb->sp exist at the same time, it should returns error.
  Thirdly, it checks xfrm_state in skb->sp with the corresponding policy.And if skb->sp is null, nothing to be really checked:
xfrm_policy_ok->xfrm_state_ok
Friday, September 19, 2008
XFRM lookup
As you know, I divide xfrm-flow into four parts. Here is the point A stuff:xfrm_lookup.
Before go thru the code, I'll give my syllabus. Also I hope that you have read RFC2401 or RFC4301. And if you understand all of them, wow congradulation! They're:
1. Where is the policy(struct xfrm_policy) comes from?
2. How to find the policy, during sending or recving packet?
3. How to find sa bundle?
4. How to resolve a sa(struct xfrm_state) if step 3 failed?
5. How to create a sa bundle and attached to policy->bundle?
6. How xfrm do ah,esp,etc?
Now, let's go through the code, and solve the questions above(during reading, I skip over code about socket).
Where is the policy(struct xfrm_policy) comes from?
  Before reading code, we should know that 'xfrm_nr' and 'xfrm_vec', which are both in 'struct xfrm_policy', are always initiated before using and they're user-defined. Here is the way:
+sendmsg->netlink_unicast->
 +xfrm_user_rcv_msg->xfrm_dispatch[].xfrm_add_policy->
  +xfrm_policy_construct->...
How to find the policy, during sending or recving packet?
  The first step to find policy is to search 'flowi cache', which accelerates the procedure. If cannot find one from the cache, it will lookup the global-hash-table, and if have one, it will create a corresponding flowi-cache for later searching. Finally, if policy is found ,everyting goes okay, othervise it returns error.The code:
+flow_cache_lookup->
 .xfrm_policy_lookup
  If you've used Cisco IPsec device, you can think the global-hash-table as acl, and so the flowi-cache as acl-cache.
  By the way, we find xfrm support sub-policy, but I don't know how vendors use it(maybe they support sub acl?), so I cannot help you understand it.
How to find sa bundle?
  After finding out the xfrm_policy and policy says 'allow', then what to do next is to extrac sa-bundles from xfrm_policy.That's the key work of xfrm_lookup to do. If find the stuff, it returns directly, or there will be some other work left to resolve one. The code:
+xfrm_find_bundle->
 __xfrm4_find_bundle->xfrm_bundle_ok
 As the function-call chain says: if found a bundle, it has to check the bundle by xfrm_bundle_ok.So what does the function do?First of all, Lets walk the structure 'xfrm_dst->dst'(you can see the diagram in xfrm.h, I just modified something):
 dst -. xfrm .-> xfrm_state #1
    |-.next<---. child .-> dst -. xfrm .-> xfrm_state #2
                     |-.next<---. child .-> dst -. xfrm .-> xfrm_state #3
                            |-.next<---. child .-> NULL
  Generally, the key part of the check is the 'xfrm_dst list' ,formed as the above, and meanwhile it checks whether the mtu in each child, including his "father", has changed or not, if changed, re-calculated 'dst->metrics[RTAX_MTU-1]' and update route_cache_mtu/child_cache_mtu.
How to resolve a sa(struct xfrm_state) if step 3 failed?
  If cannot find any bundle, it should resolve sa by the xfrm_tmpl, which is configured during the construction of xfrm_policy. And xfrm_nr(in xfrm_policy) is the number of sa(xfrm_state).Here is the code:
+xfrm_tmpl_resolve->
 +xfrm_tmpl_resolve_one->
  -xfrm_state_find
  All here should we know that to find a sa is based on xfrm_tmpl info and a few hash tables who contains all the inserted sa.Meanwhile, if there is no sa corresponding to the xfrm_tmpl(not a optional one),we should drop the packet, as it's unsafe to transmit.But there is a exception that if the error code is EAGAIN,it means xfrm requiring sa from(by netlink/pfkey) sadb-engine, so xfrm should wait(shedule()) until wake up.If no sa, xfrm try to require one:
xfrm_state_find->
 .km_query(x, tmpl, pol)
And after that xfrm should sleep:
 +xfrm_lookup->
  .set_current_state(TASK_INTERRUPTIBLE);
  .schedule();
How to create a sa bundle and attached to policy->bundle?
  If we're luck so that we found a number of sa, we put all the sa in the 'xfrm_state' arrary for later use.The really creating work does in __xfrm4_bundle_create:
 +xfrm_bundle_create->
  -__xfrm4_bundle_create
  Result is what we see just above(yeah, it's 'xfrm_dst->dst').During linking each dst, it initiates route and pmut information: if xfrm_state is in tunnel/beet mode, it calculates route infomation of the encapsulating(outer) ip, or it just use the one it already has, and at the end, it calculates pmtu in each dst(dst father's mtu should always shorter than his child, do you know why?).
  Finially, it bind the dst-list to policy->bundles and set policy->bundles->next to itself(what a smart stuff!).
How xfrm do ah,esp,etc?
  Once xfrm has bundles, in each dst there is an output handler(xfrm_output) registered by xfrm_state. During packet walking through the ip stack it will do ah, esp, and etc.In the futher(Point B) i will try to give you a clear description, not this time.
Before go thru the code, I'll give my syllabus. Also I hope that you have read RFC2401 or RFC4301. And if you understand all of them, wow congradulation! They're:
1. Where is the policy(struct xfrm_policy) comes from?
2. How to find the policy, during sending or recving packet?
3. How to find sa bundle?
4. How to resolve a sa(struct xfrm_state) if step 3 failed?
5. How to create a sa bundle and attached to policy->bundle?
6. How xfrm do ah,esp,etc?
Now, let's go through the code, and solve the questions above(during reading, I skip over code about socket).
Where is the policy(struct xfrm_policy) comes from?
  Before reading code, we should know that 'xfrm_nr' and 'xfrm_vec', which are both in 'struct xfrm_policy', are always initiated before using and they're user-defined. Here is the way:
+sendmsg->netlink_unicast->
 +xfrm_user_rcv_msg->xfrm_dispatch[].xfrm_add_policy->
  +xfrm_policy_construct->...
How to find the policy, during sending or recving packet?
  The first step to find policy is to search 'flowi cache', which accelerates the procedure. If cannot find one from the cache, it will lookup the global-hash-table, and if have one, it will create a corresponding flowi-cache for later searching. Finally, if policy is found ,everyting goes okay, othervise it returns error.The code:
+flow_cache_lookup->
 .xfrm_policy_lookup
  If you've used Cisco IPsec device, you can think the global-hash-table as acl, and so the flowi-cache as acl-cache.
  By the way, we find xfrm support sub-policy, but I don't know how vendors use it(maybe they support sub acl?), so I cannot help you understand it.
How to find sa bundle?
  After finding out the xfrm_policy and policy says 'allow', then what to do next is to extrac sa-bundles from xfrm_policy.That's the key work of xfrm_lookup to do. If find the stuff, it returns directly, or there will be some other work left to resolve one. The code:
+xfrm_find_bundle->
 __xfrm4_find_bundle->xfrm_bundle_ok
 As the function-call chain says: if found a bundle, it has to check the bundle by xfrm_bundle_ok.So what does the function do?First of all, Lets walk the structure 'xfrm_dst->dst'(you can see the diagram in xfrm.h, I just modified something):
 dst -. xfrm .-> xfrm_state #1
    |-.next<---. child .-> dst -. xfrm .-> xfrm_state #2
                     |-.next<---. child .-> dst -. xfrm .-> xfrm_state #3
                            |-.next<---. child .-> NULL
  Generally, the key part of the check is the 'xfrm_dst list' ,formed as the above, and meanwhile it checks whether the mtu in each child, including his "father", has changed or not, if changed, re-calculated 'dst->metrics[RTAX_MTU-1]' and update route_cache_mtu/child_cache_mtu.
How to resolve a sa(struct xfrm_state) if step 3 failed?
  If cannot find any bundle, it should resolve sa by the xfrm_tmpl, which is configured during the construction of xfrm_policy. And xfrm_nr(in xfrm_policy) is the number of sa(xfrm_state).Here is the code:
+xfrm_tmpl_resolve->
 +xfrm_tmpl_resolve_one->
  -xfrm_state_find
  All here should we know that to find a sa is based on xfrm_tmpl info and a few hash tables who contains all the inserted sa.Meanwhile, if there is no sa corresponding to the xfrm_tmpl(not a optional one),we should drop the packet, as it's unsafe to transmit.But there is a exception that if the error code is EAGAIN,it means xfrm requiring sa from(by netlink/pfkey) sadb-engine, so xfrm should wait(shedule()) until wake up.If no sa, xfrm try to require one:
xfrm_state_find->
 .km_query(x, tmpl, pol)
And after that xfrm should sleep:
 +xfrm_lookup->
  .set_current_state(TASK_INTERRUPTIBLE);
  .schedule();
How to create a sa bundle and attached to policy->bundle?
  If we're luck so that we found a number of sa, we put all the sa in the 'xfrm_state' arrary for later use.The really creating work does in __xfrm4_bundle_create:
 +xfrm_bundle_create->
  -__xfrm4_bundle_create
  Result is what we see just above(yeah, it's 'xfrm_dst->dst').During linking each dst, it initiates route and pmut information: if xfrm_state is in tunnel/beet mode, it calculates route infomation of the encapsulating(outer) ip, or it just use the one it already has, and at the end, it calculates pmtu in each dst(dst father's mtu should always shorter than his child, do you know why?).
  Finially, it bind the dst-list to policy->bundles and set policy->bundles->next to itself(what a smart stuff!).
How xfrm do ah,esp,etc?
  Once xfrm has bundles, in each dst there is an output handler(xfrm_output) registered by xfrm_state. During packet walking through the ip stack it will do ah, esp, and etc.In the futher(Point B) i will try to give you a clear description, not this time.
Wednesday, September 17, 2008
XFRM init procedure
Aka, xfrm initiate itself by two parts: initiate user operation and initiate sa/spd. So today I try to describe each one.
1. Initiate user operation(xfrm_user.c).
    As I mention before, xfrm use netlink or pfkey to communicate sadb-engine(may contains ike function, etc), and a overview of the relationship beween them. Here, we'll go a little deeper to see how the relationship build. Also, I still try to focus on netlink.If you're interesting in pfkey, try reading af_key.c code. Anyway xfrm can support both method at the same time.
    There're two key structure during the initiating: xfrm_km_list and xfrm_nl and they're global used. when we call "xfrm_register_km" the suit of netlink user operation , hold in the netlink_msr, add to the xfrm_km_list. Here is One example that if xfrm start "xfrm_lookup" and cannot find sa in the sa hash tables, it will go through the list to find the registered user operation suit and then aquire sa from sadb-engine. yeah, pfkey does the same way.well, xfrm_nl is a "struct sock*" type, which yields after calling "netlink_kernel_create", and it'll be used to retrieve sadb-engine user socket, which are created in linux user space, and pass down message to each one.
2. Initiate sa/spd hash tables and operation family.
    The very start of xfrm may be from "ip_rt_init", which commence two function: xfrm_init and xfrm4_init. "xfrm_init" initiate sa and spd hash tables and some housekeeper, and xfrm4_init does something with sa/spd's really operation. later during analsing the point A to point D, I will go detail nearly in each one.
1. Initiate user operation(xfrm_user.c).
    As I mention before, xfrm use netlink or pfkey to communicate sadb-engine(may contains ike function, etc), and a overview of the relationship beween them. Here, we'll go a little deeper to see how the relationship build. Also, I still try to focus on netlink.If you're interesting in pfkey, try reading af_key.c code. Anyway xfrm can support both method at the same time.
    There're two key structure during the initiating: xfrm_km_list and xfrm_nl and they're global used. when we call "xfrm_register_km" the suit of netlink user operation , hold in the netlink_msr, add to the xfrm_km_list. Here is One example that if xfrm start "xfrm_lookup" and cannot find sa in the sa hash tables, it will go through the list to find the registered user operation suit and then aquire sa from sadb-engine. yeah, pfkey does the same way.well, xfrm_nl is a "struct sock*" type, which yields after calling "netlink_kernel_create", and it'll be used to retrieve sadb-engine user socket, which are created in linux user space, and pass down message to each one.
2. Initiate sa/spd hash tables and operation family.
    The very start of xfrm may be from "ip_rt_init", which commence two function: xfrm_init and xfrm4_init. "xfrm_init" initiate sa and spd hash tables and some housekeeper, and xfrm4_init does something with sa/spd's really operation. later during analsing the point A to point D, I will go detail nearly in each one.
XFRM I/O flow diagram
The following diagram is where xfrm work while sending out a packet in the security path .
xxx-send
↓
ip_route_output_flow
↓
xfrm_lookup ------> point A
↓
dst_output-->ip_mc_output-->ip_fragment-->...
↓
xfrm_output ------> point B
↓
ip_output
↓
ip_fragment
↓
ip_finish_output/2
↓
neighboring subsystem
↓
dev_queue_xmit
↓
traffic control system
↓
hard_start_xmit
↓
end
The way of receiving a secure packet is not the same as sending:
ip_rcv
↓
ip_rcv_finish
↓
ip_route_input->+ip_forward-> xfrm4_policy_check->xfrm4_route_forward->
xfrm_output->ip_output->...(refer to the above)
↓
ip_local_deliver
↓
xfrm4_policy_check ------> point C
↓
xfrm_input ------ point D
↓
xxx_recv
↓
end
From Point A/B/C/D are key code of xfrm, i will go deep into each point later.
PS: point xfrm_lookup <==> xfrm4_route_forward
(to be continue...)
xxx-send
↓
ip_route_output_flow
↓
xfrm_lookup ------> point A
↓
dst_output-->ip_mc_output-->ip_fragment-->...
↓
xfrm_output ------> point B
↓
ip_output
↓
ip_fragment
↓
ip_finish_output/2
↓
neighboring subsystem
↓
dev_queue_xmit
↓
traffic control system
↓
hard_start_xmit
↓
end
The way of receiving a secure packet is not the same as sending:
ip_rcv
↓
ip_rcv_finish
↓
ip_route_input->+ip_forward-> xfrm4_policy_check->xfrm4_route_forward->
xfrm_output->ip_output->...(refer to the above)
↓
ip_local_deliver
↓
xfrm4_policy_check ------> point C
↓
xfrm_input ------ point D
↓
xxx_recv
↓
end
From Point A/B/C/D are key code of xfrm, i will go deep into each point later.
PS: point xfrm_lookup <==> xfrm4_route_forward
(to be continue...)
Tuesday, September 16, 2008
XFRM overview
At the begining of my analysis, I split IPsec into two parts:xfrm and sadb engine. Now i 'd like to focus on the xfrm and use netlink to commucate with sadb engine. (some guy use pf-key insead of netlink, it's okay).
The following diagram describes the relationship between xfrm and sadb engine:
sadb engine
-----------------------------↑ user space
netlink sys-call
-----------------------------↓ kernel space
xfrm
Let's go into a little detail:
sk1---------sk2 --------sk3
↓
===== system call =====
sys_sendmsg
↓
===== netlink layer =====
netlink_sendmsg
↓
netlink_broadcast--->sk2 /sk3 rcv queue
↓
netlink_unitcast
↓
===== xfrm layer =====
do xfrm callback: xfrm_netlink_rcv-->xfrm_user_rcv_msg
xfrmsk1-->xxx_notify/acq
===== xfrm layer mirror =====
↓
netlink_broadcast--->sk1/sk2 /sk3 rcv queue
===== netlink layer mirror =====
After calling netlink_broadcast every receive_queue in each sk(1,2,3) has data, and if *sadb engine* calls recvmsg, it will get what he needs.
+recvmsg
..+sys_recvmsg
....-netlink_recvmsg-->skb_recv_datagram-->skb_dequeue
Also xfrm will fetch his data through xfrm_user_rcv_msg.
As the description of the above, we just know how xfrm and sadb communicate with each other, what's more, we should understand that each message between the xfrm and sadb are strict-formated(if you wanna learn more , pls search *xfrm_dispatch* in net/xfrm/xfrm_user.c)
(to be continue ...)
The following diagram describes the relationship between xfrm and sadb engine:
sadb engine
-----------------------------↑ user space
netlink sys-call
-----------------------------↓ kernel space
xfrm
Let's go into a little detail:
sk1---------sk2 --------sk3
↓
===== system call =====
sys_sendmsg
↓
===== netlink layer =====
netlink_sendmsg
↓
netlink_broadcast--->sk2 /sk3 rcv queue
↓
netlink_unitcast
↓
===== xfrm layer =====
do xfrm callback: xfrm_netlink_rcv-->xfrm_user_rcv_msg
xfrmsk1-->xxx_notify/acq
===== xfrm layer mirror =====
↓
netlink_broadcast--->sk1/sk2 /sk3 rcv queue
===== netlink layer mirror =====
After calling netlink_broadcast every receive_queue in each sk(1,2,3) has data, and if *sadb engine* calls recvmsg, it will get what he needs.
+recvmsg
..+sys_recvmsg
....-netlink_recvmsg-->skb_recv_datagram-->skb_dequeue
Also xfrm will fetch his data through xfrm_user_rcv_msg.
As the description of the above, we just know how xfrm and sadb communicate with each other, what's more, we should understand that each message between the xfrm and sadb are strict-formated(if you wanna learn more , pls search *xfrm_dispatch* in net/xfrm/xfrm_user.c)
(to be continue ...)
Monday, September 15, 2008
IPsec analysis plan
After the project of IPsec, I think i should give technology infomation to some guy .
Task 1: analysis xfrm code
Task 1: analysis xfrm code
Friday, September 12, 2008
Tips
Note to use binary operator
if a binary operator has a floating point operand, the computation is done using floating point arithmetic and the result is a floating point value. If it has a long operand, the computation is done using long integer arithmetic, and the result is a long . Operands that are smaller than an int (such as bool and char ) are converted to int before the operator is applied.
Different between RAW and PF_PACKET socket
The former will not return the link layer header
if a binary operator has a floating point operand, the computation is done using floating point arithmetic and the result is a floating point value. If it has a long operand, the computation is done using long integer arithmetic, and the result is a long . Operands that are smaller than an int (such as bool and char ) are converted to int before the operator is applied.
Different between RAW and PF_PACKET socket
The former will not return the link layer header
Subscribe to:
Posts (Atom)