用C语言实现已知hostname返回DNS header和IP地址
// standard includes
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
// networking includes
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#define STUDENT_SPECIFY 0
#define DNS_IP "8.8.8.8"
char* resolve_name(char* hostname);
void retrieve_data(char* inetaddr, char* hostname, char* requestpath);
void convert_host_format(unsigned char* dns, unsigned char* host);
void hexdump(char* data, int sz);
int main(int argc, char** argv) {
if (argc != 2) err(1, "Example: %s www.ietf.org/rfc/rfc1149.txt", argv[0]);
char path[80];
strcpy(path, strchr(argv[1], '/'));
char host[80];
strcpy(host, strtok(argv[1], "/"));
char* host_ip = resolve_name(host);
retrieve_data(host_ip, host, path);
printf("\n\n");
return 0;
}
void convert_host_format(unsigned char* dns, unsigned char* host) {
int lock = 0, i;
strcat((char*) host, ".");
for (i = 0; i < (int) strlen((char*) host); i++) {
if (host[i] == '.') {
*dns++ = i - lock;
for (; lock < i; lock++) {
*dns++ = host[lock];
}
lock++; //or lock=i+1;
}
}
*dns++ = '\0';
}
void hexdump(char* data, int sz) {
int i;
for (i = 0; i < sz; i++) {
printf("%02hhx", *(data + i));
if ((i+1) % 16 == 0) {
printf("\n");
} else if (i != (sz - 1)) {
printf(":");
}
}
}
#define STRING ""
#define VALUE 0
char* resolve_name(char* hostname) {
int socketid;
struct sockaddr_in socket_info;
char* return_ip = malloc(sizeof(char) * 18);
if ((socketid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) err(1, "socket(2) failed");
// configure the socket_info
memset((char *) &socket_info, 0, sizeof(socket_info));
socket_info.sin_family = AF_INET;
socket_info.sin_port = htons(53);
if (inet_aton(DNS_IP, &socket_info.sin_addr) == 0) err(1, "inet_aton(3) failed");
char buffer[2046]; // input and output buffer
// header
uint16_t header[6] = { // [NB:1]
VALUE, // 2 byte ID: this is arbitrary
VALUE, // flags
VALUE, // number of questions
VALUE, // number of answers
VALUE, // number of nameservers
VALUE // number of additional records
};
char converted_name[80];
convert_host_format(converted_name, hostname);
// construct the buffer
memcpy(buffer, header, sizeof(header)); // copy the header into the
memcpy(buffer + sizeof(header), converted_name, strlen(converted_name)); // copy the string after the header (including the null)
*(buffer + sizeof(header) + strlen(converted_name) + 1) = 0x00; // append the query type after the string (CNAME)
*(buffer + sizeof(header) + strlen(converted_name) + 2) = 0x01;
*(buffer + sizeof(header) + strlen(converted_name) + 3) = 0x00; // append the address type after the query type (AN)
*(buffer + sizeof(header) + strlen(converted_name) + 4) = 0x01;
int buffer_size = sizeof(header) + strlen(converted_name) + 5;
// send the packet
sendto(socketid, (char*) buffer, buffer_size, 0, (struct sockaddr*) &socket_info, sizeof(socket_info));
// get the response
recvfrom(socketid, (char*) buffer, 2046, 0, (struct sockaddr*) &socket_info, sizeof(socket_info));
sprintf(return_ip,"%hhu.%hhu.%hhu.%hhu", buffer[VALUE], buffer[VALUE], buffer[VALUE], buffer[VALUE]);
close(socketid);
return return_ip;
}
#define HTTP_BUF_LEN 2096
void retrieve_data(char* inetaddr, char* hostname, char* requestpath) {
int socketid;
struct sockaddr_in socket_info;
char buffer[HTTP_BUF_LEN];
if ((socketid = socket(AF_INET, SOCK_STREAM, 0)) < 0) err(1, "socket(2) failed");
memset((char *) &socket_info, 0, sizeof(socket_info));
socket_info.sin_family = AF_INET;
socket_info.sin_port = htons(80);
if (inet_aton(inetaddr, &socket_info.sin_addr.s_addr) == 0) err(1, "inet_aton(3) failed");
if (connect(socketid, (struct sockaddr*) &socket_info, sizeof(socket_info)) != 0) err(1, "connect(2) failed");
const char* request_format_string = "GET %s %s HTTP: \r\n";
sprintf(buffer, request_format_string, requestpath, hostname);
send(socketid, buffer, strlen(buffer), 0);
int bytes_read;
int strip_header = 1;
while ((bytes_read = recv(socketid, buffer, sizeof(buffer), 0)) > 0) {
if (strip_header) {
char* end_of_header = strstr(buffer, "\r\n\r\n");
printf("%s", end_of_header);
strip_header = 0;
} else {
printf("%s", buffer);
}
}
close(socketid);
}
把resolve_name的header里面的VALUE换成DNS的header,然后return_ip里面buffer的几个VALUE是返回的一个IP,能够指点一下该填什么吗?对网络不怎么熟悉。。。
------解决方案--------------------
同步接口是有现成的:
NAME
res_init, res_query, res_search, res_querydomain, res_mkquery, res_send,
dn_comp, dn_expand - resolver routines
SYNOPSIS
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
extern struct state _res;
int res_init(void);
int res_query(const char *dname, int class, int type,
unsigned char *answer, int anslen);
int res_search(const char *dname, int class, int type,
unsigned char *answer, int anslen);
int res_querydomain(const char *name, const char *domain,
int class, int type, unsigned char *answer,
int anslen);
不过要做异步的还是要自己实现协议解析。