commit ae080bfe7b30a6066d4e582303957b4eee970e68 Author: Simon Deziel Date: Thu Feb 13 15:54:07 2014 -0500 SAref patch 0002 against Ubuntu 3.11.0-15.25 diff --git a/include/net/ip.h b/include/net/ip.h index edfa591..767fc0c 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -56,6 +56,9 @@ struct ipcm_cookie { int oif; struct ip_options_rcu *opt; __u8 tx_flags; +#ifdef CONFIG_INET_IPSEC_SAREF + struct sec_path *sp; +#endif }; #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index e823786..994feec 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -977,12 +977,30 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); +#ifdef CONFIG_INET_IPSEC_SAREF +typedef unsigned int xfrm_sec_unique_t; +#endif + struct sec_path { atomic_t refcnt; +#ifdef CONFIG_INET_IPSEC_SAREF + xfrm_sec_unique_t ref; /*reference to high-level policy*/ +#endif int len; struct xfrm_state *xvec[XFRM_MAX_DEPTH]; }; +#ifdef CONFIG_INET_IPSEC_SAREF +struct ipcm_cookie; +struct ipsec_secpath_saref_ops { + int (*set_ipc_saref)(struct ipcm_cookie *ipc, xfrm_sec_unique_t saref); + void (*get_secpath_sarefs)(struct sec_path *sp, + xfrm_sec_unique_t *refme, xfrm_sec_unique_t *refhim); +}; +extern int register_ipsec_secpath_saref_ops(struct ipsec_secpath_saref_ops *ops); +extern void unregister_ipsec_secpath_saref_ops(struct ipsec_secpath_saref_ops *ops); +#endif + static inline int secpath_exists(struct sk_buff *skb) { #ifdef CONFIG_XFRM diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h index 9edb441..bd5783d 100644 --- a/include/uapi/linux/in.h +++ b/include/uapi/linux/in.h @@ -76,6 +76,7 @@ struct in_addr { #define IP_XFRM_POLICY 17 #define IP_PASSSEC 18 #define IP_TRANSPARENT 19 +#define IP_IPSEC_REFINFO 30 /* used with CONFIG_INET_IPSEC_SAREF */ /* BSD compatibility */ #define IP_RECVRETOPTS IP_RETOPTS diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 37cf1a6..cd9bbf3 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -396,6 +396,16 @@ config INET_XFRM_MODE_BEET If unsure, say Y. +config INET_IPSEC_SAREF + bool "IP: IPsec SAref interface (KLIPS)" + default y + select XFRM + ---help--- + This exports a mechanism that allows the KLIPS IPsec stack to + support mast mode without using nfmark and iptables. + + If unsure, say Y. + config INET_LRO tristate "Large Receive Offload (ipv4/tcp)" default y diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 5f7d11a..fa54bf4 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -338,6 +338,8 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) struct inet_sock *inet; __be32 daddr, saddr; + memset(&ipc, 0, sizeof(ipc)); + if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb)) return; @@ -491,6 +493,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct net *net; struct sock *sk; + memset(&ipc, 0, sizeof(ipc)); + if (!rt) goto out; net = dev_net(rt->dst.dev); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 7f4ab5d..a9f0bfe 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -418,6 +419,10 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) /* Copy the flags to each fragment. */ IPCB(to)->flags = IPCB(from)->flags; +#ifdef CONFIG_INET_IPSEC_SAREF + to->sp = secpath_get(from->sp); +#endif + #ifdef CONFIG_NET_SCHED to->tc_index = from->tc_index; #endif @@ -793,6 +798,7 @@ static int __ip_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, + struct ipcm_cookie *ipc, unsigned int flags) { struct inet_sock *inet = inet_sk(sk); @@ -927,6 +933,9 @@ alloc_new_skb: */ skb->ip_summed = csummode; skb->csum = 0; +#ifdef CONFIG_INET_IPSEC_SAREF + skb->sp = secpath_get(ipc->sp); +#endif skb_reserve(skb, hh_len); skb_shinfo(skb)->tx_flags = cork->tx_flags; @@ -1099,7 +1108,7 @@ int ip_append_data(struct sock *sk, struct flowi4 *fl4, return __ip_append_data(sk, fl4, &sk->sk_write_queue, &inet->cork.base, sk_page_frag(sk), getfrag, - from, length, transhdrlen, flags); + from, length, transhdrlen, ipc, flags); } ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, @@ -1422,7 +1431,7 @@ struct sk_buff *ip_make_skb(struct sock *sk, err = __ip_append_data(sk, fl4, &queue, &cork, ¤t->task_frag, getfrag, - from, length, transhdrlen, flags); + from, length, transhdrlen, ipc, flags); if (err) { __ip_flush_pending_frames(sk, &queue, &cork); return ERR_PTR(err); @@ -1475,6 +1484,8 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, struct sock *sk; struct inet_sock *inet; + memset(&ipc, 0, sizeof(ipc)); + if (ip_options_echo(&replyopts.opt.opt, skb)) return; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index d9c4f11..b01f36f 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -52,6 +52,7 @@ #define IP_CMSG_RETOPTS 16 #define IP_CMSG_PASSSEC 32 #define IP_CMSG_ORIGDSTADDR 64 +#define IP_CMSG_IPSEC_REFINFO 128 /* * SOL_IP control messages. @@ -145,6 +146,62 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin); } +#ifdef CONFIG_INET_IPSEC_SAREF +static struct ipsec_secpath_saref_ops *ipsec_secpath_saref_ops = NULL; + +int register_ipsec_secpath_saref_ops(struct ipsec_secpath_saref_ops *ops) +{ + if (ipsec_secpath_saref_ops) + return -EBUSY; + + rcu_assign_pointer(ipsec_secpath_saref_ops, ops); + + return 0; +} +EXPORT_SYMBOL(register_ipsec_secpath_saref_ops); + +void unregister_ipsec_secpath_saref_ops(struct ipsec_secpath_saref_ops *ops) +{ + rcu_assign_pointer(ipsec_secpath_saref_ops, NULL); +} +EXPORT_SYMBOL(unregister_ipsec_secpath_saref_ops); + +static void ip_cmsg_recv_ipsec_refinfo(struct msghdr *msg, struct sk_buff *skb) +{ + struct ipsec_secpath_saref_ops *ops; + xfrm_sec_unique_t refs[2] = {0, 0}; + + rcu_read_lock_bh(); + ops = rcu_dereference(ipsec_secpath_saref_ops); + if (ops && ops->get_secpath_sarefs) + ops->get_secpath_sarefs(skb->sp, &refs[0], &refs[1]); + rcu_read_unlock_bh(); + + put_cmsg(msg, SOL_IP, IP_IPSEC_REFINFO, sizeof(refs), &refs); +} + +static int ip_cmsg_send_ipsec_refinfo(struct cmsghdr *cmsg, struct ipcm_cookie *ipc) +{ + int rc = -EINVAL; + struct ipsec_secpath_saref_ops *ops; + xfrm_sec_unique_t *ref; + + if(cmsg->cmsg_len != CMSG_LEN(sizeof(xfrm_sec_unique_t))) + goto bail; + + ref = (xfrm_sec_unique_t*)CMSG_DATA(cmsg); + + rcu_read_lock_bh(); + ops = rcu_dereference(ipsec_secpath_saref_ops); + if (ops && ops->set_ipc_saref) + rc = ops->set_ipc_saref(ipc, *ref); + rcu_read_unlock_bh(); + +bail: + return rc; +} +#endif + void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) { struct inet_sock *inet = inet_sk(skb->sk); @@ -181,8 +238,16 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) if ((flags >>= 1) == 0) return; + if (flags & 1) ip_cmsg_recv_dstaddr(msg, skb); + if ((flags >>= 1) == 0) + return; + +#ifdef CONFIG_INET_IPSEC_SAREF + if (flags & 1) + ip_cmsg_recv_ipsec_refinfo(msg, skb); +#endif } EXPORT_SYMBOL(ip_cmsg_recv); @@ -215,12 +280,25 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) ipc->addr = info->ipi_spec_dst.s_addr; break; } + +#ifdef CONFIG_INET_IPSEC_SAREF + case IP_IPSEC_REFINFO: + { + err = ip_cmsg_send_ipsec_refinfo(cmsg, ipc); + if(err) + return err; + + break; + } +#endif + default: return -EINVAL; } } return 0; } +EXPORT_SYMBOL(ip_cmsg_send); /* Special input handler for packets caught by router alert option. @@ -479,6 +557,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, case IP_MULTICAST_ALL: case IP_MULTICAST_LOOP: case IP_RECVORIGDSTADDR: +#ifdef CONFIG_INET_IPSEC_SAREF + case IP_IPSEC_REFINFO: +#endif if (optlen >= sizeof(int)) { if (get_user(val, (int __user *) optval)) return -EFAULT; @@ -576,6 +657,14 @@ static int do_ip_setsockopt(struct sock *sk, int level, else inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR; break; +#ifdef CONFIG_INET_IPSEC_SAREF + case IP_IPSEC_REFINFO: + if (val) + inet->cmsg_flags |= IP_CMSG_IPSEC_REFINFO; + else + inet->cmsg_flags &= ~IP_CMSG_IPSEC_REFINFO; + break; +#endif case IP_TOS: /* This sets both TOS and Precedence */ if (sk->sk_type == SOCK_STREAM) { val &= ~INET_ECN_MASK; @@ -1062,6 +1151,9 @@ int ip_setsockopt(struct sock *sk, int level, if (err == -ENOPROTOOPT && optname != IP_HDRINCL && optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY && +#ifdef CONFIG_INET_IPSEC_SAREF + optname != IP_IPSEC_REFINFO && +#endif !ip_mroute_opt(optname)) { lock_sock(sk); err = nf_setsockopt(sk, PF_INET, optname, optval, optlen); @@ -1091,6 +1183,9 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, if (err == -ENOPROTOOPT && optname != IP_HDRINCL && optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY && +#ifdef CONFIG_INET_IPSEC_SAREF + optname != IP_IPSEC_REFINFO && +#endif !ip_mroute_opt(optname)) { lock_sock(sk); err = compat_nf_setsockopt(sk, PF_INET, optname, @@ -1174,6 +1269,11 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_PASSSEC: val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0; break; +#ifdef CONFIG_INET_IPSEC_SAREF + case IP_IPSEC_REFINFO: + val = (inet->cmsg_flags & IP_CMSG_IPSEC_REFINFO) != 0; + break; +#endif case IP_RECVORIGDSTADDR: val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0; break; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 6fb2337..e619b18 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -474,6 +474,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int err; struct ip_options_data opt_copy; + memset(&ipc, 0, sizeof(ipc)); + err = -EMSGSIZE; if (len > 0xFFFF) goto out; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 766e6ba..3e95d43 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -842,6 +842,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, struct sk_buff *skb; struct ip_options_data opt_copy; + memset(&ipc, 0, sizeof(ipc)); + if (len > 0xFFFF) return -EMSGSIZE; @@ -1040,6 +1042,12 @@ out: ip_rt_put(rt); if (free) kfree(ipc.opt); +#ifdef CONFIG_INET_IPSEC_SAREF + if(ipc.sp) { + secpath_put(ipc.sp); + ipc.sp=NULL; + } +#endif if (!err) return len; /*