# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/04/14 02:48:48+02:00 kaber@trash.net # [NETFILTER]: netfilter+ipsec: input hooks # # net/xfrm/xfrm_input.c # 2004/04/14 02:48:38+02:00 kaber@trash.net +3 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # net/ipv4/xfrm4_tunnel.c # 2004/04/14 02:48:38+02:00 kaber@trash.net +1 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # net/ipv4/ipip.c # 2004/04/14 02:48:38+02:00 kaber@trash.net +5 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # net/ipv4/ipcomp.c # 2004/04/14 02:48:38+02:00 kaber@trash.net +1 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # net/ipv4/ip_input.c # 2004/04/14 02:48:38+02:00 kaber@trash.net +15 -6 # [NETFILTER]: netfilter+ipsec: input hooks # # net/ipv4/esp4.c # 2004/04/14 02:48:38+02:00 kaber@trash.net +1 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # net/ipv4/ah4.c # 2004/04/14 02:48:38+02:00 kaber@trash.net +1 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # net/core/netfilter.c # 2004/04/14 02:48:38+02:00 kaber@trash.net +23 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # include/net/xfrm.h # 2004/04/14 02:48:38+02:00 kaber@trash.net +3 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # include/net/protocol.h # 2004/04/14 02:48:38+02:00 kaber@trash.net +1 -0 # [NETFILTER]: netfilter+ipsec: input hooks # # include/linux/netfilter_ipv4.h # 2004/04/14 02:48:38+02:00 kaber@trash.net +54 -0 # [NETFILTER]: netfilter+ipsec: input hooks # diff -Nru a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h --- a/include/linux/netfilter_ipv4.h Wed Apr 14 03:03:04 2004 +++ b/include/linux/netfilter_ipv4.h Wed Apr 14 03:03:04 2004 @@ -7,6 +7,8 @@ #include #include +#include +#include /* IP Cache bits. */ /* Src IP address. */ @@ -83,6 +85,58 @@ Returns true or false. */ extern int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len); + +#ifdef CONFIG_XFRM +#include +#include + +static inline int nf_hook_input_cond(struct sk_buff *skb) +{ + return !skb->sp || skb->sp->decap_done; +} + +static inline int +nf_xfrm_local_done(struct sk_buff *skb, struct inet_protocol *ipprot) +{ + return skb->sp && !skb->sp->decap_done + && (!ipprot || !ipprot->xfrm_prot); +} + +static inline int nf_xfrm_nonlocal_done(struct sk_buff *skb) +{ + return skb->sp && !skb->sp->decap_done + && !(((struct rtable *)skb->dst)->rt_flags&RTCF_LOCAL); +} + +extern int nf_rcv_postxfrm_local(struct sk_buff *skb); +extern int nf_rcv_postxfrm_nonlocal(struct sk_buff *skb); +#else /* CONFIG_XFRM */ +static inline int nf_hook_input_cond(struct sk_buff *skb) +{ + return 1; +} + +static inline int +nf_xfrm_local_done(struct sk_buff *skb, struct inet_protocol *ipprot) +{ + return 0; +} + +static inline int nf_xfrm_nonlocal_done(struct sk_buff *skb) +{ + return 0; +} + +static inline int nf_rcv_postxfrm_local(struct sk_buff *skb) +{ + return 0; +} + +static inline int nf_rcv_postxfrm_nonlocal(struct sk_buff *skb) +{ + return 0; +} +#endif /* CONFIG_XFRM */ #endif /*__KERNEL__*/ #endif /*__LINUX_IP_NETFILTER_H*/ diff -Nru a/include/net/protocol.h b/include/net/protocol.h --- a/include/net/protocol.h Wed Apr 14 03:03:04 2004 +++ b/include/net/protocol.h Wed Apr 14 03:03:04 2004 @@ -39,6 +39,7 @@ int (*handler)(struct sk_buff *skb); void (*err_handler)(struct sk_buff *skb, u32 info); int no_policy; + int xfrm_prot; }; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) diff -Nru a/include/net/xfrm.h b/include/net/xfrm.h --- a/include/net/xfrm.h Wed Apr 14 03:03:04 2004 +++ b/include/net/xfrm.h Wed Apr 14 03:03:04 2004 @@ -540,6 +540,9 @@ { atomic_t refcnt; int len; +#ifdef CONFIG_NETFILTER + int decap_done; +#endif struct sec_decap_state x[XFRM_MAX_DEPTH]; }; diff -Nru a/net/core/netfilter.c b/net/core/netfilter.c --- a/net/core/netfilter.c Wed Apr 14 03:03:04 2004 +++ b/net/core/netfilter.c Wed Apr 14 03:03:04 2004 @@ -25,6 +25,7 @@ #include #include #include +#include #include /* In this code, we can be waiting indefinitely for userspace to @@ -679,6 +680,28 @@ return 0; } + +#ifdef CONFIG_XFRM +inline int nf_rcv_postxfrm_nonlocal(struct sk_buff *skb) +{ + skb->sp->decap_done = 1; + dst_release(skb->dst); + skb->dst = NULL; + nf_reset(skb); + return netif_rx(skb); +} + +int nf_rcv_postxfrm_local(struct sk_buff *skb) +{ + __skb_push(skb, skb->data - skb->nh.raw); + /* Fix header len and checksum if last xfrm was transport mode */ + if (!skb->sp->x[skb->sp->len - 1].xvec->props.mode) { + skb->nh.iph->tot_len = htons(skb->len); + ip_send_check(skb->nh.iph); + } + return nf_rcv_postxfrm_nonlocal(skb); +} +#endif int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len) { diff -Nru a/net/ipv4/ah4.c b/net/ipv4/ah4.c --- a/net/ipv4/ah4.c Wed Apr 14 03:03:04 2004 +++ b/net/ipv4/ah4.c Wed Apr 14 03:03:04 2004 @@ -344,6 +344,7 @@ .handler = xfrm4_rcv, .err_handler = ah4_err, .no_policy = 1, + .xfrm_prot = 1, }; static int __init ah4_init(void) diff -Nru a/net/ipv4/esp4.c b/net/ipv4/esp4.c --- a/net/ipv4/esp4.c Wed Apr 14 03:03:04 2004 +++ b/net/ipv4/esp4.c Wed Apr 14 03:03:04 2004 @@ -577,6 +577,7 @@ .handler = xfrm4_rcv, .err_handler = esp4_err, .no_policy = 1, + .xfrm_prot = 1, }; static int __init esp4_init(void) diff -Nru a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c --- a/net/ipv4/ip_input.c Wed Apr 14 03:03:04 2004 +++ b/net/ipv4/ip_input.c Wed Apr 14 03:03:04 2004 @@ -224,6 +224,13 @@ resubmit: hash = protocol & (MAX_INET_PROTOS - 1); raw_sk = sk_head(&raw_v4_htable[hash]); + ipprot = inet_protos[hash]; + smp_read_barrier_depends(); + + if (nf_xfrm_local_done(skb, ipprot)) { + nf_rcv_postxfrm_local(skb); + goto out; + } /* If there maybe a raw socket we must check - if not we * don't care less @@ -231,10 +238,9 @@ if (raw_sk) raw_v4_input(skb, skb->nh.iph, hash); - if ((ipprot = inet_protos[hash]) != NULL) { + if (ipprot != NULL) { int ret; - smp_read_barrier_depends(); if (!ipprot->no_policy && !xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { kfree_skb(skb); @@ -279,8 +285,8 @@ return 0; } - return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, - ip_local_deliver_finish); + return NF_HOOK_COND(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, + ip_local_deliver_finish, nf_hook_input_cond(skb)); } static inline int ip_rcv_finish(struct sk_buff *skb) @@ -297,6 +303,9 @@ goto drop; } + if (nf_xfrm_nonlocal_done(skb)) + return nf_rcv_postxfrm_nonlocal(skb); + #ifdef CONFIG_NET_CLS_ROUTE if (skb->dst->tclassid) { struct ip_rt_acct *st = ip_rt_acct + 256*smp_processor_id(); @@ -418,8 +427,8 @@ } } - return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, - ip_rcv_finish); + return NF_HOOK_COND(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, + ip_rcv_finish, nf_hook_input_cond(skb)); inhdr_error: IP_INC_STATS_BH(IpInHdrErrors); diff -Nru a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c --- a/net/ipv4/ipcomp.c Wed Apr 14 03:03:04 2004 +++ b/net/ipv4/ipcomp.c Wed Apr 14 03:03:04 2004 @@ -408,6 +408,7 @@ .handler = xfrm4_rcv, .err_handler = ipcomp4_err, .no_policy = 1, + .xfrm_prot = 1, }; static int __init ipcomp4_init(void) diff -Nru a/net/ipv4/ipip.c b/net/ipv4/ipip.c --- a/net/ipv4/ipip.c Wed Apr 14 03:03:04 2004 +++ b/net/ipv4/ipip.c Wed Apr 14 03:03:04 2004 @@ -478,6 +478,11 @@ read_lock(&ipip_lock); if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) { + /* IPIP packets decapsulated by IPsec missed netfilter hooks */ + if (nf_xfrm_local_done(skb, NULL)) { + nf_rcv_postxfrm_local(skb); + return 0; + } if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { kfree_skb(skb); return 0; diff -Nru a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c --- a/net/ipv4/xfrm4_tunnel.c Wed Apr 14 03:03:04 2004 +++ b/net/ipv4/xfrm4_tunnel.c Wed Apr 14 03:03:04 2004 @@ -171,6 +171,7 @@ .handler = ipip_rcv, .err_handler = ipip_err, .no_policy = 1, + .xfrm_prot = 1, }; static int __init ipip_init(void) diff -Nru a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c --- a/net/xfrm/xfrm_input.c Wed Apr 14 03:03:04 2004 +++ b/net/xfrm/xfrm_input.c Wed Apr 14 03:03:04 2004 @@ -29,6 +29,9 @@ if (!sp) return NULL; +#ifdef CONFIG_NETFILTER + sp->decap_done = 0; +#endif sp->len = 0; if (src) { int i; --- linux-2.6.5/net/core/netfilter.c.symbol 2004-04-19 16:57:20.000000000 +0200 +++ linux-2.6.5/net/core/netfilter.c 2004-04-19 17:13:56.000000000 +0200 @@ -857,3 +857,4 @@ EXPORT_SYMBOL(nf_unregister_hook); EXPORT_SYMBOL(nf_unregister_queue_handler); EXPORT_SYMBOL(nf_unregister_sockopt); +EXPORT_SYMBOL(nf_rcv_postxfrm_local);