How to stop behaviour: C++ Socket sendto changes interface - c++

I run Ubuntu 12.04 and I am currently writing C++ code to create a UDP socket, which sends packets to various destinations with sendto. Now it happens that my laptop has both a wlan0 and a eth0 interface. If I bind it to either one of these, using the IP address, and the SO_BINDTODEVICE option, depending on the destination address, sendto will still decide to use the other interface if it suits him.
Specifically, if I bind a UDP socket to the eth0 interface, with its ip address and some port, and I send a packet to another laptop (locally, with only wifi access), it will decide to use my wlan0 interface.
I understand that this behaviour has pros, but I would like to be able to turn it off, i.e. I want to be able to say to the socket that it should only use the one interface I assigned it.
Suggestions?
EDIT:
struct sockaddr_storage sa = address;
fd = socket(address.get_family(), SOCK_DGRAM, 0);
char *devname = "wlan0";
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, devname, strlen(devname));
bind(fd, (sockaddr*)&sa, len);

Binding a socket to an interface with SO_BINDTODEVICE or bind defines a filter for received packets. When a packet has not been received using the specified interface it is not passed to the socket's receive queue. See: http://linux.die.net/man/7/socket
But binding a socket to an interface does not affect the normal IP routing process. When you send a packet it's the responsibility of the network IP stack to find the best route and to send the IP packet over a hardware adapter. This can be an Ethernet adpter but it's not controller with and bind operation.
When you want to send a packet at a specific interface you need raw sockets. You construct the complete packet content including IP and hardware layer (probably Ethernet) and send it using the raw socket.

Related

Getting the destination IP of incoming UDP packet in C++

I found the function: GetTcpTable in C++. In the header: iphlpapi.h. That gives me the destination IP of TCP packet and I was wondering if there's a function from the same header that would give me the destination IP of UDP packet... I tried the function: GetUdpTable but it gives only the local IP and port. I will be more than happy if that function has also code example in C++ of course. Thank you anyway!
EDIT:
I using pcap.h now and i still don't know how to catch UDP packets and take from them the ip. There is a code that i can use?
GetTcpTable() does not give you the destination IP of TCP packets. It merely gives you a list of currently listening TCP ports and active TCP connections.
GetUdpTable() can give you the list of currently listening UDP ports, where UDP packets can be sent to. There are no connections in UDP.
But, if you want to know the actual destination IP for each UDP packet received, and without having to use a low-level capture library like WinPCap, then you can use the WSARecvMsg() function to receive your UDP packets, rather than using the recvfrom() or even recv() function.
WSARecvMsg() can report metadata about each packet, most notably the IP_PKTINFO (IPv4) and IPV6_PKTINFO (IPv6) control blocks, which specify the destination IP of the packet and the index of the network interface that received the packet.
You need to use WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER) to obtain a pointer to the WSARecvMsg() function (see Why is the WSARecvMsg function implemented as a function pointer and can this pointer be reused? for the reason why), and use setsockopt() to enable the IP_PKTINFO/IPV6_PKTINFO socket option, before you start calling WSARecvMsg() to receive packets.
See Function to retrieve the header destination address from a packet in windows XP for an example.

Connect a UDP socket, but still receive datagrams from other sources

Is it possible to set the default destination of a UDP socket just like connect does, but without loosing the ability to receive datagrams from other sources?
I'm talking about the native OS socket API (BSD-socket / winsock2) and I'm interested in answers for both linux and windows platforms.
[EDIT:]
In case this is unclear, here is the problematic part from the connect docs:
If the socket sockfd is of type SOCK_DGRAM then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received.
Is it possible to set the default destination of a UDP socket just
like connect does, but without loosing the ability to receive packages from other sources?
As far as I can tell, it is not -- connect() on a UDP socket both sets a default-send-destination and installs a filter so that incoming UDP packets from all other destinations than the specified address/port are dropped.
My solution to the problem was to just call sendto() and recvfrom() instead (if you have a UDPSocket class or similar in your codebase, you can cache the default-send address as a private member variable in that class, so that the rest of your codebase can just call a Send() method, and leave it to that method to handle the sendto() arguments)

Remote address of active UDP connections in Windows using IP Helper

The function GetUdpTable() in IP Helper returns a table of MIB_UDPROW.
MIB_UDPROW struct does not contain any information about the remote address of the UDP connection, the extended variants of GetUdpTable() only adds the pid to the return struct.
Is it possible to get the remote address for an active UDP connection using IP Helper (or any other winapi)?
No, it is not possible to get the remote port of the UDP connection unless you capture traffic and inspect the packets since UDP is a connectionless protocol.
See: Get Destination Ip/Port of active udp Connection?

How to Bind to the same UDP port on multiple interfaces

I have two network interfaces and am trying to bind to the same UDP port on both of them but I get an error when I try to bind to the second one, EADDRINUSE. When I bind to the sockets I pass a sockaddr* where I've setup the port and the unique IP address to use.
Do I have to use the socket option SO_REUSEADDR? Will this allow messages to be received on either socket or will they go to the socket that matches the IP address their bound to?
You can bind(2) one socket to INADDR_ANY for IPv4 or to in6addr_any for IPv6 (you don't have to, but that's the usual approach). That will make that single socket able to accept packets from all network interfaces on the box.
Then SO_REUSEADDR socket option will allow you to bind other sockets to more specific addresses, i.e. to individual interfaces, and same port.
Packets will be received on the socket that is bound to the address best matching the destination IP address of a given packet.

Cpp server, UDP socket for each client

When I'm trying to bind a UDP socket on a specific ip (other than 127.0.0.1/INADDR_LOOPBACK or 0.0.0.0/INADDR_ANY) it fails.
I need to have a dedicated UDP socket for each client (point to point connection).
If I don't bind the socket and use sendto and recvfrom function, the data never arrives.
Any obvious solution ?
You can't bind UDP sockets to nonlocal addresses -- binding a UDP socket to an address means that you want packets that are directed to that address, not ones that are being sent from that address. You'll need to figure out some way to share a single socket across all clients.