Skip to content

Commit

Permalink
[IPSEC]: Added xfrm_decode_session_reverse and xfrmX_policy_check_rev…
Browse files Browse the repository at this point in the history
…erse

RFC 4301 requires us to relookup ICMP traffic that does not match any
policies using the reverse of its payload.  This patch adds the functions
xfrm_decode_session_reverse and xfrmX_policy_check_reverse so we can get
the reverse flow to perform such a lookup.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Herbert Xu authored and David S. Miller committed Jan 28, 2008
1 parent 815f4e5 commit d5422ef
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 21 deletions.
1 change: 1 addition & 0 deletions include/linux/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ enum
XFRM_POLICY_IN = 0,
XFRM_POLICY_OUT = 1,
XFRM_POLICY_FWD = 2,
XFRM_POLICY_MASK = 3,
XFRM_POLICY_MAX = 3
};

Expand Down
63 changes: 58 additions & 5 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ struct xfrm_policy_afinfo {
int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
void (*decode_session)(struct sk_buff *skb,
struct flowi *fl);
struct flowi *fl,
int reverse);
int (*get_tos)(struct flowi *fl);
int (*fill_dst)(struct xfrm_dst *xdst,
struct net_device *dev);
Expand Down Expand Up @@ -844,14 +845,23 @@ xfrm_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned short
#ifdef CONFIG_XFRM
extern int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb, unsigned short family);

static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family)
static inline int __xfrm_policy_check2(struct sock *sk, int dir,
struct sk_buff *skb,
unsigned int family, int reverse)
{
int ndir = dir | (reverse ? XFRM_POLICY_MASK + 1 : 0);

if (sk && sk->sk_policy[XFRM_POLICY_IN])
return __xfrm_policy_check(sk, dir, skb, family);
return __xfrm_policy_check(sk, ndir, skb, family);

return (!xfrm_policy_count[dir] && !skb->sp) ||
(skb->dst->flags & DST_NOPOLICY) ||
__xfrm_policy_check(sk, dir, skb, family);
__xfrm_policy_check(sk, ndir, skb, family);
}

static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family)
{
return __xfrm_policy_check2(sk, dir, skb, family, 0);
}

static inline int xfrm4_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
Expand All @@ -864,7 +874,34 @@ static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *s
return xfrm_policy_check(sk, dir, skb, AF_INET6);
}

extern int xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family);
static inline int xfrm4_policy_check_reverse(struct sock *sk, int dir,
struct sk_buff *skb)
{
return __xfrm_policy_check2(sk, dir, skb, AF_INET, 1);
}

static inline int xfrm6_policy_check_reverse(struct sock *sk, int dir,
struct sk_buff *skb)
{
return __xfrm_policy_check2(sk, dir, skb, AF_INET6, 1);
}

extern int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
unsigned int family, int reverse);

static inline int xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
unsigned int family)
{
return __xfrm_decode_session(skb, fl, family, 0);
}

static inline int xfrm_decode_session_reverse(struct sk_buff *skb,
struct flowi *fl,
unsigned int family)
{
return __xfrm_decode_session(skb, fl, family, 1);
}

extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family);

static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family)
Expand Down Expand Up @@ -925,6 +962,22 @@ static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *sk
{
return 1;
}
static inline int xfrm_decode_session_reverse(struct sk_buff *skb,
struct flowi *fl,
unsigned int family)
{
return -ENOSYS;
}
static inline int xfrm4_policy_check_reverse(struct sock *sk, int dir,
struct sk_buff *skb)
{
return 1;
}
static inline int xfrm6_policy_check_reverse(struct sock *sk, int dir,
struct sk_buff *skb)
{
return 1;
}
#endif

static __inline__
Expand Down
10 changes: 5 additions & 5 deletions net/ipv4/xfrm4_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
}

static void
_decode_session4(struct sk_buff *skb, struct flowi *fl)
_decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
{
struct iphdr *iph = ip_hdr(skb);
u8 *xprth = skb_network_header(skb) + iph->ihl * 4;
Expand All @@ -131,8 +131,8 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl)
if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
__be16 *ports = (__be16 *)xprth;

fl->fl_ip_sport = ports[0];
fl->fl_ip_dport = ports[1];
fl->fl_ip_sport = ports[!!reverse];
fl->fl_ip_dport = ports[!reverse];
}
break;

Expand Down Expand Up @@ -174,8 +174,8 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl)
}
}
fl->proto = iph->protocol;
fl->fl4_dst = iph->daddr;
fl->fl4_src = iph->saddr;
fl->fl4_dst = reverse ? iph->saddr : iph->daddr;
fl->fl4_src = reverse ? iph->daddr : iph->saddr;
fl->fl4_tos = iph->tos;
}

Expand Down
10 changes: 5 additions & 5 deletions net/ipv6/xfrm6_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
}

static inline void
_decode_session6(struct sk_buff *skb, struct flowi *fl)
_decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
{
u16 offset = skb_network_header_len(skb);
struct ipv6hdr *hdr = ipv6_hdr(skb);
Expand All @@ -132,8 +132,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl)
u8 nexthdr = nh[IP6CB(skb)->nhoff];

memset(fl, 0, sizeof(struct flowi));
ipv6_addr_copy(&fl->fl6_dst, &hdr->daddr);
ipv6_addr_copy(&fl->fl6_src, &hdr->saddr);
ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr);
ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr);

while (pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
nh = skb_network_header(skb);
Expand All @@ -156,8 +156,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl)
if (pskb_may_pull(skb, nh + offset + 4 - skb->data)) {
__be16 *ports = (__be16 *)exthdr;

fl->fl_ip_sport = ports[0];
fl->fl_ip_dport = ports[1];
fl->fl_ip_sport = ports[!!reverse];
fl->fl_ip_dport = ports[!reverse];
}
fl->proto = nexthdr;
return;
Expand Down
17 changes: 11 additions & 6 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -1732,21 +1732,21 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
return start;
}

int
xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family)
int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
unsigned int family, int reverse)
{
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
int err;

if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;

afinfo->decode_session(skb, fl);
afinfo->decode_session(skb, fl, reverse);
err = security_xfrm_decode_session(skb, &fl->secid);
xfrm_policy_put_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_decode_session);
EXPORT_SYMBOL(__xfrm_decode_session);

static inline int secpath_has_nontransport(struct sec_path *sp, int k, int *idxp)
{
Expand All @@ -1768,11 +1768,16 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
int npols = 0;
int xfrm_nr;
int pi;
int reverse;
struct flowi fl;
u8 fl_dir = policy_to_flow_dir(dir);
u8 fl_dir;
int xerr_idx = -1;

if (xfrm_decode_session(skb, &fl, family) < 0)
reverse = dir & ~XFRM_POLICY_MASK;
dir &= XFRM_POLICY_MASK;
fl_dir = policy_to_flow_dir(dir);

if (__xfrm_decode_session(skb, &fl, family, reverse) < 0)
return 0;
nf_nat_decode_session(skb, &fl, family);

Expand Down

0 comments on commit d5422ef

Please sign in to comment.