2020-06-20 16:59:51 +08:00
|
|
|
|
#include "httpdns.h"
|
2020-07-30 18:10:31 +08:00
|
|
|
|
#include "http_request.h"
|
|
|
|
|
|
|
|
|
|
char http_rsp[HTTP_RSP_SIZE + 1];
|
|
|
|
|
struct sockaddr_in dst_addr;
|
|
|
|
|
char *host_value;
|
|
|
|
|
int dnsListenFd = -1, dns_efd;
|
|
|
|
|
unsigned int host_value_len;
|
|
|
|
|
static int8_t encodeCode = 0;
|
|
|
|
|
/* 缓存变量 */
|
|
|
|
|
FILE *cfp = NULL;
|
|
|
|
|
char *cachePath = NULL;
|
|
|
|
|
struct dns_cache *cache, *cache_temp;
|
|
|
|
|
socklen_t addr_len = sizeof(dst_addr);
|
|
|
|
|
unsigned int cache_using, cacheLimit;
|
|
|
|
|
|
|
|
|
|
int read_cache_file()
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
char *buff, *answer, *question;
|
|
|
|
|
long file_size;
|
|
|
|
|
|
|
|
|
|
cache = cache_temp = NULL;
|
|
|
|
|
cache_using = 0;
|
|
|
|
|
if ((cfp = fopen(cachePath, "rb+")) == NULL) {
|
|
|
|
|
//保持文件打开状态,防止切换uid后权限不足导致无法写入文件
|
|
|
|
|
cfp = fopen(cachePath, "wb");
|
|
|
|
|
return cfp == NULL ? 1 : 0;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
//读取文件内容
|
2020-07-30 18:10:31 +08:00
|
|
|
|
fseek(cfp, 0, SEEK_END);
|
|
|
|
|
file_size = ftell(cfp);
|
|
|
|
|
if ((buff = (char *)alloca(file_size)) == NULL) {
|
|
|
|
|
fclose(cfp);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
rewind(cfp);
|
|
|
|
|
fread(buff, file_size, 1, cfp);
|
|
|
|
|
|
|
|
|
|
//读取缓存,一组缓存的内容为[ipDomain\0],其中ip占5字节
|
|
|
|
|
for (answer = buff; answer - buff < file_size; answer = question + cache->question_len + 2) {
|
|
|
|
|
cache_temp = (struct dns_cache *)malloc(sizeof(*cache));
|
|
|
|
|
if (cache_temp == NULL)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return 1;
|
2020-07-30 18:10:31 +08:00
|
|
|
|
cache_temp->next = cache;
|
|
|
|
|
cache = cache_temp;
|
|
|
|
|
cache_using++;
|
|
|
|
|
cache->answer = strndup(answer, 5);
|
|
|
|
|
question = answer + 5;
|
|
|
|
|
cache->question = strdup(question);
|
|
|
|
|
if (cache->question == NULL || cache->answer == NULL)
|
|
|
|
|
return 1;
|
|
|
|
|
cache->question_len = strlen(question) - 1;
|
|
|
|
|
}
|
|
|
|
|
/* 删除重复记录 */
|
|
|
|
|
struct dns_cache *before, *after;
|
|
|
|
|
for (; cache_temp; cache_temp = cache_temp->next) {
|
|
|
|
|
for (before = cache_temp; before && (after = before->next) != NULL; before = before->next) {
|
|
|
|
|
if (strcmp(after->question, cache_temp->question) == 0) {
|
|
|
|
|
before->next = after->next;
|
|
|
|
|
free(after->question);
|
|
|
|
|
free(after->answer);
|
|
|
|
|
free(after);
|
|
|
|
|
cache_using--;
|
|
|
|
|
}
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
fclose(cfp);
|
|
|
|
|
cfp = fopen(cachePath, "wb");
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
void write_dns_cache()
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
while (cache) {
|
|
|
|
|
fputs(cache->answer, cfp);
|
|
|
|
|
fputs(cache->question, cfp);
|
|
|
|
|
fputc('\0', cfp);
|
|
|
|
|
cache = cache->next;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
exit(0);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
char *cache_lookup(char *question, dns_t * dns)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
struct dns_cache *c;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
for (c = cache; c; c = c->next) {
|
|
|
|
|
if (strcmp(c->question, question) == 0) {
|
|
|
|
|
dns->host_len = c->question_len;
|
|
|
|
|
dns->query_type = 1;
|
|
|
|
|
return c->answer;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-20 16:59:51 +08:00
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
return NULL;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
void cache_record(dns_t * dns)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
cache_temp = (struct dns_cache *)malloc(sizeof(*cache));
|
|
|
|
|
if (cache_temp == NULL)
|
|
|
|
|
return;
|
|
|
|
|
cache_temp->question = strdup(dns->dns_req + 12);
|
|
|
|
|
if (cache_temp->question == NULL) {
|
|
|
|
|
free(cache_temp);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
cache_temp->next = cache;
|
|
|
|
|
cache = cache_temp;
|
|
|
|
|
cache->question_len = dns->host_len;
|
|
|
|
|
cache->answer = dns->reply;
|
|
|
|
|
if (cacheLimit) {
|
|
|
|
|
//到达缓存记录条目限制则释放前一半缓存
|
|
|
|
|
if (cache_using >= cacheLimit) {
|
|
|
|
|
struct dns_cache *free_c;
|
|
|
|
|
int i;
|
|
|
|
|
for (i = cache_using = cacheLimit >> 1; i--; cache_temp = cache_temp->next) ;
|
|
|
|
|
for (free_c = cache_temp->next, cache_temp->next = NULL; free_c; free_c = cache_temp) {
|
|
|
|
|
cache_temp = free_c->next;
|
|
|
|
|
free(free_c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cache_using++;
|
|
|
|
|
}
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
int respond_client(dns_t * dns)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
int write_len = sendto(dnsListenFd, dns->dns_req, dns->dns_rsp_len, 0, (struct sockaddr *)&dns->src_addr, sizeof(struct sockaddr_in));
|
|
|
|
|
if (write_len == dns->dns_rsp_len) {
|
|
|
|
|
dns->query_type = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (write_len == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
else {
|
|
|
|
|
dns->dns_rsp_len -= write_len;
|
|
|
|
|
memcpy(dns->dns_req, dns->dns_req + write_len, dns->dns_rsp_len);
|
|
|
|
|
return 1;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
void respond_clients()
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < DNS_MAX_CONNECTION; i++) {
|
|
|
|
|
if (dns_list[i].wait_response_client) {
|
|
|
|
|
if (respond_client(&dns_list[i]) == 1)
|
|
|
|
|
return;
|
|
|
|
|
else
|
|
|
|
|
dns_list[i].wait_response_client = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ev.events = EPOLLIN;
|
|
|
|
|
ev.data.fd = dnsListenFd;
|
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_MOD, dnsListenFd, &ev);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
/* 分析DNS请求 */
|
|
|
|
|
int parse_dns_request(char *dns_req, dns_t * dns)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
dns_req += 13; //跳到域名部分
|
|
|
|
|
dns->host_len = strlen(dns_req);
|
|
|
|
|
//判断请求类型
|
|
|
|
|
switch ((dns->query_type = *(dns_req + 2 + dns->host_len))) {
|
|
|
|
|
//case 28: //查询ipv6地址
|
|
|
|
|
//dns->query_type = 1; //httpDNS不支持查询ipv6,所以改成ipv4
|
|
|
|
|
|
|
|
|
|
case 1: //查询ipv4地址
|
|
|
|
|
dns->host = strdup(dns_req);
|
|
|
|
|
if (dns->host == NULL)
|
|
|
|
|
return 1;
|
|
|
|
|
int len;
|
|
|
|
|
for (len = *(--dns_req); dns_req[len + 1] != 0; len += dns_req[len]) {
|
|
|
|
|
//防止数组越界
|
|
|
|
|
if (len > dns->host_len) {
|
|
|
|
|
free(dns->host);
|
|
|
|
|
return 1;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
dns->host[len++] = '.';
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
//printf("dns->host: %s\n", dns->host);
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
dns->host = NULL;
|
|
|
|
|
return 1;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
/* 建立DNS回应 */
|
|
|
|
|
int build_dns_response(dns_t * dns)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
char *p;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
//18: 查询资源的前(12字节)后(6字节)部分
|
|
|
|
|
dns->dns_rsp_len = 18 + dns->host_len + (dns->reply ? 16 : 0);
|
|
|
|
|
if (dns->dns_rsp_len > DATA_SIZE) {
|
|
|
|
|
dns->query_type = 0;
|
|
|
|
|
return 1; //超出缓冲大小
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
/* 问题数 */
|
|
|
|
|
dns->dns_req[4] = 0;
|
|
|
|
|
dns->dns_req[5] = 1;
|
|
|
|
|
/* 资源记录数 */
|
|
|
|
|
dns->dns_req[6] = 0;
|
|
|
|
|
dns->dns_req[7] = 0;
|
|
|
|
|
/* 授权资源记录数 */
|
|
|
|
|
dns->dns_req[8] = 0;
|
|
|
|
|
dns->dns_req[9] = 0;
|
|
|
|
|
/* 额外资源记录数 */
|
|
|
|
|
dns->dns_req[10] = 0;
|
|
|
|
|
dns->dns_req[11] = 0;
|
|
|
|
|
/* 如果有回应内容(资源记录) */
|
|
|
|
|
if (dns->reply) {
|
|
|
|
|
p = dns->dns_req + 18 + dns->host_len;
|
|
|
|
|
/* 资源记录数+1 */
|
|
|
|
|
dns->dns_req[7]++;
|
|
|
|
|
/* 成功标志 */
|
|
|
|
|
dns->dns_req[2] = (char)133;
|
|
|
|
|
dns->dns_req[3] = (char)128;
|
|
|
|
|
/* 指向主机域名 */
|
|
|
|
|
p[0] = (char)192;
|
|
|
|
|
p[1] = 12;
|
|
|
|
|
/* 回应类型 */
|
|
|
|
|
p[2] = 0;
|
|
|
|
|
p[3] = dns->query_type;
|
|
|
|
|
/* 区域类别 */
|
|
|
|
|
p[4] = 0;
|
|
|
|
|
p[5] = 1;
|
|
|
|
|
/* 生存时间 (1 ora) */
|
|
|
|
|
p[6] = 0;
|
|
|
|
|
p[7] = 0;
|
|
|
|
|
p[8] = 14;
|
|
|
|
|
p[9] = 16;
|
|
|
|
|
/* 回应长度 */
|
|
|
|
|
p[10] = 0;
|
|
|
|
|
p[11] = 4; //reply中包含回应长度
|
|
|
|
|
strcpy(p + 12, dns->reply);
|
|
|
|
|
} else {
|
|
|
|
|
/* 失败标志 */
|
|
|
|
|
dns->dns_req[2] = (char)129;
|
|
|
|
|
dns->dns_req[3] = (char)130;
|
|
|
|
|
}
|
|
|
|
|
if (respond_client(dns) == 1) {
|
|
|
|
|
dns->wait_response_client = 1;
|
|
|
|
|
ev.events = EPOLLIN | EPOLLOUT;
|
|
|
|
|
ev.data.fd = dnsListenFd;
|
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_MOD, dnsListenFd, &ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void http_out(dns_t * out)
|
|
|
|
|
{
|
|
|
|
|
int write_len;
|
|
|
|
|
|
|
|
|
|
//puts("writing");
|
|
|
|
|
//printf("%s\n", out->http_request);
|
|
|
|
|
write_len = write(out->fd, out->http_request, out->http_request_len);
|
|
|
|
|
if (write_len == out->http_request_len) {
|
|
|
|
|
//puts("write success");
|
|
|
|
|
free(out->http_request);
|
|
|
|
|
ev.events = EPOLLIN | EPOLLET;
|
|
|
|
|
ev.data.ptr = out;
|
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_MOD, out->fd, &ev);
|
|
|
|
|
} else if (write_len > 0) {
|
|
|
|
|
//puts("write a little");
|
|
|
|
|
out->http_request_len -= write_len;
|
|
|
|
|
memcpy(out->http_request, out->http_request + write_len, out->http_request_len);
|
|
|
|
|
} else {
|
|
|
|
|
//puts("write error");
|
|
|
|
|
free(out->http_request);
|
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_DEL, out->fd, NULL);
|
|
|
|
|
close(out->fd);
|
|
|
|
|
out->query_type = 0;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
void http_in(dns_t * in)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
char *ip_ptr, *p;
|
|
|
|
|
int len, i;
|
|
|
|
|
|
|
|
|
|
len = read(in->fd, http_rsp, HTTP_RSP_SIZE);
|
|
|
|
|
if (len <= 0) {
|
|
|
|
|
in->query_type = 0;
|
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_DEL, in->fd, NULL);
|
|
|
|
|
close(in->fd);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (encodeCode)
|
2020-07-30 18:10:31 +08:00
|
|
|
|
dataEncode(http_rsp, len);
|
|
|
|
|
http_rsp[len] = '\0';
|
|
|
|
|
//printf("[%s]\n", http_rsp);
|
|
|
|
|
p = strstr(http_rsp, "\n\r");
|
|
|
|
|
if (p) {
|
|
|
|
|
//部分代理服务器使用长连接,第二次读取数据才读到域名的IP
|
|
|
|
|
if (p + 3 - http_rsp >= len)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return;
|
2020-07-30 18:10:31 +08:00
|
|
|
|
p += 3;
|
|
|
|
|
} else
|
|
|
|
|
p = http_rsp;
|
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_DEL, in->fd, NULL);
|
|
|
|
|
close(in->fd);
|
|
|
|
|
in->reply = (char *)malloc(5);
|
|
|
|
|
if (in->reply == NULL)
|
|
|
|
|
goto error;
|
|
|
|
|
do {
|
|
|
|
|
if (*p == '\n')
|
|
|
|
|
p++;
|
|
|
|
|
/* 匹配IP */
|
|
|
|
|
if (*p > 57 || *p < 49)
|
|
|
|
|
continue;
|
|
|
|
|
for (i = 0, ip_ptr = p, p = strchr(ip_ptr, '.');; ip_ptr = p + 1, p = strchr(ip_ptr, '.')) {
|
|
|
|
|
if (i < 3) {
|
|
|
|
|
if (p == NULL)
|
|
|
|
|
goto error;
|
|
|
|
|
//查找下一行
|
|
|
|
|
if (p - ip_ptr > 3)
|
|
|
|
|
break;
|
|
|
|
|
in->reply[i++] = atoi(ip_ptr);
|
|
|
|
|
} else {
|
|
|
|
|
in->reply[3] = atoi(ip_ptr);
|
|
|
|
|
in->reply[4] = 0;
|
|
|
|
|
build_dns_response(in);
|
|
|
|
|
cfp ? cache_record(in) : free(in->reply);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
} while ((p = strchr(p, '\n')) != NULL);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
error:
|
|
|
|
|
free(in->reply);
|
|
|
|
|
in->reply = NULL;
|
|
|
|
|
if (build_dns_response(in) == 1)
|
|
|
|
|
in->query_type = 0;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
void new_client(conf *configure)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
dns_t *dns;
|
|
|
|
|
int i, len;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
for (i = 0; i < DNS_MAX_CONNECTION; i++)
|
|
|
|
|
if (dns_list[i].query_type == 0)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
break;
|
2020-07-30 18:10:31 +08:00
|
|
|
|
if (i == DNS_MAX_CONNECTION)
|
|
|
|
|
return;
|
|
|
|
|
dns = &dns_list[i];
|
|
|
|
|
len = recvfrom(dnsListenFd, &dns->dns_req, DATA_SIZE, 0, (struct sockaddr *)&dns->src_addr, &addr_len);
|
|
|
|
|
//printf("addr: [%s:%d]\n", inet_ntoa(dns->src_addr.sin_addr), ntohs(dns->src_addr.sin_port));
|
|
|
|
|
//dns请求必须大于18
|
|
|
|
|
if (len <= 18)
|
|
|
|
|
return;
|
|
|
|
|
/* 查询缓存 */
|
|
|
|
|
if (cachePath) {
|
|
|
|
|
dns->reply = cache_lookup(dns->dns_req + 12, dns);
|
|
|
|
|
if (dns->reply != NULL) {
|
|
|
|
|
if (build_dns_response(dns) != 0)
|
|
|
|
|
dns->query_type = 0;
|
|
|
|
|
return;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
if (parse_dns_request(dns->dns_req, dns) != 0) {
|
|
|
|
|
if (dns->host == NULL) {
|
|
|
|
|
if (build_dns_response(dns) != 0)
|
|
|
|
|
dns->query_type = 0;
|
|
|
|
|
} else
|
|
|
|
|
dns->query_type = 0;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return;
|
2020-07-30 18:10:31 +08:00
|
|
|
|
}
|
|
|
|
|
dns->fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
if (dns->fd < 0) {
|
|
|
|
|
dns->query_type = 0;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
fcntl(dns->fd, F_SETFL, O_NONBLOCK);
|
|
|
|
|
if (connect(dns->fd, (struct sockaddr *)&dst_addr, sizeof(dst_addr)) != 0 && errno != EINPROGRESS) {
|
|
|
|
|
close(dns->fd);
|
|
|
|
|
dns->query_type = 0;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
if (encodeCode)
|
|
|
|
|
dataEncode(dns->host, strlen(dns->host));
|
|
|
|
|
/* "GET /d?dn=" + dns->host + " HTTP/1.0\r\nHost: " + host_value + "\r\n\r\n" */
|
|
|
|
|
dns->http_request = (char *)malloc(10 + strlen(dns->host) + 17 + host_value_len + 4 + 1);
|
|
|
|
|
free(dns->host);
|
|
|
|
|
if (dns->http_request == NULL) {
|
|
|
|
|
close(dns->fd);
|
|
|
|
|
dns->query_type = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//dns->http_request_len = sprintf(dns->http_request, "GET /d?dn=%s HTTP/1.0\r\nHost: %s\r\n\r\n", dns->host, host_value);
|
|
|
|
|
|
|
|
|
|
strcpy(dns->http_request, configure->http_req);
|
|
|
|
|
dns->http_request_len = strlen(dns->http_request);
|
|
|
|
|
int http_request_len = (int)dns->http_request_len;
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "[M]", 3, "GET", 3);
|
|
|
|
|
dns->host_len = strlen(dns->host);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "[D]", 3, dns->host, dns->host_len);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "[V]", 3, "HTTP/1.0", 8);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\r", 2, "\r", 1);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\n", 2, "\n", 1);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\b", 2, "\b", 1);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\v", 2, "\v", 1);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\f", 2, "\f", 1);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\a", 2, "\a", 1);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\t", 2, "\t", 1);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\r", 2, "\r", 1);
|
|
|
|
|
dns->http_request = replace(dns->http_request, &http_request_len, "\\n", 2, "\n", 1);
|
|
|
|
|
dns->http_request_len = strlen(dns->http_request);
|
|
|
|
|
//printf("%s\n", dns->http_request);
|
|
|
|
|
|
|
|
|
|
ev.events = EPOLLOUT | EPOLLERR | EPOLLET;
|
|
|
|
|
ev.data.ptr = dns;
|
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_ADD, dns->fd, &ev);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
void *httpdns_loop(void *p)
|
2020-06-20 16:59:51 +08:00
|
|
|
|
{
|
2020-07-30 18:10:31 +08:00
|
|
|
|
conf *configure = (conf *) p;
|
|
|
|
|
int n;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
|
2020-07-30 18:10:31 +08:00
|
|
|
|
fcntl(dnsListenFd, F_SETFL, O_NONBLOCK);
|
|
|
|
|
dns_efd = epoll_create(DNS_MAX_CONNECTION + 1);
|
|
|
|
|
if (dns_efd < 0) {
|
2020-06-20 16:59:51 +08:00
|
|
|
|
perror("epoll_create");
|
2020-07-30 18:10:31 +08:00
|
|
|
|
return NULL;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
ev.data.fd = dnsListenFd;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
ev.events = EPOLLIN;
|
2020-07-30 18:10:31 +08:00
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_ADD, dnsListenFd, &ev);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
memset(dns_list, 0, sizeof(dns_list));
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2020-07-30 18:10:31 +08:00
|
|
|
|
n = epoll_wait(dns_efd, evs, DNS_MAX_CONNECTION + 1, -1);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
while (n-- > 0) {
|
2020-07-30 18:10:31 +08:00
|
|
|
|
if (evs[n].data.fd == dnsListenFd) {
|
2020-06-20 16:59:51 +08:00
|
|
|
|
if (evs[n].events & EPOLLIN) {
|
2020-07-30 18:10:31 +08:00
|
|
|
|
new_client(configure);
|
|
|
|
|
}
|
|
|
|
|
if (evs[n].events & EPOLLOUT) {
|
|
|
|
|
respond_clients();
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
} else if (evs[n].events & EPOLLIN) {
|
2020-07-30 18:10:31 +08:00
|
|
|
|
http_in(evs[n].data.ptr);
|
2020-06-20 16:59:51 +08:00
|
|
|
|
} else if (evs[n].events & EPOLLOUT) {
|
2020-07-30 18:10:31 +08:00
|
|
|
|
http_out(evs[n].data.ptr);
|
|
|
|
|
} else if (evs[n].events & EPOLLERR) {
|
|
|
|
|
dns_t *err = evs[n].data.ptr;
|
|
|
|
|
free(err->http_request);
|
|
|
|
|
epoll_ctl(dns_efd, EPOLL_CTL_DEL, err->fd, NULL);
|
|
|
|
|
close(err->fd);
|
|
|
|
|
err->query_type = 0;
|
2020-06-20 16:59:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
|
2020-06-20 16:59:51 +08:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-07-30 18:10:31 +08:00
|
|
|
|
|
|
|
|
|
int udp_listen(char *ip, int port)
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
|
|
|
|
|
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
|
|
|
perror("udp socket");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
|
addr.sin_port = htons(port);
|
|
|
|
|
addr.sin_addr.s_addr = inet_addr(ip);
|
|
|
|
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
|
|
|
|
|
perror("udp bind");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int httpdns_initialize(conf * configure) {
|
|
|
|
|
char *p;
|
|
|
|
|
p = strchr(configure->addr, ':');
|
|
|
|
|
host_value = configure->addr;
|
|
|
|
|
*p = '\0';
|
|
|
|
|
//printf("udp: %s %d %d\n", configure->addr, configure->dns_listen, atoi(p+1));
|
|
|
|
|
|
|
|
|
|
dnsListenFd = udp_listen("0.0.0.0", configure->dns_listen);
|
|
|
|
|
dst_addr.sin_addr.s_addr = inet_addr(configure->addr);
|
|
|
|
|
dst_addr.sin_family = AF_INET;
|
|
|
|
|
dst_addr.sin_port = htons(atoi(p+1));
|
|
|
|
|
|
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
signal(SIGTERM, write_dns_cache);
|
|
|
|
|
host_value_len = strlen(host_value);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|