From: Patrick McHardy <kaber@trash.net>
To: Netfilter Development Mailinglist <netfilter-devel@lists.netfilter.org>
Cc: Kernel Netdev Mailing List <netdev@vger.kernel.org>,
Herbert Xu <herbert@gondor.apana.org.au>
Subject: [NF+IPsec 3/6]: IPsec output hooks
Date: Mon, 17 Oct 2005 02:22:24 +0200 [thread overview]
Message-ID: <4352EEC0.9050507@trash.net> (raw)
[-- Attachment #1: 03.diff --]
[-- Type: text/x-patch, Size: 13396 bytes --]
[NETFILTER]: IPsec output hooks
Packets visit the FORWARD/LOCAL_OUT->POST_ROUTING hooks in plain text
and LOCAL_OUT->POST_ROUTING once for each tunnel mode transform.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 92dffb4b8138637d28173cc9c10fe5990914cf5d
tree 7d9e5fe149ab4bbee3afd2eafb1848ef2f978056
parent b8225d3928324d81a16b7d82c6c413005ac52c50
author Patrick McHardy <kaber@trash.net> Mon, 17 Oct 2005 00:40:48 +0200
committer Patrick McHardy <kaber@trash.net> Mon, 17 Oct 2005 00:40:48 +0200
include/net/dst.h | 9 +++++++++
include/net/ipip.h | 2 +-
net/ipv4/igmp.c | 4 ++--
net/ipv4/ip_forward.c | 2 +-
net/ipv4/ip_output.c | 6 +++---
net/ipv4/ipmr.c | 2 +-
net/ipv4/ipvs/ip_vs_xmit.c | 2 +-
net/ipv4/netfilter.c | 32 +++++++++++++++++++++++++++++++-
net/ipv4/netfilter/ipt_REJECT.c | 2 +-
net/ipv4/raw.c | 2 +-
net/ipv4/xfrm4_output.c | 1 +
net/ipv6/ip6_input.c | 4 ++--
net/ipv6/ip6_output.c | 7 ++++---
net/ipv6/ip6_tunnel.c | 2 +-
net/ipv6/ndisc.c | 8 ++++----
net/ipv6/netfilter.c | 29 +++++++++++++++++++++++++++++
net/ipv6/netfilter/ip6t_REJECT.c | 2 +-
net/ipv6/raw.c | 2 +-
net/ipv6/xfrm6_output.c | 1 +
19 files changed, 95 insertions(+), 24 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -237,6 +237,15 @@ static inline int dst_output(struct sk_b
}
}
+#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
+extern int __ip_dst_output(struct sk_buff *skb);
+extern int ip_dst_output(struct sk_buff *skb);
+extern int ip6_dst_output(struct sk_buff *skb);
+#else
+#define ip_dst_output dst_output
+#define ip6_dst_output dst_output
+#endif
+
/* Input packet from network to transport. */
static inline int dst_input(struct sk_buff *skb)
{
diff --git a/include/net/ipip.h b/include/net/ipip.h
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -34,7 +34,7 @@ struct ip_tunnel
ip_select_ident(iph, &rt->u.dst, NULL); \
ip_send_check(iph); \
\
- err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output);\
+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, ip_dst_output);\
if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) { \
stats->tx_bytes += pkt_len; \
stats->tx_packets++; \
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -343,7 +343,7 @@ static int igmpv3_sendpack(struct sk_buf
pig->csum = ip_compute_csum((void *)skb->h.igmph, igmplen);
return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dev,
- dst_output);
+ ip_dst_output);
}
static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel)
@@ -674,7 +674,7 @@ static int igmp_send_report(struct in_de
ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
- dst_output);
+ ip_dst_output);
}
static void igmp_gq_timer_expire(unsigned long data)
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -51,7 +51,7 @@ static inline int ip_forward_finish(stru
if (unlikely(opt->optlen))
ip_forward_options(skb);
- return dst_output(skb);
+ return ip_dst_output(skb);
}
int ip_forward(struct sk_buff *skb)
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -155,7 +155,7 @@ int ip_build_and_send_pkt(struct sk_buff
/* Send it out. */
return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
- dst_output);
+ ip_dst_output);
}
EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
@@ -371,7 +371,7 @@ packet_routed:
skb->priority = sk->sk_priority;
return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
- dst_output);
+ ip_dst_output);
no_route:
IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
@@ -1190,7 +1190,7 @@ int ip_push_pending_frames(struct sock *
/* Netfilter gets whole the not fragmented skb. */
err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
- skb->dst->dev, dst_output);
+ skb->dst->dev, ip_dst_output);
if (err) {
if (err > 0)
err = inet->recverr ? net_xmit_errno(err) : 0;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1125,7 +1125,7 @@ static inline int ipmr_forward_finish(st
if (unlikely(opt->optlen))
ip_forward_options(skb);
- return dst_output(skb);
+ return ip_dst_output(skb);
}
/*
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -130,7 +130,7 @@ do { \
(skb)->ipvs_property = 1; \
(skb)->ip_summed = CHECKSUM_NONE; \
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, (skb), NULL, \
- (rt)->u.dst.dev, dst_output); \
+ (rt)->u.dst.dev, ip_dst_output); \
} while (0)
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -10,8 +10,9 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
-#include <net/route.h>
#include <linux/ip.h>
+#include <net/route.h>
+#include <net/xfrm.h>
/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
int ip_route_me_harder(struct sk_buff **pskb)
@@ -78,6 +79,35 @@ int ip_route_me_harder(struct sk_buff **
}
EXPORT_SYMBOL(ip_route_me_harder);
+#ifdef CONFIG_XFRM
+inline int __ip_dst_output(struct sk_buff *skb)
+{
+ int err;
+
+ do {
+ err = skb->dst->output(skb);
+
+ if (likely(err == 0))
+ return err;
+ if (unlikely(err != NET_XMIT_BYPASS))
+ return err;
+ } while (skb->dst->xfrm && !skb->dst->xfrm->props.mode);
+
+ return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev,
+ ip_dst_output);
+}
+EXPORT_SYMBOL(__ip_dst_output);
+
+int ip_dst_output(struct sk_buff *skb)
+{
+ if (skb->dst->xfrm != NULL)
+ return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
+ skb->dst->dev, __ip_dst_output);
+ return dst_output(skb);
+}
+EXPORT_SYMBOL(ip_dst_output);
+#endif /* CONFIG_XFRM */
+
/*
* Extra routing may needed on local out, as the QUEUE target never
* returns control to the table.
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -220,7 +220,7 @@ static void send_reset(struct sk_buff *o
nf_ct_attach(nskb, oldskb);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
- dst_output);
+ ip_dst_output);
return;
free_nskb:
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -313,7 +313,7 @@ static int raw_send_hdrinc(struct sock *
}
err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
- dst_output);
+ ip_dst_output);
if (err > 0)
err = inet->recverr ? net_xmit_errno(err) : 0;
if (err)
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -133,6 +133,7 @@ int xfrm4_output(struct sk_buff *skb)
err = -EHOSTUNREACH;
goto error_nolock;
}
+ nf_reset(skb);
err = NET_XMIT_BYPASS;
out_exit:
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -250,9 +250,9 @@ int ip6_mc_input(struct sk_buff *skb)
if (deliver) {
skb2 = skb_clone(skb, GFP_ATOMIC);
- dst_output(skb2);
+ ip_dst_output(skb2);
} else {
- dst_output(skb);
+ ip_dst_output(skb);
return 0;
}
}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -229,7 +229,7 @@ int ip6_xmit(struct sock *sk, struct sk_
if ((skb->len <= mtu) || ipfragok) {
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev,
- dst_output);
+ ip6_dst_output);
}
if (net_ratelimit())
@@ -307,7 +307,7 @@ static int ip6_call_ra_chain(struct sk_b
static inline int ip6_forward_finish(struct sk_buff *skb)
{
- return dst_output(skb);
+ return ip6_dst_output(skb);
}
int ip6_forward(struct sk_buff *skb)
@@ -1107,7 +1107,8 @@ int ip6_push_pending_frames(struct sock
skb->dst = dst_clone(&rt->u.dst);
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
- err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
+ err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev,
+ ip6_dst_output);
if (err) {
if (err > 0)
err = np->recverr ? net_xmit_errno(err) : 0;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -745,7 +745,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
nf_reset(skb);
pkt_len = skb->len;
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
- skb->dst->dev, dst_output);
+ skb->dst->dev, ip6_dst_output);
if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) {
stats->tx_bytes += pkt_len;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -499,7 +499,7 @@ static void ndisc_send_na(struct net_dev
skb->dst = dst;
idev = in6_dev_get(dst->dev);
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
- err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
+ err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_dst_output);
if (!err) {
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS);
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
@@ -582,7 +582,7 @@ void ndisc_send_ns(struct net_device *de
skb->dst = dst;
idev = in6_dev_get(dst->dev);
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
- err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
+ err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_dst_output);
if (!err) {
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS);
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
@@ -654,7 +654,7 @@ void ndisc_send_rs(struct net_device *de
skb->dst = dst;
idev = in6_dev_get(dst->dev);
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
- err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
+ err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_dst_output);
if (!err) {
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTROUTERSOLICITS);
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
@@ -1438,7 +1438,7 @@ void ndisc_send_redirect(struct sk_buff
buff->dst = dst;
idev = in6_dev_get(dst->dev);
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
- err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, buff, NULL, dst->dev, dst_output);
+ err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, buff, NULL, dst->dev, ip6_dst_output);
if (!err) {
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTREDIRECTS);
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -10,6 +10,7 @@
#include <net/dst.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
+#include <net/xfrm.h>
int ip6_route_me_harder(struct sk_buff *skb)
{
@@ -41,6 +42,34 @@ int ip6_route_me_harder(struct sk_buff *
}
EXPORT_SYMBOL(ip6_route_me_harder);
+#ifdef CONFIG_XFRM
+static inline int __ip6_dst_output(struct sk_buff *skb)
+{
+ int err;
+
+ do {
+ err = skb->dst->output(skb);
+
+ if (likely(err == 0))
+ return err;
+ if (unlikely(err != NET_XMIT_BYPASS))
+ return err;
+ } while (skb->dst->xfrm && !skb->dst->xfrm->props.mode);
+
+ return NF_HOOK(PF_INET, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev,
+ ip6_dst_output);
+}
+
+int ip6_dst_output(struct sk_buff *skb)
+{
+ if (skb->dst->xfrm != NULL)
+ return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL,
+ skb->dst->dev, __ip6_dst_output);
+ return dst_output(skb);
+}
+EXPORT_SYMBOL(ip6_dst_output);
+#endif /* CONFIG_XFRM */
+
/*
* Extra routing may needed on local out, as the QUEUE target never
* returns control to the table.
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -161,7 +161,7 @@ static void send_reset(struct sk_buff *o
sizeof(struct tcphdr), 0));
NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
- dst_output);
+ ip6_dst_output);
}
static inline void
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -579,7 +579,7 @@ static int rawv6_send_hdrinc(struct sock
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
- dst_output);
+ ip6_dst_output);
if (err > 0)
err = np->recverr ? net_xmit_errno(err) : 0;
if (err)
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -132,6 +132,7 @@ int xfrm6_output(struct sk_buff *skb)
err = -EHOSTUNREACH;
goto error_nolock;
}
+ nf_reset(skb);
err = NET_XMIT_BYPASS;
out_exit:
next reply other threads:[~2005-10-17 0:22 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-10-17 0:22 Patrick McHardy [this message]
2005-10-17 0:37 ` [NF+IPsec 3/6]: IPsec output hooks YOSHIFUJI Hideaki / 吉藤英明
2005-10-17 0:42 ` Patrick McHardy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4352EEC0.9050507@trash.net \
--to=kaber@trash.net \
--cc=herbert@gondor.apana.org.au \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@lists.netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).