文章目錄
- 一、問題背景
- 二、解決方案
- (方法一)修改全局設置的 轉發( forward) 為 接受(ACCEPT)
- (方法二)設置 net.bridge.bridge-nf-call-iptables=0 并將 docker 的容器網絡設置為host
- 三、原因探析
- (一)確認無法訪問
- (二)使用 tcpdump 檢查流量
- (三)檢查防火墻配置
- 四、為什么安裝 docker 之后才會出現這樣的問題呢
一、問題背景
參考 OpenWrt as Docker container host 官方的教程,可以知道只要安裝了 luci-app-dockerman
luci包,即可在 OpenWrt
上運行 docker
,隨后就可以安裝各類鏡像,并部署運行各類容器。
luci-app-dockerman
包的位置位于:LuCI
> 3. Applications
> luci-app-dockerman
,勾選編譯即可。
但是,安裝新鏡像之后發現,局域網下的設備之間不能互相訪問通信了,而取消勾選luci-app-dockerman
包之后重新編譯安裝,即可互相訪問。因此可以推測,這個問題是因為安裝 docker
之后引起的問題。
本文將詳細探尋 OpenWrt 安裝 docker 之后局域網的設備之間無法互相訪問通信 的原因,并提出一種簡單的解決方案。
二、解決方案
限于筆者目前對
OpenWrt
了解還不夠深入,暫且用這些方式進行解決。
先直接說解決方案:
(方法一)修改全局設置的 轉發( forward) 為 接受(ACCEPT)
在 luci
管理界面,網絡
> 防火墻
> 防火墻 - 區域設置
> 常規設置
中,將 轉發
設置為 接受
即可,配置如下:
也可以直接修改配置文件,在 /etc/config/firewall
文件中,在 defaults
的配置中修改 forward
屬性為 ACCEPT
,相關代碼如下:
config defaultsoption input 'REJECT'option output 'ACCEPT'option forward 'ACCEPT'
(方法二)設置 net.bridge.bridge-nf-call-iptables=0 并將 docker 的容器網絡設置為host
由后文介紹可以知道,發生此問題是由于 docker
配置了 net.bridge.bridge-nf-call-iptables=1
,導致原本隱式允許的 LAN 通信被顯示拒絕。因此我們可以修改 docker
創建出來的配置文件 /etc/sysctl.d/12-br-netfilter-ip.conf
,將net.bridge.bridge-nf-call-ip6tables=1
和 net.bridge.bridge-nf-call-iptables=1
注釋掉即可,代碼如下:
# Do not edit, changes to this file will be lost on upgrades
# /etc/sysctl.conf can be used to customize sysctl settings# enable bridge firewalling for docker
# net.bridge.bridge-nf-call-ip6tables=1
# net.bridge.bridge-nf-call-iptables=1
但此方法會導致 docker
中的 容器
不能使用 bridge
的網絡模式,因此需要將 docker
中的 容器
的網路模式都修改為 host
。
三、原因探析
(一)確認無法訪問
首先我們需要先找到一個合適的方法確認是否無法互相訪問,并確定出特征流量,方便通過流量去追蹤,因此我們選用 ping
命令,去 ping
另一個設備的 IP
,檢查是否可以連通。可確定其是 ICMP
流量。
通過 ping DeviceIP
可以確定這兩個設備無法 ping
通,也即無法互相訪問
(二)使用 tcpdump 檢查流量
tcpdump
是一個強大的命令行網絡抓包工具,可以獲取 OpenWrt
的指定接口的 流量。可以安裝 tcpdump
包,去獲取流量并進行分析。也可以在編譯的時候勾選 tcpdump
包,其路徑為 Network
> tcpdump
,如下:
當安裝完 tcpdump
包之后,即可使用 tcpdump
命令進行抓包分析。
首先需要確認局域網的接口名,其需要在 tcpdump
被指定,用于抓取指定接口的網絡流量,例如 br.lan
。隨后在命令之后再帶上 icmp
可以過濾 icmp
流量,進行分析。命令格式如下:
tcpdump -i br-lan icmp
通過此命令,可以看到有如下的打印:
21:04:30.316761 IP Device1.lan > OpenWrt.lan: ICMP echo request, id 21972, seq 227, length 11
21:04:30.316887 IP OpenWrt.lan > Device1.lan: ICMP echo reply, id 21972, seq 227, length 1121:04:30.738076 IP Device2.lan > OpenWrt.lan: ICMP echo request, id 4441, seq 308, length 11
21:04:30.738136 IP OpenWrt.lan > Device2.lan: ICMP echo reply, id 4441, seq 308, length 1121:04:35.799464 IP Device1.lan > Device2.lan: ICMP echo request, id 1, seq 93, length 40
21:04:35.803724 IP OpenWrt.lan > Device2.lan: ICMP Device1.lan protocol 1 port 21758 unreachable, length 68
21:04:35.803613 IP Device2.lan > Device1.lan: ICMP echo reply, id 1, seq 93, length 40
這段日志來可以被分成三部分:
第一部分是 Device1
與 OpenWrt
的 ICMP
的流量,從 Device1.lan > OpenWrt.lan: ICMP echo request
和 OpenWrt.lan > Device1.lan: ICMP echo reply
可以看出 Device1
與 OpenWrt
是可以正常訪問, ICMP
的流量可以正常通行。
第二部分是 Device2
與 OpenWrt
的 ICMP
的流量,從 Device2.lan > OpenWrt.lan: ICMP echo request
和 OpenWrt.lan > Device2.lan: ICMP echo reply
可以看出 Device2
與 OpenWrt
是可以正常訪問, ICMP
的流量可以正常通行。
而第三部分是 Device1.lan
到 Device2.lan
的 ICMP
的流量,可以看到 Device1.lan protocol 1 port 21758 unreachable
,此時流量無法到達 Device2.lan
,而是直接被路由器攔截了直接通信并返回了 unreachable
消息。
因此,這表明 OpenWrt
正在阻止 LAN
設備間的直接通信,而這點極有可能是因為 LAN
區域的轉發( Forward
)策略可能被設置為拒絕( REJECT/DROP
)
(三)檢查防火墻配置
通過命令 cat /etc/config/firewall
輸出防火墻的相關配置,可以得到如下結果:
config defaultsoption input 'REJECT'option output 'ACCEPT'option forward 'REJECT'config zoneoption name 'lan'option input 'ACCEPT'option output 'ACCEPT'option forward 'ACCEPT'list network 'lan'
可以看到,lan
的 zone
的 forward
已經被設置為 ACCEPT
(即 option forward 'ACCEPT'
),但是全局配置中的 forward
被設置為了 REJECT
(即 option forward 'REJECT'
),因此可以推測出這里是無法相互訪問的原因。
四、為什么安裝 docker 之后才會出現這樣的問題呢
-
Docker
自動創建的防火墻規則
Docker
默認會修改iptables
規則,在/etc/firewall.user
或自定義鏈中插入規則,可能導致了覆蓋原有的LAN
轉發規則 或者 創建新的DOCKER-USER
鏈并設置默認策略為DROP
-
Docker
網絡接口的隔離特性
Docker
創建的docker0
網橋默認會:啟用net.bridge.bridge-nf-call-iptables=1
(讓橋接流量經過iptables
),此時觸發OpenWrt
的默認REJECT
策略,導致原本隱式允許的 LAN 通信被顯示拒絕。(參考:https://github.com/openwrt/packages/blob/master/utils/dockerd/files/etc/sysctl.d/sysctl-br-netfilter-ip.conf)
而原始配置中,因net.bridge.bridge-nf-call-iptables=0
,雖然全局默認是REJECT
,但br-lan
橋接流量繞過了iptables