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");
}
Related
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).
I'm trying to run an UDP Client-Server message exchange program for a university course, when I try it in a local network even with different PCs works really fine. But the moment I try to run it on different internet connections it seems like the server doesn't receive anything. I am running Ubuntu and allowed the specific port for UDP connection but maybe I'm missing something else
Server side:
int sockfd;
struct sockaddr_in servaddr;
//creating socket file descriptor
if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0 , sizeof(servaddr));
//filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
//bind the socket with server address
if( bind(sockfd,(const struct sockaddr *) &servaddr ,sizeof(servaddr)) < 0){
perror("bind failed");
exit(EXIT_FAILURE);
}
Client side:
int main(int argc, char ** argv) {
int sockfd;
char username[MAXLENGHT];
struct sockaddr_in servaddr;
//creating socket file descriptor
if( (sockfd = socket(AF_INET,SOCK_DGRAM, 0)) < 0 ){
perror("socket creation failed!");
exit(EXIT_FAILURE);
}
memset(&servaddr,0, sizeof(servaddr));
//filling server info
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
I am using as address 192.168.1.179 and the port I am using is 8080
... when I try it in a local network even with different PCs works really fine.
For this reason I doubt that it is a problem in your program.
maybe I'm missing something else
First of all, most internet connections today use a NAT.
This means that one internet access (e.g. at your home) has one IP address in the internet (called the "global address") and multiple computers share that IP address.
The computer's IP address (e.g. 192.168.1.179) is only valid in the local network; in other local networks, there are other computers having that address.
If you send a UDP packet to the IP address of the computer (192.168.1.179), both computers must be in the same local network.
If you send a UDP packet to the "global IP address" of the internet access, the router does not know which computer shall receive the packet because all computers in the local network share the same "global address".
You may configure your router (e.g. WLAN router) in a way that it knows that UDP packets from the internet to port 8080 shall be sent to the computer 192.168.1.179. This is called "port forwarding".
The sending computer must send the UDP packet to the "global IP address" of the internet access, not to the IP address of the computer (192.168.1.179) in this case.
And if it's not your internet access (e.g. it is not your WLAN router), you already have a problem here.
However, because this has nothing to do with programming, it is out of scope on this web site; you might ask further questions on the SuperUser web site, which also belongs to the StackExchange network. Your account (user name and password) is valid on all StackExchange web sites.
Today, many internet connections even use CGNAT.
This means that even multiple customers share one IP address in the internet.
In this case, it depends on your internet provider if it is possible at all to receive UDP packets:
If your internet access shares the IP address with another person that also wants to receive UDP packets on port 8080, there is a problem...
I have a UDP client program that uses Berkley sockets and Winsock (depending on the platform).
Basically it uses getaddrinfo(), then socket(), then sendto(). sendto() takes the address info returned by getaddrinfo(). My code looks like this:
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_socktype = SOCK_DGRAM;
struct addrinfo *address;
getaddrinfo("127.0.0.1", "9999", &hint, &address);
SOCKET s = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
sendto(s, "test", 4, 0, address->ai_addr, address->ai_addrlen);
My question is, when is the local/ephemeral port number set? Is it set with the call to sendto()? If I send more data to a different server, does sendto() reuse the same ephemeral port number? How can I get the ephemeral port number (in a protocol independent way)? I know that knowing this may not be useful, and NAT can change it anyway, but I'm just trying to understand how it all works better.
I also know I can use bind() to set the local port, but my question is about what happens when the OS chooses the local port for me.
You want the getsockname function:
struct sockaddr_storage ss;
socklen_t len;
len = sizeof(ss);
if (getsockname(s, (struct sockaddr *)&ss, &len) == 0) {
// print contents of ss
}
It populates the given sockaddr with the address and port that the socket is bound to.
This function is available in both winsock and Berkely sockets.
MSDN's documentation for sendto() states:
Note If a socket is opened, a setsockopt call is made, and then a sendto call is made, Windows Sockets performs an implicit bind function call.
If the socket is unbound, unique values are assigned to the local association by the system, and the socket is then marked as bound. If the socket is connected, the getsockname function can be used to determine the local IP address and port associated with the socket.
If the socket is not connected, the getsockname function can be used to determine the local port number associated with the socket but the IP address returned is set to the wildcard address for the given protocol (for example, INADDR_ANY or "0.0.0.0" for IPv4 and IN6ADDR_ANY_INIT or "::" for IPv6).
You can bind to port zero (0) which will cause OS to find an open ephemeral port that you can discover with getsockname, or return EADDRINUSE, even before you tried to send anything.
As for when an ephemeral port is allocated by the operating system, from ip(7) Linux manual page:
[...] An ephemeral port is allocated to a socket in the following
circumstances:
the port number in a socket address is specified as 0 when
calling bind(2);
listen(2) is called on a stream socket that was not previously bound;
connect(2) was called on a socket that was not previously
bound;
sendto(2) is called on a datagram socket that was not previously bound.
I am trying to create Linux tool with multiple TCP connections, which supports both IPv4 and IPv6 so I choose to use "sockaddr_storage".
Now, my question is, how do I bind client side socket to a specified (or random) TCP port?
For TCP client side, in one thread, if I just create 10 sockets and then connect() to server, then those 10 sockets will use sequential TCP ports in client side, for example, starting from 54594, then 54596, 54600, 54602, etc.
Now, I would like to bind those client sockets to different (randomized) TCP ports, how do I do with sockaddr_storage?
Thanks!
=============adding code ============
struct sockaddr_storage local_addr;
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)
(*(struct sockaddr_in*)&local_addr).sin_port = 0;
local_addr_size = sizeof(local_addr);
bind(sockfd, (struct sockaddr *)&local_addr, local_addr_size);
............
connect(sockfd, p->ai_addr, p->ai_addrlen)
I would like to bind those client sockets to different (randomized) TCP ports
That happens automatically when you call connect() without calling bind() first. You don't need to write any code for this, and sockaddr_storage therefore doesn't come into it at all.
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.