Skip to content

Commit

Permalink
TPROXY: implemented IP_RECVORIGDSTADDR socket option
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Balazs Scheidler authored and David S. Miller committed Nov 17, 2008
1 parent 8164f1b commit e8b2dfe
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
4 changes: 4 additions & 0 deletions include/linux/in.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ struct in_addr {
/* BSD compatibility */
#define IP_RECVRETOPTS IP_RETOPTS

/* TProxy original addresses */
#define IP_ORIGDSTADDR 20
#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR

/* IP_MTU_DISCOVER values */
#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
#define IP_PMTUDISC_WANT 1 /* Use per route hints */
Expand Down
40 changes: 39 additions & 1 deletion net/ipv4/ip_sockglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#define IP_CMSG_RECVOPTS 8
#define IP_CMSG_RETOPTS 16
#define IP_CMSG_PASSSEC 32
#define IP_CMSG_ORIGDSTADDR 64

/*
* SOL_IP control messages.
Expand Down Expand Up @@ -126,6 +127,27 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
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)
{
Expand Down Expand Up @@ -160,6 +182,12 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)

if (flags & 1)
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)
Expand Down Expand Up @@ -421,7 +449,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
(1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
optname == IP_MULTICAST_TTL ||
optname == IP_MULTICAST_LOOP) {
optname == IP_MULTICAST_LOOP ||
optname == IP_RECVORIGDSTADDR) {
if (optlen >= sizeof(int)) {
if (get_user(val, (int __user *) optval))
return -EFAULT;
Expand Down Expand Up @@ -509,6 +538,12 @@ static int do_ip_setsockopt(struct sock *sk, int level,
else
inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
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 */
if (sk->sk_type == SOCK_STREAM) {
val &= ~3;
Expand Down Expand Up @@ -1022,6 +1057,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
case IP_PASSSEC:
val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
break;
case IP_RECVORIGDSTADDR:
val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
break;
case IP_TOS:
val = inet->tos;
break;
Expand Down

0 comments on commit e8b2dfe

Please sign in to comment.