Can we detect different clients(devices) from same IP on TCPConnection ?
Example :
I have a TCP Server called s1 and I have 2 PCs called p1,p2 and my PCs IP is same (e.g. 1.2.3.4)
when I connect to s1 (my TCP Server) with p1 and p2 (Pc1 and Pc2) can s1(my TCP server) detect these clients with same IP, isn't same device ?
From my understanding you are basically asking to detect different devices behind a NAT, i.e. devices sharing the same external IP address. There is no fully reliable way to do this but one can employ heuristics. Typically these are based on the ID field in the IP header and/or the TCP timestamp option, see for example A Technique for Counting NATted Hosts or Time has something to tell us about Network
Address Translation. One might also try to use passive OS fingerprinting in order to detect if different OS are used (and thus different real or virtual devices) - see Passive Fingerprinting.
None of these heuristics are fully reliable though and they also will not work if the devices are behind a proxy, since in this case the TCP/IP connections visible to the server originate from a single device - the proxy.
Yes you can. The server can ask the operating system for the connection information of client associated with the socket. In 'C' this would look like:
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (new_socket<0)
{
perror("accept failed");
return 1;
}
The client sockaddr structure will be filled with the information about the connecting client. The server can look into this to extract the IP Address as a string doing something like:
char *ip = inet_ntoa((struct sockaddr_in *)client.sin_addr);
You can now see if ip matches p1 or p2.
Related
I am trying to send UDP packet to my server 10.20.1.2 with port number 20000. I have implemented UDP client on PC and when i send data using sendto API , at the same time i monitor data on wireshark wireshark shows it as an ARP packet.
18967 5440.858646 PcsCompu_ef:b4:89 Broadcast ARP 42 Who has 10.20.1.2? Tell 192.168.1.70
192.168.1.70 is my machine ip where UDP client is running.
I am not sure how UDP packet is getting converted into ARP packet ?
I understand ARP is for finding MAC address of target node but here i already know MAC address of target device , How can i add it in my udp client so it directly starts UDP communication . My target device is one embedded camera , i am not expecting it to reply on ARP request so i want to prevent sending ARP request.
Below is my UDP client code :
Any inputs are highly appreciated. Thanks in advance.
/*
Simple udp client
*/
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#define SERVER "10.20.1.2"
#define PORT 20000 //The port on which to send data
char message[3]={0x00, 0x00 , 0x24};
int main(void)
{
struct sockaddr_in si_other;
int s, i, slen=sizeof(si_other);
int ret;
if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("socket failed");
}
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SERVER , &si_other.sin_addr) == 0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
ret = sendto(s, message, sizeof(message) , 0 , (struct sockaddr *) &si_other, slen);
close(s);
return 0;
}
Some clarifications regarding networking.
1. ARP must be sent and replied
Your camera has IP interface, which means it must handle ARP requests fine without any doubts. ARP is essential part of communicating via IP, camera without ARP support makes no sense. And ARP isn't a result of converting UDP, it's a preliminary step before sending actual UDP datagram. Once ARP reply is discovered with destination MAC-address, UDP packet is sent to that destination. The issue you see isn't about hardcoding MAC to avoid ARP.
2. Your code looks fine
Compiled it locally with minor corrections (missing #include <unistd.h> header with close() declaration), tested on several targets, client works as expected.
3. Something is wrong with your network topology
You are sending message from 192.168.1.70 to 10.20.1.2, which is weird. 192.168.0.0/24 and 10.0.0.0/8 are private IP addresses from different ranges, so they normally can't reach each other without black magic (like NAT traversal). And, what is much weirder, during your attempt ARP request is sent to strange destination. Let me illustrate different cases:
if both devices are in same subnet (e.g. 192.168.1.70 sends to 192.168.1.71), then message is sent directly, so client asks "who has 192.168.1.71" in ARP request.
if devices are in different subnets (e.g. 192.168.1.70 sends to 8.8.8.8), then message is sent through gateway, thus ARP request reads "who has 192.168.1.1" or whatever your gateway address is. Gateway MAC may be already in cache, in which case ARP isn't sent at all.
in your case subnets are obviously different, but ARP is asking about direct destination address rather than gateway MAC address.
It's a shot in the dark, but probably you have two network interfaces on your PC, one connected to 192.168.0.0 subnet, the other to 10.0.0.0 and ARP request is sent from both. If you sniff the wrong interface, you see weird ARP request and don't see UDP, which is actually sent after it. By the way, seeing single arp request is also confusing, because it should be repeated several times if noone answers.
Anyway, you need to check network topology and/or simplify it. Remove unnecessary network interfaces, configure PC and camera to be on the same subnet connected to the same switch/router and investigate further.
I want to connect clients to a server using ZeroMQ (java bindings, jzmq), but I need the TCP information badly, for example the TCP/IP address of a client request! The problem is, for being able to announce a service in the network I need to grab the TCP address of a request to be able to redirect clients to that service. The broker is a central "service registry" in that case. However, having ZeroMQ services on both sides, I do not see an option to retrieve that information.
What I do now, is to establish a dummy connection using a standard socket to the broker, after the connection is established I grab the IP address used for this connection and close the connection again. The IP address which has been retrieved is now being used for binding on it using a ZeroMQ socket on a random port.
I think this solution is the ugliest solution ever possible, so: What is a better solution to this problem?
Greetings.
0MQ doesn't provide the address of peers, for a number of reasons. It's also not that useful since what you really want is the endpoint to receive connections on, not the address the connection was made on.
What I usually do, and it's elegant enough, is pass bind a service to an ephemeral port, get a full connection endpoint ("tcp://ipaddress:port") and send that string in some way, either broadcast to peers, to a central registry, etc. along with my service name. Then, peers who want to connect back can take the service name, look up to find my endpoint, and connect back to me.
In ZMQ 4.x, you may get the string property "Peer-Address" or the "Identity" property. http://api.zeromq.org/4-2:zmq-msg-gets
The Identity is set in the other peer before connect(). http://api.zeromq.org/4-2:zmq-setsockopt#toc20
For example,
const char *identityString = "identity";
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REQ);
socket.setsockopt(ZMQ_IDENTITY, identityString, strlen(identityString));
socket.connect("tcp://127.0.0.1:5555");
Then the other side:
while(1)
{
zmq::message_t request;
if (socket.recv(&request, ZMQ_NOBLOCK))
{
const char* identity = request.gets("Identity");
const char* peerAddress = request.gets("Peer-Address");
printf("Received from %s %s\n", peerAddress, identity);
break;
}
}
I'm using CppZmq btw, you should be able to find the relevant calls easily.
Digging deeper into the libzmq code, I discovered that the library attaches to every message instance the file descriptor that it was received on.
This worked for me
int sockfd = zmq_msg_get(&msg, ZMQ_SRCFD);
sockaddr_in addr;
socklen_t asize = sizeof(addr);
getpeername(sockfd, (sockaddr*)&addr, &asize);
std::cout << inet_ntoa(addr.sin_addr) << ":" << addr.sin_port << std::endl;
Note that the FDs can and will be reused by other connections.
I'm working with version 4.2.1 of the api using the CZMQ binding and I found a solution for my case (ZMQ_STREAM). It works by setting an id before connecting.
The relevant socket option is "ZMQ_CONNECT_RID".
ZMQ api via zmq_setsockopt()
CZMQ api via zsock_set_connect_rid()
Some codes with redacted redacted ips.
const char endpoint1[] = "tcp://1.2.3.4:12345"
const char endpoint2[] = "tcp://5.6.7.8:12345"
zsock_t *stream = zsock_new(ZMQ_STREAM);
zsock_set_connect_rid(stream, endpoint1);
zsock_connect(stream, endpoint1);
zsock_set_connect_rid(stream, endpoint2);
zsock_connect(stream, endpoint2);
Then I get those 2 messages if there is a connection. First frame is the id and second frame is empty on connect/disconnect for ZMQ_STREAM sockets.
[Message1]
[019] tcp://1.2.3.4:12345
[000]
[Message2]
[019] tcp://5.6.7.8:12345
[000]
Another option is to use the zmq_socket_monitor() or czmq zmonitor. It was one of my first solution but I was looking for something lighter. I was able the get the endpoint that way without setting the id directly on the socket.
The zmonitor zactor make it possible to subscribe to socket events and then it sends a message with 3 frames:
[009] CONNECTED
[002] 14
[021] tcp://127.0.0.1:33445
I have a root node(server) connected to many other nodes(clients) through TCP sockets. I want to send some data from server to client, but the data is different for each node and depends on the ip address of that node.
Thus I should have ip address of each node connected to server. How can I have that information?
When you call accept(2) you can choose to retrieve the address of the client.
int accept(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);
You need to store those addresses and then send(2) to each what you need to send.
So the workflow should be something like this:
Keep a list of connected clients. Initially the list is empty, of course
When you accept a connection, push its details into that list (the address and the socket returned by accept(2)).
When you need to send something to every client, simply walk the list and send it (using the stored socket)
The one tricky part is that socklen_t *restrict address_len is a value-result argument, so you need to be careful with that.
This is a more nuanced question than it first appears.
If the clients are sitting behind a NAT, you may get the same IP from more than one client. This is perfectly natural and expected behavior. If you need to distinguish between multiple clients behind the same NAT, you'll need some other form of unique client id (say, IP address and port).
As long as you have access to the list of file descriptors for the connected TCP sockets, it is easy to retrieve the addresses of the remote hosts. The key is the getpeername() system call, which allows you to find out the address of the remote end of a socket. Sample C code:
// This is ugly, but simpler than the alternative
union {
struct sockaddr sa;
struct sockaddr_in sa4;
struct sockaddr_storage sas;
} address;
socklen_t size = sizeof(address);
// Assume the file descriptor is in the var 'fd':
if (getpeername(fd, &address.sa, &size) < 0) {
// Deal with error here...
}
if (address.sa.family == AF_INET) {
// IP address now in address.sa4.sin_addr, port in address.sa4.sin_port
} else {
// Some other kind of socket...
}
I'm writing a SIP stack, and I need to insert an ip address in the message. This address needs to be the one used for sending the message. I know the destination IP and need to determine the NIC (its address) that will be used to send the message....
To expand a bit on Remy Lebeau's comment, GetBestInterfaceEx() is your best bet, if you're on Windows XP or newer. That will work for both IPv4 and IPv6 addresses.
GetBestInterface/GetBestInterfaceEx return the index (call it IDX) of the most appropriate interface to use to contact some address.
Then you can map that index into a local IP address by getting your interface<->IP address mapping using GetIpAddrTable or GetAdaptersAddresses if you're dual-stacking (supporting both IPv6 and IPv4).
Iterate over that table and find the interface with the dwIndex (or IfIndex, in the case of GetAdaptersAddresses) matching IDX.
It's usually best to allow the IP address your SIP stack will operate on to be set as an adjustable configuration option. It means the user will need to set a configuration option but at least your stack will know the IP address it's operating on.
If that's not feasible then an approach you could use is to send out the SIP request on all IP addresses using a dummy value in the Via header such as 0.0.0.0 and set the interface you get a response back on as the default one. This approach alos as the advantage that the SIP response will tell you the public IP address the request was received from which can be useful if your SIP stack is behind a NAT.
Over TCP, I think you can get the address of the local side of the socket after connect(). I don't know if the same is true for UDP (I suspect not), but it might be worth a try.
The socket will allow you to Bind to a local endpoint before calling connect (both UDP and TCP).
That is all ok if you know the port. However, if you want the port to be ephemeral (e.g. some random port number) then you must come up with your own algorithm to do so and robust code to handle the cases where the port is exclusivly taken by another application.
I am writing a UDP test client/server and i want to get it through firewall. Supposedly all i need to do is have both sides send to the correct IP and server. Getting an IP is not a problem but how do i have the client pick a random free port and report it to the user? I eventually would want it to connect to a matchmaker server but right now i need a simple working prototype and i would like to cout the port number so my friend/tester can send me the # via IM so we can test.
How do i get the port number?
sorry for the long desc. I notice people tell me not to do what i am asking when i dont give a desc :(
To use the highly technical term, this is actually a pretty icky problem or even a pair of icky problems. Depending on the configuration of the firewall, it will usually allow responses from another endpoint on the IP endpoint as the request came from. So... if you friend receives the UDP datagram using something like the recvfrom() system call, the address parameter will receive the IP endpoint information to respond to. So the other end should be able to respond with a sendto() using the same addressing information. Something like:
/* initiator */
struct sockaddr_in hisaddr;
memset(&hisaddr, 0, sizeof(hisaddr));
hisaddr.sin_addr.s_addr = htonl(target_ip);
hisaddr.sin_port = htons(target_port);
sendto(sd, msg_ptr, msg_sz, 0, (struct sockaddr*)&hisaddr, sizeof(hisaddr));
/* receiver */
struct sockaddr_in peeraddr;
socklen_t peer_sz = sizeof(peeraddr);
recvfrom(sd, buf_ptr, buf_sz, 0, (struct sockaddr*)&peeraddr, &peer_sz);
/* build response */
sendto(sd, msg_ptr, msg_sz, 0, (struct sockaddr*)&peeraddr, peer_sz);
The peeraddr on the other side will be your external address or, more correctly, the IP address of your firewall and the port number that it chose to use. The port number that you specify in your code may be completely different than the port that your friend would have to send data to. Ultimately, it might not matter what port you choose to use since the firewall might be sending and receiving on an entirely different port - this is what Network Address Translation is all about. I would recommend reading RFC3235 for some tips on how to overcome that hurdle.
The best approach IMHO is to:
Let the OS choose a port by either calling bind() with a zero port number or skipping the bind altogether
Having the client receive the address information from the socket layer (e.g., the fifth and sixth arguments to recvfrom())
The client sends response to the endpoint retrieved in the previous step
Tweak the firewall configurations until the previous steps work
Of course, all of the magic is in the last step. If you can disable NAT or ensure that the firewall is never going to switch ports, then nailing down a port number and bind-ing to it will work as well. You might want to take a look at %WINDIR%\system32\drivers\etc\services (or /etc/services depending on your OS inclination) to get an idea of what port numbers are reserved or generally in use.
bind() the socket before you send your data. Specify port 0 to bind(), and the OS will pick an unused port for you. You can then use getsockname() to find out what port wsa chosen.
Generally speaking - you - as the developer - choose the port. You can set your application to read the port from a config file or user input - but no magic firewall is going to tell you what port to use...
If I'm understanding your question correctly, I'm not sure there's a way to do what you want programatically (and even if there is, I don't think it's the right approach). I think you need to find a port that isn't in use on the server machine (and perhaps a different or the same port on the client machine, if communication is bi-directional) AND that port must be able to pass through your firewall. I assume since you say "getting an IP is not a problem", you've already configured your firewall to forward some or all ports to a specific computer inside the firewall? If so, the port you seek is one of the ones you forwarded. You can just pick an arbitrary one, as long as no other service is running on that port. Ports below 1024 are reserved, so you probably want to pick a higher number than that. You can use a simple portscanning tool such as nmap to see which services are running on your computer on which ports and pick a different one. Note that nmap can be fooled by firewalls and various bind rules when sockets are created.
I think you're better off picking a fixed port rather than relying on the random port number chosen by the O/S.
If you use a random port you'd have to change your firewall settings each and every time you run the program.
If you're using WINSOCK check this link:
http://msdn.microsoft.com/en-us/library/aa280717(VS.60).aspx
Basically you have 2 choices set the port to 0 and let the system assign you one or chose a random one try to open the socket if it doesn't work try another (be sure to steer clear of reserved ports)