iptables:使用conntrack和owner匹配传出流量。适用于奇怪的滴


11

在我的iptables脚本中,我一直在尝试编写尽可能细化的规则。我限制了允许哪些用户使用哪些服务,部分出于安全性考虑,一部分作为学习练习。

在运行3.6.2内核的Debian 6.0.6上使用iptables v1.4.16.2。

但是我遇到了一个我不太了解的问题。

所有用户的传出端口

这工作得很好。我没有任何通用的状态跟踪规则。

##出口端口81
$ IPTABLES -A输出-p tcp –dport 81 -m conntrack –ctstate新的,已确定的-j接受
$ IPTABLES -A INPUT -p tcp --sport 81 -s $ MYIP -m conntrack --ctstate已建立-j接受

用户匹配的出站端口

##用户帐户的传出端口80
$ IPTABLES -A输出-匹配所有者--uid-owner用户帐户-p tcp --dport 80 -m conntrack --ctstate新创建的--sport 1024:65535 -j接受
$ IPTABLES -A INPUT -p tcp --sport 80 --dport 1024:65535 -d $ MYIP -m conntrack --ctstate已建立-j接受

这仅将端口80拨出给帐户“ useraccount”,但是TCP流量这样的规则存在问题。

##默认传出日志+阻止规则
$ IPTABLES -A OUTPUT -j LOG --log-prefix“ BAD OUTGOING” --log-ip-options --log-tcp-options --log-uid
$ IPTABLES -A输出-j DROP

问题

上面的作品,用户“ useraccount”可以很好地获取文件。系统上的其他用户都无法建立到端口80的传出连接。

useraccount @ host:$ wget http://cachefly.cachefly.net/10mb.test

但是上面的wget在我的系统日志中留下了x7删除的条目:

10月18日02:00:35 xxxx内核:BAD OUTGOING IN = OUT = eth0 SRC = xx.xx.xx.xx DST = 205.234.175.175 LEN = 40 TOS = 0x00 PREC = 0x00 TTL = 64 ID = 12170 DF PROTO = TCP SPT = 37792 DPT = 80 SEQ = 164520678 ACK = 3997126942 WINDOW = 979 RES = 0x00 ACK URGP = 0  

对于类似的UDP流量规则,我不会得到这些丢弃。我已经制定了限制哪些用户可以发出DNS请求的规则。

丢弃的传出ACK数据包似乎来自我不了解的根帐户(URGP = 0)。即使当我将useraccount换成root时。

我认为ACK数据包被归类为新消息,因为conntrack在3向握手的第3步之后开始跟踪连接,但是为什么会被丢弃呢?

这些下降可以安全地忽略吗?

编辑

因此,我经常看到这样的规则,这些规则对我来说很有效:

$ IPTABLES -A输出-s $ MYIP -p tcp -m tcp --dport 80 -m状态-状态NEW,已建立-j接受
$ IPTABLES -A INPUT -p tcp -m tcp --sport 80 -d $ MYIP -m状态--state已建立-j接受

我将“ -m state --state”替换为“ -m conntrack --ctstate”,因为状态匹配显然已经过时了。

拥有通用状态跟踪规则是最佳实践吗?上面的规则不正确吗?

要严格控制传出用户的连接,这样会更好吗?

$ IPTABLES -A INPUT -m conntrack --ctstate已建立-j接受
$ IPTABLES -A输出-m conntrack --ctstate已建立-j接受

$ IPTABLES -A输出-p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner useraccount -j ACCEPT

$ IPTABLES -A输出-p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner otheraccount -j ACCEPT

如果此主机也正在路由来自LAN的流量,您能否发布所有规则,包括FORWARD链和nat表。
Serge 2012年

该主机未进行任何路由,流量来自具有这些规则的计算机。我只发布了特定传出流量的相关规则。
arcX 2012年

Answers:


16

简而言之,当套接字不属于任何人时,发送ACK。与其允许属于用户套接字的x数据包,不如允许套接字与用户发起的连接有关的数据包x

更长的故事。

要了解此问题,它有助于理解wgetHTTP请求的工作原理。

wget http://cachefly.cachefly.net/10mb.test

wget建立与的TCP连接cachefly.cachefly.net,一旦建立,就会以HTTP协议发送一个请求,请求内容为:“请向我发送/10mb.testGET /10mb.test HTTP/1.1)的内容,顺便说一句,请您在完成(Connection: Keep-alive)之后不能关闭连接。原因这样做是因为,如果服务器以相同IP地址上的URL答复重定向,则它可以重用连接。

现在,服务器可以使用以下任一方式进行答复:“请您提供请求的数据,请注意它的大小为10MB(是Content-Length: 10485760),是的,我将保持打开状态”。或者,如果它不知道数据的大小,则“这是数据,很抱歉,我无法打开连接,但是我会通过关闭连接末端来告诉您何时可以停止下载数据”。

在上面的URL中,我们是第一种情况。

因此,一旦wget获得了响应的标头,它就知道一旦下载了10MB数据就完成了工作。

基本上,wget将读取数据直到接收到10MB并退出。但是到那时,还有更多工作要做。服务器呢?有人告诉您保持连接打开状态。

退出之前,wget关闭(close系统调用)套接字的文件描述符。之后,close系统完成对服务器发送的数据的确认,并发送一条消息FIN:“我将不再发送任何数据”。此时close返回并wget退出。不再有与TCP连接关联的套接字(至少不是任何用户拥有的套接字)。但是还没有完成。收到该消息后FIN,HTTP服务器在从客户端读取下一个请求时会看到文件结尾。在HTTP中,这意味着“没有更多请求,我将结束我的结局”。因此它也发送其FIN,例如,“我也不会发送任何东西,该连接将消失”。

客户端收到该FIN后,将发送“ ACK”。但是,那一点wget早已一去不复返了,因此ACK不会来自任何用户。这就是为什么它被您的防火墙阻止了。因为服务器没有收到ACK,所以它将一遍又一遍地发送FIN,直到它放弃为止,您将看到更多丢弃的ACK。这也意味着通过丢弃这些ACK,您将不必要地使用服务器的资源(需要将套接字保持在LAST-ACK状态)相当长的时间。

如果客户端未请求“保持活动”或服务器未答复“保持活动”,则该行为将有所不同。

如前所述,如果您正在使用连接跟踪器,那么您要做的就是让处于ESTABLISHED和RELATED状态的每个数据包都通过,只担心NEW数据包。

如果您允许NEW来自用户的数据包,x而不允许来自用户的数据包y,则将通过用户建立连接的其他数据包x,并且由于用户无法建立连接y(因为我们正在阻止NEW建立连接的数据包),用户y连接不会通过任何数据包。


3

这将端口80仅用于帐户“ useraccount”

-嗯,至少您显示的规则实际上并不暗示这一点。

还有建议的余地-不要在ESTABLISHED流上进行用户检查,仅在NEW上进行检查。在检查Incoming ESTABLISHED时,我也看不到检查源端口的意义,它与conntrack的PoV已经处于ESTABLISHED状态是什么区别。防火墙应尽可能简单但有效,因此Occam的剃刀方法最适合。


1
谢谢你的建议。通常,我只是为了简单起见,但这不是此特定练习的重点。
arcX 2012年

1
@arcX,此练习可能由于过于复杂和不一致而失败— IOW,您看到的行为可能不是由于netfilter内部(错误,怪癖),而是由于您使用它的方式。首先尝试简化规则集…
poige 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.