Communicate to public IP from a local network (WinSock, C) - c

I'm new to this forum (at least at asking questions), so please be patient. I'm trying to write simple client-server applications to communicate using datagram (UDP) sockets, with C and Windows.
The scenario is very simple, I want to be able to send/receive data from a machine in some local network (behind a GATEWAY/NAT) to some host having public IP. I can send the data, but it seems impossible to receive any data back, because the remote server can't see the client's local IP.
I don't want the user to perform manual port forwarding on the GATEWAY, and I also don't want to use UPnP because of security issues (though it also should be enabled by the user).
I think it is possible because applications like Skype or Browsers can do it, but how ?
Are there some automatically forwarded ports or things like that ? I'm exhausted of searching the web ... PLEASE HELP !

For UDP connections, most home NAT gateways will automatically create a temporary reverse mapping for each outbound packet.
Consider a scenario where your client is running on the internal machine with IP address 192.168.4.5, sending a UDP packet from port 65000 to the external address 64.34.119.12:6789, via a gateway with external IP address 192.0.43.10. When the gateway sees your internal client send a UDP packet from 192.168.4.5:65000 to the external address, it will NAT it to an external address and port, like 192.0.43.10:5500. Your server will see a packet with a source address of 192.0.43.10:5500 and destination address 64.34.119.12:6789. The router also sets up a reverse mapping, so that if it sees a packet arrive on the external interface with a source of 64.34.119.12:6789 and a destination of 192.0.43.10:5500, it will redirect it back to 192.168.4.5:65000. This mapping typically times out after a short while.
This means that in simple cases, all you need to do is:
On the client, use the same port to send to the server and listen for responses;
On the server, respond to the client at the address and port that the client's packet was receieved from, using the same server port that recieved the packet;
Have the client send the initial packet in the conversation;
Don't leave the "connection" idle for more than a few minutes at a time.

Related

Socket, how to find local address when binded with INADDR_ANY

I'm recoding a simple ftp server and I'm stuck of the implemetation of the PASV command.
In fact, when the client send a PASV command, I have to create a new server socket and send back the infos (address and port) to the client so that he can connect to it to create the data connection.
What I do step by step is:
Create a server socket with INADDR_ANY and random port (port 0)
listen() with this socket
getsockname() this socket to get it's infos
send back the infos to the client on the command connection
the accept() is done later, when the user need to use the data con
(Is that the right way to do it ?)
The thing is, the server socket that I create on the server side is binded with INADDR_ANY so getsockname() on it always return 0.0.0.0 (cause it is binded to virtually all the ips off the system).
Is that case, what address should I send back to the client and how to find it ?
How real ftp servers handle this ?
Thanks :)
What I do step by step is:
Create a server socket with INADDR_ANY and random port (port 0)
listen() with this socket
getsockname() this socket to get it's infos
send back the infos to the client on the command connection
the accept() is done later, when the user need to use the data con
(Is that the right way to do it ?)
In general, yes, however steps #1 and #3 tend to be more complicated than that.
For one thing, getsockname() cannot get the true IP until the socket is actually connected to someone (which, in this case, means you would have to call getsockname() on the socket returned by accept(), not on the socket that you call accept() on). So, when binding to INADDR_ANY, you should just report the IP of the interface that the command socket is connected to. In which case, it is better to just bind the listening socket to only that interface directly and not to INAADDR_ANY at all.
For another thing, even if the server machine only has 1 interface installed, if the server is behind a NAT router, and the client is outside the NAT, then you would have to report the router's public IP instead of your server's listening IP. You would have to know the router's public IP ahead of time, either by storing it in your app's configuration, or by dynamically querying the router itself via uPNP, or by querying an outside service like http://iplookup.flashfxp.com/. Unless the router is FTP-aware (some are) and is smart enough to replace the reported IP for you when passing through the router, in which case you do have to report your listening IP instead.
You should call getsockname() on the command socket. That gives you the IP address the client used to connect to you. It can be different for each client on a multi-homed host. If you're behind a NAT device you should use its public IP address, which you will have to obtain via configuration.

Broadcast on different subnets

Please if you can help me about my problem. On one side I have server with IP 172.27.13.2 connected to the WAN interface of router 172.27.13.1 ...Then on wireless LAN of my router 192.168.1.1 I have connected a few clients. Now I will write code in C where client are requesting some UDP streams from server, then server broadcasts streams to clients, and if some packets get lost clients must send NACK to server. My questions is:
Because server and clients are on different subnets how can I broadcast from server?
And how the client can send request and NACKs to server because they are in different subnets?
Are these problems can be solved by router configurations or in C code?
Thank you for helping
You cannot broadcast to different subnets. Routers do not usually forward broadcast packets to different subnets, unless you have a very special router that can be configured properly (e.g. Cisco ...). You could however use multicast for such a task. Here's a C example
Also check this: UDP broadcast packets across subnets
NOTE: some includes in the c example are missing, but they are easy to find
As both server & users are in different subnets .As router donot forward broadcast .But we have solution by modifying the router configuration .
If you have cisco router & users are connected on cisco switch ,you can use ip helper address command on switch on vlan .You can allow udp packet on router ACL

Forwarding UDP packets in C using the socket API

I am writing a content filter in C using the socket API that will intercept DNS requests, and only return the response if the domain is allowed. The pseudocode to describe this is:
Redirect all DNS queries to the content filter program which is listening on UDP port X.
Content filter program extracts domain being queried and determines if it is allowed or not.
If it is allowed, then the content filter program forwards the original DNS request packet to the original destination DNS server while maintaining the original source and IP+port so that the DNS server can send the reply directly back to the client.
If the domain is not allowed, then no reply is sent.
I currently have the program listening on UDP port X but the problem is that I can't access the IP headers, and therefore can't simply forward the DNS request to the original server while maintaining the original headers.
I have tried using socket(AF_INET, SOCK_RAW, IPPROTO_UDP) but that doesn't bind on port X (understandably), and doesn't receive any traffic.
What is the best way to go about listening on UDP port X, while still being able to access the IP headers of incoming packets?
I think recvfrom on an UDP socket should give you the correct source address. You still probably need a raw socket for forwarding the message.
The functionality for SOCK_RAW based sockets varies depending on the platform you are on. Generally, when you want to get access to the full IP datagram information, then I would recommend using the Berkeley Packet Filter to tap the data-link layer frames addressed to UDP port of interest.

Raw Sockets - Internet Protocol Layers

I have been working with Raw Berkeley Sockets in C, which allow the programmer to access Layer 2 (IP Headers) of the Internet Protocol Suite. I would like to know how the raw sockets handle transport on Layer 1 (Link Layer), specifically with regard to wireless local area networks.
For example, how does the socket know which network interface (eth0 or wlan0) to send the packet to?
If I am behind a wireless router, should I still fill the IP Source Address of my IP Header with my LAN address (192.168.1.1), or with the internet address (74.125.226.68) of my router?
If I do fill the IP Source address with my LAN address (192.168.1.1), does the IP Header get changed when it goes through the router, or does it stay that way, so that the receiving end of the packet attempts to send the response to a local host on its network?
I would appreciate any insights in this area.
For example, how does the socket know which network interface (eth0 or wlan0) to send the packet to?
You can use the socket option SO_BINDTODEVICE to bind your socket to a specific interface. Otherwise, the operating system chooses one.
If I am behind a wireless router, should I still fill the IP Source Address of my IP Header with my LAN address (192.168.1.1), or with the internet address (74.125.226.68) of my router?
You should use your LAN address. The router is responsible to take care of NAT (network address translation) if necessary.
If I do fill the IP Source address with my LAN address (192.168.1.1), does the IP Header get changed when it goes through the router, or does it stay that way, so that the receiving end of the packet attempts to send the response to a local host on its network?
If NAT is enabled at the router, the source address is changed to reflect the router's external address. Otherwise, your packages are likely to be dropped by routers or firewalls, because your source address is invalid in their context.

How to connect socket via external IP (Mac )

My question is, how to connect to socket on romote mechine?
I can only connect sockets on same network..
I wrote a simple code (in c), that simulate a server (open socket and listen for client). in Mac.
I'm trying to connect this socket as a client from iPhone (with simple objectiv-c code).
If my internet on both, server and client, is on the same network (WiFi) and in client I trying to connect to 192.168.1.x, it's working.
But when, in client, I'm trying to connect via external IP (with the same port) connection is failed.
I never did this bofore. Maybe I miss somthing.. I've tried to turn my FireWall off. It did not help.
Thanks.
Edit: If it's not clear.. my Mac is connected by router.
In a setting like this, the "external IP" would typically be the IP of the router. In all likelihood you'll need to configure the router to forward the relevant port to the internal IP address.
It could also be the case that for the port forwarding to work, the request has to come in on the external (WAN) interface. This depends on how the router is configured. If that's the case, you'll need to make sure that you're accessing the external IP via the cellular network and not the Wi-Fi connection on your iPhone.
If you're connecting to your server via a local IP address (i.e., you're connecting to another machine on the same local router via a delegated DHCP address), then your issue is on the network, not the IP-stack of the local machine.
You'll need to look into your router settings ... many routers will block a number of services, especially those on custom ports, in order to prevent malicious attacks from sources external to the local network.

Resources