---
tags: batch, regedit, windows firewall
---
# 如何透過指令實現阻擋指定IP以外的連出連入
今天有個需求需要透過指令碼封鎖所有進出入連線,
僅放行特定IP與服務可連線
依據這篇文章[Windows 防火牆設定:阻擋指定 IP 以外的電腦連入](https://kheresy.wordpress.com/2019/01/10/windows-firewall-setting-only-aloow-some-ip-connect/)提到如下
1. 沒有例外條件功能
2. 先處理封鎖、再處理允許
>但是,Windows Firewall 在建立規則的時候,並沒有「例外條件」的功能可以設定,而根據官方的文件,防火牆內部的處理順序,又是先處理封鎖、再處理允許(參考);所以要滿足這邊的需求,也不能靠兩個條件的組合來達成。
## 規則設計
我需要的規則如下
1. 阻擋所有連入但有兩個例外
2. 阻擋所有連出
3. 例外1:
IP: 192.168.66.253
服務: RDP、SMB(為了遠端桌面的檔案傳輸)、SSH、FTP
PORT: 無(天曉得人家有無變更RDP PORT)
方向: 外對內
4. 例外2:
IP: 211.20.177.238
PORT: 443, 80
協定: TCP
方向: 雙向
因此調整如下
1. 封鎖 0.0.0.0-192.168.66.252
1. 封鎖 192.168.66.254-211.20.177.237
1. 封鎖 211.20.177.239-255.255.255.255
細節設定的部分暫時沒想法,
目前變成對這兩個IP完全開放
192.168.66.253、211.20.177.238
## 指令研究
### :heavy_check_mark:防火牆狀態檢視與變更
之後打算用備份還原的方式,所以這個就用不到了~
**檢視**
```bash=
> netsh advfirewall show currentprofile state
私人設定檔 設定:
----------------------------------------------------------------------
狀態 開啟
公用設定檔 設定:
----------------------------------------------------------------------
狀態 開啟
確定。
```
恩...看來會因為不同語系而有不同版本,
那能否固定英文?
網路上幾乎是從系統語系調整,目前google不到相關文章
**編輯**
```bash=
netsh advfirewall set currentprofile state on/off
```
這個指令會一口氣啟動/關閉全部使用中的設定檔
以我為例會一次變動privateprofile、publicprofile,
而沒使用的domainprofile就不受影響
### :heavy_check_mark:批次檔語系調整
可透過chcp 來解決
參考如下
https://blog.typeart.cc/windows-cmd-change-encoding/
```bash=
REM 常見的utf-8
REM chcp 65001
REM 這是我要的英文(美國)
chcp 437
```
### :X:確認防火牆服務有啟動
*權限不夠無法操作*
這篇文章提到[電腦系統防火牆無法開啟的解決辦法2](https://zaitiyu.com/basketball/69098.html)
相關服務如下
系統名稱|顯示名稱
---|---
mpssvc|Windows Firewall
查詢語法如下
```bash=
# 查詢狀態
> sc query mpssvc | find "STATE"
STATE : 4 RUNNING
# 執行服務(確認執行成功)
net start "mpssvc"
# 執行服務(只送出執行服務指令,不會確保正在執行成功)
sc start "mpssvc"
```
如果嘗試暫停的話會出現...
恩,系統管理員身分都沒權限..
```bash=
C:\Users\ma2g0> sc stop mpssvc
[SC] OpenService FAILED 5:
Access is denied.
C:\Users\ma2g0>net stop mpssvc
The requested pause, continue, or stop is not valid for this service.
More help is available by typing NET HELPMSG 2191.
```
### ~~確認防火牆當前設定檔有啟用~~
管他有沒有啟用,直接透過`netsh advfirewall set currentprofile state on`解決
### :heavy_check_mark:新增防火牆規則語法
```bash=
使用方式:
netsh advfirewall firewall add rule name=<string>
dir=in|out
action=allow|block|bypass
[program=<program path>]
[service=<service short name>|any]
[description=<string>]
[enable=yes|no (default=yes)]
[profile=public|private|domain|any[,...]]
[localip=any|<IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
[remoteip=any|localsubnet|dns|dhcp|wins|defaultgateway|
<IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
[localport=0-65535|<port range>[,...]|RPC|RPC-EPMap|IPHTTPS|any (default=any)]
[remoteport=0-65535|<port range>[,...]|any (default=any)]
[protocol=0-255|icmpv4|icmpv6|icmpv4:type,code|icmpv6:type,code|
tcp|udp|any (default=any)]
[interfacetype=wireless|lan|ras|any]
[rmtcomputergrp=<SDDL string>]
[rmtusrgrp=<SDDL string>]
[edge=yes|deferapp|deferuser|no (default=no)]
[security=authenticate|authenc|authdynenc|authnoencap|notrequired
(default=notrequired)]
```
### :heavy_check_mark:刪除防火牆規則語法
```bash=
使用方式:
netsh advfirewall firewall delete rule name=<string>
[dir=in|out]
[profile=public|private|domain|any[,...]]
[program=<program path>]
[service=<service short name>|any]
[localip=any|<IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
[remoteip=any|localsubnet|dns|dhcp|wins|defaultgateway|
<IPv4 address>|<IPv6 address>|<subnet>|<range>|<list>]
[localport=0-65535|<port range>[,...]|RPC|RPC-EPMap|any]
[remoteport=0-65535|<port range>[,...]|any]
[protocol=0-255|icmpv4|icmpv6|icmpv4:type,code|icmpv6:type,code|
tcp|udp|any]
備註:
- 刪除由名稱或選擇性地由端點、連接埠、通訊協定以及類型來
識別的規則。
- 若找到多個符合的項目,則會刪除所有符合的規則。
- 若指定 name=all,則會從指定的類型與設定檔刪除所有規則。
```
### :heavy_check_mark:防火牆設定備份與還原
我們變更設定後,當使用完畢就要還原
原本想說將防火牆狀態儲存到我新增的臨時規則的備註中,
要刪掉臨時規則前再依照備註的內容一一還原,
但感覺有點麻煩XDD
網路上看到這篇文章[透過註冊表開啟或關閉防火牆](https://ithelp.ithome.com.tw/articles/10023771)
防火牆設定會記錄再登入檔中,
那我直接對相關登入檔進行備份與還原應該會比較簡單
登入檔位置如下,只是不知道有沒有漏掉的
>[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess]
>[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\SharedAccess]
目前在論壇問問其他前輩們有沒有更好的做法
https://ithelp.ithome.com.tw/questions/10208741
網友告知還有一個實現方法
```bash=
REM 備份
netsh advfirewall export "D:\fw-rules.wfw"
REM return Ok.
REM 還原
netsh advfirewall import "D:\fw-rules.wfw"
REM return Ok.
```
## 最終批次檔
### 登入限制
```bash=
REM 備份設定
netsh advfirewall export "C:\TainanMDRFwRules.wfw"
REM 啟用防火牆
netsh advfirewall set currentprofile state on
REM 新增阻擋規則
REM out: deny all exclude FireEye
netsh advfirewall firewall add rule name="TainanMDRBlock" dir=out action=block enable=yes remoteip=0.0.0.0-211.20.177.237 protocol=any
netsh advfirewall firewall add rule name="TainanMDRBlock" dir=out action=block enable=yes remoteip=211.20.177.239-255.255.255.255 protocol=any
REM in: deny all exclude FireEye and 192.168.66.253
netsh advfirewall firewall add rule name="TainanMDRBlock" dir=in action=block enable=yes remoteip=0.0.0.0-192.168.66.252 protocol=any
netsh advfirewall firewall add rule name="TainanMDRBlock" dir=in action=block enable=yes remoteip=192.168.66.254-211.20.177.237 protocol=any
netsh advfirewall firewall add rule name="TainanMDRBlock" dir=in action=block enable=yes remoteip=211.20.177.239-255.255.255.255 protocol=any
```
### 解除限制
```bash=
REM 刪除規則
netsh advfirewall firewall delete rule name="TainanMDRBlock"
REM 還原設定
netsh advfirewall import "C:\TainanMDRFwRules.wfw"
```