TPROXY: implemented IP_RECVORIGDSTADDR socket option
In case UDP traffic is redirected to a local UDP socket, the originally addressed destination address/port cannot be recovered with the in-kernel tproxy. This patch adds an IP_RECVORIGDSTADDR sockopt that enables a IP_ORIGDSTADDR ancillary message in recvmsg(). This ancillary message contains the original destination address/port of the packet being received. Signed-off-by: Balazs Scheidler <bazsi@balabit.hu> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
8164f1b797
Коммит
e8b2dfe9b4
|
@ -80,6 +80,10 @@ struct in_addr {
|
||||||
/* BSD compatibility */
|
/* BSD compatibility */
|
||||||
#define IP_RECVRETOPTS IP_RETOPTS
|
#define IP_RECVRETOPTS IP_RETOPTS
|
||||||
|
|
||||||
|
/* TProxy original addresses */
|
||||||
|
#define IP_ORIGDSTADDR 20
|
||||||
|
#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR
|
||||||
|
|
||||||
/* IP_MTU_DISCOVER values */
|
/* IP_MTU_DISCOVER values */
|
||||||
#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
|
#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
|
||||||
#define IP_PMTUDISC_WANT 1 /* Use per route hints */
|
#define IP_PMTUDISC_WANT 1 /* Use per route hints */
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#define IP_CMSG_RECVOPTS 8
|
#define IP_CMSG_RECVOPTS 8
|
||||||
#define IP_CMSG_RETOPTS 16
|
#define IP_CMSG_RETOPTS 16
|
||||||
#define IP_CMSG_PASSSEC 32
|
#define IP_CMSG_PASSSEC 32
|
||||||
|
#define IP_CMSG_ORIGDSTADDR 64
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SOL_IP control messages.
|
* SOL_IP control messages.
|
||||||
|
@ -126,6 +127,27 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
|
||||||
security_release_secctx(secdata, seclen);
|
security_release_secctx(secdata, seclen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct iphdr *iph = ip_hdr(skb);
|
||||||
|
u16 *ports = (u16 *) skb_transport_header(skb);
|
||||||
|
|
||||||
|
if (skb_transport_offset(skb) + 4 > skb->len)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* All current transport protocols have the port numbers in the
|
||||||
|
* first four bytes of the transport header and this function is
|
||||||
|
* written with this assumption in mind.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_addr.s_addr = iph->daddr;
|
||||||
|
sin.sin_port = ports[1];
|
||||||
|
memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
|
||||||
|
|
||||||
|
put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin);
|
||||||
|
}
|
||||||
|
|
||||||
void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
|
void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -160,6 +182,12 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
|
||||||
|
|
||||||
if (flags & 1)
|
if (flags & 1)
|
||||||
ip_cmsg_recv_security(msg, skb);
|
ip_cmsg_recv_security(msg, skb);
|
||||||
|
|
||||||
|
if ((flags>>=1) == 0)
|
||||||
|
return;
|
||||||
|
if (flags & 1)
|
||||||
|
ip_cmsg_recv_dstaddr(msg, skb);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
|
int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
|
||||||
|
@ -421,7 +449,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
|
||||||
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
|
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
|
||||||
(1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
|
(1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
|
||||||
optname == IP_MULTICAST_TTL ||
|
optname == IP_MULTICAST_TTL ||
|
||||||
optname == IP_MULTICAST_LOOP) {
|
optname == IP_MULTICAST_LOOP ||
|
||||||
|
optname == IP_RECVORIGDSTADDR) {
|
||||||
if (optlen >= sizeof(int)) {
|
if (optlen >= sizeof(int)) {
|
||||||
if (get_user(val, (int __user *) optval))
|
if (get_user(val, (int __user *) optval))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -509,6 +538,12 @@ static int do_ip_setsockopt(struct sock *sk, int level,
|
||||||
else
|
else
|
||||||
inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
|
inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
|
||||||
break;
|
break;
|
||||||
|
case IP_RECVORIGDSTADDR:
|
||||||
|
if (val)
|
||||||
|
inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR;
|
||||||
|
else
|
||||||
|
inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
|
||||||
|
break;
|
||||||
case IP_TOS: /* This sets both TOS and Precedence */
|
case IP_TOS: /* This sets both TOS and Precedence */
|
||||||
if (sk->sk_type == SOCK_STREAM) {
|
if (sk->sk_type == SOCK_STREAM) {
|
||||||
val &= ~3;
|
val &= ~3;
|
||||||
|
@ -1022,6 +1057,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
|
||||||
case IP_PASSSEC:
|
case IP_PASSSEC:
|
||||||
val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
|
val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
|
||||||
break;
|
break;
|
||||||
|
case IP_RECVORIGDSTADDR:
|
||||||
|
val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
|
||||||
|
break;
|
||||||
case IP_TOS:
|
case IP_TOS:
|
||||||
val = inet->tos;
|
val = inet->tos;
|
||||||
break;
|
break;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче