[Openswan dev] ESP fragments with zero packet id cause reassembly errors

Peter Lenci peterlenci at yahoo.ca
Wed Jul 27 17:40:50 CEST 2005

Hi all

In klips/net/ipsec/ipsec_tunnel.c:ipsec_tunnel_start_xmit() Openswan
builds IP packets and then sends them off using include/net/ip.h:ip_send().
Unfortunately the id in the ip header (skb->nh.iph->id) is not set for ESP
nor IKE packets which may cause faulty packet reassembly on the receiver
side (especially with lots of peers and fast links).

There are two things I don't understand (does anybody?):

1. There is one single(!) invocation of ip_select_ident() in ipsec_tunnel.c
   but that section is only called if tdbp->tdb_encalg == IPPROTO_IPIP which
   is not the case for IKE or ESP packets. Therefore the packet id always
   remains set to zero which is very bad for packets to be fragmented.
   try: tcpdump -v 'ip[4]=0' and 'ip[5]=0'

2. When the code reaches ip_send() the DF (do not fragment) bit is always
   set even if the packet size is huge (like 20000 bytes)!
   try: tcpdump -v \( 'ip[6]&0x20=0x20' or 'ip[6]&0x1f!=0' or 'ip[7]!=0' \)

I have written an ugly patch as an immediate fix to my problem. Works fine
but probably is not done right as I haven't spent much time understanding
Openswan source code:

/usr/src/openswan-1.0.10rc1/klips/net/ipsec]# diff -c ipsec_tunnel.c.orig
*** ipsec_tunnel.c.orig Tue Feb 22 01:37:18 2005
--- ipsec_tunnel.c      Wed Jul 27 22:24:21 2005
*** 2145,2150 ****
--- 2145,2169 ----
                    "With hard_header, final head,tailroom: %d,%d\n",
                    skb_headroom(skb), skb_tailroom(skb));
+       /* hack: always enforce a packet id by temporary */
+       /* deleting the DF bit and calling the id creation routine. The */
+       /* original code always resulted in a zero id even when the packet */
+       /* was fragmented later on which caused reassembly errors on the */
+       /* receiver side */
+       if(skb->nh.iph->id == 0 ) {
+               struct iphdr *ipp = skb->nh.iph;
+               __u16 frag_save = ipp->frag_off;
+               ipp->frag_off = ipp->frag_off - (ipp->frag_off &
+               ip_select_ident(ipp, skb->dst, skb->sk);
+ #else /* IP_SELECT_IDENT_NEW */
+               ip_select_ident(ipp, skb->dst);
+ #endif /* IP_SELECT_IDENT_NEW */
+               ipp->frag_off = ipp->frag_off | frag_save;
+               ipp->check = 0;
+               ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);
+       }
  #ifdef NET_21 /* 2.2 and 2.4 kernels */
        /* new route/dst cache code from James Morris */
        skb->dev = physdev;

Oh, BTW the above code is for openswan-1.0.10rc1. The same problem existed
for openswan v2 so I figured it would be better to investigate and patch the
more mature v1 code.


Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 

More information about the Dev mailing list