-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi All,
thanks for revising Patrick! Attached is the updated patch.
Sorry had no time yet to remove the sysctl variables.
It will follow in a few weeks if I have more time :)
Best regards
Ulrich
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFC8fRi22t2oTuElzoRAkPIAJ40Ej2cs+1DX2IYiVcpr/OF8dUKJgCeJj6T
o639zBMfTeeEwY1OgxRcsw0=
=ggAG
-----END PGP SIGNATURE-----
diff -Nru linux-2.6.13-rc3.org/include/linux/sysctl.h
linux-2.6.13-rc3/include/linux/sysctl.h
--- linux-2.6.13-rc3.org/include/linux/sysctl.h 2005-07-18 10:24:11.000000000
+0200
+++ linux-2.6.13-rc3/include/linux/sysctl.h 2005-07-19 10:10:22.000000000
+0200
@@ -253,6 +253,8 @@
NET_CORE_DEV_WEIGHT=17,
NET_CORE_SOMAXCONN=18,
NET_CORE_BUDGET=19,
+ NET_CORE_XFRM_SEQDIFF_IN=20,
+ NET_CORE_XFRM_SEQDIFF_OUT=21,
};
/* /proc/sys/net/ethernet */
diff -Nru linux-2.6.13-rc3.org/include/linux/xfrm.h
linux-2.6.13-rc3/include/linux/xfrm.h
--- linux-2.6.13-rc3.org/include/linux/xfrm.h 2005-07-18 10:49:43.000000000
+0200
+++ linux-2.6.13-rc3/include/linux/xfrm.h 2005-07-19 10:10:22.000000000
+0200
@@ -140,6 +140,9 @@
XFRM_MSG_FLUSHPOLICY,
#define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY
+ XFRM_MSG_UPDSEQ,
+#define XFRM_MSG_UPDSEQ XFRM_MSG_UPDSEQ
+
__XFRM_MSG_MAX
};
#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -263,5 +266,6 @@
#define XFRMGRP_EXPIRE 2
#define XFRMGRP_SA 4
#define XFRMGRP_POLICY 8
+#define XFRMGRP_REPLAY 16
#endif /* _LINUX_XFRM_H */
diff -Nru linux-2.6.13-rc3.org/include/net/xfrm.h
linux-2.6.13-rc3/include/net/xfrm.h
--- linux-2.6.13-rc3.org/include/net/xfrm.h 2005-07-18 10:24:11.000000000
+0200
+++ linux-2.6.13-rc3/include/net/xfrm.h 2005-08-04 12:28:36.000000000 +0200
@@ -134,6 +134,9 @@
/* State for replay detection */
struct xfrm_replay_state replay;
+ /* Replay detection state at the time we sent the last notification */
+ struct xfrm_replay_state preplay;
+
/* Statistics */
struct xfrm_stats stats;
@@ -301,6 +304,10 @@
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
+/* which seqno */
+#define XFRM_REPLAY_INBOUND 1
+#define XFRM_REPLAY_OUTBOUND 2
+
#define XFRM_KM_TIMEOUT 30
struct xfrm_mgr
@@ -312,6 +319,7 @@
struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8
*data, int len, int *dir);
int (*new_mapping)(struct xfrm_state *x,
xfrm_address_t *ipaddr, u16 sport);
int (*notify_policy)(struct xfrm_policy *x, int
dir, struct km_event *c);
+ int (*notify_seq)(struct xfrm_state *x, u32 pid,
u32 seq);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -838,6 +846,8 @@
extern void xfrm_state_flush(u8 proto);
extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
+extern void xfrm_replay_notify(struct xfrm_state *x, int event);
+extern void xfrm_state_replay_update(struct xfrm_state *x, struct
xfrm_replay_state *replay);
extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);
extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
extern int xfrm_init_state(struct xfrm_state *x);
@@ -888,6 +898,7 @@
struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
xfrm_address_t *daddr, xfrm_address_t *saddr,
int create, unsigned short family);
+extern void km_replay_notify(struct xfrm_state *);
extern void xfrm_policy_flush(void);
extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy
*pol);
extern int xfrm_flush_bundles(void);
diff -Nru linux-2.6.13-rc3.org/net/core/sysctl_net_core.c
linux-2.6.13-rc3/net/core/sysctl_net_core.c
--- linux-2.6.13-rc3.org/net/core/sysctl_net_core.c 2005-07-18
10:24:11.000000000 +0200
+++ linux-2.6.13-rc3/net/core/sysctl_net_core.c 2005-07-19 10:10:22.000000000
+0200
@@ -31,6 +31,11 @@
extern char sysctl_divert_version[];
#endif /* CONFIG_NET_DIVERT */
+#ifdef CONFIG_XFRM
+extern u32 sysctl_xfrm_seqdiff_in;
+extern u32 sysctl_xfrm_seqdiff_out;
+#endif /* CONFIG_XFRM */
+
ctl_table core_table[] = {
#ifdef CONFIG_NET
{
@@ -116,6 +121,24 @@
.proc_handler = &proc_dostring
},
#endif /* CONFIG_NET_DIVERT */
+#ifdef CONFIG_XFRM
+ {
+ .ctl_name = NET_CORE_XFRM_SEQDIFF_IN,
+ .procname = "xfrm_seqdiff_in",
+ .data = &sysctl_xfrm_seqdiff_in,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = NET_CORE_XFRM_SEQDIFF_OUT,
+ .procname = "xfrm_seqdiff_out",
+ .data = &sysctl_xfrm_seqdiff_out,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif /* CONFIG_XFRM */
#endif /* CONFIG_NET */
{
.ctl_name = NET_CORE_SOMAXCONN,
diff -Nru linux-2.6.13-rc3.org/net/ipv4/ah4.c linux-2.6.13-rc3/net/ipv4/ah4.c
--- linux-2.6.13-rc3.org/net/ipv4/ah4.c 2005-07-18 10:24:11.000000000 +0200
+++ linux-2.6.13-rc3/net/ipv4/ah4.c 2005-07-19 10:10:22.000000000 +0200
@@ -96,6 +96,8 @@
ah->reserved = 0;
ah->spi = x->id.spi;
ah->seq_no = htonl(++x->replay.oseq);
+ xfrm_replay_notify(x, XFRM_REPLAY_OUTBOUND);
+
ahp->icv(ahp, skb, ah->auth_data);
top_iph->tos = iph->tos;
diff -Nru linux-2.6.13-rc3.org/net/ipv4/esp4.c linux-2.6.13-rc3/net/ipv4/esp4.c
--- linux-2.6.13-rc3.org/net/ipv4/esp4.c 2005-07-18 10:24:11.000000000
+0200
+++ linux-2.6.13-rc3/net/ipv4/esp4.c 2005-07-19 10:10:22.000000000 +0200
@@ -96,6 +96,8 @@
esph->spi = x->id.spi;
esph->seq_no = htonl(++x->replay.oseq);
+ xfrm_replay_notify(x, XFRM_REPLAY_OUTBOUND);
+
if (esp->conf.ivlen)
crypto_cipher_set_iv(tfm, esp->conf.ivec,
crypto_tfm_alg_ivsize(tfm));
diff -Nru linux-2.6.13-rc3.org/net/ipv6/ah6.c linux-2.6.13-rc3/net/ipv6/ah6.c
--- linux-2.6.13-rc3.org/net/ipv6/ah6.c 2005-07-18 10:24:12.000000000 +0200
+++ linux-2.6.13-rc3/net/ipv6/ah6.c 2005-07-19 10:10:22.000000000 +0200
@@ -212,6 +212,8 @@
ah->reserved = 0;
ah->spi = x->id.spi;
ah->seq_no = htonl(++x->replay.oseq);
+ xfrm_replay_notify(x, XFRM_REPLAY_OUTBOUND);
+
ahp->icv(ahp, skb, ah->auth_data);
err = 0;
diff -Nru linux-2.6.13-rc3.org/net/ipv6/esp6.c linux-2.6.13-rc3/net/ipv6/esp6.c
--- linux-2.6.13-rc3.org/net/ipv6/esp6.c 2005-07-18 10:24:12.000000000
+0200
+++ linux-2.6.13-rc3/net/ipv6/esp6.c 2005-07-19 10:10:22.000000000 +0200
@@ -93,6 +93,8 @@
esph->spi = x->id.spi;
esph->seq_no = htonl(++x->replay.oseq);
+ xfrm_replay_notify(x, XFRM_REPLAY_OUTBOUND);
+
if (esp->conf.ivlen)
crypto_cipher_set_iv(tfm, esp->conf.ivec,
crypto_tfm_alg_ivsize(tfm));
diff -Nru linux-2.6.13-rc3.org/net/key/af_key.c
linux-2.6.13-rc3/net/key/af_key.c
--- linux-2.6.13-rc3.org/net/key/af_key.c 2005-07-18 10:49:41.000000000
+0200
+++ linux-2.6.13-rc3/net/key/af_key.c 2005-07-19 10:10:22.000000000 +0200
@@ -2860,6 +2860,12 @@
return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
}
+static int pfkey_send_replay_notify(struct xfrm_state *x, u32 pid, u32 seq)
+{
+ /* FIXME: To be done*/
+ return 0;
+}
+
static int pfkey_sendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, size_t len)
{
@@ -3029,6 +3035,7 @@
.compile_policy = pfkey_compile_policy,
.new_mapping = pfkey_send_new_mapping,
.notify_policy = pfkey_send_policy_notify,
+ .notify_seq = pfkey_send_replay_notify,
};
static void __exit ipsec_pfkey_exit(void)
diff -Nru linux-2.6.13-rc3.org/net/xfrm/xfrm_state.c
linux-2.6.13-rc3/net/xfrm/xfrm_state.c
--- linux-2.6.13-rc3.org/net/xfrm/xfrm_state.c 2005-07-18 10:24:12.000000000
+0200
+++ linux-2.6.13-rc3/net/xfrm/xfrm_state.c 2005-08-04 12:29:41.000000000
+0200
@@ -20,6 +20,9 @@
#include <linux/module.h>
#include <asm/uaccess.h>
+u32 sysctl_xfrm_seqdiff_in = 0;
+u32 sysctl_xfrm_seqdiff_out = 0;
+
/* Each xfrm_state may be linked to two tables:
1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
@@ -758,6 +761,29 @@
}
EXPORT_SYMBOL(xfrm_state_walk);
+void xfrm_replay_notify(struct xfrm_state *x, int event)
+{
+ switch (event) {
+ case XFRM_REPLAY_INBOUND:
+ if (!sysctl_xfrm_seqdiff_in ||
+ (x->replay.seq - x->preplay.seq < sysctl_xfrm_seqdiff_in))
+ return;
+
+ break;
+
+ case XFRM_REPLAY_OUTBOUND:
+ if (!sysctl_xfrm_seqdiff_out ||
+ (x->replay.oseq - x->preplay.oseq <
sysctl_xfrm_seqdiff_out))
+ return;
+
+ break;
+ }
+
+ memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
+ km_replay_notify(x);
+}
+EXPORT_SYMBOL(xfrm_replay_notify);
+
int xfrm_replay_check(struct xfrm_state *x, u32 seq)
{
u32 diff;
@@ -801,9 +827,19 @@
diff = x->replay.seq - seq;
x->replay.bitmap |= (1U << diff);
}
+
+ xfrm_replay_notify(x, XFRM_REPLAY_INBOUND);
}
EXPORT_SYMBOL(xfrm_replay_advance);
+void xfrm_state_replay_update(struct xfrm_state *x, struct xfrm_replay_state
*replay)
+{
+ spin_lock_bh(&x->lock);
+ memcpy(&x->replay, replay, sizeof(*replay));
+ memcpy(&x->preplay, replay, sizeof(*replay));
+ spin_unlock_bh(&x->lock);
+}
+
static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
static DEFINE_RWLOCK(xfrm_km_lock);
@@ -891,6 +927,17 @@
wake_up(&km_waitq);
}
+void km_replay_notify(struct xfrm_state *x)
+{
+ struct xfrm_mgr *km;
+
+ read_lock(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list)
+ if (km->notify_seq)
+ km->notify_seq(x, 0, 0);
+ read_unlock(&xfrm_km_lock);
+}
+
int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int
optlen)
{
int err;
@@ -1104,3 +1151,7 @@
INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);
}
+#ifdef CONFIG_SYSCTL
+EXPORT_SYMBOL(sysctl_xfrm_seqdiff_in);
+EXPORT_SYMBOL(sysctl_xfrm_seqdiff_out);
+#endif
diff -Nru linux-2.6.13-rc3.org/net/xfrm/xfrm_user.c
linux-2.6.13-rc3/net/xfrm/xfrm_user.c
--- linux-2.6.13-rc3.org/net/xfrm/xfrm_user.c 2005-07-18 10:49:43.000000000
+0200
+++ linux-2.6.13-rc3/net/xfrm/xfrm_user.c 2005-08-04 12:44:53.000000000
+0200
@@ -250,7 +250,8 @@
if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1])))
goto error;
- if( xfrma[XFRMA_REPLAY-1] && (rt->rta_len == (sizeof(struct
xfrm_replay_state) + sizeof(struct rtattr)))) {
+ if (xfrma[XFRMA_REPLAY-1] &&
+ (rt->rta_len == RTA_LENGTH(sizeof(struct xfrm_replay_state)))) {
struct xfrm_replay_state *replay;
replay = RTA_DATA(xfrma[XFRMA_REPLAY - 1]);
x->replay = *replay;
@@ -917,6 +918,75 @@
return 0;
}
+static int build_replay(struct sk_buff *skb, struct xfrm_state *x, __u32 pid,
__u32 seq)
+{
+ struct xfrm_usersa_id *id;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, pid, seq, XFRM_MSG_UPDSEQ, sizeof(*id));
+ id = NLMSG_DATA(nlh);
+ nlh->nlmsg_flags = 0;
+
+ id->daddr = x->id.daddr;
+ id->spi = x->id.spi;
+ id->family = x->props.family;
+ id->proto = x->id.proto;
+
+ RTA_PUT(skb, XFRMA_REPLAY, sizeof(x->replay), &x->replay);
+
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+rtattr_failure:
+nlmsg_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+static int xfrm_send_replay_notify(struct xfrm_state *x, __u32 pid,__u32 seq) {
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sizeof(struct xfrm_usersa_id) + sizeof(struct
xfrm_replay_state) + 16, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ if (build_replay(skb, x, pid, seq) < 0)
+ BUG();
+
+ if (pid == 0) {
+ NETLINK_CB(skb).dst_groups = XFRMGRP_REPLAY;
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_REPLAY,
GFP_ATOMIC);
+ }
+ else
+ return netlink_unicast(xfrm_nl, skb, pid, MSG_DONTWAIT);
+}
+
+static int xfrm_update_seq(struct sk_buff *skb, struct nlmsghdr *nlh, void
**xfrma)
+{
+ struct xfrm_state *x;
+ struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
+ struct xfrm_replay_state *replay;
+ struct rtattr *rt = xfrma[XFRMA_REPLAY-1];
+
+ x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
+ if (x == NULL) {
+ return -ESRCH;
+ }
+
+ if (xfrma[XFRMA_REPLAY-1] != NULL &&
+ (rt->rta_len == RTA_LENGTH(sizeof(struct xfrm_replay_state)))) {
+ replay = RTA_DATA(xfrma[XFRMA_REPLAY - 1]);
+ xfrm_state_replay_update(x, replay);
+ }
+ else {
+ xfrm_send_replay_notify(x, nlh->nlmsg_pid, nlh->nlmsg_seq);
+ }
+ xfrm_state_put(x);
+
+ return 0;
+}
+
#define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type))
static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
@@ -934,6 +1004,7 @@
[XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
[XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0),
+ [XFRM_MSG_UPDSEQ - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
};
#undef XMSGSIZE
@@ -955,6 +1026,7 @@
[XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
[XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa },
[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy },
+ [XFRM_MSG_UPDSEQ - XFRM_MSG_BASE] = { .doit = xfrm_update_seq },
};
static int xfrm_done(struct netlink_callback *cb)
@@ -1519,6 +1591,7 @@
.acquire = xfrm_send_acquire,
.compile_policy = xfrm_compile_policy,
.notify_policy = xfrm_send_policy_notify,
+ .notify_seq = xfrm_send_replay_notify,
};
static int __init xfrm_user_init(void)