Build a DNS Proxy in C - c

I want to build a simple DNS Proxy in C, which accepts DNS Queries from UDP Port 53, forwards the query to Google's DNS server TCP port 53 to do the lookup, and then returns the answer offered by Google.
Yes, this is a school project and I'm so confused that I don't know where to get started.
Thanks for helping!!

You've struck lucky with the requirements - because you're going from UDP -> TCP, it's actually a lot simpler than doing UDP -> UDP.
Specifically, what I mean is that because the outward facing side is using a connection orientated socket, you know straight away that the response you receive must pertain to the query you just sent, so long as you use a new TCP socket for each query.
If the outward facing side had been UDP it becomes a lot harder to figure out which query each response relates to - there's no guarantee in the protocol that responses arrive in the same order as the queries.
If multithreading isn't a requirement, then (in pseudo-code)
"open" a UDP socket
"bind" that socket to port 53
while (true) {
"recvfrom" a packet from the UDP socket
... and remember the address it was received from
"open" a TCP socket
"connect" it to Google's DNS
"write" the length of the original query (two bytes, network order - RFC 1035)
"write" the contents of the original query
"read" a two byte length header
"read" that many bytes from the TCP socket
"close" the TCP socket
"sendto" those bytes back over the UDP socket to the original client address
}

first of all you need to chose an API for writing messages on to a network.
For windows, you have Winsock API.
For unix-like systems you have the BSD Sockets API.
Although most of the courses use the BSD API.
Now your steps may be:
have a look at rfc for DNS implementation. You can only focus on format of request and response messages, as you may need to change some fields.
Now write a client server code which consists of two modules:
Server side code to receive a DNS query request, may need to change some fields.
Pass it on to the Module that interacts with Google's DNS server.
Capture the response and forward it back to requesting client. (again you may need to change some fields)

Related

Can a RAW socket be bound to an ip:port instead of an interface?

I need to write a proxy server in C language on Linux (Ubuntu 20.04). The purpose of this proxy server is as follows. There're illogical governmental barriers in accessing the free internet. Some are:
Name resolution: I ping telegram.org and many other sites which the government doesn't want me to access. I ask 8.8.8.8 to resolve the name, but they response of behalf of the server that the IP may be resolved to 10.10.34.35!
Let's concentrate on this one, because when this is solved many other problems will be solved too. For this, I need to setup such a configuration:
A server outside of my country is required. I prepared it. It's a VPS. Let's call it RS (Remote Server).
A local proxy server is required. Let's call it PS. PS runs on the local machine (client) and knows RS's IP. I need it to gather all requests going to be sent through the only NIC available on client, process them, scramble them, and send them to RS in a way to be hidden from the government.
The server-side program should be running on RS on a specific port to get the packet, unscramble it, and send it to the internet on behalf of the client. After receiving the response from the internet, it should send it back to the client via the PS.
PS will deliver the response to the client application which originates the request. Of course this happens after it will unscramble and will find the original response from the internet.
This is the design and some parts is remained gloomy for me. Since I'm not an expert in network programming context, I'm going to ask my questions in the parts I'm getting into trouble or are not clear for me.
Now, I'm in part 2. See whether I'm right. There're two types of sockets, a RAW socket and a stream socket. A RAW socket is opened this way:
socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
And a stream socket is opened this way:
socket(AF_INET, SOCK_STREAM, 0);
For RAW sockets, we use sockaddr_ll and for stream sockets we use sockaddr_in. May I use stream sockets between client applications and PS? I think not, because I need the whole RAW packet. I should know the protocol and maybe some other info of the packet, because the whole packet should be retrieved transparently in RS. For example, I should know whether it has been a ping packet (ICMP) or a web request (TCP). For this, I need to have packet header in PS. So I can't use a stream socket, because it doesn't contain the packet header. But until now, I've used RAW sockets for interfaces and have not written a proxy server to receive RAW packets. Is it possible? In another words, I've the following questions to go to next step:
Can a RAW socket be bound to localhost:port instead of an interface so that it may receive all low-level packets containing packet headers (RAW packets)?
I may define a proxy server for browser. But can I put the whole system behind the proxy server so that packets of other apps like PING may route automatically via it?
Do I really need RAW sockets in PS? Can't I change the design to suffice the data I got from the packets payload?
Maybe I'm wrong in some of the concepts and will appreciate your guidance.
Thank you
Can a RAW socket be bound to localhost:port instead of an interface so that it may receive all low-level packets containing packet headers (RAW packets)?
No, it doesn't make sense. Raw packets don't have port numbers so how would it know which socket to go to?
It looks like you are trying to write a VPN. You can do this on Linux by creating a fake network interface called a "tun interface". You create a tun interface, and whenever Linux tries to send a packet through the interface, instead of going to a network cable, it goes to your program! Then you can do whatever you like with the packet. Of course, it works both ways - you can send packets from your program back to Linux through the tun interface, and Linux will act like they just arrived on a network cable.
Then, you can set up your routing table so that all traffic goes to the tun interface, except for traffic to the VPN server ("RS"), which goes to your real ethernet/wifi interface. Otherwise you'd have an endless loop where your VPN program PS tried to send packets to RS but they just went back to PS.

UDP - Multi-server single client

I have a linux computer with a code in C that must communicate in UDP with 4 differents equipments. The computer sends differents commands to each equipment and receives responses, sometimes in parallel ...
I am a perfect beginner, and managed to communicate with one equipment using UDP socket. But now, i'm looking for a way to communicate with all these equipments, what i would like to call "multiple socket", but i don't know where to look/ what word to search to find a way ...
My linux computer is the client and all the equipment servers. I only have one eth port on the computer and will have to use a switch to have access to all the equipment. I would like to create functions like :
sendcmd(IPnumber, PORTnumber, cmd , ...)
readbuff(IPnumber, PORTnumber, buff, ...)
so i can choose which IP will received cmd ... i don't know if it's possible or if i need to open the socket, then close and redo the operation with another IP ...
So, if I ever managed to make myself understood, where should I look for a solution to my problem?
Thank you !
You can use a single UDP socket for your scenario. You can keep the socket open for the lifetime of your application.
UDP is not connection oriented. UDP sockets are also not classified into client sockets and server sockets. UDP sockets are always bound to a local port, either implicitly (typically for pure clients) or explicitly (which is usually the case for servers). In your case you do not care about the port for your UDP client.
To send to your four UDP server you can use sendto(). This lets you specify the destination IP address and port the UDP packet gets sent to.
To receive from your four UDP servers you can use recvfrom(). This will tell the IP address and port where the UDP packet came from.
You most likely want to have a receive loop of some kind. If you want to do anything else in your application you most likely want to either make recvfrom() non-blocking or you want to have the receive loop in its own thread. But this goes beyond your question.
The most important aspect of UDP is that it is not a protocol (despite its name which is misleading). It is one puzzle piece for a protocol. It is a tool to develop your own protocol. But I assume you already have a specific protocol at hand defined by your peripherals.

How do apps like LogMeIn and TeamViewer work?

There's already a question How exactly does a remote program like team viewer work which gives a basic description, but I'm interested in how the comms works once the client has registered with the server. If the client is behind a NAT then it won't have its own IP address so how can the server (or another client) send a message to it? Or does the client just keep polling the server to see if its got any requests?
Are there any open source equivalents of LogMeIn or TeamViewer?
The simplest and most reliable way (although not always the most efficient) is to have each client make an outgoing TCP connection to a well-known server somewhere and keep that connection open. As long as the TCP connection is open, data can pass over that TCP connection in either direction at any time. It appears that both LogMeIn and TeamViewer use this method, at least as a fall-back. The main drawbacks for this technique are that all data has to pass through a TeamViewer/LogMeIn company server (which can become a bottleneck), and that TCP doesn't handle dropped packets very well -- it will stall and wait for the dropped packets to be resent, rather than giving up on them and sending newer data instead.
The other technique that they can sometimes use (in order to get better performance) is UDP hole-punching. That technique relies on the fact that many firewalls will accept incoming UDP packets from remote hosts that the firewalled-host has recently sent an outgoing UDP packet to. Given that, the TeamViewer/LogMeIn company's server can tell both clients to send an outgoing packet to the IP address of the other client's firewall, and after that (hopefully) each firewall will accept UDP packets from the other client's Internet-facing IP address. This doesn't always work, though, since different firewalls work in different ways and may not include the aforementioned UDP-allowing logic.

udp - client to multiple servers

I have looked through many pages and forums, but still am unsure about this. I am writing a project where the client reads in a txt file of numbers and sends the numbers to the server who will do some computation and send the result back to the client. Is it possible to connect a client to multiple servers using udp? and if so, an explanation would be nice. I don't think I quite understand udp fully yet. I am writing this in c also. The reason for connecting to multiple servers from one client is because I need to run the client using 1, 2, 4, and 8 servers (distributing numbers to each server until none are left) and compare the run time. Any quick help would be appreciated.
You can use UDP to multiple servers with the same socket. Probably the simplest way to do it is to have the client assign a session ID to each connection, include the session ID in each datagram it sends, and have the server return that session ID in each reply datagram it sends. Don't use the IP address to distinguish which server the packet is from because a server can have more than one IP address, making it unreliable.
Just remember that if you use UDP, you don't get any of the things TCP adds. If you need any of them, you need to do them yourself. If you need all or most of them, TCP is a much better choice. TCP does:
Session establishment
Session teardown
Retransmissions
Transmit pacing
Backoff and retry
Out of order detection and rearrangement
Sliding windows
Acknowledgments
If you need any of these things and choose to use UDP, you need to do them yourself.

A file server and its associated clients

I am extremely new to socket programming and I am implementaing a file server that receives request like open(), read(), write(), close() from clients. The file server will process the requests and send the clients the return value of each system call.
I don't know what type of socket I need to define(i.e. stream socket, datagram socket etc). and what command will send the request from the client, how will I receive the return value from the server, how will I receive it at the server end and send the return value to my client.
Will be gratefull to get some pointers.
Thanks
An edit: Is something simple like this work for starting Server not able to properly read/open a filename sent by client in C
It depends in part upon your file server design.
If you're going for a stateless server, then datagram or stream would be fine. Datagram is relatively nice because your servers and clients don't need to handle partial requests -- the entire contents of the request are contained in the datagram.
If you're going for a stateful server, then stream might be nicer -- you can automatically release locks and de-allocate resources 'owned' by a client when you receive a TCP RST packet. (Client gone, throw away their state.) You could of course build a stateful server with datagram services, but it doesn't seem like a good fit.
But on the open Internet, typically you have just UDP and TCP -- I have no idea if RDP, a reliable datagram transport, is routed on given ISPs or not. And being forced between unreliable datagrams and reliable streams, I'd recommend reliable streams almost every time. Will your use your protocol on reliable LANs only? Or on lossy wireless or public Internet links?
I would use a streaming socket, but others have done differently, for example the Network File System (NFS).
To communicate between a client and the server you need a protocol. The one that OpenSSH uses for their scp and sftp programs is nice to implement. Have a look at it. http://openssh.org/txt/draft-ietf-secsh-filexfer-02.txt

Resources