3

I'm trying to get an MX record from an DNS server in C. My problem is, that everytime I call sendto or recvfrom I get a Permission denied error. (IDE - Xcode 4, Mac OS X Lion) Haven't really done anything in C up to this point but I need this for an assignment. "Inspiration" from http://www.binarytides.com/blog/dns-query-code-in-c-with-linux-sockets/ My code so far:

struct QUESTION
{
unsigned short qtype;
unsigned short qclass;
};

typedef struct
{
unsigned char *name;
struct QUESTION *ques;
} QUERY;

typedef struct
{
unsigned short type;
unsigned short _class;
unsigned int ttl;
unsigned short data_len;
} R_DATA;



int main(int argc, char *argv[]) 
{ 



int sockfd, i;
unsigned char buf[65536],*qname;
struct QUESTION *qinfo = NULL;

struct sockaddr_in dest;

struct dnsheader *dns = NULL;

sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);


dest.sin_family=AF_INET;
dest.sin_port=htons(53);
dest.sin_addr.s_addr= inet_addr("ns1.sil.at");


srand((unsigned)time(NULL)); 
int16_t rand_number = (rand()%1000+1);
printf("generated random number : %i \n", rand_number);


dns = (struct dnsheader *)&buf;
dns->flags = STANDARD_QUERY_FLAGS;
dns->question_count = 1;
dns->transaction_id = rand_number;
dns->answer_rr_count = 0;
dns->additional_rr_count = 0;
dns->nameserver_rr_count = 0;


qname =(unsigned char*)&buf[sizeof(struct dnsheader)];


qinfo =(struct QUESTION*)&buf[sizeof(struct dnsheader) + (strlen((const char*)qname) + 1)]; //fill it

qinfo->qtype = htons( 15 ); // MX = 15
qinfo->qclass = htons(1); 

printf("\nSending Packet...");
if( sendto(sockfd,(char*)buf,sizeof(struct dnsheader) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION),0,(struct sockaddr*)&dest,sizeof(dest)) < 0){
    perror("\nsendto failed");
}
printf("\nDone\n");


i = sizeof dest;
printf("\nReceiving answer...");
if(recvfrom (sockfd,(char*)buf , 65536 , 0 , (struct sockaddr*)&dest , (socklen_t*)&i ) < 0){
    perror("recvfrom failed");
}
printf("Done");

dns = (struct dnsheader*) buf;

print_dns_answers(buf, sizeof((char*)buf));




close(sockfd); 


return 0; 
} 
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
Patrick
  • 45
  • 1
  • 1
  • 7
  • your code does not compile. However, as a rule of thumb, did you check the firewall? Is the destination accessible? – cateof Jan 16 '12 at 13:32

2 Answers2

8

The inet_addr function takes an IP address in string form, not a host name. Try replacing "ns1.sil.at"with its IP address, "213.129.232.1"

Joni
  • 108,737
  • 14
  • 143
  • 193
  • 2
    Which likely means inet_addr() returns -1, which will be interpreted as the IP address 255.255.255.255 , and likely OSX denies normal users to send to the broadcast address (or atleast requires you to set the SO_BROADCAST socket option first) – nos Jan 16 '12 at 13:56
  • 1
    Trying to use the host name, rather than the IP, makes no sense anyway. Even if it did work, it would mean the DNS client relies on DNS in order queries to work... – ugoren Jan 16 '12 at 14:01
0

In addition to @joni-salonen's answer, you need to bind the socket.
Use a bind function call.
It needs a struct sockaddr_in, which would identify the local side of the socket. You can be initialize it with with family AF_INET, port 0 and address INADDR_ANY.

ugoren
  • 16,023
  • 3
  • 35
  • 65