-----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)