ipv4: Implement IP_TRANSPARENT socket option
This patch introduces the IP_TRANSPARENT socket option: enabling that will make the IPv4 routing omit the non-local source address check on output. Setting IP_TRANSPARENT requires NET_ADMIN capability. Signed-off-by: KOVACS Krisztian <hidden@sch.bme.hu> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
a210d01ae3
Коммит
f5715aea45
|
@ -75,6 +75,7 @@ struct in_addr {
|
||||||
#define IP_IPSEC_POLICY 16
|
#define IP_IPSEC_POLICY 16
|
||||||
#define IP_XFRM_POLICY 17
|
#define IP_XFRM_POLICY 17
|
||||||
#define IP_PASSSEC 18
|
#define IP_PASSSEC 18
|
||||||
|
#define IP_TRANSPARENT 19
|
||||||
|
|
||||||
/* BSD compatibility */
|
/* BSD compatibility */
|
||||||
#define IP_RECVRETOPTS IP_RETOPTS
|
#define IP_RECVRETOPTS IP_RETOPTS
|
||||||
|
|
|
@ -129,7 +129,8 @@ struct inet_sock {
|
||||||
is_icsk:1,
|
is_icsk:1,
|
||||||
freebind:1,
|
freebind:1,
|
||||||
hdrincl:1,
|
hdrincl:1,
|
||||||
mc_loop:1;
|
mc_loop:1,
|
||||||
|
transparent:1;
|
||||||
int mc_index;
|
int mc_index;
|
||||||
__be32 mc_addr;
|
__be32 mc_addr;
|
||||||
struct ip_mc_socklist *mc_list;
|
struct ip_mc_socklist *mc_list;
|
||||||
|
|
|
@ -128,7 +128,8 @@ struct inet_timewait_sock {
|
||||||
__be16 tw_dport;
|
__be16 tw_dport;
|
||||||
__u16 tw_num;
|
__u16 tw_num;
|
||||||
/* And these are ours. */
|
/* And these are ours. */
|
||||||
__u8 tw_ipv6only:1;
|
__u8 tw_ipv6only:1,
|
||||||
|
tw_transparent:1;
|
||||||
/* 15 bits hole, try to pack */
|
/* 15 bits hole, try to pack */
|
||||||
__u16 tw_ipv6_offset;
|
__u16 tw_ipv6_offset;
|
||||||
unsigned long tw_ttd;
|
unsigned long tw_ttd;
|
||||||
|
|
|
@ -126,6 +126,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat
|
||||||
tw->tw_reuse = sk->sk_reuse;
|
tw->tw_reuse = sk->sk_reuse;
|
||||||
tw->tw_hash = sk->sk_hash;
|
tw->tw_hash = sk->sk_hash;
|
||||||
tw->tw_ipv6only = 0;
|
tw->tw_ipv6only = 0;
|
||||||
|
tw->tw_transparent = inet->transparent;
|
||||||
tw->tw_prot = sk->sk_prot_creator;
|
tw->tw_prot = sk->sk_prot_creator;
|
||||||
twsk_net_set(tw, hold_net(sock_net(sk)));
|
twsk_net_set(tw, hold_net(sock_net(sk)));
|
||||||
atomic_set(&tw->tw_refcnt, 1);
|
atomic_set(&tw->tw_refcnt, 1);
|
||||||
|
|
|
@ -419,7 +419,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
|
||||||
(1<<IP_TTL) | (1<<IP_HDRINCL) |
|
(1<<IP_TTL) | (1<<IP_HDRINCL) |
|
||||||
(1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
|
(1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
|
||||||
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
|
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
|
||||||
(1<<IP_PASSSEC))) ||
|
(1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
|
||||||
optname == IP_MULTICAST_TTL ||
|
optname == IP_MULTICAST_TTL ||
|
||||||
optname == IP_MULTICAST_LOOP) {
|
optname == IP_MULTICAST_LOOP) {
|
||||||
if (optlen >= sizeof(int)) {
|
if (optlen >= sizeof(int)) {
|
||||||
|
@ -878,6 +878,16 @@ static int do_ip_setsockopt(struct sock *sk, int level,
|
||||||
err = xfrm_user_policy(sk, optname, optval, optlen);
|
err = xfrm_user_policy(sk, optname, optval, optlen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IP_TRANSPARENT:
|
||||||
|
if (!capable(CAP_NET_ADMIN)) {
|
||||||
|
err = -EPERM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (optlen < 1)
|
||||||
|
goto e_inval;
|
||||||
|
inet->transparent = !!val;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = -ENOPROTOOPT;
|
err = -ENOPROTOOPT;
|
||||||
break;
|
break;
|
||||||
|
@ -1130,6 +1140,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
|
||||||
case IP_FREEBIND:
|
case IP_FREEBIND:
|
||||||
val = inet->freebind;
|
val = inet->freebind;
|
||||||
break;
|
break;
|
||||||
|
case IP_TRANSPARENT:
|
||||||
|
val = inet->transparent;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче