How to Get Original Destination Port of Redirected Udp Message

How to get original destination port of redirected UDP message?

Depends on the redirection mechanism. If you are using REDIRECT (which is NAT under the hood), then you need to use SO_ORIGINAL_DST, or libnetfilter_conntrack to query the original destination of the connection before NAT was applied. However since you can serve several connections with the same listener socket, this lookup has to be done for every packet.

You can experiment with libnetfilter_conntrack and the services it provides using the conntrack command line tool.

An alterntive is to use TPROXY for the redirection, which was meant to be used in cases like this. There you can get the original destination of the packet using an ancillirary message using recvmsg(). The key to look for is the IP_RECVORIGDST setsockopt.

More information on TPROXY can be found in the kernel Documentation directory, in a file called tproxy.txt. It is a bit difficult to use, but works more reliably as it is implemented by the stack, rather than the packet filtering subsystem.

Edited: to add how to query UDP destination addresses with TProxy.

  1. open an UDP socket, bind it to 0.0.0.0 or to a more specific IP
  2. you enable IP_RECVORIGDST via setsockopt(fd, SOL_IP, IP_RECVORIGDSTADDR, ...)
  3. you use recvmsg() instead of recvfrom()/recv() to receive frames
  4. recvmsg() will return the packet and a series of ancillary messages,
  5. iterate the ancillary messages, and locate the CMSG block with level SOL_IP, index IP_ORIGDSTADDR
  6. this CMSG block will contain a struct sockaddr_in with both the IP and the port information.

Edited: SO_ORIGINAL_DST vs. udp

SO_ORIGINAL_DST should work with udp sockets, however the kernel doesn't let you specify the connection endpoints, it'll use the socket that you call SO_ORIGINAL_DST on to get this address information.

This means that it'll only work, if the UDP socket is properly bound (to the redirected-to address/port) and connected (to the client in question). Your listener socket is probably bound to 0.0.0.0 and is servicing not just a single, but mulitple clients.

However, you don't need to use your actual listener socket to query the destination address. Since since UDP doesn't transmit datagrams on connection establishment, you can create a new UDP socket, bind it to the redirect address and connect it to the client (whose address you know since it sent the first packet to your listener anyway). Then you could use this socket to run SO_ORIGINAL_DST on, however there are culprits:

  1. once you open such a socket, the kernel will prefer that if the client would send additional packets after the first one, not your listener socket
  2. this is inherently racy, since by the time your application has a chance to call SO_ORIGINAL_DST, the conntrack entry may have timed out.
  3. it is slow and a lot of overhead

The TProxy based method is clearly better.

Retrieving original destination from iptables after REDIRECT

Perhaps this is what you were looking for?

http://www.network-builders.com/iptables-redirect-original-destination-ip-t69515.html

Read the SO_ORIGINAL_DST option of the TCP socket.

Or look up the connection tracking table in /proc/net/ip_conntrack.

#include <linux/netfilter_ipv4.h>

struct sockaddr_in addr;
socklen_t addr_sz = sizeof(addr);
memset(&addr, 0, addr_sz);
addr.sin_family = AF_INET;
getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, &addr, &addr_sz);

 
I think you should be able to convert that to something similar for python.

Getting UDP Destination Address:Port from TPROXY'd Traffic

I believe I was setting the iov_len to the size of a const char* by doing sizeof(buffer), thus getting essentially no writable space. Upon fiddling with declarations and ending up at this, I obtained the IP and port correctly with the cmsg loop. I still don't know why TPROXY warps the packets when viewing them through a raw socket, which would be interesting to know.

iov.iov_base = cPacket;
iov.iov_len = BUFSIZE;

mHeader.msg_name = &sSourceAddr; //sockaddr_storage
mHeader.msg_namelen = sizeof(struct sockaddr_in);
mHeader.msg_iov = &iov;
mHeader.msg_iovlen = 1;
mHeader.msg_control = cControl;
mHeader.msg_controllen = BUFSIZE;

for (cmsghdr *cmsg = CMSG_FIRSTHDR(&mHeader); cmsg != NULL; cmsg = CMSG_NXTHDR(&mHeader, cmsg))
{
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_ORIGDSTADDR) continue;
std::memcpy(&sDestIP, CMSG_DATA(cmsg), sizeof(sockaddr_in));
iPort = ntohs(sDestIP.sin_port);
sAddress = sDestIP.sin_addr;
}

Python/iptables: Capturing all UDP packets and their original destination

I found your question interesting.

The following solution is based on marking the UDP traffic generated by the host and re-routing it back to the local host application. At the application, a UDP socket should be used to read the data, even one that is not destined for the host itself (see below how).

Networking settings:

  • Mark the UDP traffic that exits the host
  • Traffic that is marked with 1, pass to routing table 100 for
    processing
  • Route traffic to the application
iptables -A OUTPUT -t mangle -p udp -j MARK --set-mark 1
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

Socket settings:

  • Create UDP socket (regular)
  • Enable binding/reading for non local addresses
#ifndef IP_TRANSPARENT
#define IP_TRANSPARENT 19
#endif

int val = 1;
setsockopt(sockfd, SOL_IP, IP_TRANSPARENT, &val, sizeof(val));

You should be able now to read from the socket.
Tip form Etienne Perot: For accepting all UDP traffic, bind to 0.0.0.0.

What I found here very interesting, is that locally generated traffic (and not routed one) may be classified and re-routed using iptables and route rules.

Hope this helps.

Get destination addres for UDP in nodejs

It is currently not possible.

See this Github bug link

Workaround:

  • have different internal ports for the broadcast and the normal traffic.
  • Use iptables to redirect broadcast traffic to one of the internal port and the other traffic to the other port.

C++ DGRAM socket get the RECEIVER address

On Linux you want to use IP_PKTINFO option, see ip(7), and the recvmsg(2) call.

Stevens has examples of doing this but with IP_RECVDSTADDR and IP_RECVIF options that are not available on Linux.

How to read tcp packets, which have been redirected to localhost?

You could just use libpcap which will capture any traffic occurring on the ethernet device, and then just filter out what you want/need.

You cant make a connection to a port if there is no service listening on it, even with DNAT. You need to explain exactly what your trying to accomplish, explain your network setup and what data your trying to capture.



Related Topics



Leave a reply



Submit