一、bind一个非本地地址
这个问题看起来还是比较奇怪的,如果bind系统调用中绑定一个本地并不存在的IP地址会怎样呢?直观的反应就是绑定会失败,但是从内核的角度来看,这就要求内核在某个结构中保存有整个系统的所有的已经注册或者说设置过的IP地址。IP地址是inter网的基本概念,所以顺便看看内核中对于所有的网络地址的处理也是一个比较好的切入点。
二、bind的执行
大致看来,用户态的bind在内核中的对应实现叫做sys_bind,这一路走下来,走到我们感兴趣的一个地址,就是
sys_bind--->>>>sys_bind
就像教室里阴暗的角落里总会发出不和谐的声音一样,这个函数的开始也横亘着一个常常被我们忽略的一段代码
chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
/* Not specified by any standard per-se, however it breaks too
* many applications when removed. It is unfortunate since
* allowing applications to make a non-local bind solves
* several problems with systems using dynamic addressing.
* (ie. your servers still start up even if your ISDN link
* is temporarily down)
*/
err = -EADDRNOTAVAIL;
if (!sysctl_ip_nonlocal_bind &&
!inet->freebind &&
addr->sin_addr.s_addr != INADDR_ANY &&
chk_addr_ret != RTN_LOCAL &&
chk_addr_ret != RTN_MULTICAST &&
chk_addr_ret != RTN_BROADCAST)
goto out;
内核代码的一个好处就是在于大家写代码比较随意,所以注释也比较随意,一些比较生僻的代码中都会包含一些比较有指导性的注释。在这个函数中,作者说了这段代码的意义:“这个功能在任何的标准文档中都没有描述过,只是如果说删除这些代码很多的应用程序将会挂掉。使用非本地地址绑定可以解决一些使用动态地址绑定的服务器程序,所以这个实现还是有实际意义的”。
从这里的代码看,如果一个非本地绑定可以成功,里面有两个标志置位即可。其中第一个sysctl_ip_nonlocal变量从命令看明显就是一个proc下的sysctl文件,通过查看代码可以知道,该proc文件位于
[tsecer@Harry template]$ cat /proc/sys/net/ipv4/ip_nonlocal_bind
0
[tsecer@Harry template]$
默认值为零,也就是不允许非本地地址的绑定。如果把该值修改为1,那么就可以通过bind来bind一个非本地网络地址了。而且还有一个freebind,这个是通过sec_sockopt来修改的,所以就不用管了。
执行了bind+listen之后,此时系统还是没有这个IP地址,但是这个并不影响问题。因为这个listen只是申请一个侦听的套接口结构,当网络的报文到达之后,它从内存中搜索这个数据结构,如果找到那么就把报文分配给它。如果这个机器本身并不拥有这个网络地址,那么这个过程可能性不大。以太网的报文首先要经过网卡的物理过滤(除非设置为杂收模式),然后还有本机的IP层路由。