mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 12:16:20 +00:00
afeb14b490
This patch adds a number of new IPsec audit events to meet the auditing requirements of RFC4303. This includes audit hooks for the following events: * Could not find a valid SA [sections 2.1, 3.4.2] . xfrm_audit_state_notfound() . xfrm_audit_state_notfound_simple() * Sequence number overflow [section 3.3.3] . xfrm_audit_state_replay_overflow() * Replayed packet [section 3.4.3] . xfrm_audit_state_replay() * Integrity check failure [sections 3.4.4.1, 3.4.4.2] . xfrm_audit_state_icvfail() While RFC4304 deals only with ESP most of the changes in this patch apply to IPsec in general, i.e. both AH and ESP. The one case, integrity check failure, where ESP specific code had to be modified the same was done to the AH code for the sake of consistency. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: James Morris <jmorris@namei.org> Signed-off-by: David S. Miller <davem@davemloft.net>
174 lines
3.3 KiB
C
174 lines
3.3 KiB
C
/*
|
|
* xfrm6_input.c: based on net/ipv4/xfrm4_input.c
|
|
*
|
|
* Authors:
|
|
* Mitsuru KANDA @USAGI
|
|
* Kazunori MIYAZAWA @USAGI
|
|
* Kunihiro Ishiguro <kunihiro@ipinfusion.com>
|
|
* YOSHIFUJI Hideaki @USAGI
|
|
* IPv6 support
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/string.h>
|
|
#include <linux/netfilter.h>
|
|
#include <linux/netfilter_ipv6.h>
|
|
#include <net/ipv6.h>
|
|
#include <net/xfrm.h>
|
|
|
|
int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
return xfrm6_extract_header(skb);
|
|
}
|
|
|
|
int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
|
|
{
|
|
XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
|
|
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
|
|
return xfrm_input(skb, nexthdr, spi, 0);
|
|
}
|
|
EXPORT_SYMBOL(xfrm6_rcv_spi);
|
|
|
|
int xfrm6_transport_finish(struct sk_buff *skb, int async)
|
|
{
|
|
skb_network_header(skb)[IP6CB(skb)->nhoff] =
|
|
XFRM_MODE_SKB_CB(skb)->protocol;
|
|
|
|
#ifdef CONFIG_NETFILTER
|
|
ipv6_hdr(skb)->payload_len = htons(skb->len);
|
|
__skb_push(skb, skb->data - skb_network_header(skb));
|
|
|
|
NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
|
|
ip6_rcv_finish);
|
|
return -1;
|
|
#else
|
|
if (async)
|
|
return ip6_rcv_finish(skb);
|
|
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
int xfrm6_rcv(struct sk_buff *skb)
|
|
{
|
|
return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
|
|
0);
|
|
}
|
|
|
|
EXPORT_SYMBOL(xfrm6_rcv);
|
|
|
|
int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
|
|
xfrm_address_t *saddr, u8 proto)
|
|
{
|
|
struct xfrm_state *x = NULL;
|
|
int wildcard = 0;
|
|
xfrm_address_t *xany;
|
|
int nh = 0;
|
|
int i = 0;
|
|
|
|
/* Allocate new secpath or COW existing one. */
|
|
if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
|
|
struct sec_path *sp;
|
|
|
|
sp = secpath_dup(skb->sp);
|
|
if (!sp) {
|
|
XFRM_INC_STATS(LINUX_MIB_XFRMINERROR);
|
|
goto drop;
|
|
}
|
|
if (skb->sp)
|
|
secpath_put(skb->sp);
|
|
skb->sp = sp;
|
|
}
|
|
|
|
if (1 + skb->sp->len == XFRM_MAX_DEPTH) {
|
|
XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR);
|
|
goto drop;
|
|
}
|
|
|
|
xany = (xfrm_address_t *)&in6addr_any;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
xfrm_address_t *dst, *src;
|
|
switch (i) {
|
|
case 0:
|
|
dst = daddr;
|
|
src = saddr;
|
|
break;
|
|
case 1:
|
|
/* lookup state with wild-card source address */
|
|
wildcard = 1;
|
|
dst = daddr;
|
|
src = xany;
|
|
break;
|
|
case 2:
|
|
default:
|
|
/* lookup state with wild-card addresses */
|
|
wildcard = 1; /* XXX */
|
|
dst = xany;
|
|
src = xany;
|
|
break;
|
|
}
|
|
|
|
x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6);
|
|
if (!x)
|
|
continue;
|
|
|
|
spin_lock(&x->lock);
|
|
|
|
if (wildcard) {
|
|
if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) {
|
|
spin_unlock(&x->lock);
|
|
xfrm_state_put(x);
|
|
x = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (unlikely(x->km.state != XFRM_STATE_VALID)) {
|
|
spin_unlock(&x->lock);
|
|
xfrm_state_put(x);
|
|
x = NULL;
|
|
continue;
|
|
}
|
|
if (xfrm_state_check_expire(x)) {
|
|
spin_unlock(&x->lock);
|
|
xfrm_state_put(x);
|
|
x = NULL;
|
|
continue;
|
|
}
|
|
|
|
spin_unlock(&x->lock);
|
|
|
|
nh = x->type->input(x, skb);
|
|
if (nh <= 0) {
|
|
xfrm_state_put(x);
|
|
x = NULL;
|
|
continue;
|
|
}
|
|
|
|
/* Found a state */
|
|
break;
|
|
}
|
|
|
|
if (!x) {
|
|
XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES);
|
|
xfrm_audit_state_notfound_simple(skb, AF_INET6);
|
|
goto drop;
|
|
}
|
|
|
|
skb->sp->xvec[skb->sp->len++] = x;
|
|
|
|
spin_lock(&x->lock);
|
|
|
|
x->curlft.bytes += skb->len;
|
|
x->curlft.packets++;
|
|
|
|
spin_unlock(&x->lock);
|
|
|
|
return 1;
|
|
|
|
drop:
|
|
return -1;
|
|
}
|
|
|
|
EXPORT_SYMBOL(xfrm6_input_addr);
|