引言
此文档是对发往Docker容器内的数据包源地址被修改的研究做的实践记录。
实践环境一
Centos7.2+Docker1.12.6
关闭firewalld:
systemctl stop firewalld
设置selinux为Permissive模式:
setenforce 0
/etc/docker/daemon.json内容:
{
"userland-proxy": true
}
创建名为python的容器:
docker run -itd --name python --network bridge -p 8000:9999/udp --entrypoint bash python:2.7.15
容器内接收udp数据包的程序内容为:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口:
s.bind(('0.0.0.0', 9999))
print 'Bind UDP on 9999...'
while 1:
# 接收数据:
data, addr = s.recvfrom(1024)
print 'addr: {0}, data: {1}'.format(addr, data)
路由信息:
一、通过另一台主机向当前主机发送数据包
1.192.168.84.75主机上运行接收udp数据包的程序,运行配置基于实践环境,在192.168.84.79主机上通过 echo mac | nc -s 192.168.84.79 -p 42731 -u 192.168.84.75 8000(产生数据包的源地址、源端口与目的地址、目的端口为:192.168.84.79.42731 > 192.168.84.75.8000) 向192.168.84.75发送数据包。
对192.168.84.79主机的网卡进行抓包处理:
tcpdump -i eno16777984 udp port 8000 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
13:33:15.227775 IP (tos 0x0, ttl 64, id 58746, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.79.42731 > 192.168.84.75.8000: [bad udp cksum 0x2a09 -> 0x3f53!] UDP, length 4
分别对192.168.84.75主机的lo、物理网卡(eno16777984)、docker0以及容器的网卡进行抓包处理:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i eno16777984 udp port 8000 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
13:33:25.690285 IP (tos 0x0, ttl 64, id 58746, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.79.42731 > 192.168.84.75.8000: [udp sum ok] UDP, length 4
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:33:25.690319 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:33:25.690354 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
13:33:25.690362 IP (tos 0x0, ttl 63, id 58746, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.79.42731 > 172.17.0.2.9999: [udp sum ok] UDP, length 4
tcpdump -i vethc4d778f -nn -vv
tcpdump: listening on vethc4d778f, link-type EN10MB (Ethernet), capture size 262144 bytes
13:33:25.690332 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:33:25.690354 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
13:33:25.690364 IP (tos 0x0, ttl 63, id 58746, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.79.42731 > 172.17.0.2.9999: [udp sum ok] UDP, length 4
由上述的时间可知数据包先经过84.79主机的网卡,然后数据包被发往84.75主机,在84.75主机上经过的设备依次为:主机网卡(eno16777984 )---> docker0 ---> 容器网卡(vethc4d778f)
数据包发送前与发送后84.75主机的nat表的对比:
发送前执行 iptables -t nat -nvL > pre
发送后执行 iptables -t nat -nvL > now
然后通过diff命令对比两个文件的内容:
-
在84.79主机上执行 echo mac | nc -s 127.0.0.1 -p 42731 -u 192.168.84.75 8000 ,报错误信息Ncat: Invalid argument.
二、本机上通过网卡ip地址发送数据包
- 在192.168.84.75主机上执行 echo mac | nc -s 192.168.84.75 -p 34191 -u 192.168.84.75 8000
分别lo、物理网卡(eno16777984)、docker0以及容器的网卡进行抓包处理:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i eno16777984 udp port 8000 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:37:07.072740 IP (tos 0x0, ttl 64, id 64295, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.75.34191 > 172.17.0.2.9999: [bad udp cksum 0xc124 -> 0xc1c4!] UDP, length 4
13:37:12.075322 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:37:12.075355 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethc4d778f -nn -vv
tcpdump: listening on vethc4d778f, link-type EN10MB (Ethernet), capture size 262144 bytes
13:37:07.072758 IP (tos 0x0, ttl 64, id 64295, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.75.34191 > 172.17.0.2.9999: [bad udp cksum 0xc124 -> 0xc1c4!] UDP, length 4
13:37:12.075332 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:37:12.075355 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
可知数据包仅经过docker0然后去往容器设备vethc4d778f,并没有经过绑定192.168.84.75 IP的网卡eno16777984
数据包发送前与发送后84.75主机的nat表的对比:
-
echo mac | nc -s 127.0.0.1 -p 34191 -u 192.168.84.75 8000 Ncat: Invalid argument.
三、本机上通过127.0.0.1地址发送数据包
- 在192.168.84.75主机上执行 echo mac | nc -s 127.0.0.1 -p 33089 -u 127.0.0.1 8000
分别对主机的lo、物理网卡(eno16777984)、docker0以及容器的网卡进行抓包处理:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
13:41:30.463055 IP (tos 0x0, ttl 64, id 54997, offset 0, flags [DF], proto UDP (17), length 32)
127.0.0.1.33089 > 127.0.0.1.8000: [bad udp cksum 0xfe1f -> 0x90e6!] UDP, length 4
tcpdump -i eno16777984 udp port 8000 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:41:30.463419 IP (tos 0x0, ttl 64, id 35536, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.33987 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x2b72!] UDP, length 4
13:41:35.467315 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:41:35.467348 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethc4d778f -nn -vv
tcpdump: listening on vethc4d778f, link-type EN10MB (Ethernet), capture size 262144 bytes
13:41:30.463430 IP (tos 0x0, ttl 64, id 35536, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.33987 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x2b72!] UDP, length 4
13:41:35.467325 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:41:35.467348 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
可知数据包在主机上经过的设备次序为:lo ---> docker0 ---> vethc4d778f
数据包发送前与发送后主机nat表的对比如下:
- echo mac | nc -s 192.168.84.75 -p 33089 -u 127.0.0.1 8000(程序能够收到数据包)
lo设备、docker0与容器网卡抓包结果:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
13:46:14.238701 IP (tos 0x0, ttl 64, id 54998, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.75.33089 > 127.0.0.1.8000: [bad udp cksum 0x9412 -> 0xfaf3!] UDP, length 4
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:46:14.238980 IP (tos 0x0, ttl 64, id 35537, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.36234 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x22ab!] UDP, length 4
13:46:19.243339 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:46:19.243377 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethc4d778f -nn -vv
tcpdump: listening on vethc4d778f, link-type EN10MB (Ethernet), capture size 262144 bytes
13:46:14.238992 IP (tos 0x0, ttl 64, id 35537, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.36234 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x22ab!] UDP, length 4
13:46:19.243350 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:46:19.243377 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
程序输出结果:addr: ('172.17.0.1', 36234), data: mac
四、通过容器ip地址发送数据包
-
192.168.84.75主机上容器python的ip地址为172.17.0.2,可通过下面方式获得:
在主机上执行 echo mac | nc -s 172.17.0.1 -p 42883 -u 172.17.0.2 9999分别对192.168.84.75主机的lo、物理网卡(eno16777984)、docker0以及容器的网卡进行抓包处理:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i eno16777984 udp port 9999 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:49:05.123460 IP (tos 0x0, ttl 64, id 35538, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.42883 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x08b2!] UDP, length 4
13:49:10.139337 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:49:10.139376 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethc4d778f -nn -vv
tcpdump: listening on vethc4d778f, link-type EN10MB (Ethernet), capture size 262144 bytes
13:49:05.123479 IP (tos 0x0, ttl 64, id 35538, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.42883 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x08b2!] UDP, length 4
13:49:10.139347 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:49:10.139376 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
数据包经过的设备依次为:docker0 ---> vethc4d778f
数据包发送前与发送后主机nat对比:
- echo mac | nc -s 172.17.0.2 -p 42883 -u 172.17.0.2 9999
libnsock mksock_bind_addr(): Bind to 172.17.0.2:42883 failed (IOD #1): Cannot assign requested address (99)
docker0与容器网卡抓包结果:
tcpdump -i docker0 -nn -vv(数据包的源地址、源端口已经被修改)
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:51:26.388949 IP (tos 0x0, ttl 64, id 35539, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.54670 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0xdaa6!] UDP, length 4
13:51:31.403315 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:51:31.403347 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethc4d778f -nn -vv
tcpdump: listening on vethc4d778f, link-type EN10MB (Ethernet), capture size 262144 bytes
13:51:26.388966 IP (tos 0x0, ttl 64, id 35539, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.54670 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0xdaa6!] UDP, length 4
13:51:31.403325 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:51:31.403347 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
程序结果:addr: ('172.17.0.1', 54670), data: mac
-
echo mac | nc -s 127.0.0.1 -p 42883 -u 172.17.0.2 9999 Ncat: Invalid argument.
实践环境二
Centos7.2 + Docker1.12.6
关闭firewalld:
systemctl stop firewalld
设置selinux为Permissive模式:
setenforce 0
/etc/docker/daemon.json内容:
{
"userland-proxy": false
}
创建名为python的容器:
docker run -itd --name python --network bridge -p 8000:9999/udp --entrypoint bash python:2.7.15
容器内接收udp数据包的程序内容为:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口:
s.bind(('0.0.0.0', 9999))
print 'Bind UDP on 9999...'
while 1:
# 接收数据:
data, addr = s.recvfrom(1024)
print 'addr: {0}, data: {1}'.format(addr, data)
路由信息:-
docker-proxy进程消失
-
dockerd进程监听8000端口
- nat表的POSTROUTING链多了一条源地址伪装的规则
-A POSTROUTING -o docker0 -m addrtype --src-type LOCAL -j MASQUERADE
(将源地址类型为LOCAL且从docker0设备流出的数据包的源地址伪装成docker0设备的地址)
一、通过另一台主机向当前主机发送数据包
- 192.168.84.75主机上运行接收udp数据包的程序,运行配置基于实践环境,在192.168.84.79主机上通过 echo mac | nc -s 192.168.84.79 -p 55902 -u 192.168.84.75 8000 发送数据包。
对192.168.84.79主机的网卡进行抓包处理:
tcpdump -i eno16777984 udp port 8000 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
13:57:35.975290 IP (tos 0x0, ttl 64, id 58747, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.79.55902 > 192.168.84.75.8000: [bad udp cksum 0x2a09 -> 0x0be0!] UDP, length 4
分别对192.168.84.75主机的lo、物理网卡(eno16777984)、docker0以及容器的网卡进行抓包处理:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i eno16777984 udp port 8000 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
13:57:46.437799 IP (tos 0x0, ttl 64, id 58747, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.79.55902 > 192.168.84.75.8000: [udp sum ok] UDP, length 4
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:57:46.437850 IP (tos 0x0, ttl 63, id 58747, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.79.55902 > 172.17.0.2.9999: [udp sum ok] UDP, length 4
13:57:51.451317 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:57:51.451355 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
13:57:46.437863 IP (tos 0x0, ttl 63, id 58747, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.79.55902 > 172.17.0.2.9999: [udp sum ok] UDP, length 4
13:57:51.451327 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
13:57:51.451355 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
数据包流经设备的顺序依次为:eno16777984(84.79) ---> eno16777984(84.75) ---> docker0 ---> vethcbcc4e9
数据包发送前与发送后主机nat表对比:
-
192.168.84.79主机上执行 echo mac | nc -s 127.0.0.1 -p 55902 -u 192.168.84.75 8000 Ncat: Invalid argument.
二、本机上通过网卡ip地址发送数据包
- 在192.168.84.75主机上执行 echo mac | nc -s 192.168.84.75 -p 41003 -u 192.168.84.75 8000
分别lo设备、物理网卡(eno16777984)、docker0以及容器网卡进行抓包处理:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
tcpdump -i eno16777984 udp port 8000 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:03:41.089945 IP (tos 0x0, ttl 64, id 64296, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.41003 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x100a!] UDP, length 4
14:03:46.091328 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:03:46.091387 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
14:03:41.089961 IP (tos 0x0, ttl 64, id 64296, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.41003 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x100a!] UDP, length 4
14:03:46.091343 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:03:46.091387 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
可知,数据包仅经过docker0与容器设备vethcbcc4e9
数据包发送前与发送后主机nat表对比:
- echo mac | nc -s 127.0.0.1 -p 41003 -u 192.168.84.75 8000
docker0与容器网卡抓包结果:
tcpdump -i docker0 -nn -vv(数据包的源地址已经被修改)
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:06:19.694983 IP (tos 0x0, ttl 64, id 64297, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.41003 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x100a!] UDP, length 4
14:06:24.699338 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:06:24.699375 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
14:06:19.695000 IP (tos 0x0, ttl 64, id 64297, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.41003 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x100a!] UDP, length 4
14:06:24.699348 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:06:24.699375 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
程序结果:addr: ('172.17.0.1', 41003), data: mac
三、本机上通过127.0.0.1发送数据包
- 在192.168.84.75主机上执行 echo mac | nc -s 127.0.0.1 -p 44818 -u 127.0.0.1 8000
分别主机的lo设备、物理网卡(eno16777984)、docker0以及容器网卡进行抓包处理:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
tcpdump -i eno16777984 udp port 8000 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:08:58.946048 IP (tos 0x0, ttl 64, id 54997, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.44818 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x0123!] UDP, length 4
14:09:03.947336 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:09:03.947379 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
14:08:58.946065 IP (tos 0x0, ttl 64, id 54997, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.44818 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x0123!] UDP, length 4
14:09:03.947349 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:09:03.947379 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
数据包经过的设备依次为:docker0 ---> vethcbcc4e9
数据包发送前与发送后nat表规则对比:
四、通过容器ip地址发送数据包
-
192.168.84.75主机上容器python的ip地址为172.17.0.2,可通过下面方式获得:
在主机上执行 echo mac | nc -s 172.17.0.1 -p 54877 -u 172.17.0.2 9999,分别对主机的lo、物理网卡(eno16777984)、docker0以及容器网卡进行抓包处理:
tcpdump -i lo -nn -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i eno16777984 udp port 9999 -nn -vv
tcpdump: listening on eno16777984, link-type EN10MB (Ethernet), capture size 262144 bytes
无内容
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:10:58.373599 IP (tos 0x0, ttl 64, id 35536, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.54877 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0xd9d7!] UDP, length 4
14:11:03.387315 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:11:03.387349 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
14:10:58.373617 IP (tos 0x0, ttl 64, id 35536, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.54877 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0xd9d7!] UDP, length 4
14:11:03.387325 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:11:03.387349 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
数据包经过的设备依次为:docker0 ---> vethcbcc4e9
数据包发送前与发送后主机nat对比:
- echo mac | nc -s 172.17.0.2 -p 54877 -u 172.17.0.2 9999
libnsock mksock_bind_addr(): Bind to 172.17.0.2:54877 failed (IOD #1): Cannot assign requested address (99)
docker0与容器网卡抓包结果:
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:13:04.045159 IP (tos 0x0, ttl 64, id 35537, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.35950 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x23c7!] UDP, length 4
14:13:09.051330 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:13:09.051367 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
14:13:04.045176 IP (tos 0x0, ttl 64, id 35537, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.35950 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0x23c7!] UDP, length 4
14:13:09.051340 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:13:09.051367 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
程序结果:addr: ('172.17.0.1', 35950), data: mac
- echo mac | nc -s 127.0.0.1 -p 54877 -u 172.17.0.2 9999
docker0与容器网卡抓包结果:
tcpdump -i docker0 -nn -vv(数据包的源地址被规则 -A POSTROUTING -o docker0 -m addrtype --src-type LOCAL -j MASQUERADE 修改为docker0地址172.17.0.1)
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:15:08.717851 IP (tos 0x0, ttl 64, id 35538, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.54877 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0xd9d7!] UDP, length 4
14:15:13.723315 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:15:13.723350 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
14:15:08.717868 IP (tos 0x0, ttl 64, id 35538, offset 0, flags [DF], proto UDP (17), length 32)
172.17.0.1.54877 > 172.17.0.2.9999: [bad udp cksum 0x5843 -> 0xd9d7!] UDP, length 4
14:15:13.723326 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:15:13.723350 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
程序结果:addr: ('172.17.0.1', 54877), data: mac
-
去除POSTROUTING链的规则 -A POSTROUTING -o docker0 -m addrtype --src-type LOCAL -j MASQUERADE
执行 echo mac | nc -s 127.0.0.1 -p 54877 -u 172.17.0.2 9999
docker0与容器网卡抓包结果:
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:17:35.597021 IP (tos 0x0, ttl 64, id 35539, offset 0, flags [DF], proto UDP (17), length 32)
127.0.0.1.54877 > 172.17.0.2.9999: [bad udp cksum 0x2b32 -> 0x06e9!] UDP, length 4
14:17:40.603314 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:17:40.603346 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
14:17:35.597050 IP (tos 0x0, ttl 64, id 35539, offset 0, flags [DF], proto UDP (17), length 32)
127.0.0.1.54877 > 172.17.0.2.9999: [bad udp cksum 0x2b32 -> 0x06e9!] UDP, length 4
14:17:40.603323 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:17:40.603346 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
程序结果:空,即程序没有接收到数据包
-
添加将udp协议、源地址类型为LOCAL的数据包的源地址修改为主机地址192.168.84.75
执行 echo mac | nc -s 127.0.0.1 -p 54877 -u 172.17.0.2 9999
docker0与容器网卡veth1a4e47a抓包结果:
tcpdump -i docker0 -nn -vv
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:20:10.098644 IP (tos 0x0, ttl 64, id 35540, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.75.54877 > 172.17.0.2.9999: [bad udp cksum 0xc124 -> 0x70f6!] UDP, length 4
14:20:15.115338 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:20:15.115377 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
tcpdump -i vethcbcc4e9 -nn -vv
tcpdump: listening on vethcbcc4e9, link-type EN10MB (Ethernet), capture size 262144 bytes
14:20:10.098661 IP (tos 0x0, ttl 64, id 35540, offset 0, flags [DF], proto UDP (17), length 32)
192.168.84.75.54877 > 172.17.0.2.9999: [bad udp cksum 0xc124 -> 0x70f6!] UDP, length 4
14:20:15.115350 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 172.17.0.2 tell 172.17.0.1, length 28
14:20:15.115377 ARP, Ethernet (len 6), IPv4 (len 4), Reply 172.17.0.2 is-at 02:42:ac:11:00:02, length 28
程序结果:addr: ('192.168.84.75', 54877), data: mac
总结
Centos7中更改数据包源地址的操作即SNAT可以在INPUT链与POSTROUTING链两个地方操作。Docker在INPUT链中没有定义SNAT规则,全部的SNAT操作均定义在POSTROUTING链中。所以对Docker数据包的SNAT的研究只需关注POSTROUTING链即可。我们自己产品对docker的使用属于上述实验一的范围,即是将userland设置为true,包括以下几种情况:
如果机器的iptables规则没有做额外的配置,通过外主机向本机访问或在本机上通过ip地址访问,数据包的源地址不会被修改
本机上通过127.0.0.1访问的数据包的源地址会被docker-proxy进程修改,因此本机访问若想要数据包的源地址不被修改,需使用本机ip地址访问
通过上面实践可发现,源地址为127.0.0.1的数据包在多数场景下不能成功发送出去,能够发送出去且能被容器内程序接收到的数据包在容器网卡或docker0那一层其源地址127.0.0.1已经被修改了;即容器内程序接收到的数据包的源地址不可能是127.0.0.1。源地址为127.0.0.1的数据包在传输过程中意义不大,因为无法根据源地址127.0.0.1找到发包的设备
数据包在主机与主机或主机与容器之间传输时,数据包的源地址多数情况下会发生改变,如果某功能是以数据包源IP地址作为来源主机的判断是不可靠的;因为可能取的数据包是处于中间状态的包,这类包的源IP地址可能已被修改,这样就会导致来源主机判断的错误。