您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > DDNS的工作原理及其在Linux上的实现
花边厂酥油灯厂家简介:DDNS(DynamicDNS)扩展了DNS将客户端IP与其域名进行静态映射的功能,它可以将同一域名实时地解析为不同的动态IP,而不需要额外的人工干预。这在客户端IP地址不断发生变化的情况下,尤其是在无线网络和DHCP环境中,都有着极其重要的意义。本文通过分析DDNS的工作原理,简单演示了其在Linux网络协议栈的内核空间及用户空间创建netlink套接字、进行数据交换、并最终通过nsupate工具将更新消息发送给DNS服务器的过程。DDNS工作原理的分析DDNS的实现最根本的一点是当主机的IP地址发生变化的时候,实现DNS映射信息的及时更新,应用程序需要及时地获得这一信息,主要的方法可分为两大类:一类是轮询机制,即:应用程序每隔一定的时间,去从查询主机当前的IP地址,并与之前的进行比较,从而判断网络地址是否发生了变化。显然,这种方法不仅效率低下,而且对每次查询IP地址的时间间隔很难得到一个折中的数值。第二类方法是异步实现方式,即:每当主机的IP地址发生变化的时候,应用程序能够被及时地通知到。这的确是一个简单而又高效的方法,但与此同时,另一个问题又产生了,那就是:通知源又应该由谁来担当呢?显然,这是处于用户空间的应用程序无法胜任的。于是,我们想到了让内核来充当这一消息源。这样,在内核空间和用户空间之间就需要通过消息来进行通信了。在Linux下用户空间与内核空间的信息交互方式有许多种,比如:软中断、系统调用、netlink等等。关于这些通信方式的介绍以及其各自的优缺点并不在本文的讨论范围内,您可以自行查看参考资源。在这许多种通信方式中,netlink凭借其标准的socketAPI、模块化实现、异步通信机制、多播机制等等多种优势,成为了内核与越来越多应用程序之间交互的主要方式。在Linux的内核中,已经为我们封装了使用netlink对特定网络状态变化进行消息通知的功能,这就是著名的rtnetlink。有关netlink在内核空间实现的详细代码以及其API参数的介绍,您可以自行查看参考资源,本文在此不作过多的赘述。本文讨论的重点是针对DDNS这一特定的应用,演示rtnetlink检测到IP地址发生了变化、并将消息告知用户空间的应用程序的整个过程,以及应用程序利用netlink套接字接收消息、并告知DNS服务器的实现方法。DDNS工作流程的简单介绍结合上述对DDNS工作原理的分析,我们可以将DDNS的工作流程简单地用图1来表示:图1.DDNS的工作流程图花边厂酥油灯厂家从图1中可以看到,DDNS的工作流程主要有三个部分:1.应用程序实时感知到IP地址发生了变化,如上介绍,利用基于netlink的异步通知机制可以让应用程序及时得到内核空间对这些事件的“通知”,具体可以分为如下5个步骤:o1、内核空间初始化rtnetlink模块,创建NETLINK_ROUTE协议簇类型的netlink套接字;o2、用户空间创建NETLINK_ROUTE协议簇类型的netlink套接字,并且绑定到RTMGRP_IPV4_IFADDR组播group中;o3、用户空间接收从内核空间发来的消息,如果没有消息,则阻塞自身;o4、当主机被分配了新的IPV4地址,内核空间通过netlink_broadcast,将RTM_NEWADDR消息发送到RTNLGRP_IPV4_IFADDR组播group中;o5、用户空间接收消息,进行验证、处理;2.应用程序接收到“通知”后,把DNSupdate信息发送给DNS服务器,目的是将更新后的IP地址及时地通知DNS服务器,以便网络上的主机仍然能够通过原来的域名访问到自己,通用的做法是利用开源软件nsupdate发送DNSupdate信息给DNS服务器以实现DNS信息的动态更新。3.最后,对应于第一部分netlink套接字的创建,用户空间和内核空间关闭所创建的netlink套接字。下文将详细阐述其中的每一环节及其实现。内核空间rtnetlink检测IP地址变化的实现与分析在我们开始利用netlink套接字、实现与内核通信的应用程序之前,先来分析一下内核空间的rtnetlink模块是如何工作的。内核空间rtnetlink的初始化清单1.rtnetlink的初始化/*花边厂酥油灯厂家以下代码摘自Linuxkernel2.6.18,net/core/rtnetlink.c文件,并只选择了与本主题相关的最重要的部分,其他的都用省略号略过,之后的各清单也一样。*/void__initrtnetlink_init(void){......rtnl=netlink_kernel_create(NETLINK_ROUTE,RTNLGRP_MAX,rtnetlink_rcv,THIS_MODULE);if(rtnl==NULL)panic(rtnetlink_init:cannotinitializertnetlink\n);......}从清单1中可以看到:在rtnetlink进行初始化的时候,首先会调用netlink_kernel_create来创建一个NETLINK_ROUTE类型的netlink套接字,并指定接收函数为rtnetlink_rcv,有关rtnetlink_rcv的实现细节可以查阅内核net/core/rtnetlink.c文件。这里需要指出的是,netlink提供了包括NETLINK_ROUTE、NETLINK_FIREWALL、NETLINK_INET_DIAG等在内的多种协议簇(详细列表及各协议簇的含义可以自行查看参考资源),其中NETLINK_ROUTE类型提供了网络地址发生变化的消息,这正是DDNS需要用到的。内核空间IP地址变化事件的通知过程引起主机IP地址变化的原因有很多种,如:DHCP分配的IP过期、用户手动修改了IP等等。无论何种原因,最终都会触发内核空间对相应事件的通知机制,这里以最常用的修改IPV4地址的工具ifconfig为例。ifconfig先是创建一个AF_INET的socket,然后通过系统调用ioctl来完成配置的,ioctl在内核中对应的函数是sys_ioctl,对于IP地址、子网掩码、默认网关等配置的修改,其最终会调用devinet_ioctl。devinet_ioctl函数处理包括get、set在内的多种命令,与DDNS应用有关的是set类命令,图2给出了SIOCSIFADDR命令(设置网络地址)的ifconfig调用树:图2.SIOCSIFADDR命令的ifconfig调用树花边厂酥油灯厂家从图2中可以看到,当用户使用ifconfig对主机的IP地址作了修改,内核在进行了新地址的设置之后,会调用rtmsg_ifa,传递的事件为RTM_NEWADDR。清单2.rtmsg_ifa发送IP地址变化消息/*以下代码摘自Linuxkernel2.6.18,net/ipv4/devinet.c文件*/staticvoidrtmsg_ifa(intevent,structin_ifaddr*ifa){intsize=NLMSG_SPACE(sizeof(structifaddrmsg)+128);structsk_buff*skb=alloc_skb(size,GFP_KERNEL);if(!skb)netlink_set_err(rtnl,0,RTNLGRP_IPV4_IFADDR,ENOBUFS);elseif(inet_fill_ifaddr(skb,ifa,0,0,event,0)0){kfree_skb(skb);netlink_set_err(rtnl,0,RTNLGRP_IPV4_IFADDR,EINVAL);}else{netlink_broadcast(rtnl,skb,0,RTNLGRP_IPV4_IFADDR,GFP_KERNEL);}}从清单2中可以看到,rtmsg_ifa的实现主要包括:花边厂酥油灯厂家首先分配了一块类型为structsk_buff的空间用于存放需要发送的消息内容。2.随后,调用inet_fill_ifaddr将消息填充至上述缓存(有关消息的格式,您可以自行查看参考资源)。值得注意的是,RTM_NEWADDR被作为nlmsg_type封装到了内核发送给应用程序的netlink消息头nlmsghdr中,这样用户空间的应用程序在接收后就能够根据type来分别处理不同类型的消息了。3.rtmsg_ifa的最后是调用了netlink_broadcast将上述封装完毕的sk_buff结构广播到RTNLGRP_IPV4_IFADDR这个group,以下是内核空间组播group与用户空间组播group的对应关系:清单3.内核空间组播group与用户空间组播group的对应关系/*以下代码摘自Linuxkernel2.6.18,include/linux/rtnetlink.h文件*//*RTnetlinkmulticastgroups*/enumrtnetlink_groups{RTNLGRP_NONE,#defineRTNLGRP_NONERTNLGRP_NONERTNLGRP_LINK,#defineRTNLGRP_LINKRTNLGRP_LINK.....RTNLGRP_IPV4_IFADDR,#defineRTNLGRP_IPV4_IFADDRRTNLGRP_IPV4_IFADDR......};#ifndef__KERNEL__/*RTnetlinkmulticastgroups-backwardscompatibilityforuserspace*/#defineRTMGRP_LINK1#defineRTMGRP_NOTIFY2......#defineRTMGRP_IPV4_IFADDR0x10......#endif综上所述,当主机的IP地址发生变化时,内核会向所有RTNLGRP_IPV4_IFADDR组播成员发送RTM_NEWADDR消息。因此,在用户空间创建netlink套接字时,只需要加入到RTMGRP_IPV4_IFADDR这个组播group中,就可以实现当本机IP地址有更新的时候,DDNS应用程序能够异步地收到内核空间发来的通知消息了。###NextPage###用户空间netlinksocket的创建、绑定与消息接收处理用户空间创建netlink套接字用户空间的netlinksocket相关操作与标准socketAPI完全一致,因此可以像使用标准socket来进行两台主机间的IP协议通信一样地来使用它,这也是netlink之所以能够得到越来越广泛应用的一个重要原因。清单4.用户空间创建netlinksocket花边厂酥油灯厂家(void){......if((nl_socket=socket(PF_NETLINK,SOCK_DGRAM,NETLINK_ROUTE))==-1)//指定通信域、通信方式以及通信协议exit(1);......}在创建netlink套接字时:我们指定了通信域为PF_NETLINK,表明这是一个netlink套接字。其定义可以在如下所示的内核include/linux/socket.h文件中找到。从中我们也可以看
本文标题:DDNS的工作原理及其在Linux上的实现
链接地址:https://www.777doc.com/doc-2909061 .html