#include "dnsmap.h"
/*加载内核IP_QUEUE模块,同时添加IPTABLES规则*/
static void creat_iptable_rules(const char *addr)
{
char cmd[CMD_LEN];
sprintf(cmd, "modprobe ip_queue\n");
system(cmd);
sprintf(cmd, "iptables -D FORWARD -d %s -p udp --sport 53 -j QUEUE\n", addr);
system(cmd);
sprintf(cmd, "iptables -A FORWARD -d %s -p udp --sport 53 -j QUEUE\n", addr);
system(cmd);
sprintf(cmd, "iptables -D FORWARD -s %s -p udp --dport 53 -j QUEUE\n", addr);
system(cmd);
sprintf(cmd, "iptables -A FORWARD -s %s -p udp --dport 53 -j QUEUE\n", addr);
system(cmd);
return;
}
/*获取要替换的域名的IP*/
static int get_new_domain_ip(char *ipstr)
{
struct hostent *hent;
struct in_addr host;
hent = gethostbyname(domain2);
if (hent != NULL) {
memcpy(&host, hent->h_addr_list[0], 4);
strncpy(ipstr, (char *)inet_ntoa(host), 16);
} else {
printf("get the new domain ip error\n");
return RS_WRONG;
}
return RS_OK;
}
/*计算IP头校验和*/
static unsigned short check_sum(unsigned short *buffer, int size)
{
unsigned long cksum = 0;
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(unsigned short);
}
if (size)
{
cksum += *(unsigned char *)buffer;
}
//turn 32 bit number to 16 bit
while (cksum >> 16)
{
cksum = (cksum >> 16) + (cksum & 0xffff);
}
return (unsigned short)(~cksum);
}
/*计算UDP头部校验和*/
static unsigned short udp_check(struct _ip_hdr *iphd)
{
char check_buf[BUFSIZE];
struct _udp_hdr *udph = (struct _udp_hdr *)&iphd[1];
struct proto_checknum *check;
check = (struct proto_checknum *)check_buf;
check ->ip_src = iphd->srcaddr.s_addr;
check ->ip_dst = iphd->dstaddr.s_addr;
check ->mbz = 0;
check ->ip_type = iphd->protocol;
check ->len = htons(ntohs(iphd->tot_len) - sizeof(struct _ip_hdr));
memcpy(check_buf + sizeof(struct proto_checknum), udph, ntohs(iphd->tot_len) - sizeof(struct _ip_hdr));
udph->chk_sum = check_sum((unsigned short *)check_buf, sizeof(struct proto_checknum) + ntohs(iphd->tot_len) - sizeof(struct _ip_hdr));
}
/*获取DNS报文里面的域名字符串*/
static int get_domain(unsigned char *domain, char dnbuf[MAX_LEN])
{
unsigned char *dn;
int i, l, n, len;
dn = domain;
len = 0;
n = 0;
do
{
l = (int)*dn;
if(!l)
{
n--;
break;
}
for(i = 0; i < l; i++)
{
dnbuf[n++] = dn[i+1];
}
dnbuf[n++] = '.';
dn = dn + l + 1;
len += (l + 1);
}while(n<60);
dnbuf[n] = '\0';
len += 5;
return len;
}
/*将域名转换成报文里的域名存储格式*/
static int replace_domain(unsigned char *domain)
{
unsigned char i, l, n;
unsigned char *q = domain;
char *dn = domain2;
char *p = domain2;
l=0;
i=0;
n=0;
for (;;) {
if (*p && (*p != '.')) {
l++;
p++;
} else {
domain[n] = l;
n++;
for(i=0; i < l; i++) {
domain[n] = dn[n-1];
n++;
}
l = 0;
p++;
if (*p == '\0') break;
}
}
domain[n] = (unsigned char)0;
domain[++n] = (unsigned char)0;
domain[++n] = (unsigned char)1;
domain[++n] = (unsigned char)0;
domain[++n] = (unsigned char)1;
return n+1;
}
/*出错时清附IPQ资源*/
static void die(struct ipq_handle *h)
{
ipq_destroy_handle(h);
printf("create ipqhander error\n");
exit(1);
}
/*初始化IPQ,和内核建立netlink通信,设置获取报文的模式*/
static struct ipq_handle *init_dnsmap(void)
{
int status;
struct ipq_handle *h;
h = ipq_create_handle(0, PF_INET);
if (!h) {
printf("h is NULL \n");
die(h);
}
status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
if (status < 0) {
die(h);
}
return h;
}
static void hand_packet(struct ipq_handle *h, const char *ipstr)
{
ipq_packet_msg_t *m;
int status;
int oldlen, newlen, answerlen;
char name[MAX_LEN];
unsigned char buf[BUFSIZE];
struct dns *dnspack;
unsigned char *olddn;
unsigned char newdn[MAX_LEN];
unsigned char *answer;
unsigned char answers[BUFSIZE];
int i;
printf("the new ip is %s\n", ipstr);
do{
status = ipq_read(h, buf, BUFSIZE, 0);
if (status < 0)
die(h);
switch (ipq_message_type(buf)) {
case NLMSG_ERROR:
printf("Received error message\n");
break;
case IPQM_PACKET:
m = ipq_get_packet(buf);
dnspack = (struct dns*)m->payload;
/*对进来的DNS报文即DNS回复报文,修改其IP*/
if (ntohs(dnspack->udph.dst_port) == 53) {
olddn = (unsigned char *)&dnspack->dnsh + 12;
oldlen = get_domain(olddn, name);
if (!strncmp(name, domain1, MIN(strlen(name), strlen(domain1)))) {
printf("the domain want to change is %s\n", name);
olddata.id = ntohs(dnspack->dnsh.id);
olddata.len = oldlen;
memset(olddata.question, 0, sizeof(olddata.question));
memcpy(olddata.question, olddn, oldlen);
newlen = replace_domain(newdn);
memset(olddn, 0, oldlen);
memcpy(olddn, newdn, newlen);
dnspack->iph.tot_len = htons(20 + 8 + 12 + newlen);
dnspack->udph.uhl = htons(8+12+newlen);
m->data_len = 20 + 8 + 12 + newlen;
dnspack->iph.chk_sum = 0x0;
dnspack->udph.chk_sum = 0x0;
dnspack->iph.chk_sum = check_sum((unsigned short *)&dnspack->iph, sizeof(struct _ip_hdr));
udp_check((struct _ip_hdr*)&dnspack->iph);
}
}
if (ntohs(dnspack->udph.src_port) == 53 && (ntohs(dnspack->dnsh.id) == olddata.id)) {
olddn = (unsigned char *)&dnspack->dnsh + 12;
oldlen = get_domain(olddn, name);
answer = olddn + oldlen;
answerlen = htons(dnspack->udph.uhl) -8 -12 -oldlen;
if (!strncmp(name, domain2, MIN(strlen(name), strlen(domain2)))) {
memset(answers, 0, sizeof(answers));
memcpy(answers, olddata.question, olddata.len);
get_domain(answers, name);
printf("now change back the domain %s\n", name);
memcpy(answers + olddata.len, answer, answerlen);
memset(olddn, 0 , answerlen + oldlen);
memcpy(olddn, answers, answerlen + olddata.len);
dnspack->iph.tot_len = htons(20 + 8 + 12 + olddata.len + answerlen);
dnspack->udph.uhl = htons(8+12+olddata.len + answerlen);
m->data_len = 20 + 8 + 12 + answerlen + olddata.len;
dnspack->iph.chk_sum = 0x0;
dnspack->udph.chk_sum = 0x0;
dnspack->iph.chk_sum = check_sum((unsigned short *)&dnspack->iph, sizeof(struct _ip_hdr));
udp_check((struct _ip_hdr*)&dnspack->iph);
}
}
status = ipq_set_verdict(h, m->packet_id, NF_ACCEPT, m->data_len, m->payload);
memset(buf, 0, BUFSIZE);
memset(name, 0, MAX_LEN);
memset(newdn, 0, MAX_LEN);
memset(answers, 0, BUFSIZE);
if (status < 0)
die(h);
break;
default:
printf("Unknown message type!\n");
break;
- 1
- 2
前往页