I want to pass message between two devices, for an example devices are PCs. Currently I am using UDPServer.c and UDPClient.c for reference. By using this reference, I can pass messages, now I want to implement both side listen and send, also I want to create an API for sending message, that API can be used by other functions. May I need to use two different port for sending message and receiving message?? what is the best way to set up UDP socket programming for message passing??
From your description, it doesn't look like you need any more than what sendto()/recvfrom() already do. You might as well treat them as your "API" for message passing. Once you set up/open the socket, just send/recv as needed. You don't need to worry about different ports for sending/receiving; your example is fine. FYI, you can sendto/recvfrom on the same socket.
Related
I need to create two sockets listening on the same IP:port but on different interfaces:
socket0 receives UDP traffic sent to 224.2.2.2:5000 on interface eth0
socket1 receives UDP traffic sent to 224.2.2.2:5000 on interface eth1
It seemed pretty straight forward until I realized that Linux merges all of that into the same traffic. For example, say there's only traffic on eth1 and there's no activity on eth0. When I first create socket0 it won't be receiving any data but as soon as I create socket1 (and join the multicast group) then socket0 will also start receiving the same data. I found this link that explains this.
Now this actually makes sense to me because the only moment when I specify the network interface is when joining the multicast group setsockopt(socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,...) with ip_mreq.imr_interface.s_addr. I believe this specifies which interface joins the group but has nothing to do with from which interface your socket will receive from.
What I tried so far is binding the sockets to the multicast address and port, which behaves like mentioned above. I've tried binding to the interface address but that doesn't work on Linux (it seems to do so on Windows though), you don't receive any traffic on the socket. And finally, I've tried binding to INADDR_ANY but this isn't what I want since I will receive any other data sent to the port regardless of the destination IP, say unicast for example, and it will still not stop multicast data from other interfaces.
I cannot use SO_BINDTODEVICE since it requires root privileges.
So what I want to know is if this is possible at all. If it can't be done then that's fine, I'll take that as an answer and move on, I just haven't been able to find any way around it. Oh, and I've tagged the question as C because that's what we're using, but I'm thinking it really might not be specific to the language.
I haven't included the code for this because I believe it's more of a theoretical question rather than a problem with the source code. We've been working with sockets (multicast or otherwise) for a while now without any problems, it's just this is the first time we've had to deal with multiple interfaces. But if you think it might help I can write some minimal working example.
Edit about the possible duplicate:
I think the usecase I'm trying to achieve here is different. The socket is supposed to receive data from the same multicast group and port (224.2.2.2:5000 in the example above) but only from one specific interface. To put it another way, both interfaces are receiving data from the same multicast group (but different networks, so data is different) and I need each socket to only listen on one interface.
I think that question is about multiple groups on same port, rather than same group from different interfaces. Unless there's something I'm not seeing there that might actually help me with this.
Yes, you can do what you want on Linux, without root privileges:
Bind to INADDR_ANY and set the IP_PKTINFO socket option. You then have to use recvmsg() to receive your multicast UDP packets and to scan for the IP_PKTINFO control message. This gives you some side band information of the received UDP packet:
struct in_pktinfo {
unsigned int ipi_ifindex; /* Interface index */
struct in_addr ipi_spec_dst; /* Local address */
struct in_addr ipi_addr; /* Header Destination address */
};
The ipi_ifindex is the interface index the packet was received on. (You can turn this into an interface name using if_indextoname() or the other way round with if_nametoindex().
As you said on Windows the same network functions have different semantics, especially for UDP and even more for multicast.
The Linux bind() semantics for the IP address for UDP sockets are mostly useless. It is essentially just a destination address filter. You will almost always want to bind to INADDR_ANY for UDP sockets since you either do not care to which address a packet was sent or you want to receive packets for multiple addresses (e.g. receiving unicast and multicast).
Correct me if I'm wrong, but my understanding of sending a raw packet inevitably is defined as buffering an array of bytes in an array, and writing it to a socket. However, most example code I've seen so far tend towards sendto, rarely is send used, and I've never seen code other than my own use write. Am I missing something? What is with this apparent preoccupation with complicating code like this?
Why use send and sendto when write seems to me to be the obvious choice when dealing with raw sockets?
sendto is typically used with unconnected UDP sockets or raw sockets. It takes a parameter specifying the destination address/port of the packet. send and write don't have this parameter, so there's no way to tell the data where to go.
send is used with TCP sockets and connected UDP sockets. Since a connection has been established, a destination does not need to be specified, and in fact this function doesn't have a parameter for one.
While the write function can be used in places where send can be used, it lacks the flags parameter which can enable certain behaviors on TCP sockets. It also doesn't return the same set of error codes as send, so if things go wrong you might not get a meaningful error code. In theory you could also use write on a raw socket if the IP_HDRINCL socket option is set, but again it's not preferable since it doesn't support the same error codes as send.
I'm supposed to make a communicator in C, based on dgrams. I don't know what arguments should I pass to bind() function. I skimmed through most UDP-chat questions & codes here on StackOverflow but I still can't find any specific information on the issue.
What type of address structure should I use?
What port can I use? Any number bigger than 1024 ?
What IP adress do I bind my socket with? (most of people put INADDR_ANY but isn't it for receiving only?)
Also, do I need multiple sockets? One for receiving & another for sending messages.
What type of address structure should I use?
If you are using IPv4, use a sockaddr_in. If you want to use IPv6 instead, use a sockaddr_in6.
What port can I use? Any number bigger than 1024 ?
Yes, assuming no other program is already using that port number for its own UDP socket. (If another program is using the port number you chose, it will cause bind() to fail with errno EADDRINUSE)
What IP adress do I bind my socket with? (most of people put
INADDR_ANY but isn't it for receiving only?)
INADDR_ANY is what you generally want to use. It tells the OS that you want to receive incoming UDP packets on any of the computers network interfaces. (If you only wanted to receive UDP packets from a particular network interface, OTOH, e.g. only on WiFi, you could specify that network interface's IP address instead)
Also, do I need multiple sockets? One for receiving & another for
sending messages.
You can have multiple sockets if you want, but it's not necessary to do it that way. You can instead use a single socket for both sending and receiving UDP packets. One common pattern is to use a single socket, set to non-blocking mode, and something like select() or poll() to multiplex the input and output needs of your program. An alternative pattern would be to use two threads (one for sending and one for receiving), blocking I/O, and either one or two sockets (depending on whether you prefer to have the two threads share a socket, or give each thread its own socket). I prefer the single-threaded/single-socket/select() solution myself, as I think it is the least error-prone approach.
I'm wondering how feasible it is to be able to convert an AF_INET socket to use an AF_UNIX instead. The reason for this is that I've got a program which will open a TCP socket, but which we cannot change. To reduce overhead we would therefore like to instead tie this socket to use an AF_UNIX one for its communication instead.
So far, my idea has been to use LD_PRELOAD to achieve this---intercepting bind() and accept(), however it is not clear how best to achieve this, or even if this is the best approach.
So far, bind in bind(), if the socket type is AF_INET and its IP/port is the socket I wish to convert to AF_UNIX, I then close the sockd here, and open an AF_UNIX one. However, this seems to be causing problems further on in accept() -- because I am unsure what to do when the sockfd in accept() matches the one I wish to tell to use an AF_UNIX socket.
Any help kindly appreciated.
Jason
Your idea sounds perfectly feasible. In fact, I think it sounds like the best way to achieve what you want. I wouldn't expect very different, or even measurably different, overhead/performance though.
Of course you'd also have to intercept socket() in addition to bind() and accept(). In bind(), you could, for example, converted the requested TCP port to a fixed pathname /tmp/converted_socket.<port-number> or something like that.
I had a similar problem and came up with unsock, a shim library that does what you describe, and more.
unsock supports other address types like AF_VSOCK and AF_TIPC, and the Firecracker VM multiplexing proxy as well.
There are three key insights I want to share:
Since sockets are created for a particular address family using socket(2), and then later connected or bound using connect(2)/bind(2), you may be tempted to simply intercept socket and fix the address there.
One problem is that you may want to selectively intercept certain addresses only, which you don't know at the time of the call.
The other problem is that file descriptors may be passed upon you from another process (e.g., via AF_UNIX auxiliary mes, so you may not be able to intercept socket(2) in the first place.
In other words, you need to intercept connect(2), bind(2), and sendto(2).
When you intercept connect(2), bind(2), and sendto(2), you need to retroactively change the address family for socket(2). Thankfully, you can just create a new socket and use dup3(2) to reassign the new socket to the existing file descriptor. This saves a lot of housekeeping!
accept(2) and recvfrom(2) also need to be intercepted, and the returned addresses converted back to something the caller understands. This will inevitably break certain assumptions unless you do maintain a mapping back to the actual, non-AF_INET address.
I'm trying to use libpcap to sniff some "network interfaces" (loopback included).
In my example application, I have packets coming from the loopback in the ports 1234, 1235 and 1236. I found already a way to make libpcap filter only packets coming from these addresses, using libpcap_setfilter(): my goal was to forward these packets accordingly to the address/port from which they came (for example, packets coming from 127.0.0.1/1234 could go through the eth0 interface; packets coming from 127.0.0.1/1235 could be forwarded through the eth1; and the ones coming from 127.0.0.1/1236 could be forwarded though the eth2).
My question is: is there any way to know from exactly what port these packets came without having to look at their content? Can I, for example, set many filters and somehow know from what filter was the one who filtered my packet?
I've already read a lot of the documentation and of tutorials, but none seemed useful so far. I also will be ok if the answer is "it is not possible".
Thanks in advance.
The capture mechanisms atop which libpcap runs support only one filter, so libpcap has no APIs to set multiple filters.
You could, however, open multiple pcap_t's for the same network interface and apply different filters to them. Reading from multiple pcap_t's, however, is potentially platform-dependent. I infer from the "eth0", "eth1", and "eth2" that this is Linux, so you should be able to use select() or poll() or... on the return values from pcap_get_selectable_fd() on the pcap_t's and, if select() or poll() or... says a given descriptor is readable, call pcap_dispatch() on the corresponding pcap_t to process packets for that pcap_t.