linux kernel bind()时发生了什么
配置
实验一下,我有两个口lo和enp0s3, 两个地址,如下所示。
真实物理口测试
访问同子网的10.0.2.2
如果没有地址,返回:Cannot assign requested address,说明bind失败了。
lo口测试
访问loopback地址127.0.0.1
如果没有地址,返回:Cannot assign requested address,说明bind失败了。
上图的红框,有个例外。
用与127.0.0.1/8同子网的127.0.0.2可以发包,bind成功了。
如果把本地地址改为127.0.0.1/24,则127.0.0.2可以发包,127.0.1.2不可以。
内核代码分析
inet_bind() 函数 linux/net/ipv4/af_inet.c
命中local路由的源地址可以bind成功。
实验分析
通过实验分析如上代码。
可以观察到,lo口上的地址127.0.0.1会追加一条127.0.0.0/8的local路由(猜测目的是为了将loopback网段的包拦截在本机内并上送)。
在试验,增加一个1.0.0.1/8的地址在lo上,可以看见多了一个1.0.0.0/8的local路由
综上可以解释,为什么127.0.0.2访问127.0.0.1可以bind成功。
透明模式
如何突破上述限制
可以使用setsockopt(IP_TRANSPARENT),
nginx的透明代理便是这样做的,代码如下:
详见:
[转]使用nginx的proxy_bind选项配置透明的反向代理