I got a program which does
...
/* Only rx/tx packets on the interface */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
...
}
...
for each given ethernet interface and uses UDP.
I want every interface to use the same IP I specified (for example: 50.0.0.1/24).
So that packets coming out from eth0 tell "my source IP is 50.0.0.1"
and packets from eth1 tell the same("source IP: 50.0.0.1").
Both receiving and sending in required.
Is there any way to achieve this?
I've tried
addr.sin_addr.s_addr = inet_addr("50.0.0.1");
...
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
but it won't work (error: cannot assign IP address) unless I set an unrelated interface's IP to 50.0.0.1.
After that, the packets coming out say "source IP: 50.0.0.1" but sending packets with "source IP: 50.0.0.X" to the machine (which runs the above program), it will not receive any.
You can't bind a socket to an interface and an IP at the same time, only one or the other. If an interface is bound, its IP gets used. If an IP is bound, its interface gets used.
And, you can't use bind() to set a source IP that does not belong to the bound interface.
On some platforms (Linux, etc), you can use sendmsg() with IP_PKTINFO to specify a source IP for outgoing packets. However, the OS will lookup and use the interface that belongs to the specified IP, which could be different than the bound interface, so this doesn't address your issue.
So, you will likely have to use a RAW socket and send your UDP packets with a custom IP header, then you can populate that header however you want.
I found the solution.
ip addr add 50.0.0.1/24 dev eth0
ip addr add 50.0.0.1/24 dev eth1
Start the program which does
setsocketopt(fd1, SOL_SOCKET, SO_BINDTODEVICE, "eth0", strlen("eth0"));
...
setsocketopt(fd2, SOL_SOCKET, SO_BINDTODEVICE, "eth1", strlen("eth1"));
Works like a charm.
They all send packets with source IP "50.0.0.1".
And are able receive packets belong to 50.0.0.0/24 network.
The output packets will not go to the wrong interface due to the socket is bond to specific interface(SO_BINDTODEVICE socket option).
Related
This is a macOS question. I am trying to setup a UDP socket that receives SSDP messages, i.e. UDP packets, sent to multicast addresses. I want to restrict receiving these packets from a single network interface.
I tried
int fd = socket(AF_INET, SOCK_DGRAM, 0);
char* itf = "en0";
int res = setsockopt(fd, SOL_SOCKET, IP_RECVIF, itf, strlen(itf));
The setsockopt call fails with errno 42 (Protocol not available).
I have also found SO_BINDTODEVICE that can be used for the same purpose, but it seems that this is not available on macOS.
Using bind with port and address also does not work. Then no packets sent to the multicast address are received on that socket.
From the OSX documentation on IP multicast...
A host must become a member of a multicast group before it can receive datagrams sent to the group. To join a multicast group, use the IP_ADD_MEMBERSHIP option...
To receive multicast traffic on a specific interface you need to tell the OS that you want to join that multicast group. Follow these steps (you were almost there)...
Create a datagram socket (done).
Bind to INADDR_ANY with the expected port.
Join the multicast group via setsockopt() with the IP_ADD_MEMBERSHIP option. Here you can pass the IP address of the specific network interface you wish to receive multicast traffic on in the ip_mreq struct.
Note: the question was edited.
I have few questions on Berkeley Socket Programming:
Is it possible to change a socket address after binding? If so- What are the C commands to do so?
2.According to https://www.cs.cmu.edu/~srini/15-441/F01.full/www/assignments/P2/htmlsim_split/node18.html, when a socket is bind to INADDR_ANY, it receives packets from all interfaces, but when a packet is sent,(using sent command) it sends through a single NIC with the default IP.
If I understand correctly- if a server has two active NICs, with different IPs, then a socket with the INADDR_ANY parameter can receive a packet with dst IP=x and send a packet with src IP=y, where x is not y. This can cause problems, for example in TCP connections, where the socket in the other destination is will receive the packet, but will drop it due as the dest IP is not the one expected.
Is it true? And if so- does it means that server programs are NOT using INADDR_ANY where there are (two or more) active NICs with different IPs?
Suppose the NIC of the default IP causes bottleneck. Can we change the socket options so that the packets will be send through another NICs(and not the previous NIC)? Can we do so if the NICs have the default IP address?
Can we send packets through one NIC, and set the IP destination to another NIC? (I.e, NIC1 will only send packets, and NIC2 will only receive packets )
Is it possible to change a socket address after created?
Sockets don't have an IP address to change when created. They get one when bound.
If so- What are the C commands to do so?
The Berkeley Sockets API functions to do so are bind() and connect().
When a socket is bind to INADDR_ANY, it receives packets from all interfaces, but sends through a single NIC with the default IP.
No. It sends packets via whichever NIC is necessary to reach the target in each case.
Your cited source draws a distinction without a difference. A socket bound to INADDR_ANY receives packets from any interface. There is no difference between 'any' and 'all' as far as INADDR_ANY is concerned. It is far easier to understand as 'any'.
If I understand correctly- if a server has two active NICs, with different IPs, then a socket with the INADDR_ANY parameter can receive a packet with dst IP=x and send a packet with src IP=y, where x is not y
No. It sends the packet with the same source address the client originally connected to. That's part of what defines the connection.
This can cause problems, for example in TCP connections, where the socket in the other destination is will receive the packet, but will drop it due as the dest IP is not the one expected.
No. The destination in the packet is the client's IP address. Otherwise it wouldn't even get there. This is just nonsense. If you mean the source IP, see above.
Is it true?
No.
And if so- does it means that server programs are NOT using INADDR_ANY where there are (two or more) active NICs with different IPs?
No. INADDR_ANY means exactly what it says. Any IP address: any NIC.
Suppose the NIC of the default IP causes bottleneck. Can we change the socket options so that the packets will be send through another NICs (and not the previous NIC)?
No, but you can alter the IP routing tables.
Can we do so if the NICs have the default IP address?
Only one of them can have the default IP address. The question doesn't make sense.
Can we send packets through one NIC, and set the destination to another NIC?
Only if you're sending to yourself. Otherwise the question doesn't make sense.
(from your citation) When sending, a socket bound with INADDR_ANY binds to the default IP address, which is that of the lowest-numbered interface
I hope this refers to whatever simulator is being described. If it is meant to be a description of how TCP works it is wrong.
I am doing raw socket programming in C. I am creating my own ethernet, ip and tcp headers. Then I add data to the packet and send it. Then I need to wait for response from the other program.
I have one computer. So using lo as my interface. I have something like
CreateSocket
BindSocketToInterface
Sendto
recvfrom
Now it is receiving it's own data which is undesirable. So I am thinking to bind socket to specific address.
Can I do it?
Also How to do it??
Can select solve this problem ??
Thanks :)
Like if you want interface then as follows
char *opt;
opt = "eth0";
setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, 4);
But if you want port address then
You cannot bind a raw socket to a specific port because "port" is a concept in TCP and UDP, not IP. Look at the header diagrams for those three protocols and it should become obvious: you are working at a lower level, where the concept of port is not known.
you can use setsockopt to bind it to a specific device.
struct ifreq *ifr = <populate some values>;
setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)ifr, sizeof(struct ifreq))
Try the above code and it should work. populate the ifreq correctly for the required network device.
I have a created a UDP socket and bind that socket to inaddr_any (0.0.0.0) and and some
well known port number. As per my understanding this socket can receive data over all the interfaces of the machine over the specified port number.
But When i will call send() it will use the default IP address as the source address.
How is the default IP address chosen?
If I want to use some other interface (other than the default) for sending the data, how can this be done?
Context of the problem:
I am implementing LDP protocol. It can have many hello adjacencies. Thus i am creating a server to recv data from the other interfaces of the router. Once the hello adjacency is formed, then hello messages are to sent be on the specific interface over UDP over which the hello adjacency is created.
The default IP address is chosen based on the network the packet is sent to. For example if you have two interfaces, one connected to network A and the other connected to network B, if you send a packet to network B the packet will be sent with the IP address of the second interface. For this reason, most of the time you don't have to worry about it.
If you have two network interfaces connected to the same network, you can bind the socket to the address of one of them, and the packet will go out with that address. For example, this will bind an IP socket to 192.168.122.1, if allowed by the network stack:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.122.1");
addr.sin_port = 0;
if (bind(s, (struct sockaddr*) &addr, sizeof addr) == -1) {
perror("bind");
}
I am using BSD sockets in Ubuntu 9.10 to send UDP packets in broadcast with the following code:
sock_fd = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
//sock_fd=socket(AF_INET,SOCK_DGRAM,0);
receiver_addr.sin_family = PF_INET;
//does not send with broadcast in ad hoc
receiver_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
inet_aton("169.254.255.255",&receiver_addr.sin_addr);
receiver_addr.sin_port = htons(port);
int broadcast = 1;
// this call is what allows broadcast packets to be sent:
if (setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof broadcast) == -1) {
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
ret=sendto(sock_fd, packet, size, 0,(struct sockaddr*)&receiver_addr,sizeof(receiver_addr));
Note that is not all the code, it is only to have an idea.
The program sends all the data with INADDR_BROADCAST if I am connected to an infrastructure wireless network. However, if my laptop is connected to an ad-hoc network, it is able to receive all the data, but not to send it. I have solved the problem using the 169.254.255.255 broadcast address, but I would like to know what is going on.
Thank you in advance!
Do you have more than one adapter (i.e. wired ethernet, WLAN)?
When you send to the limited broadcast address (INADDR_BROADCAST) your IP stack uses the first adapter and sends the frame. You dont have any control about choosing a specific adapter. The IP stack has done it's job, when it sends to the first adapter found. The frame would be flooded over the whole Internet if this would not be prevented by routers. That's why UDP broadcast are not routable by default. (Exceptions exist as implemented in DHCP relays.)
When you need to send a UDP frame on a specific network, you need the network broadcast address. You did this already, when you send to 169.254.255.255 on a AUTOIP net.
The setsocket(SOL_SOCKET, SO_BROADCAST) just configures the socket to allow sending broadcast at all.