admin管理员组文章数量:1565825
需求背景:
目前路由器的配置界面是通过输入网关IP来访问,市面上其他的路由器可以通过域名来访问,例如腾达路由器的配置界面地址 routendawifi。
所以我们也希望支持域名访问路由器的配置界面。如在浏览器中输入www.9344base 就可以访问路由器界面。
实现原理:
一次正常的域名访问流程如下:
(1) 客户端向DNS服务器发送域名解析请求,该请求会先发到路由器。
(2) 路由器收到DNS请求后会对其进行转发,发给外网的DNS服务器。
(3) 外网的DNS服务器收到请求后,进行解析,之后发出DNS应答,其中就包括了域名对应的IP。
(4) 路由器收到DNS服务器发来的应答包,将其转发给客户端。
(5) 客户端收到应答,按照对应IP进行访问。
我们的修改发生在第2步,当路由器收到客户端的DNS请求包后,筛选出特定域名的请求包,不对其进行转发,而是将其丢弃,然后生成一个DNS应答包发给客户端,该应答包中IP就是网关IP或者A20的IP。这样客户端收到应答包后就可以把特定域名和网关对应起来了。
这部分的实现主要是在iptables 和netfilter中,netfilter中对DNS数据包进行筛选、丢弃和生成。
源码介绍
对源码的修改主要分两部分:iptables 部分和netfilter 部分,关于iptables和netfilter关系以及match、target、hook点、iptables 表、iptables链的详细介绍参考如下资料 :
http://blog.chinaunix/uid-20775448-id-3504538.html
(1) iptables 部分
源码位置:apps/iptables/iptables-1.4.5-qos/extensions
主要添加了libipt_DNS.c 和 libipt_dnsurl.c 两个文件。其中libipt_DNS.c 是DNS功能的iptables 中的target模块。
核心代码如下:
static int DNS_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct ipt_dns_info *dnsinfo = (struct ipt_dns_info *)(*target)->data;
const struct in_addr *ip;
xtables_check_inverse(optarg, &invert, &optind, 0);
switch (c) {
case '1':
ip = xtables_numeric_to_ipaddr(argv[optind-1]);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
argv[optind-1]);
dnsinfo->ip = ip->s_addr;
//printf("ip = %x\n", dnsinfo->ip);
break;
default:
return 0;
}
return 1;
}
主要功能就是将iptables 命令传入的IP参数进行解析,然后填充到ipt_dns_info结构体中,之后将该结构体传入内核,交个DNS 的netfilter target模块使用。
libipt_dnsurl.c 文件 是DNS功能的iptables 中的match模块,核心代码如下:
static int parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry,
struct xt_entry_match **match)
{
struct xt_dnsurl_info *info = (struct xt_dnsurl_info *)(*match)->data;
xtables_check_inverse(optarg, &invert, &optind, 0);
if (invert) xtables_error(PARAMETER_PROBLEM, "Sorry, you can't have an inverted comment");
// printf("dnsurl parse\n");
if (c == '1')
{
strcpy(info->url, argv[optind-1]);
info->url_len = strlen(argv[optind-1]);
if(!strcmp(argv[optind-1],"enforcedns"))
{
info->enforce_dns = 1;
}
}
else
{
return 0;
}
if (*flags)
xtables_error(PARAMETER_PROBLEM, "multiurl can only have one option");
*flags = 2;
return 1;
}
主要作用是将iptables 命令传入的URL参数进行解析,然后填充到xt_dnsurl_info 结构体中,之后将该结构体传入内核,交个DNS 的netfilter match模块使用。
(2)netfilter 部分
主要添加了netfilter 的match模块和target模块。
target模块源码位于 linux/kernels/mips-linux-2.6.31/net/ipv4/netfilter/ nf_nat_rule.c文件中,核心源码如下:
static unsigned int
ipt_dns_target(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct ipt_dns_info *dnsinfo = par->targinfo;
struct iphdr *iph = ip_hdr(skb);
struct udphdr *udph = (void *)iph + iph->ihl*4; /* Might be TCP, UDP */
int ret = 0;
int addr = 0;
u_int16_t port = 0;
u_int16_t *flag = (void *)udph + 10;
char buff[50] = {0};
char *buff_p = buff;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
u_int16_t *udp_check = (void *)udph + 6;
u_int8_t *url_len = (void *)udph + 20;
char *url = url_len+1;
/*将DNS数据包的目的IP和源IP进行互换,源端口和目的端口互换,这样就可以将收的数据包又返回给发送者*/
addr = iph->daddr;iph->daddr = iph->saddr; iph->saddr = addr;
port = udph->dest;
udph->dest = udph->source;
udph->source = port;
/*修改flag将请求模式改成应答模式*/
*flag ++= 0x8580;
/*修改资源记录数为1,修改问题数为1*/
*flag ++= 0x0001;
*flag = 0x0001;
/*填充应答包中资源记录部分数据,即要给客户端的DNS IP数据*/
*buff_p++=0xc0;
*buff_p++=0x0c;
*(int *)buff_p = 0x00010001;
buff_p +=4;
*(int *)buff_p = 0x0;
buff_p +=4;
*(u_int16_t *)buff_p = 0x4;
buff_p +=2;
/*查询的URL对应的IP*/
*(int *)buff_p = dnsinfo->ip;
/*完成对UDP包的修改,进行相关的校验*/
nf_nat_mangle_udp_packet_fw(skb, ct, ctinfo,
udph->len-8, 0,
&buff, 16);
return 1;
}
主要作用是将match筛选过的数据包进行修改,填充DNS应答包,这样就可以把客户端发来的DNS请求包变成应答包,然后再返还给客户端,从而模拟了一次完整的DNS请求应答过程。
Match模块源码位于:linux/kernels/mips-linux-2.6.31/net/ipv4/netfilter/ ipt_multiurl.c文件中。核心代码如下:
static bool dnsmatch(const struct sk_buff *skb,
const struct xt_match_param *param)
{
const struct xt_dnsurl_info *info = param->matchinfo;
struct iphdr *iph = ip_hdr(skb);
struct udphdr *udph = (void *)iph + iph->ihl*4; /* Might be TCP, UDP */
u_int8_t *url_len = (void *)udph + 20;
char *url = url_len+1;
if(info->enforce_dns)
{
return 1;
}
/*判断DNS请求包中的URL长度是不是和特定URL的长度一致*/
if( *url_len == info->url_len)
{
/*判断DNS请求包中的URL内容是不是和特定URL一致,如果一致将返回1,表明该数据包通过筛选*/
if (!memcmp(url, info->url, info->url_len))
{
// printk("yaomoon: match dnsurl url_len = %d\n",info->url_len);
return 1;
}
}
if( (*url_len == 3)&&(*(url_len+4) == info->url_len))
{
url_len +=4;
url = url_len+1;
if (!memcmp(url, info->url, info->url_len))
{
// printk("yaomoon: match dnsurl url_len = %d\n",info->url_len);
return 1;
}
}
return 0;
}
主要作用就是筛选DNS请求包,DNS请求包中包含所请求的URL内容和长度,我们可以通过判断出是不是我们要改的DNS请求包。
版权声明:本文标题:通过域名访问路由器配置界面的功能实现 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1726680028a1080740.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论