I’m trying to recieve a DNS request (DNS content with DNS header) in C++ on Linux 2.6.32. The code works when I write a string over UDP with netcat. But if I do a “nslookup google.com”, it recieves only this:
root@EliteBook:/home/.../dns# xxd request.bin
0000000: 8a2b 01
And if I use “tcpdump -x ‘udp port 53’ it shows me many bytes more.
My C++ code:
#include <string>
#include <iostream>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFLEN 1024*6
#define NPACK 10
#define PORT 53
using namespace std;
void diep(const string &s)
{
perror(s.c_str());
exit(1);
}
int main()
{
struct sockaddr_in si_me;
struct sockaddr si_other;
int slen=sizeof(si_other);
int s; // UDP Socket
char buf[BUFLEN];
buf[0] = 'X';
buf[1] = 'Y';
buf[2] = 'Z';
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
diep("Failed to create socket!");
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, (const sockaddr*) &si_me, sizeof(si_me))==-1)
diep("bind");
for (int i=0; i<NPACK; i++) {
if (recvfrom(s, buf, BUFLEN, 0, &si_other, (socklen_t*) &slen)==-1)
diep("recvfrom()");
struct sockaddr_in *si_other_in = (struct sockaddr_in *)&si_other;
cout << "Pkg arrived: " << buf << " " << inet_ntoa(si_other_in->sin_addr) << ":" << ntohs(si_other_in->sin_port) << endl;
FILE * pFile;
pFile = fopen ("request.bin","wb");
if (pFile!=NULL)
{
fputs (buf, pFile);
fclose (pFile);
}
}
close(s);
return 0;
}
Compile this with
g++ -Wall main.cpp -o dns
So, what is my fault, did I forget something or must I use an other call to read binary data?
PS: Localhost is the first nameserver in /etc/resolv.conf
EDIT:
I looket at the return value from recvfrom, and it shows me:
size: **27**
Pkg arrived: �. 127.0.0.1:36686
size: **45**
Pkg arrived: l 127.0.0.1:38952
That should be OK. Why does my buffer doesn’t hold all bytes?
You are mostly ignoring the return value of
recvfrom(). That return value tells you how many bytes you received.From the man page:
Without that information, you cannot know that you didn’t receive all of the bytes.
You are reading the binary data just fine, but you are writing it incorrectly. Your call to
std::cout << bufand your call tofputs(buf, pFile)each operate in character strings, not on binary data. Specifically, they each write the bytes up to, but not including, the first zero-valued byte.To fix your program, record the answer from recvfrom, skip the call to
cout << buf, and replace yourfputs()with anfwrite.