iptables监控reset的连接信息

iptables监控reset的连接信息

需求

如果连接被reset需要记录下reset包是哪边放出来的,并记录reset连接的四元组信息

iptables规则

1
2
3
4
5
6
7
8
9
10
11
# Generated by iptables-save v1.4.21 on Wed Apr 1 11:39:31 2020
*filter
:INPUT ACCEPT [557:88127]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [527:171711]
# 不监听3406上的reset,日志前面添加 [drds]
-A INPUT -p tcp -m tcp ! --sport 3406 --tcp-flags RST RST -j LOG --log-prefix "[drds] " --log-level 7 --log-tcp-sequence --log-tcp-options --log-ip-options
# -A INPUT -p tcp -m tcp ! --dport 3406 --tcp-flags RST RST -j LOG --log-prefix "[drds] " --log-level7 --log-tcp-sequence --log-tcp-options --log-ip-options
-A OUTPUT -p tcp -m tcp ! --sport 3406 --tcp-flags RST RST -j LOG --log-prefix "[drds] " --log-level 7 --log-tcp-sequence --log-tcp-options --log-ip-options
COMMIT
# Completed on Wed Apr 1 11:39:31 2020

将如上配置保存在 drds_filter.conf中,设置开机启动:

1
2
3
//注意,tee 命令的 "-a" 选项的作用等同于 ">>" 命令,如果去除该选项,那么 tee 命令的作用就等同于 ">" 命令。
//echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid //sudo强行修改写入
echo "sudo iptables-restore < drds_filter.conf" | sudo tee -a /etc/rc.d/rc.local

单独记录到日志文件中

默认情况下 iptables 日志记录在 dmesg中不方便查询,可以修改rsyslog.d规则将日志存到单独的文件中:

1
2
# cat /etc/rsyslog.d/drds_filter_log.conf
:msg, startswith, "[drds]" -/home/admin/logs/drds-tcp.log

将 [drds] 开头的日志存到对应的文件

将如上配置放到: /etc/rsyslog.d/ 目录下, 重启 rsyslog 就生效了

1
2
3
sudo cp /home/admin/drds-worker/install/drds_filter_log.conf /etc/rsyslog.d/drds_filter_log.conf
sudo chown -R root:root /etc/rsyslog.d/drds_filter_log.conf
sudo systemctl restart rsyslog

防止日志打满磁盘

配置 logrotate, 保留最近30天的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#cat /etc/logrotate.d/drds
/home/admin/logs/drds-tcp.log
{
daily
rotate 30
copytruncate
compress
dateext
#size 1k
prerotate
/usr/bin/chattr -a /home/admin/logs/drds-tcp.log
endscript
postrotate
/usr/bin/chattr +a /home/admin/logs/drds-tcp.log
endscript
}
执行:
sudo /usr/sbin/logrotate --force --verbose /etc/logrotate.d/drds
debug:
sudo /usr/sbin/logrotate -d --verbose /etc/logrotate.d/drds
查看日志:
cat /var/lib/logrotate/logrotate.status

logrotate操作的日志需要权限正常,并且上级目录权限也要对,解决方案参考:https://chasemp.github.io/2013/07/24/su-directive-logrotate/ 报错信息:

1
2
3
4
5
6
7
rotating pattern: /var/log/myapp/*.log weekly (4 rotations)
empty log files are rotated, old logs are removed
considering log /var/log/myapp/default.log
error: skipping "/var/log/myapp/default.log" because parent directory has insecure permissions
(It's world writable or writable by group which is not "root") Set "su" directive in
config file to tell logrotate which user/group should be used for rotation

最终效果

1
2
3
4
5
$tail -10 logs/drds-tcp.log
Apr 26 15:27:36 vb kernel: [drds] IN= OUT=eth0 SRC=10.0.186.75 DST=10.0.175.109 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=8182 DPT=9366 SEQ=0 ACK=1747027778 WINDOW=0 RES=0x00 ACK RST URGP=0
Apr 26 15:27:36 vb kernel: [drds] IN= OUT=eth0 SRC=10.0.186.75 DST=10.0.175.109 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=8182 DPT=9368 SEQ=0 ACK=3840170438 WINDOW=0 RES=0x00 ACK RST URGP=0
Apr 26 15:27:36 vb kernel: [drds] IN= OUT=eth0 SRC=10.0.186.75 DST=10.0.175.109 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=8182 DPT=9370 SEQ=0 ACK=3892381139 WINDOW=0 RES=0x00 ACK RST URGP=0
Apr 26 15:27:38 vb kernel: [drds] IN= OUT=eth0 SRC=10.0.186.75 DST=10.0.171.173 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=8182 DPT=38225 SEQ=0 ACK=1436910913 WINDOW=0 RES=0x00 ACK RST URGP=0

NetFilter Hooks

下面几个 hook 是内核协议栈中已经定义好的:

  • NF_IP_PRE_ROUTING: 接收到的包进入协议栈后立即触发此 hook,在进行任何路由判断 (将包发往哪里)之前
  • NF_IP_LOCAL_IN: 接收到的包经过路由判断,如果目的是本机,将触发此 hook
  • NF_IP_FORWARD: 接收到的包经过路由判断,如果目的是其他机器,将触发此 hook
  • NF_IP_LOCAL_OUT: 本机产生的准备发送的包,在进入协议栈后立即触发此 hook
  • NF_IP_POST_ROUTING: 本机产生的准备发送的包或者转发的包,在经过路由判断之后, 将触发此 hook

IPTables 表和链(Tables and Chains)

下面可以看出,内置的 chain 名字和 netfilter hook 名字是一一对应的:

  • PREROUTING: 由 NF_IP_PRE_ROUTING hook 触发
  • INPUT: 由 NF_IP_LOCAL_IN hook 触发
  • FORWARD: 由 NF_IP_FORWARD hook 触发
  • OUTPUT: 由 NF_IP_LOCAL_OUT hook 触发
  • POSTROUTING: 由 NF_IP_POST_ROUTING hook 触发

tracing_point 监控

对于 4.19内核的kernel,可以通过tracing point来监控重传以及reset包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# grep tcp:tcp /sys/kernel/debug/tracing/available_events
tcp:tcp_probe
tcp:tcp_retransmit_synack
tcp:tcp_rcv_space_adjust
tcp:tcp_destroy_sock
tcp:tcp_receive_reset
tcp:tcp_send_reset
tcp:tcp_retransmit_skb
#开启本机发出的 reset 监控,默认输出到:/sys/kernel/debug/tracing/trace_pipe
# echo 1 > /sys/kernel/debug/tracing/events/tcp/tcp_send_reset/enable
#如下是开启重传以及reset的记录,本机ip 10.0.186.140
# cat trace_pipe
//重传
<idle>-0 [002] ..s. 9520196.657431: tcp_retransmit_skb: sport=3306 dport=62460 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70
Wisp-Root-Worke-540 [000] .... 9522308.074233: tcp_destroy_sock: sport=3306 dport=20594 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70 sock_cookie=51a
C2 CompilerThre-543 [002] ..s. 9522308.074296: tcp_destroy_sock: sport=3306 dport=20670 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70 sock_cookie=574
// 被reset
Wisp-Root-Worke-540 [002] ..s. 9522519.353756: tcp_receive_reset: sport=33822 dport=8080 saddr=10.0.186.140 daddr=10.0.171.193 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.171.193 sock_cookie=5dd
// 主动reset
DragoonAgent-28297 [002] .... 9522433.144611: tcp_send_reset: sport=8182 dport=61783 saddr=10.0.186.140 daddr=10.0.171.174 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.171.174
Wisp-Root-Worke-540 [002] ..s. 9522519.353773: tcp_send_reset: sport=33822 dport=8080 saddr=10.0.186.140 daddr=10.0.171.193 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.171.193
// 3306对端中断
cat-28727 [000] ..s. 9524341.650740: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=3306 dport=23262 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70 oldstate=TCP_SYN_RECV newstate=TCP_ESTABLISHED
<idle>-0 [000] .ns. 9524397.184608: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=3306 dport=23262 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70 oldstate=TCP_ESTABLISHED newstate=TCP_CLOSE
//8182 主动关闭
<idle>-0 [000] .Ns. 9525499.045236: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=8182 dport=25448 saddr=10.0.186.140 daddr=10.0.171.174 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.171.174 oldstate=TCP_SYN_RECV newstate=TCP_ESTABLISHED
DragoonAgent-6240 [001] .... 9525499.118092: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=8182 dport=25448 saddr=10.0.186.140 daddr=10.0.171.174 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.171.174 oldstate=TCP_ESTABLISHED newstate=TCP_FIN_WAIT1
<idle>-0 [000] ..s. 9525499.159032: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=8182 dport=25448 saddr=10.0.186.140 daddr=10.0.171.174 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.171.174 oldstate=TCP_FIN_WAIT1 newstate=TCP_FIN_WAIT2
<idle>-0 [000] .Ns. 9525499.159056: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=8182 dport=25448 saddr=10.0.186.140 daddr=10.0.171.174 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.171.174 oldstate=TCP_FIN_WAIT2 newstate=TCP_CLOSE
//3306 被动关闭
<idle>-0 [002] .Ns. 9524484.864509: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=3306 dport=23360 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70 oldstate=TCP_SYN_RECV newstate=TCP_ESTABLISHED
cat-28568 [002] ..s. 9524496.913199: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=3306 dport=23360 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70 oldstate=TCP_ESTABLISHED newstate=TCP_CLOSE_WAIT
Wisp-Root-Worke-540 [003] .... 9524496.915450: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=3306 dport=23360 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70 oldstate=TCP_CLOSE_WAIT newstate=TCP_LAST_ACK
Wisp-Root-Worke-539 [002] .Ns. 9524496.915572: inet_sock_set_state: family=AF_INET protocol=IPPROTO_TCP sport=3306 dport=23360 saddr=10.0.186.140 daddr=10.0.186.70 saddrv6=::ffff:10.0.186.140 daddrv6=::ffff:10.0.186.70 oldstate=TCP_LAST_ACK newstate=TCP_CLOSE

iptables 打通网络

1
2
//本机到 172.16.0.102 不通,但是和 47.100.29.16能通(阿里云弹性ip)
iptables -t nat -A OUTPUT -d 172.16.0.102 -j DNAT --to-destination 47.100.29.16

参考资料

深入理解 iptables 和 netfilter 架构

NAT - 网络地址转换(2016)