From cc17555c99001470bddcd00e29f5a0a5a3861adf Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Mon, 31 May 2010 16:19:19 -0400 Subject: [PATCH 2/2] SAREF: implement IP_IPSEC_BINDREF Add sockopt IP_IPSEC_BINDREF, which associates an IPsec SAref to an inet socket. The ref is used to seed the skb->sp->ref for each skb on that connection, which will force packets out a specific klips SA. --- include/linux/in.h | 1 + include/net/sock.h | 2 +- include/net/xfrm.h | 15 +++++++++++++++ net/core/sock.c | 3 +++ net/ipv4/ip_sockglue.c | 9 +++++++++ net/ipv4/tcp.c | 3 +++ net/ipv4/tcp_output.c | 7 +++++++ 7 files changed, 39 insertions(+), 1 deletions(-) diff --git a/include/linux/in.h b/include/linux/in.h index b7e431e..06977b4 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -77,6 +77,7 @@ struct in_addr { #define IP_PASSSEC 18 #define IP_TRANSPARENT 19 #define IP_IPSEC_REFINFO 30 /* used with CONFIG_INET_IPSEC_SAREF */ +#define IP_IPSEC_BINDREF 31 /* BSD compatibility */ #define IP_RECVRETOPTS IP_RETOPTS diff --git a/include/net/sock.h b/include/net/sock.h index 1ad6435..24216d5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -307,7 +307,7 @@ struct sock { void *sk_security; #endif __u32 sk_mark; - /* XXX 4 bytes hole on 64 bit */ + __u32 sk_saref; void (*sk_state_change)(struct sock *sk); void (*sk_data_ready)(struct sock *sk, int bytes); void (*sk_write_space)(struct sock *sk); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 341077d..ec4f044 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -949,6 +949,21 @@ secpath_put(struct sec_path *sp) extern struct sec_path *secpath_dup(struct sec_path *src); +/* + * Attach IPsec SAref value to skb, if appropriate. + */ +static inline void skb_sec_assign_sk_saref(struct sk_buff *skb, struct sock *sk) +{ +#if defined(CONFIG_XFRM) + if (sk->sk_saref) { + if (!skb->sp) + skb->sp = secpath_dup(NULL); + if (skb->sp) + skb->sp->ref = sk->sk_saref; + } +#endif +} + static inline void secpath_reset(struct sk_buff *skb) { diff --git a/net/core/sock.c b/net/core/sock.c index c5812bb..8645d0f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1442,6 +1442,9 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, int npages; int i; + /* associate the skb with the socket's SAref */ + skb_sec_assign_sk_saref(skb, sk); + /* No pages, we're done... */ if (!data_len) break; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 3db631d..072d0c1 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -538,6 +538,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, optname == IP_RECVORIGDSTADDR #ifdef CONFIG_INET_IPSEC_SAREF || optname == IP_IPSEC_REFINFO + || optname == IP_IPSEC_BINDREF #endif ) { if (optlen >= sizeof(int)) { @@ -640,6 +641,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, else inet->cmsg_flags &= ~IP_CMSG_IPSEC_REFINFO; break; + case IP_IPSEC_BINDREF: + sk->sk_saref = val; + break; #endif case IP_TOS: /* This sets both TOS and Precedence */ if (sk->sk_type == SOCK_STREAM) { @@ -1064,6 +1068,7 @@ int ip_setsockopt(struct sock *sk, int level, optname != IP_XFRM_POLICY && #ifdef CONFIG_INET_IPSEC_SAREF optname != IP_IPSEC_REFINFO && + optname != IP_IPSEC_BINDREF && #endif !ip_mroute_opt(optname)) { lock_sock(sk); @@ -1096,6 +1101,7 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, optname != IP_XFRM_POLICY && #ifdef CONFIG_INET_IPSEC_SAREF optname != IP_IPSEC_REFINFO && + optname != IP_IPSEC_BINDREF && #endif !ip_mroute_opt(optname)) { lock_sock(sk); @@ -1180,6 +1186,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_IPSEC_REFINFO: val = (inet->cmsg_flags & IP_CMSG_IPSEC_REFINFO) != 0; break; + case IP_IPSEC_BINDREF: + val = sk->sk_saref; + break; #endif case IP_RECVORIGDSTADDR: val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 296150b..9de3dc1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -686,6 +686,9 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp) skb = alloc_skb_fclone(size + sk->sk_prot->max_header, gfp); if (skb) { if (sk_wmem_schedule(sk, skb->truesize)) { + /* associate the skb with the socket's SAref */ + skb_sec_assign_sk_saref(skb, sk); + /* * Make sure that we have exactly size bytes * available to the caller, no more, no less. diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 0dda86e..462f5fe 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -35,6 +35,7 @@ */ #include +#include #include #include @@ -815,6 +816,9 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, return -ENOBUFS; } + /* associate the skb with the socket's SAref */ + skb_sec_assign_sk_saref(skb, sk); + inet = inet_sk(sk); tp = tcp_sk(sk); tcb = TCP_SKB_CB(skb); @@ -2587,6 +2591,9 @@ int tcp_connect(struct sock *sk) if (unlikely(buff == NULL)) return -ENOBUFS; + /* associate the skb with the socket's SAref */ + skb_sec_assign_sk_saref(buff, sk); + /* Reserve space for headers. */ skb_reserve(buff, MAX_TCP_HEADER); -- 1.7.0.2.g2b0b7e7