I wish to know is there any way I can disable the UDP broadcast packet from the node A to not received by node A itself.
For braodcast I am simply using INADDR_BROADCAST and on the
receiver side I am using AI_PASSIVE | AI_NUMERICHOST.
No, this is fundamental property of broadcasting - every host on the subnet, including the sender, will have to process the packet all the way up the network stack. You options are:
Switch to multicast. This is preferred since multicast reduces the load on the whole network compared to broadcast, and because you can explicitly control multicast loopback with the IP_MULTICAST_LOOP socket option.
Don't bind(2) the destination port on the sending machine. This works but is sort of kludgy since it puts restrictions on application design and/or deployment.
Bind to interface, not just address.
#include <net/if.h>
#include <socket.h>
struct ifreq interface;
strcpy(interface.ifr_ifrn.ifrn_name, "eth0");
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(interface));
//... bind(fd,...) ...
This way data that didn't arrive at the interface specified (but originated from it instead) will not be received.
Here are results of my experiments with Python's socket library. Whether UDP broadcaster receives messages sent by itself is dependent on what address will you bind broadcasting socket to. For greater clarity, broadcaster's IP address was 192.168.2.1.
When binding to '192.168.2.255' or '' (empty address), broadcaster receives messages sent by itself
When binding to '192.168.2.1', '255.255.255.255' or '<broadcast>', broadcaster will NOT receive messages sent by itself
Receiver received broadcasted UDP messages in all these cases.
P.S. Tested on Python 2.7.9, OS Raspbian 8 (adaptation of Debian for Raspberry Pi), Linux kernel 4.4.38
Related
I have two UDP sockets bound to the same address and connected to addresses A and B. I have two more UDP sockets bound to A and B and not connected.
This is what my /proc/net/udp looks like (trimmed for readability):
sl local_address rem_address
3937: 0100007F:DD9C 0300007F:9910
3937: 0100007F:DD9C 0200007F:907D
16962: 0200007F:907D 00000000:0000
19157: 0300007F:9910 00000000:0000
According to connect(2): "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."
For some reason, my connected sockets are receiving packets that were destined for each other. eg: The UDP socket connected to A sends a message to A, A then sends a reply back. The UDP socket connected to B sends a message to B, B then sends a reply back. But the reply from A arrives at the socket connected to B and the reply from B arrives at the socket connected to A.
Why on earth would this be happening? Note that it happens randomly - sometimes the replies arrive at the correct sockets and sometimes they don't. Is there any way to prevent this or any situation under which connect is supposed to not work?
Ehm, as far as I can see there is no ordering guarantee.
From the man page:
SO_REUSEPORT (since Linux 3.9)
Permits multiple AF_INET or AF_INET6 sockets to be bound to an identical socket address. This option must be set on each socket (including the first socket) prior to calling bind(2) on the socket. To prevent port hijacking, all
of the processes binding to the same address must have the same effective UID. This option can be employed with both TCP and UDP sockets.
For TCP sockets, this option allows accept(2) load distribution in a multi-threaded server to be improved by using a distinct listener socket for each thread. This provides improved load distribution as compared to traditional
techniques such using a single accept(2)ing thread that distributes connections, or having multiple threads that compete to accept(2) from the same socket.
For UDP sockets, the use of this option can provide better distribution of incoming datagrams to multiple processes (or threads) as compared to the traditional technique of having multiple processes compete to receive datagrams on
the same socket.
So you're using something that is mainly seen as a option for servers (or in some cases clients, but ordering can never be guaranteed - especially in UDP) as a client.
I suspect your approach is wrong, and needs a rethink =)
PS. Just had a quick glance but IMHO it's a bug in your approach
I have opened a raw socket to get all the raw packets:
socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)
When a packet is received on an interface which is member of a LAG or bond, the kernel is sending the packets to the user application 2 times. One for the actual physical interface and another one for the bond interface. How can I restrict the kernel to lift the packet only for the interface which I am interested?
We can achieve it by binding the application interested interface to the socket. But I don't want to create multiple sockets (one for each interface) to avoid scalability issue. Is it possible to bind multiple interface to the raw socket dynamically?
Use SO_BINDTODEVICE socket option to bind to specific interface:
char *iface = "eth0";
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, iface, 4);
In this case you'll have to create separate socket for each interface.
Alternative solution would be to use bind(2) with INADDR_ANY.
You do not have a third option.
For my application, I need to intercept certain TCP/IP packets and route them to a different device over a custom communications link (not Ethernet). I need all the TCP control packets and the full headers. I have figured out how to obtain these using a raw socket via socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); This works well and allows me to attach filters to just see the TCP port I'm interested in.
However, Linux also sees these packets. By default, it sends a RST when it receives a packet to a TCP port number it doesn't know about. That's no good as I plan to send back a response myself later. If I open up a second "normal" socket on that same port using socket(PF_INET, SOCK_STREAM, 0); and listen() on it, Linux then sends ACK to incoming TCP packets. Neither of these options is what I want. I want it to do nothing with these packets so I can handle everything myself. How can I accomplish this?
I would like to do the same thing. My reason is from a security perspective… I am wanting to construct a Tarpit application. I intent to forward TCP traffic from certain source IPs to the Tarpit. The Tarpit must receive the ACK. It will reply with a SYN/ACK of its own. I do not want the kernel to respond. Hence, a raw socket will not work (because the supplied TCP packets are teed), I need to also implement a Divert socket. That's about all I know so far… have not yet implemented.
My application has opened an UDP socket that is bound to INADDR_ANY to listen to packets on all the interfaces my server has. I'm sending out replies through the same socket.
However, while sending a reply from the server, default IP is chosen by the IP layer of linux depending upon which interface is chosen for packet to going out. The IP associated with this interface may not be the destination address with which this UDP server got a query from a client. Thus source IP of the reply from server becomes different from the destination IP with which the query came. The client may be uncomfortable with such a reply.
Following link gives the behavior of INADDR_ANY with UDP:
http://www.cs.cmu.edu/~srini/15-441/F01.full/www/assignments/P2/htmlsim_split/node18.html
How can I change this default behavior and use a particular interface IP in the source address? That is more control on the application code to decide what will be the source address. Also it make sense that source address in the reply be same as the destination address with which the query came.
Assuming you have multiple interfaces (one of which has the correct ip) of course you can bind to an interface for outgoing response. Take a look at SO_BINDTODEVICE socket option.
int bind_sock2inf(int sock, char *interface_name)
{
int status = -1;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), interface_name);
if ( (status = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
(void *)&ifr, sizeof(ifr))) < 0) {
log_debug(4, "Failed binding to interface named %s", inf_name);
}
else log_debug(3, "Binding to interface %s", inf_name);
return status;
}
Now your outgoing request should automatically use the ip address attached to this interface. The only down side is that you stop receiving messages on any other interface for this socket.
Possible work arounds are:
Use a separate socket for listening which is not bound to any interface and another one for sending and bind to whatever interface you need before sending.
Bind to interface before sending a message and bind to "" again which clears the previous bind immediately after sending. However, you might loose any packets received during this time frame which your socket was bound to interface say eth0 and packets arrived at eth1.
Also you can simply use bind() for associating a source ip for an outgoing packet.
Once a socket is bound to an address you can not bind it again to another address or you will get error EINVAL. But there is another technique described in this post Setting the source IP for a UDP socket
I have a Linux application that opens a UDP socket and binds it to a port. I haven't had any problem sending unicast packets through the socket. I had occasion to send a broadcast packet, so I enabled SO_BROADCAST, which allowed the broadcast packets to pass, but then I noticed that the unicast packets were being broadcast as well. Is this expected behaviour for a UDP socket, or is it more likely that I've misconfigured something?
From what I understand SO_BROADCAST is a socket option. So if you enable it on your socket this socket will broadcast. I guess you will need to open different sockets if you want to do unicast and broadcast from the same code.
I have not done much hands on programming here, but you probably need to provide more information about the library, OS version, code, etc. Maybe a code sample?
If I remember the books I read, if you set the flag on the socket, that is going to affect all datagrams sent from the socket, because the socket is a basically a data structure of network flags + a file descriptor.
I have figured out the same issue on Linux about having a socket getting unicast and broadcast at the same time. I solved the problem as follow (pseudo-code):
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
Open the socket
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &1)
Allows incoming and outgoing broadcast from this socket
bind(sock, bindaddr, sizeof(struct sockaddr) with
bindaddr.sin_family = AF_INET
bindaddr.sin_port = <YourPort>
bindaddr.sin_addr.s_addr = INADDR_ANY
Get all incoming messages on any card for <YourPort>
The caveat is that there is no filtering (see caveat in 3.). So you will get all messages.
The sent messages are either unicasted or broadcasted depedning on the given address in the sendto().