|
Subject: [PATCH 3/4] IPSEC policy lookups Newsgroups: gmane.comp.security.firewalls.netfilter.devel Date: 2005-02-17 19:12:27 GMT (3 years, 39 weeks, 4 days, 11 hours and 2 minutes ago)
The updated ipsec-03-policy-lookup.diff
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_nat_standalone.c 2005-02-16 00:59:44.000000000 +0100
+++ linux-2.6.11-rc4-cs1/net/ipv4/netfilter/ip_nat_standalone.c 2005-02-17
18:28:45.623989072 +0100
@@ -172,6 +172,47 @@
return ret;
}
+struct nat_route_key
+{
+ u_int32_t addr;
+#ifdef CONFIG_XFRM
+ u_int16_t port;
+#endif
+};
+
+static inline void
+nat_route_key_get(struct sk_buff *skb, struct nat_route_key *key, int which)
+{
+ struct iphdr *iph = skb->nh.iph;
+
+ key->addr = which ? iph->daddr : iph->saddr;
+#ifdef CONFIG_XFRM
+ key->port = 0;
+ if (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) {
+ u_int16_t *ports = (u_int16_t *)(skb->nh.raw + iph->ihl*4);
+ key->port = ports[which];
+ }
+#endif
+}
+
+static inline int
+nat_route_key_compare(struct sk_buff *skb, struct nat_route_key *key, int which)
+{
+ struct iphdr *iph = skb->nh.iph;
+
+ if (key->addr != (which ? iph->daddr : iph->saddr))
+ return 1;
+#ifdef CONFIG_XFRM
+ if (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) {
+ u_int16_t *ports = (u_int16_t *)(skb->nh.raw + iph->ihl*4);
+ if (key->port != ports[which])
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
static unsigned int
ip_nat_out(unsigned int hooknum,
struct sk_buff **pskb,
@@ -179,6 +220,9 @@
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+ struct nat_route_key key;
+ unsigned int ret;
+
/* root is playing with raw sockets. */
if ((*pskb)->len < sizeof(struct iphdr)
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
@@ -201,7 +245,29 @@
return NF_STOLEN;
}
- return ip_nat_fn(hooknum, pskb, in, out, okfn);
+ nat_route_key_get(*pskb, &key, 0);
+ ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
+
+ if (ret != NF_DROP && ret != NF_STOLEN
+ && nat_route_key_compare(*pskb, &key, 0)) {
+ if (ip_route_me_harder(pskb) != 0)
+ ret = NF_DROP;
+#ifdef CONFIG_XFRM
+ /*
+ * POST_ROUTING hook is called with fixed outfn, we need
+ * to manually confirm the packet and direct it to the
+ * transformers if a policy matches.
+ */
+ else if ((*pskb)->dst->xfrm != NULL) {
+ ret = ip_conntrack_confirm(pskb);
+ if (ret != NF_DROP) {
+ dst_output(*pskb);
+ ret = NF_STOLEN;
+ }
+ }
+#endif
+ }
+ return ret;
}
static unsigned int
@@ -211,7 +277,7 @@
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- u_int32_t saddr, daddr;
+ struct nat_route_key key;
unsigned int ret;
/* root is playing with raw sockets. */
@@ -219,14 +285,14 @@
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
return NF_ACCEPT;
- saddr = (*pskb)->nh.iph->saddr;
- daddr = (*pskb)->nh.iph->daddr;
-
+ nat_route_key_get(*pskb, &key, 1);
ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
+
if (ret != NF_DROP && ret != NF_STOLEN
- && ((*pskb)->nh.iph->saddr != saddr
- || (*pskb)->nh.iph->daddr != daddr))
- return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+ && nat_route_key_compare(*pskb, &key, 1)) {
+ if (ip_route_me_harder(pskb) != 0)
+ ret = NF_DROP;
+ }
return ret;
}
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-02-16
00:59:44.000000000 +0100
+++ linux-2.6.11-rc4-cs1/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-02-17
18:28:46.554847560 +0100
@@ -896,6 +896,7 @@
EXPORT_SYMBOL(invert_tuplepr);
EXPORT_SYMBOL(ip_conntrack_alter_reply);
EXPORT_SYMBOL(ip_conntrack_destroyed);
+EXPORT_SYMBOL(__ip_conntrack_confirm);
EXPORT_SYMBOL(need_ip_conntrack);
EXPORT_SYMBOL(ip_conntrack_helper_register);
EXPORT_SYMBOL(ip_conntrack_helper_unregister);
--- linux-2.6.11-rc4/net/core/netfilter.c 2005-02-17 18:26:58.398289856 +0100
+++ linux-2.6.11-rc4-cs1/net/core/netfilter.c 2005-02-17 18:28:47.404718360 +0100
@@ -28,6 +28,7 @@
#include <net/sock.h>
#include <net/route.h>
#include <net/xfrm.h>
+#include <net/ip.h>
#include <linux/ip.h>
/* In this code, we can be waiting indefinitely for userspace to
@@ -631,7 +632,6 @@
#ifdef CONFIG_IP_ROUTE_FWMARK
fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
#endif
- fl.proto = iph->protocol;
if (ip_route_output_key(&rt, &fl) != 0)
return -1;
@@ -658,6 +658,20 @@
if ((*pskb)->dst->error)
return -1;
+#ifdef CONFIG_XFRM
+ if (!(IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED)) {
+ struct xfrm_policy_afinfo *afinfo;
+
+ afinfo = xfrm_policy_get_afinfo(AF_INET);
+ if (afinfo != NULL) {
+ afinfo->decode_session(*pskb, &fl);
+ xfrm_policy_put_afinfo(afinfo);
+ if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0) != 0)
+ return -1;
+ }
+ }
+#endif
+
/* Change in oif may mean change in hh_len. */
hh_len = (*pskb)->dst->dev->hard_header_len;
if (skb_headroom(*pskb) < hh_len) {
|
|
|