openziti / ziti-tunnel-sdk-c

Apache License 2.0
44 stars 17 forks source link

tunnelers cannot intercept and spoof the same IP #443

Open scareything opened 2 years ago

scareything commented 2 years ago

Tunnelers cannot currently spoof and intercept a given IP. This situation arises with applications where a single endpoint acts as both a client and a server, and source IP of inbound connections needs to be preserved. SIP and RTP are two examples.

When a client connects to a service with sourceIp set, the hosting tunneler calls bind to set the local address of its connection with the server. In order for bind to succeed, the specified address must be local (assigned to a network interface on the host) - otherwise bind fails with EADDRNOTAVAIL*.

Tunnelers intercept packets by manipulating the operating system's route tables so that packets destined for intercepted IPs are routed to the tun interface that the tSDK is reading from. So essentially the tun read loop receives packets that are going to non-local addresses. Packets that are destined for local addresses (such as those that a hosting tunneler added for IP spoofing) are handled by the operating system's IP stack, and therefore cannot be intercepted by the tun interface because they will not be seen at the tSDK's tun read loop.

* The (Linux-only) IP_FREEBIND socket option is not helpful. While IP_FREEBIND does allow the bind to succeed, the subsequent connect to the server fails with ENETUNREACH if the socket's local address is not assigned to a network interface.

scareything commented 2 years ago

Perhaps the most obvious solution would be to create a server socket using the operating system's sockets API to listen on spoofed IPs. Indeed this could work, but would be cumbersome for services that contain multiple ports and/or ranges in the intercept configuration (a separate listener would be needed for each port).

Alternatively, all packets going to a given IP could be sniffed with a raw socket. Packets from the raw socket could then be fed into the tSDK (via on_packet), and the tSDK's existing service selection and packet processing logic wouldn't know the difference between packets that came from a raw socket or a tun interface.

The raw socket reader approach has been started in https://github.com/openziti/ziti-tunnel-sdk-c/tree/rawsock.forwarder.3

scareything commented 9 months ago

https://github.com/netfoundry/zfw can be used to work around this limitation.