diff options
author | Balazs Scheidler <bazsi@balabit.hu> | 2008-11-16 22:32:39 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-16 22:32:39 -0500 |
commit | e8b2dfe9b4501ed0047459b2756ba26e5a940a69 (patch) | |
tree | 6f7d497284a8951b8681517f7866851b32a7b02e /net/ipv4/ip_sockglue.c | |
parent | 8164f1b79731ad8ad9c713dc53d587a3b746f82f (diff) |
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>
Diffstat (limited to 'net/ipv4/ip_sockglue.c')
-rw-r--r-- | net/ipv4/ip_sockglue.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index e976efeb1456..624b534201e2 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #define IP_CMSG_RECVOPTS 8 | 48 | #define IP_CMSG_RECVOPTS 8 |
49 | #define IP_CMSG_RETOPTS 16 | 49 | #define IP_CMSG_RETOPTS 16 |
50 | #define IP_CMSG_PASSSEC 32 | 50 | #define IP_CMSG_PASSSEC 32 |
51 | #define IP_CMSG_ORIGDSTADDR 64 | ||
51 | 52 | ||
52 | /* | 53 | /* |
53 | * SOL_IP control messages. | 54 | * SOL_IP control messages. |
@@ -126,6 +127,27 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) | |||
126 | security_release_secctx(secdata, seclen); | 127 | security_release_secctx(secdata, seclen); |
127 | } | 128 | } |
128 | 129 | ||
130 | void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) | ||
131 | { | ||
132 | struct sockaddr_in sin; | ||
133 | struct iphdr *iph = ip_hdr(skb); | ||
134 | u16 *ports = (u16 *) skb_transport_header(skb); | ||
135 | |||
136 | if (skb_transport_offset(skb) + 4 > skb->len) | ||
137 | return; | ||
138 | |||
139 | /* All current transport protocols have the port numbers in the | ||
140 | * first four bytes of the transport header and this function is | ||
141 | * written with this assumption in mind. | ||
142 | */ | ||
143 | |||
144 | sin.sin_family = AF_INET; | ||
145 | sin.sin_addr.s_addr = iph->daddr; | ||
146 | sin.sin_port = ports[1]; | ||
147 | memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); | ||
148 | |||
149 | put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin); | ||
150 | } | ||
129 | 151 | ||
130 | void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) | 152 | void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) |
131 | { | 153 | { |
@@ -160,6 +182,12 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) | |||
160 | 182 | ||
161 | if (flags & 1) | 183 | if (flags & 1) |
162 | ip_cmsg_recv_security(msg, skb); | 184 | ip_cmsg_recv_security(msg, skb); |
185 | |||
186 | if ((flags>>=1) == 0) | ||
187 | return; | ||
188 | if (flags & 1) | ||
189 | ip_cmsg_recv_dstaddr(msg, skb); | ||
190 | |||
163 | } | 191 | } |
164 | 192 | ||
165 | int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) | 193 | 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, | |||
421 | (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | | 449 | (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | |
422 | (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) || | 450 | (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) || |
423 | optname == IP_MULTICAST_TTL || | 451 | optname == IP_MULTICAST_TTL || |
424 | optname == IP_MULTICAST_LOOP) { | 452 | optname == IP_MULTICAST_LOOP || |
453 | optname == IP_RECVORIGDSTADDR) { | ||
425 | if (optlen >= sizeof(int)) { | 454 | if (optlen >= sizeof(int)) { |
426 | if (get_user(val, (int __user *) optval)) | 455 | if (get_user(val, (int __user *) optval)) |
427 | return -EFAULT; | 456 | return -EFAULT; |
@@ -509,6 +538,12 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
509 | else | 538 | else |
510 | inet->cmsg_flags &= ~IP_CMSG_PASSSEC; | 539 | inet->cmsg_flags &= ~IP_CMSG_PASSSEC; |
511 | break; | 540 | break; |
541 | case IP_RECVORIGDSTADDR: | ||
542 | if (val) | ||
543 | inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR; | ||
544 | else | ||
545 | inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR; | ||
546 | break; | ||
512 | case IP_TOS: /* This sets both TOS and Precedence */ | 547 | case IP_TOS: /* This sets both TOS and Precedence */ |
513 | if (sk->sk_type == SOCK_STREAM) { | 548 | if (sk->sk_type == SOCK_STREAM) { |
514 | val &= ~3; | 549 | val &= ~3; |
@@ -1022,6 +1057,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, | |||
1022 | case IP_PASSSEC: | 1057 | case IP_PASSSEC: |
1023 | val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0; | 1058 | val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0; |
1024 | break; | 1059 | break; |
1060 | case IP_RECVORIGDSTADDR: | ||
1061 | val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0; | ||
1062 | break; | ||
1025 | case IP_TOS: | 1063 | case IP_TOS: |
1026 | val = inet->tos; | 1064 | val = inet->tos; |
1027 | break; | 1065 | break; |