forked from mirrors/linux
		
	[NET]: Introducing socket mark socket option.
A userspace program may wish to set the mark for each packets its send without using the netfilter MARK target. Changing the mark can be used for mark based routing without netfilter or for packet filtering. It requires CAP_NET_ADMIN capability. Signed-off-by: Laszlo Attila Toth <panther@balabit.hu> Acked-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									036c2e27bc
								
							
						
					
					
						commit
						4a19ec5800
					
				
					 27 changed files with 65 additions and 0 deletions
				
			
		|  | @ -60,4 +60,6 @@ | ||||||
| #define SO_SECURITY_ENCRYPTION_TRANSPORT	20 | #define SO_SECURITY_ENCRYPTION_TRANSPORT	20 | ||||||
| #define SO_SECURITY_ENCRYPTION_NETWORK		21 | #define SO_SECURITY_ENCRYPTION_NETWORK		21 | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* __ASM_AVR32_SOCKET_H */ | #endif /* __ASM_AVR32_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -50,4 +50,7 @@ | ||||||
| #define SO_PASSSEC		34 | #define SO_PASSSEC		34 | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
|  | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif				/* _ASM_SOCKET_H */ | #endif				/* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -54,6 +54,8 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -52,5 +52,7 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -61,4 +61,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_IA64_SOCKET_H */ | #endif /* _ASM_IA64_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_M32R_SOCKET_H */ | #endif /* _ASM_M32R_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -73,6 +73,8 @@ To add: #define SO_REUSEPORT 0x0200	/* Allow local address and port reuse.  */ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #ifdef __KERNEL__ | #ifdef __KERNEL__ | ||||||
| 
 | 
 | ||||||
| /** sock_type - Socket types
 | /** sock_type - Socket types
 | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_PEERSEC		0x401d | #define SO_PEERSEC		0x401d | ||||||
| #define SO_PASSSEC		0x401e | #define SO_PASSSEC		0x401e | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			0x401f | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -59,4 +59,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif	/* _ASM_POWERPC_SOCKET_H */ | #endif	/* _ASM_POWERPC_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -60,4 +60,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* __ASM_SH_SOCKET_H */ | #endif /* __ASM_SH_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -52,6 +52,8 @@ | ||||||
| #define SO_TIMESTAMPNS		0x0021 | #define SO_TIMESTAMPNS		0x0021 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			0x0022 | ||||||
|  | 
 | ||||||
| /* Security levels - as per NRL IPv6 - don't actually do anything */ | /* Security levels - as per NRL IPv6 - don't actually do anything */ | ||||||
| #define SO_SECURITY_AUTHENTICATION		0x5001 | #define SO_SECURITY_AUTHENTICATION		0x5001 | ||||||
| #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002 | #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002 | ||||||
|  |  | ||||||
|  | @ -57,4 +57,5 @@ | ||||||
| #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002 | #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002 | ||||||
| #define SO_SECURITY_ENCRYPTION_NETWORK		0x5004 | #define SO_SECURITY_ENCRYPTION_NETWORK		0x5004 | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			0x0022 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* __V850_SOCKET_H__ */ | #endif /* __V850_SOCKET_H__ */ | ||||||
|  |  | ||||||
|  | @ -52,4 +52,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif /* _ASM_SOCKET_H */ | #endif /* _ASM_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -63,4 +63,6 @@ | ||||||
| #define SO_TIMESTAMPNS		35 | #define SO_TIMESTAMPNS		35 | ||||||
| #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS | ||||||
| 
 | 
 | ||||||
|  | #define SO_MARK			36 | ||||||
|  | 
 | ||||||
| #endif	/* _XTENSA_SOCKET_H */ | #endif	/* _XTENSA_SOCKET_H */ | ||||||
|  |  | ||||||
|  | @ -27,6 +27,7 @@ | ||||||
| #include <net/dst.h> | #include <net/dst.h> | ||||||
| #include <net/inetpeer.h> | #include <net/inetpeer.h> | ||||||
| #include <net/flow.h> | #include <net/flow.h> | ||||||
|  | #include <net/sock.h> | ||||||
| #include <linux/in_route.h> | #include <linux/in_route.h> | ||||||
| #include <linux/rtnetlink.h> | #include <linux/rtnetlink.h> | ||||||
| #include <linux/route.h> | #include <linux/route.h> | ||||||
|  | @ -149,6 +150,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst, | ||||||
| 				   int flags) | 				   int flags) | ||||||
| { | { | ||||||
| 	struct flowi fl = { .oif = oif, | 	struct flowi fl = { .oif = oif, | ||||||
|  | 			    .mark = sk->sk_mark, | ||||||
| 			    .nl_u = { .ip4_u = { .daddr = dst, | 			    .nl_u = { .ip4_u = { .daddr = dst, | ||||||
| 						 .saddr = src, | 						 .saddr = src, | ||||||
| 						 .tos   = tos } }, | 						 .tos   = tos } }, | ||||||
|  |  | ||||||
|  | @ -262,6 +262,8 @@ struct sock { | ||||||
| 	__u32			sk_sndmsg_off; | 	__u32			sk_sndmsg_off; | ||||||
| 	int			sk_write_pending; | 	int			sk_write_pending; | ||||||
| 	void			*sk_security; | 	void			*sk_security; | ||||||
|  | 	__u32			sk_mark; | ||||||
|  | 	/* XXX 4 bytes hole on 64 bit */ | ||||||
| 	void			(*sk_state_change)(struct sock *sk); | 	void			(*sk_state_change)(struct sock *sk); | ||||||
| 	void			(*sk_data_ready)(struct sock *sk, int bytes); | 	void			(*sk_data_ready)(struct sock *sk, int bytes); | ||||||
| 	void			(*sk_write_space)(struct sock *sk); | 	void			(*sk_write_space)(struct sock *sk); | ||||||
|  |  | ||||||
|  | @ -667,6 +667,13 @@ int sock_setsockopt(struct socket *sock, int level, int optname, | ||||||
| 		else | 		else | ||||||
| 			clear_bit(SOCK_PASSSEC, &sock->flags); | 			clear_bit(SOCK_PASSSEC, &sock->flags); | ||||||
| 		break; | 		break; | ||||||
|  | 	case SO_MARK: | ||||||
|  | 		if (!capable(CAP_NET_ADMIN)) | ||||||
|  | 			ret = -EPERM; | ||||||
|  | 		else { | ||||||
|  | 			sk->sk_mark = val; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
| 
 | 
 | ||||||
| 		/* We implement the SO_SNDLOWAT etc to
 | 		/* We implement the SO_SNDLOWAT etc to
 | ||||||
| 		   not be settable (1003.1g 5.3) */ | 		   not be settable (1003.1g 5.3) */ | ||||||
|  | @ -836,6 +843,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, | ||||||
| 	case SO_PEERSEC: | 	case SO_PEERSEC: | ||||||
| 		return security_socket_getpeersec_stream(sock, optval, optlen, len); | 		return security_socket_getpeersec_stream(sock, optval, optlen, len); | ||||||
| 
 | 
 | ||||||
|  | 	case SO_MARK: | ||||||
|  | 		v.val = sk->sk_mark; | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
| 	default: | 	default: | ||||||
| 		return -ENOPROTOOPT; | 		return -ENOPROTOOPT; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -168,6 +168,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	skb->priority = sk->sk_priority; | 	skb->priority = sk->sk_priority; | ||||||
|  | 	skb->mark = sk->sk_mark; | ||||||
| 
 | 
 | ||||||
| 	/* Send it out. */ | 	/* Send it out. */ | ||||||
| 	return ip_local_out(skb); | 	return ip_local_out(skb); | ||||||
|  | @ -385,6 +386,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) | ||||||
| 			     (skb_shinfo(skb)->gso_segs ?: 1) - 1); | 			     (skb_shinfo(skb)->gso_segs ?: 1) - 1); | ||||||
| 
 | 
 | ||||||
| 	skb->priority = sk->sk_priority; | 	skb->priority = sk->sk_priority; | ||||||
|  | 	skb->mark = sk->sk_mark; | ||||||
| 
 | 
 | ||||||
| 	return ip_local_out(skb); | 	return ip_local_out(skb); | ||||||
| 
 | 
 | ||||||
|  | @ -1286,6 +1288,7 @@ int ip_push_pending_frames(struct sock *sk) | ||||||
| 	iph->daddr = rt->rt_dst; | 	iph->daddr = rt->rt_dst; | ||||||
| 
 | 
 | ||||||
| 	skb->priority = sk->sk_priority; | 	skb->priority = sk->sk_priority; | ||||||
|  | 	skb->mark = sk->sk_mark; | ||||||
| 	skb->dst = dst_clone(&rt->u.dst); | 	skb->dst = dst_clone(&rt->u.dst); | ||||||
| 
 | 
 | ||||||
| 	if (iph->protocol == IPPROTO_ICMP) | 	if (iph->protocol == IPPROTO_ICMP) | ||||||
|  |  | ||||||
|  | @ -352,6 +352,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | ||||||
| 	skb_reserve(skb, hh_len); | 	skb_reserve(skb, hh_len); | ||||||
| 
 | 
 | ||||||
| 	skb->priority = sk->sk_priority; | 	skb->priority = sk->sk_priority; | ||||||
|  | 	skb->mark = sk->sk_mark; | ||||||
| 	skb->dst = dst_clone(&rt->u.dst); | 	skb->dst = dst_clone(&rt->u.dst); | ||||||
| 
 | 
 | ||||||
| 	skb_reset_network_header(skb); | 	skb_reset_network_header(skb); | ||||||
|  | @ -544,6 +545,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | ||||||
| 
 | 
 | ||||||
| 	{ | 	{ | ||||||
| 		struct flowi fl = { .oif = ipc.oif, | 		struct flowi fl = { .oif = ipc.oif, | ||||||
|  | 				    .mark = sk->sk_mark, | ||||||
| 				    .nl_u = { .ip4_u = | 				    .nl_u = { .ip4_u = | ||||||
| 					      { .daddr = daddr, | 					      { .daddr = daddr, | ||||||
| 						.saddr = saddr, | 						.saddr = saddr, | ||||||
|  |  | ||||||
|  | @ -257,6 +257,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | ||||||
| 	ipv6_addr_copy(&hdr->daddr, first_hop); | 	ipv6_addr_copy(&hdr->daddr, first_hop); | ||||||
| 
 | 
 | ||||||
| 	skb->priority = sk->sk_priority; | 	skb->priority = sk->sk_priority; | ||||||
|  | 	skb->mark = sk->sk_mark; | ||||||
| 
 | 
 | ||||||
| 	mtu = dst_mtu(dst); | 	mtu = dst_mtu(dst); | ||||||
| 	if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { | 	if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { | ||||||
|  | @ -1439,6 +1440,7 @@ int ip6_push_pending_frames(struct sock *sk) | ||||||
| 	ipv6_addr_copy(&hdr->daddr, final_dst); | 	ipv6_addr_copy(&hdr->daddr, final_dst); | ||||||
| 
 | 
 | ||||||
| 	skb->priority = sk->sk_priority; | 	skb->priority = sk->sk_priority; | ||||||
|  | 	skb->mark = sk->sk_mark; | ||||||
| 
 | 
 | ||||||
| 	skb->dst = dst_clone(&rt->u.dst); | 	skb->dst = dst_clone(&rt->u.dst); | ||||||
| 	IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); | 	IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); | ||||||
|  |  | ||||||
|  | @ -641,6 +641,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | ||||||
| 	skb_reserve(skb, hh_len); | 	skb_reserve(skb, hh_len); | ||||||
| 
 | 
 | ||||||
| 	skb->priority = sk->sk_priority; | 	skb->priority = sk->sk_priority; | ||||||
|  | 	skb->mark = sk->sk_mark; | ||||||
| 	skb->dst = dst_clone(&rt->u.dst); | 	skb->dst = dst_clone(&rt->u.dst); | ||||||
| 
 | 
 | ||||||
| 	skb_put(skb, length); | 	skb_put(skb, length); | ||||||
|  | @ -767,6 +768,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | ||||||
| 	 */ | 	 */ | ||||||
| 	memset(&fl, 0, sizeof(fl)); | 	memset(&fl, 0, sizeof(fl)); | ||||||
| 
 | 
 | ||||||
|  | 	fl.mark = sk->sk_mark; | ||||||
|  | 
 | ||||||
| 	if (sin6) { | 	if (sin6) { | ||||||
| 		if (addr_len < SIN6_LEN_RFC2133) | 		if (addr_len < SIN6_LEN_RFC2133) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Laszlo Attila Toth
						Laszlo Attila Toth