2015-08-03 212 views
0

我目前正在爲我的夏季實習項目工作,而且我必須做一個不經意的DNS翻譯服務器。我不是在這裏詳細講述這個無意義的部分,但我會解釋我的程序的體系結構。自定義DNS答案

有一個服務器端接收混淆的請求,併發回一個它自己不理解的答案。

在客戶端,有一個將請求轉換爲混淆請求的代理。爲此,我使用iptables規則將所有DNS請求發送到NFQUEUE,然後使用libnetfilter_queue處理數據包。 之後,我從服務器收到答案,然後用我得到的所有信息(來自DNS請求和服務器)做出DNS答案,並使用libnet發送它。

現在讓我們來談談我的問題:使用我的代理時,我使用Wireshark檢查流量,並且似乎我的代理髮送了有效的答案,但是如果我嘗試使用Firefox瀏覽Internet,則不起作用。 你可以在這裏找到我的代碼:https://github.com/AurelienCasimir/PrivateDNS

在我構建DNS數據包的方式中存在問題嗎?

這裏是DNS發件人:

int send_answer(char *dst_ip_array, char *src_ip_array, int dport, int sport, int dns_id, char *query, char *req_ip, int logfd) 
{ 
char c; 
u_long src_ip = arrayToLong(src_ip_array), dst_ip = arrayToLong(dst_ip_array), requested_ip_long=dotToLong(req_ip); 
char requested_ip[4]; 
u_short type = LIBNET_UDP_DNSV4_H; 
libnet_t *l; 

libnet_ptag_t ip; 
libnet_ptag_t ptag4; /* TCP or UDP ptag */ 
libnet_ptag_t dns; 

char errbuf[LIBNET_ERRBUF_SIZE]; 
char payload[1024]; 
u_short payload_s; 
char log_buffer[500]; 
int length = 0; 

/* 
* Initialize the library. Root priviledges are required. 
*/ 
l = libnet_init(
     LIBNET_RAW4,       /* injection type */ 
     NULL,         /* network interface */ 
     errbuf);        /* error buffer */ 

if (!l) 
{ 
    length += sprintf(log_buffer + length, "\tlibnet_init: %s", errbuf); 
    exit(EXIT_FAILURE); 
} 

/* 
* build dns payload 
*/ 
requested_ip[0]=requested_ip_long/(256*256*256); 
requested_ip_long=requested_ip_long%(256*256*256); 
requested_ip[1]=requested_ip_long/(256*256); 
requested_ip_long=requested_ip_long%(256*256); 
requested_ip[2]=requested_ip_long/256; 
requested_ip_long=requested_ip_long%256; 
requested_ip[3]=requested_ip_long; 

payload_s = snprintf(payload, sizeof payload, "%c%s%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", 
     (char)(strlen(query)&0xff), query, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xe0, 0x00, 0x04, requested_ip[0], requested_ip[1], requested_ip[2], requested_ip[3]); 

/* 
* build packet 
*/ 
dns = libnet_build_dnsv4(
type,   /* TCP or UDP */ 
dns_id,  /* id */ 
0x8100,  /* request */ 
1,    /* num_q */ 
1,    /* num_anws_rr */ 
0,    /* num_auth_rr */ 
0,    /* num_addi_rr */ 
payload, 
payload_s, 
l, 
0 
); 

if (dns == -1) 
{ 
    length += sprintf(log_buffer + length, "\tCan't build DNS packet: %s\n", libnet_geterror(l)); 
    goto bad; 
} 

ptag4 = libnet_build_udp(
    sport,        /* source port */ 
    dport,         /* destination port */ 
    LIBNET_UDP_H + LIBNET_UDP_DNSV4_H + payload_s, /* packet length */ 
    0,          /* checksum */ 
    NULL,         /* payload */ 
    0,          /* payload size */ 
    l,          /* libnet handle */ 
    0);          /* libnet id */ 

if (ptag4 == -1) 
{ 
    length += sprintf(log_buffer + length, "\tCan't build UDP header: %s\n", libnet_geterror(l)); 
    goto bad; 
} 


ip = libnet_build_ipv4(
    LIBNET_IPV4_H + LIBNET_UDP_H + type + payload_s,/* length */ 
    0,           /* TOS */ 
    242,          /* IP ID */ 
    0,           /* IP Frag */ 
    64,           /* TTL */ 
    IPPROTO_UDP,        /* protocol */ 
    0,           /* checksum */ 
    src_ip,          /* source IP */ 
    dst_ip,          /* destination IP */ 
    NULL,          /* payload */ 
    0,           /* payload size */ 
    l,           /* libnet handle */ 
    0);           /* libnet id */ 

if (ip == -1) 
{ 
    length += sprintf(log_buffer + length, "\tCan't build IP header: %s\n", libnet_geterror(l)); 
    exit(EXIT_FAILURE); 
} 


/* 
* write to the wire 
*/ 
c = libnet_write(l); 
if (c == -1) 
{ 
    length += sprintf(log_buffer + length, "\tWrite error: %s\n", libnet_geterror(l)); 
    goto bad; 
} 
else 
{ 
    length += sprintf(log_buffer + length, "\tWrote %d byte DNS packet; check the wire.\n", c); 
} 
length = strlen(log_buffer); 
write(logfd, log_buffer, length); // Write to the log. 
libnet_destroy(l); 
return (EXIT_SUCCESS); 
bad: 
length = strlen(log_buffer); 
write(logfd, log_buffer, length); // Write to the log. 
libnet_destroy(l); 
return (EXIT_FAILURE); 
} 

這裏是我的代理髮送DNS答案的例子: http://imgur.com/9c5RgLj

+0

當你使用Firefox,會發生什麼的那個類型及類別?它是否將UDP請求發送給您的代理,或者直接發送給另一臺DNS服務器? – rodolk

+0

它將它發送到DNS服務器,我在nfqueue中捕獲並在獲取所需信息後將其刪除。 – Kromoz0hm

+0

您可以顯示DNS響應,因爲它會到達瀏覽器? – rodolk

回答

0

看來DNS響應是正確的。我想看看:

  1. 如果可用的標誌遞歸是必要的(0x8180)
  2. 檢查返回的IP地址就可以了。我無法訪問您在映像中顯示的IP地址(https://db-ip.com/26.193.206.130
  3. UDP校驗和是否正確?
  4. 交易ID是否對應於DNS查詢的交易ID?
  5. 我敢肯定,這是確定的,但只是檢查服務器請求地址
+0

1.試過了,它仍然不起作用。 2.我的數據庫中的所有IP地址都來自真正的DNS服務器的答案。 3.在libnet_build_udp中使用0作爲校驗和,它應該讓內核自己計算校驗和。這是我從NFQUEU中的數據包中獲得的信息之一。 5.這可能是棘手的部分,因爲目前我的項目不處理CNAME條目。 (後面的評論部分) – Kromoz0hm

+0

我不認爲它應該是一個問題,因爲請求不知道它是否是一個CNAME或主機地址,所以而不是回答一個CNAME +主機名它只是回答一個主機名(另一個區別是它只有一個IP地址而不是多個IP地址) – Kromoz0hm

+0

@ Kromoz0hm,我不認爲它與CNAME相關,這是DNS服務器的內部。你可以嘗試直接在瀏覽器中使用該IP地址嗎?在主機文件中添加域名和IP地址,並在Firefox中添加您的域名(不含您的解決方案)。這是澄清任何可能的疑問的方法。在第4點中,您可以通過捕獲查詢和迴應來澄清: – rodolk