I'm learning C by writing a small application that sends a DNS query to a specified server. Here is an example of the network code:
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
This works fine as the query is succesfully sent, and a reply is recieved. However, by sniffing the traffic with Wireshark I can see the message: Destination unreachable (Port unreachable)
.
I found out that I can avoid this by calling bind()
before sendto()
:
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
if(bind(sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind failed\n");
}
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
Now the Destination unreachable (Port unreachable)
message is gone, but the application has to be run with root privileges as it will bind to port 53.
Is it possible to modify the code so a random non-privileged source port is used instead?
Problem solved
The problem occured because of a stupid mistake. I had simply commented out recvfrom()
. As I was sniffing the traffic while testing the application, I could see the response and error arrving at my computer, and mistakenly confused this as the application was receving. Because I don't know what the hell I'm doing, I started to mess around with bind()
etc. and this avalanche of failure started.
For brevity I did not post all the code, but the issue had probably been solved instantly if had did that instead.
The fields in a UDP header are: Source port – The port of the device sending the data. This field can be set to zero if the destination computer doesn't need to reply to the sender. Destination port – The port of the device receiving the data. UDP port numbers can be between 0 and 65,535.
Each UDP (and TCP) endpoint is characterized by an (address, port) pair. That corresponds pretty well to (machine, program). A port is a characteristic of one endpoint alone, not of the communication channel overall, so there is no requirement that the same port be used at both ends.
Yes. UDP, like TCP, requires a source and destination port at the transport layer to identify the process which is being used. It might be natural to think that we won't require a source port since it is a connectionless protocol.
A server process (program), listens for packets received with a particular well-known port number and tells its local UDP layer to send packets matching this destination port number to the server program.
You can bind to port 0 to let the OS randomly pick one available for you (just like INADDR_ANY is 0). See https://stackoverflow.com/a/1077305/3543692
Also, binding to port 53 makes no sense. The 53 port is the port of the DNS server, not the DNS client. Think if all the DNS clients on your computer use 53 for DNS client port, then only one DNS request to a server can be proceeded concurrently. Typically, all clients (both TCP/UDP) use random unused ports assigned by OS.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With