chundev
日期:2026-03-25 環境:CentOS/RHEL 最小化安裝(無 tcpdump、nc、telnet)
設定 rsyslog 將 EDR 告警轉發到遠端 SIEM,ss 看到 UDP ESTAB 但 SIEM 收不到。排查後發現根本原因是 rsyslog 設定檔中 &(action continuation)沒有獨立成行。在最小化系統上用 bash /dev/tcp、iptables -j LOG、ss -tunp 三件套取代常見的網路診斷工具。
EDR(Endpoint Detection & Response)產品通常需要將告警 syslog 轉發到 SIEM 平台集中監控。轉發機制是透過 rsyslog 修改設定檔,新增一行 action 將 log 透過 UDP/TCP 送到遠端 syslog server。
EDR 設備通常是精簡安裝的 Linux,很多常用的網路診斷工具都沒裝,排錯時需要用替代方案。
設定完 rsyslog 轉發後:
rsyslogd -N1 語法檢查通過ss -tunp 可以看到 udp ESTAB 到 SIEM IP沒有明確的錯誤訊息,這正是最難排的類型。
ss 有 ESTAB 但 SIEM 沒收到,直覺懷疑防火牆。但用 iptables LOG 確認封包有送出,且同網段另一台可以通 → 排除中間防火牆。
跨網段傳輸(10.x.x.x → 192.168.x.x),懷疑路由問題。但 ip route get 路由正確,gateway 可 ping → 排除路由。
同網段舊機可以通,新機不行,高度懷疑 ACL 只放了舊機 IP。但確認 ASA 和 Core Switch ACL 都有放行 → 排除 ACL。
& 沒有獨立成行重新檢查設定檔,發現 & action continuation 行沒有正確換行。修正後 systemctl restart rsyslog,立刻通了。
rsyslog 傳統語法(legacy format)以「行」為單位解析,& 是 action continuation 符號,必須出現在新行的開頭:
# ❌ 錯誤:& 黏在前一行
if $programname == 'my-service' then /var/log/my-service.log;MyFormat & @10.0.0.1:514;MyFormat
& stop
# ✅ 正確:每個 action 獨立一行
if $programname == 'my-service' then /var/log/my-service.log;MyFormat
& @10.0.0.1:514;MyFormat
& stop
坑在於:rsyslogd -N1 語法檢查不一定會報錯,服務也能正常啟動,ss 甚至會顯示 ESTAB,但實際轉發行為不正確。
ss 輸出中看到 UDP socket 的 ESTAB 狀態,容易誤解為「連線已建立」。實際上:
| 狀態 | 意義 |
|---|---|
UNCONN |
未連線的 UDP socket,等待任意來源的封包 |
ESTAB |
已對特定目的地呼叫 connect() 的 UDP socket |
UDP 的 connect() 不是真正的連線,只是告訴 kernel:
send() 時不用再指定UDP ESTAB 只代表本機 socket 設定好了,不代表對方有在監聽或封包有到達。
在沒有 tcpdump、nc、telnet 的環境下:
bash /dev/tcp — TCP 連通性測試# 測試 TCP port 是否開通
timeout 3 bash -c 'echo > /dev/tcp/10.0.0.1/514' && echo "OK" || echo "FAIL"
/dev/tcp 是 bash 的虛擬裝置,不是真實檔案(ls 看不到)timeout 避免連不上時卡死iptables -j LOG — 替代 tcpdump 抓包# 記錄所有送往目標 IP 的封包
iptables -I OUTPUT -d 10.0.0.1 -j LOG --log-prefix "MYTEST: "
# 觸發流量
logger -t my-service "test message"
# 查看結果
dmesg | grep "MYTEST"
# ⚠️ 用完一定要刪除,否則 kernel log 會被灌爆
iptables -D OUTPUT -d 10.0.0.1 -j LOG --log-prefix "MYTEST: "
--log-prefix 是任意字串,純粹方便 grepdmesg 查看ss -tunp — 連線狀態確認# 查看 rsyslog 的所有連線
ss -tunp | grep rsyslog
# 只看 UDP
ss -unp | grep 514
ss 來自 iproute2 套件,CentOS 7+ 預設都有netstat 的現代替代品logger 的進階用法# 模擬特定 program name 的 syslog 訊息
logger -t my-service "test message"
# 直接送 UDP 到遠端(不經過本機 rsyslog)
logger -d -n 10.0.0.1 -P 514 "direct UDP test"
# -d = UDP, -n = 遠端主機, -P = port
轉發 syslog 時,不同 template 包含的欄位不同:
| Template 類型 | 含 hostname | 適用場景 |
|---|---|---|
| 標準 syslog 格式(RFC 3164) | ✅ | 遠端轉發(SIEM 能正確解析) |
| 自訂 log 格式(精簡) | ❌ | 本機檔案記錄 |
如果 SIEM 收到的 log 缺少設備名稱(hostname),通常是轉發行使用了不含 %hostname% 的 template。解法是改用標準 syslog 格式的 template,或自訂一個帶 hostname 的 template:
template(name="WithHost" type="string"
string="%timegenerated% %hostname% [%procid%] <%syslogseverity-text%> %msg%\n")
rsyslogd -N1 語法檢查通過不代表行為正確 — legacy syntax 的 & 行位置錯誤不一定被語法檢查抓到,是隱形 bugiptables -j LOG 是最可靠的精簡系統抓包方式 — 幾乎所有 Linux 都有 iptables,比找替代工具更實際if/then 結構更直觀,不會有 & 行位置的問題& 語法說明%hostname% 等變數的行為connect() 的行為說明