# WAN Ping 基本介紹與設定
## Ping
在測試是否能到達位在某個網路的某個 host 時,很常用到的一個工具就是 `ping`。`ping` 會先發出 `ICMP echo request` 封包,若此封包有到達指定的 host,且該 host 的設定是會回覆 `ICMP echo request`,那就會回傳 `ICMP echo reply` 的封包。待我們收到 `ICMP echo reply` 後,`ping` 就會計算 round-trip time、packet loss 等資訊。
:::info
ICMP 是 network-layer 的 protocol,也就是第三層的 protocol。TCP 跟 UDP 由於會用到 port number,所以是屬於第四層的 protocol。而 ICMP 不需要用到 port number,只需要用到 IP address,所以是第三層的 protocol。
:::
所以若 `ping` 了某個 IP 但沒回應,並不一定代表那個 IP 沒有 host,有可能是那個 host 選擇不回應 `ICMP echo request`。
那什麼情況會選擇不回應 `ICMP echo request`?
由於若我們的電腦回覆了 `ICMP echo request`,那別人就能知道這個 IP address 是有電腦在的,那駭客就能更進一步地做攻擊。
## WAN Ping

從前面的說明可以知道若我們的電腦會回覆 `ICMP echo request`,那就可能將我們的電腦暴露於駭客攻擊的風險下。
尤其若是 router 或 modem 這類裝置,若會回覆 `ICMP echo reply`,那駭客就有可能可以攻擊到內網的裝置。
所以 WAN ping 就是設定說,若有人從外網對我們裝置的 public WAN IP 發送了 `ICMP echo request`,那我們的裝置是否要回傳 `ICMP echo reply`?


若開啟 WAN ping,就會回傳 `ICMP echo reply` 封包;若沒開啟 WAN ping,那就是忽略 `ICMP echo request`、不回傳 `ICMP echo reply` 封包。
### 開啟 WAN Ping 的時機
大部分都會建議不要開啟 WAN ping,除非是在診斷網路相關問題時,才會暫時將此功能開啟。
## 透過 `iptables` 設定是否回應 Ping
> 由於一般小老百姓好像不太容易拿到免費的 public WAN IP,所以以下都是用內網的 IP 做設定
以下用我的 MacBook 跟 Virtualbox 的 Ubuntu 虛擬機做測試,Ubuntu 虛擬機被分配到的 IP 是 192.168.50.241,MacBook 被分配到的 IP 則是 192.168.50.180。

以下是都沒有做任何設定的情況,從 Macbook ping 到 Ubuntu 虛擬機,理論上是可以順利 ping 過去的。


用 `tcpdump` 可以看到有收到來自 MacBook 的 `ICMP echo request` 封包,且 Ubuntu 虛擬機也有回傳 `ICMP echo reply` 封包。
### 設定不回應 `ICMP echo request`
以下測試也是從 MacBook ping 到 Ubuntu 虛擬機,但是這次會在 Ubuntu 做以下設定讓 Ubuntu 不回應來自 `enp0s8` interface 的 `ICMP echo request` 封包:
```shell
$ sudo iptables -t filter -A INPUT -i enp0s8 -p icmp --icmp-type echo-request -j DROP
```
- 由於是要對來到本機的 `ICMP echo request` 封包做操作,所以是 `INPUT` chain。
那由於做的操作是將這個封包丟掉、不處理它(`DROP`),所以要用 `filter` table。
所以就是 `filter` table 的 `INPUT` chain。
- `-i enp0s8`:只有指定是從 `enp0s8` 這個 network interface 進來的封包(實際應用時要換成自己 router 的 WAN interface)。如果沒有指定哪個 network interface 的話,會變成全部的 `ICMP echo request` 都 `DROP`。
- `-p icmp --icmp-type echo-request`:指定這個封包的 protocol 是 `icmp`,且 ICMP type 是 `echo-request`。
- `-j DROP`:記得要做 `DROP` 而不是 `REJECT`。用 `REJECT` 的話對方還是會知道這個 public WAN IP 是有效的。


從以上截圖畫面可以看到,我的 MacBook ping 到 Ubuntu 虛擬機時,全部都 `Request timeout`。從 `tcpdump` 的結果也可以看到 `enp0s8` 這個 interface 有收到來自 MacBook 的 `ICMP echo request`,但這裡就都沒有回送 `ICMP echo reply` 給 MacBook。
:::info
若要查詢 ICMP type,可以用 `sudo iptables -p icmp -h` 指令,會列出有哪些 ICMP type 可以用。
```shell
$ sudo iptables -p icmp -h
iptables v1.8.10 (nf_tables)
Usage: iptables -[ACD] chain rule-specification [options]
iptables -I chain [rulenum] rule-specification [options]
iptables -R chain rulenum rule-specification [options]
iptables -D chain rulenum [options]
iptables -[LS] [chain [rulenum]] [options]
iptables -[FZ] [chain] [options]
iptables -[NX] chain
iptables -E old-chain-name new-chain-name
iptables -P chain target [options]
iptables -h (print this help information)
Commands:
Either long or short options are allowed.
--append -A chain Append to chain
--check -C chain Check for the existence of a rule
--delete -D chain Delete matching rule from chain
--delete -D chain rulenum
Delete rule rulenum (1 = first) from chain
--insert -I chain [rulenum]
Insert in chain as rulenum (default 1=first)
--replace -R chain rulenum
Replace rule rulenum (1 = first) in chain
--list -L [chain [rulenum]]
List the rules in a chain or all chains
--list-rules -S [chain [rulenum]]
Print the rules in a chain or all chains
--flush -F [chain] Delete all rules in chain or all chains
--zero -Z [chain [rulenum]]
Zero counters in chain or all chains
--new -N chain Create a new user-defined chain
--delete-chain
-X [chain] Delete a user-defined chain
--policy -P chain target
Change policy on chain to target
--rename-chain
-E old-chain new-chain
Change chain name, (moving any references)
Options:
--ipv4 -4 Nothing (line is ignored by ip6tables-restore)
--ipv6 -6 Error (line is ignored by iptables-restore)
[!] --protocol -p proto protocol: by number or name, eg. `tcp'
[!] --source -s address[/mask][...]
source specification
[!] --destination -d address[/mask][...]
destination specification
[!] --in-interface -i input name[+]
network interface name ([+] for wildcard)
--jump -j target
target for rule (may load target extension)
--goto -g chain
jump to chain with no return
--match -m match
extended match (may load extension)
--numeric -n numeric output of addresses and ports
[!] --out-interface -o output name[+]
network interface name ([+] for wildcard)
--table -t table table to manipulate (default: `filter')
--verbose -v verbose mode
--wait -w [seconds] maximum wait to acquire xtables lock before give up
--line-numbers print line numbers when listing
--exact -x expand numbers (display exact values)
[!] --fragment -f match second or further fragments only
--modprobe=<command> try to insert modules using this command
--set-counters -c PKTS BYTES set the counter during insert/append
[!] --version -V print package version.
icmp match options:
[!] --icmp-type typename match icmp type
[!] --icmp-type type[/code] (or numeric type or type/code)
Valid ICMP Types:
any
echo-reply (pong)
destination-unreachable
network-unreachable
host-unreachable
protocol-unreachable
port-unreachable
fragmentation-needed
source-route-failed
network-unknown
host-unknown
network-prohibited
host-prohibited
TOS-network-unreachable
TOS-host-unreachable
communication-prohibited
host-precedence-violation
precedence-cutoff
source-quench
redirect
network-redirect
host-redirect
TOS-network-redirect
TOS-host-redirect
echo-request (ping)
router-advertisement
router-solicitation
time-exceeded (ttl-exceeded)
ttl-zero-during-transit
ttl-zero-during-reassembly
parameter-problem
ip-header-bad
required-option-missing
timestamp-request
timestamp-reply
address-mask-request
address-mask-reply
```
:::
## 透過 OpenWRT 的 `uci` 指令設定是否回應 Ping
接下來將我的安裝了 OpenWRT 23.05.5 的 Marvell ESPRESSObin v7 開發板一起加入同一個 LAN 內。從以下截圖可看到我的開發板被分配到的 IP 是 192.168.50.141。


OpenWRT 內建的防火牆本身就有針對 WAN ping 的規則,可以查看 `/etc/config/firewall`:

或者用 `uci show firewall` 指令查看:

如果沒更改過的話,預設上應該是針對來自 `wan` 的 `icmp` `echo-request`,且只有 `ipv4`,且是 `ACCEPT`。
OpenWRT 預設沒有 `tcpdump`,但可以安裝 `tcpdump-mini` 來監測是否有人正在 ping:
```shell
$ opkg update
$ opkg install tcpdump-mini
```


從以上截圖可看到,目前 OpenWRT 對於來自 `wan` 的 `ipv4` 的 `ICMP echo request` 是 `ACCEPT`,所以我的 MacBook 可以 `ping` 成功過去,且用 `tcpdump` 也能看到我的 Marvell ESPRESSObin v7 開發板有收到 `ICMP echo request` 封包,也有回傳 `ICMP echo reply` 封包。
### 不回應 `ICMP echo request`
接下來,如果要設定成不回應 `ICMP echo request`,就需要對 OpenWRT 做以下設定:
```openwrt=
root@OpenWrt:/# uci set firewall.@rule[1].target='DROP'
root@OpenWrt:/# uci commit firewall
root@OpenWrt:/# /etc/init.d/firewall restart
```
- 從 `uci show firewall` 可以看到 `Allow-Ping` 這個規則是 `firewall.@rule[1]`,編號是 `1`,所以就設定編號 `1` 的防火牆規則的 target 是 `'DROP'`
- 我們用 `uci set` 所做的設定只會儲存在記憶體裡面,並不會修改到 `/etc/config/` 裡面的設定檔,也不會立即生效,當我們的 OpenWRT 裝置重新開機後,用 `uci set` 做的設定就會消失,所以才需要做後面兩個指令。
- 做 `uci commit firewall` 才會將目前記憶體中 firewall 的設定儲存到 `/etc/config/firewall` 裡面,重開機時才能把這些設定保留住。
- `/etc/init.d/firewall restart`,重新啟動 firewall。由於大部分 `/etc/config/` 底下的設定檔都只有在啟動該服務時才會讀取 config 檔案,所以我們要重新啟動防火牆,這樣他才會去讀取並載入 `/etc/config/firewall` 的設定,並且立即生效~
以下是實際測試時的截圖:


可以看到目前已將 `Allow-Ping` 這個防火牆規則的 target 改成 `'DROP'`,且當我從 MacBook `ping` 到 192.168.50.141,得到的結果都是 `Request timeout`。用 `tcpdump` 也能看到我的 OpenWRT 裝置有從 192.168.50.180(也就是 MacBook 被分配到的 LAN IP)收到 `ICMP echo request` 封包,但都沒有回傳 `ICMP echo reply` 封包。
## References
- https://en.wikipedia.org/wiki/Ping_(networking_utility)
- https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol