精华内容
下载资源
问答
  • Conntrack support

    2020-11-27 22:25:40
    <div><p>These 2 commits are introducing the support for netfilter conntrack into the library. This PR is a dependency for the fix of the bug: https://github.com/docker/docker/issues/8795</p> <p>The ...
  • Conntrack netlink

    2021-01-12 03:22:49
    <div><p>This switches the endpoint probe to use the netfilter netlink interface over spawning conntrack as a child process. This is somewhat of a half measure between where master is now and the eBPF ...
  • Failed to execute conntrack; Calico requires iptables to be installed.", which is obviously incorrect. Fixed to correctly ask for conntrack.</p><p>该提问来源于开源项目:projectcalico/felix...
  • ConnTrack issues

    2021-01-09 18:38:56
    <div><p>Creating this issue to report of a different issues, related to ConnTrack addition. <p>I have a report of waiting for 1 minute till <code>GotInfo</code> returns <pre><code> 10:17:40.681 T:...
  • ERRO: 2016/08/17 16:01:27.216530 conntrack stderr:conntrack v1.4.3 (conntrack-tools): Operation failed: No buffer space available <probe> ERRO: 2016/08/17 16:01:27.416339 conntrack error: EOF &...
  • 再次深入到ip conntrackconntrack full问题

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

    也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

                    增加nf_conntrack_max固然可以缓解这个问题,或者说减小conntrack表项占据内核内存的时间也可以缓解之,然而这种补救措施都是治标不治本的.

    注解:不要过度减小NEW以及TCP的establish的CT状态的timeout的原因

    尽量不要减小NEW状态时间,因为对于某些恶劣的网络,一个数据包的来回确实需要很长时间,对于TCP而言,此时RTT还没有测量呢。如果NEW状态的conntrack保留时间过短,就会导致大量NEW状态的连接,而对于很多依赖ctstate的模块而言,这样就会有问题,比如iptables的filter表中使用ESTABLISH状态来放过前向包的返回包就会有问题,此时ip_conntrack很有可能由于NEW状态时间过短而将返回包作为NEW状态处理而不是ESTABLISH状态,如此一来,返回包就无法通过了。如下图所示:


    使用简单的实验可以很容易证实上面的图示,以简单的udp通信为例,编写一个udp-echo程序,服务器简单echo客户端送达的字符串:
        for(;;)    {     n = recvfrom(sd, msg, MAXLINE, 0, pcliaddr, &len);          sleep(5);          sendto(sd, msg, n, 0, pcliaddr, len);    }

    然后在客户端上执行echo $sec /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout
    其中sec要比服务器端的sleep参数更小即可。
    如此udp客户端将收不到服务器eho回来的字符串,因为客户端只是放行状态为establish的入流量,如果ip_conntrack_udp_timeout配置过于短暂,NEW状态的conntrack过早被释放,这样将不会有establish状态的流量了。对于UDP而言,由于它是不确认无连接允许丢包的,因此影响还不是很大,TCP也有类似的问题,那就是如果你连接一个很远的且网络状况很恶劣的TCP服务器,然后你把ip_conntrack_tcp_timeout_synsent设置很小,这样就几乎完不成三次握手了,更进一步,如果你把ip_conntrack_tcp_timeout_established设置过小,那么一旦三次握手建立连接之后,客户端和服务器之间很久不发包,当establish状态到期后,conntrack被释放,此时服务器端主动发来一个包,该包的conntrack状态会是什么呢?因此给予tcp的establish状态5天的时间,是可以理解的。需要注意的是,对于tcp而言,由于无法简单的控制服务器发送syn-ack的延时,因此需要在establish状态而不是new状态做文章了(实际上,ip_conntrack的establish状态映射成了tcp的多个状态,包括syn-ack,ack,established),试试看,效果和udp的一样。
            前面关于ip_conntrack扯的太远了,我们的首要问题是conntrack full的问题。实际上,如果深入思考这个conntrack full的问题,就会发现,并不是conntrack容量太小或者表项保留时间过长引发的full。现实中的万事万物都不是无限的,对于计算机资源而言,更应该节约使用,不能让无关人士浪费这种资源,另外既然内核默认了一个表项的存活时间,那肯定是经过测试的经验值,自有它的道理。因此本质问题在于很多不需要conntrack的包也被conntrack了,这样就会挤掉很多真正需要conntrack的流量。
            那么都是哪些流量需要conntrack呢?常用的就两个,一个是任何使用ctstate或者state这些match的iptables规则,另外一个就是所有的iptables的nat表中的规则,如果我们事先知道哪些流量需要使用iptables的[ct]state来控制,并且也知道哪些流量需要做NAT,那么余下的流量就都是和conntrack无关的流量了,可以不被ip_conntrack来跟踪。
            幸运的是,Linux的Netfilter在PREROUTING以及OUTPUT这两个HOOK的conntrack之前安插了一个优先级更高的table,那就是raw,通过它就可以分离出不需要被conntrack的流量。如果你确定只有某个网卡进来的流量才需要做NAT,那么就执行下面的规则:
    iptables -t raw -A PREROUTING ! –I $网卡 -j NOTRACKiptables –t raw –A OUTPUT –j NOTRACK
    这样一来,资源就不会浪费在无关人士身上了,性能也会有所提高,因为凡是NOTRACK的流量,都不会去查询conntrack的hash表,因为在ip(nf)_conntrack_in的内部的开始有一个判断:
    if ((*pskb)->nfct)    return NF_ACCEPT;
    而NOTRACK这个target的实现也很简单:
    (*pskb)->nfct = &ip_conntrack_untracked.info[IP_CT_NEW];
    事实上将一个占位者设置给skb的nfct,这样可以保持其它代码的一致性。
         可见,必要时同时采取三种方式比较有效:1.增大conntrack_max;2.减少状态保存时间;3.分离无关流量。然而除了第三种方式,其余两种方式在操作时必须给自己十足的理由那么做才行,对于1,比必须明白内核内存被占有的方式,对于2,看看本文的前半部分。
    iptables -A FORWARD -m state --state UNTRACKED -j ACCEPT

    最后有个提问:

    对于没有keepalive的TCP连接而言,试想服务器和客户端在establish状态之后5天内都没有互相通信,5天后的一天,服务器主动发送了一个数据包给客户端,然而此时防火墙/NAT设备上的conntrack状态已经过期被删除,此时该数据包将会被认为是NEW状态的数据包,被DROP,客户端永远收不到这个数据包,进而也不会发送ACK,服务器端不断重发,不断被防火墙DROP,当重发次数达到一定次数后,服务器RESET该连接,然而客户端如何得知,只有客户端主动发包才能打破这个僵局,然而谁能保证客户端一定会主动发包?这是不是Linux的ip_conntrack的一种缺陷,设计5天时间的establish状态是不是一种极限措施,然而谁又能保证5天内两端不断通信呢?
               

    给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

    这里写图片描述
    展开全文
  • Faster conntrack parser

    2021-01-12 02:03:06
    <div><p>Profiling indicated that conntrack parsing was around 20% of the CPU time of the probe in Weave Cloud dev, so I wrote a scanner/parser instead of relying on <code>sscanf</code> and <code>split...
  • nf_conntrack

    2021-01-17 16:55:31
    nf_conntrack(在老版本的 Linux 内核中叫 ip_conntrack)是一个内核模块,用于跟踪一个连接的状态的。连接状态跟踪可以供其他模块使用,最常见的两个使用场景是 iptables 的 nat 的 state 模块。 iptables 的 nat 通过...

    nf_conntrack(在老版本的 Linux 内核中叫 ip_conntrack)是一个内核模块,用于跟踪一个连接的状态的。连接状态跟踪可以供其他模块使用,最常见的两个使用场景是 iptables 的 nat 的 state 模块。 iptables 的 nat 通过规则来修改目的/源地址,但光修改地址不行,我们还需要能让回来的包能路由到最初的来源主机。这就需要借助 nf_conntrack 来找到原来那个连接的记录才行。而 state 模块则是直接使用 nf_conntrack 里记录的连接的状态来匹配用户定义的相关规则。例如下面这条 INPUT 规则用于放行 80 端口上的状态为 NEW 的连接上的包。

    iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT。

    iptables中的状态检测功能是由state选项来实现iptable的。对这个选项,在iptables的手册页中有以下描述:

    state

    这个模块能够跟踪分组的连接状态(即状态检测)。

    格式:–state XXXXX

    这里,state是一个用逗号分割的列表,表示要匹配的连接状态。

    在iptables中有四种状态:NEW,ESTABLISHED,RELATED,INVALID。

    NEW,表示这个分组需要发起一个连接,或者说,分组对应的连接在两个方向上都没有进行过分组传输。NEW说明 这个包是我们看到的第一个包。意思就是,这是conntrack模块看到的某个连接第一个包,它即将被匹配了。比如,我们看到一个SYN包,是我们所留意 的连接的第一个包,就要匹配它。第一个包也可能不是SYN包,但它仍会被认为是NEW状态。比如一个特意发出的探测包,可能只有RST位,但仍然是 NEW。

    ESTABLISHED,表示分组对应的连接已经进行了双向的分组传输,也就是说连接已经建立,而且会继续匹配 这个连接的包。处于ESTABLISHED状态的连接是非常容易理解的。只要发送并接到应答,连接就是ESTABLISHED的了。一个连接要从NEW变 为ESTABLISHED,只需要接到应答包即可,不管这个包是发往防火墙的,还是要由防火墙转发的。ICMP的错误和重定向等信息包也被看作是 ESTABLISHED,只要它们是我们所发出的信息的应答。

    RELATED,表示分组要发起一个新的连接,但是这个连接和一个现有的连接有关,例如:FTP的数据传输连接 和控制连接之间就是RELATED关系。RELATED是个比较麻烦的状态。当一个连接和某个已处于ESTABLISHED状态的连接有关系时,就被认为 是RELATED的了。换句话说,一个连接要想是RELATED的,首先要有一个ESTABLISHED的连接。这个ESTABLISHED连接再产生一 个主连接之外的连接,这个新的连接就是RELATED的了,当然前提是conntrack模块要能理解RELATED。ftp是个很好的例子,FTP- data连接就是和FTP-control有RELATED的。还有其他的例子,

    INVAILD,表示分组对应的连接是未知的,说明数据包不能被识别属于哪个连接或没有任何状态。有几个原因可以产生这种情况,比如,内存溢出,收到不知属于哪个连接的ICMP错误信息。一般地,我们DROP这个状态的任何东西。

    nf_conntrack模块常用命令
    查看nf_conntrack表当前连接数
    cat /proc/sys/net/netfilter/nf_conntrack_count

    查看nf_conntrack表最大连接数
    cat /proc/sys/net/netfilter/nf_conntrack_max

    通过dmesg可以查看nf_conntrack的状况:
    dmesg |grep nf_conntrack

    查看存储conntrack条目的哈希表大小,此为只读文件
    cat /proc/sys/net/netfilter/nf_conntrack_buckets

    查看nf_conntrack的TCP连接记录时间
    cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established

    通过内核参数查看命令,查看所有参数配置
    sysctl -a | grep nf_conntrack

    通过conntrack命令行工具查看conntrack的内容
    yum install -y conntrack
    conntrack -L

    加载对应跟踪模块
    [root@plop ~]# modprobe /proc/net/nf_conntrack_ipv4
    [root@plop ~]# lsmod | grep nf_conntrack
    nf_conntrack_ipv4 9506 0
    nf_defrag_ipv4 1483 1 nf_conntrack_ipv4
    nf_conntrack_ipv6 8748 2
    nf_defrag_ipv6 11182 1 nf_conntrack_ipv6
    nf_conntrack 79758 3 nf_conntrack_ipv4,nf_conntrack_ipv6,xt_state
    ipv6 317340 28 sctp,ip6t_REJECT,nf_conntrack_ipv6,nf_defrag_ipv6

    移除 nf_conntrack 模块
    $ sudo modprobe -r xt_NOTRACK nf_conntrack_netbios_ns nf_conntrack_ipv4 xt_state
    $ sudo modprobe -r nf_conntrack

    查看当前的连接数:
    grep nf_conntrack /proc/slabinfo

    查出目前 nf_conntrack 的排名:
    cat /proc/net/nf_conntrack | cut -d ’ ’ -f 10 | cut -d ‘=’ -f 2 | sort | uniq -c | sort -nr | head -n 10

    nf_conntrack会话表的内容解释
    会话表样例
    通过conntrack -L与/proc/net/nf_conntrack是完全一样的,除了少了前面的两列。
    下面以cat /proc/net/nf_conntrack为例进行说明:

    ipv4 2 tcp 6 25 SYN_SENT src=182.168.77.7 dst=42.236.9.57 sport=57430 dport=443 [UNREPLIED] src=42.236.9.57 dst=182.168.77.7 sport=443 dport=57430 mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
    ipv4 2 tcp 6 299 ESTABLISHED src=172.18.15.56 dst=172.18.15.96 sport=40248 dport=22 src=172.18.15.96 dst=172.18.15.56 sport=22 dport=40248 [ASSURED] mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
    ipv4 2 tcp 6 5 SYN_SENT src=182.168.77.7 dst=221.181.72.250 sport=57428 dport=443 [UNREPLIED] src=221.181.72.250 dst=182.168.77.7 sport=443 dport=57428 mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
    ipv4 2 tcp 6 1 SYN_SENT src=182.168.77.7 dst=221.181.72.250 sport=57427 dport=80 [UNREPLIED] src=221.181.72.250 dst=182.168.77.7 sport=80 dport=57427 mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
    每一列表达的意思
    第一列:网络层协议名字。
    第二列:网络层协议号。
    第三列:传输层协议名字。
    第四列:传输层协议号。
    第五列:无后续包进入时无效的秒数,即老化时间。
    第六列:不是所有协议都有,连接状态。
    其它的列都是通过名字的方式(key与value对)表述,或和呈现标识([UNREPLIED], [ASSURED], …)。一行的不同列可能包含相同的名字(例如src和dst),第一个表示请求方,第二个表示应答方。
    呈现标识含义
    [ASSURED]: 在两个方面(即请求和响应)方向都看到了流量。
    [UNREPLIED]: 尚未在响应方向上看到流量。如果连接跟踪缓存溢出,则首先删除这些连接。
    请注意,某些列名仅出现在特定协议中(例如,TCP和UDP的sport和dport,ICMP的type和code)。 仅当内核使用特定选项构建时,才会显示其他列名称(例如mark)。

    举例说明
    ipv4 2 tcp 6 300 ESTABLISHED src=1.1.1.2 dst=2.2.2.2 sport=2000 dport=80 src=2.2.2.2 dst=1.1.1.1 sport=80 dport=12000 [ASSURED] mark=0 use=2
    属于从主机1.1.1.2,端口2000到主机2.2.2.2,端口80的已建立的TCP连接,从中将响应发送到主机1.1.1.2,端口2000,在五分钟内超时。对于此连接,已在两个方向上看到数据包。

    ipv4 2 icmp 1 3 src=1.1.1.2 dst=1.1.1.1 type=8 code=0 id=32354 src=1.1.1.1 dst=1.1.1.2 type=0 code=0 id=32354 mark=0 use=2
    属于从主机1.1.1.2到主机1.1.1.1的ICMP回应请求数据包,具有从主机1.1.1.1到主机1.1.1.2的预期回应应答数据包,在三秒内超时。响应目标主机不一定与请求源主机相同,因为请求源地址可能已被响应目标主机伪装。

    主要标识
    请注意,以下信息可能不是最新信息!

    Fields available for all entries:

    bytes (if accounting is enabled, request and response)
    delta-time (if CONFIG_NF_CONNTRACK_TIMESTAMP is enabled)
    dst (request and response)
    mark (if CONFIG_NF_CONNTRACK_MARK is enabled)
    packets (if accounting is enabled, request and response)
    secctx (if CONFIG_NF_CONNTRACK_SECMARK is enabled)
    src (request and response)
    use
    zone (if CONFIG_NF_CONNTRACK_ZONES is enabled)
    Fields available for dccp, sctp, tcp, udp and udplite transmission layer protocols:

    dport (request and response)
    sport (request and response)
    Fields available for icmp transmission layer protocol:

    code (request and response)
    id (request and response)
    type (request and response)
    Fields available for gre transmission layer protocol:

    dstkey (request and response)
    srckey (request and response)
    stream_timeout
    timeout
    Allowed values for the sixth field:

    dccp transmission layer protocol
    CLOSEREQ
    CLOSING
    IGNORE
    INVALID
    NONE
    OPEN
    PARTOPEN
    REQUEST
    RESPOND
    TIME_WAIT

    sctp transmission layer protocol
    CLOSED
    COOKIE_ECHOED
    COOKIE_WAIT
    ESTABLISHED
    NONE
    SHUTDOWN_ACK_SENT
    SHUTDOWN_RECD
    SHUTDOWN_SENT

    tcp transmission layer protocol
    CLOSE
    CLOSE_WAIT
    ESTABLISHED
    FIN_WAIT
    LAST_ACK
    NONE
    SYN_RECV
    SYN_SENT
    SYN_SENT2
    TIME_WAIT

    nf_conntrack相关内核参数和解释
    参考内核帮助文档/usr/share/doc/kernel-doc-3.10.0/Documentation/networking/nf_conntrack-sysctl.txt
    /proc/sys/net/netfilter/nf_conntrack_*:

    nf_conntrack_acct
    值类型:BOOLEAN
    0 - disabled (default)
    not 0 - enabled
    启用连接跟踪流记帐。64位字节和数据包每个流量的计数器被添加。

    nf_conntrack_buckets
    值类型:INTEGER (read-only)
    哈希表的大小。 如果在模块加载期间未指定为参数,则通过将总内存除以16384来计算默认大小以确定存储区的数量,但是哈希表将永远不会少于32并且限制为16384个存储区。 对于内存超过4GB的系统,它将是65536个桶。

    nf_conntrack_checksum
    值类型:BOOLEAN
    0 - disabled
    not 0 - enabled (default)
    验证传入数据包的校验和。 具有错误校验和的数据包处于INVALID状态。 如果启用此选项,则不会考虑此类数据包进行连接跟踪。

    nf_conntrack_count
    值类型:INTEGER (read-only)
    当前分配的流条目数。

    nf_conntrack_events
    值类型:BOOLEAN
    0 - disabled
    not 0 - enabled (default)
    如果启用此选项,则连接跟踪代码将通过ctnetlink为用户空间提供连接跟踪事件。

    nf_conntrack_events_retry_timeout
    值类型:INTEGER (seconds)
    default 15
    此选项仅在使用“可靠连接跟踪事件”时才相关。 通常,ctnetlink是“有损”的,也就是说,当用户空间监听器无法跟上时,事件通常会被丢弃。
    用户空间可以请求“可靠的事件模式”。 当此模式处于活动状态时,conntrack将仅在事件发布后销毁。 如果事件传递失败,则内核会定期重新尝试将事件发送到用户空间。
    这是内核在重新尝试传递destroy事件时应使用的最大间隔。
    数字越大意味着交付重试次数越少,处理待办事项的时间就越长。

    nf_conntrack_expect_max
    值类型:INTEGER
    期望表的最大大小。 默认值为nf_conntrack_buckets / 256.最小值为1。

    nf_conntrack_frag6_high_thresh
    值类型:INTEGER
    用于重组IPv6片段的最大内存。 当为达到重组目标时分配nf_conntrack_frag6_high_thresh字节的内存时,若超出此值片段处理程序将抛出数据包。

    nf_conntrack_frag6_timeout
    值类型:INTEGER (seconds)
    default 60
    ipv6分片在内存中保存的老化时间。

    nf_conntrack_generic_timeout
    值类型:INTEGER (seconds)
    default 600
    通用超时的默认值。 这指的是第4层未知/不支持的协议。

    nf_conntrack_helper
    值类型:BOOLEAN
    0 - disabled
    not 0 - enabled (default)
    启用自动conntrack帮助程序分配。

    nf_conntrack_icmp_timeout
    值类型:INTEGER (seconds)
    default 30
    ICMP连接状态超时的默认值。

    nf_conntrack_icmpv6_timeout
    值类型:INTEGER (seconds)
    default 30
    ICMP6连接状态超时的默认值。

    nf_conntrack_log_invalid
    值类型:INTEGER
    0 - disable (default)
    1 - log ICMP packets
    6 - log TCP packets
    17 - log UDP packets
    33 - log DCCP packets
    41 - log ICMPv6 packets
    136 - log UDPLITE packets
    255 - log packets of any protocol
    根据值类型记录指定类型无效数据包。

    nf_conntrack_max
    值类型:INTEGER
    连接跟踪表的大小。 默认值为nf_conntrack_buckets值* 4。

    nf_conntrack_tcp_be_liberal
    值类型:BOOLEAN
    0 - disabled (default)
    not 0 - enabled
    Be conservative in what you do, be liberal in what you accept from others.If it’s non-zero, we mark only out of window RST segments as INVALID.

    nf_conntrack_tcp_loose
    值类型:BOOLEAN
    0 - disabled
    not 0 - enabled (default)
    如果它设置为零,我们将禁用拾取已建立的连接。
    它的意思是,是否仅仅允许为经过TCP三次握手的流创建nf_conntrack表项还是说为任意收到的TCP数据包(有可能是一个构造出来的攻击包)查询未果后均创建新的nf_conntrack表项。

    nf_conntrack_tcp_max_retrans
    值类型:INTEGER
    default 3
    在未收到来自目标的(可接受)ACK的情况下可以重新传输的最大数据包数。 如果达到此数字,将启动更短的计时器。

    nf_conntrack_tcp_timeout_close
    值类型:INTEGER (seconds)
    default 10

    nf_conntrack_tcp_timeout_close_wait
    值类型:INTEGER (seconds)
    default 60

    nf_conntrack_tcp_timeout_established
    值类型:INTEGER (seconds)
    default 432000 (5 days)
    默认是432000=3600245即5天的超时时间,超时后清空对应的那条记录。

    nf_conntrack_tcp_timeout_fin_wait
    值类型:INTEGER (seconds)
    default 120

    nf_conntrack_tcp_timeout_last_ack
    值类型:INTEGER (seconds)
    default 30

    nf_conntrack_tcp_timeout_max_retrans
    值类型:INTEGER (seconds)
    default 300

    nf_conntrack_tcp_timeout_syn_recv
    值类型:INTEGER (seconds)
    default 60

    nf_conntrack_tcp_timeout_syn_sent
    值类型:INTEGER (seconds)
    default 120

    nf_conntrack_tcp_timeout_time_wait
    值类型:INTEGER (seconds)
    default 120

    nf_conntrack_tcp_timeout_unacknowledged
    值类型:INTEGER (seconds)
    default 300

    nf_conntrack_timestamp
    值类型:BOOLEAN
    0 - disabled (default)
    not 0 - enabled
    启用连接跟踪流时间戳。

    nf_conntrack_udp_timeout
    值类型:INTEGER (seconds)
    default 30

    nf_conntrack_udp_timeout_stream2
    值类型:INTEGER (seconds)
    default 180
    如果检测到UDP流,将使用此扩展超时。

    还有多少秒这条会话信息会从跟踪表清除,取决于超时参数的配置,以及是否有包传输,有包传输时,这个时间会重置为超时时间。

    如何判断会话表是否满
    当会话表中的记录大于内核设置nf_conntrack_max的值时,会导致会话表满。

    nf_conntrack_max - INTEGER
    Size of connection tracking table. Default value is
    nf_conntrack_buckets value * 4.
    错误例子: less /var/log/messages

    Nov 3 23:30:27 digoal_host kernel: : [63500383.870591] nf_conntrack: table full, dropping packet.
    Nov 3 23:30:27 digoal_host kernel: : [63500383.962423] nf_conntrack: table full, dropping packet.
    Nov 3 23:30:27 digoal_host kernel: : [63500384.060399] nf_conntrack: table full, dropping packet.

    会话表满的解决办法
    nf_conntrack table full的问题,会导致丢包,影响网络质量,严重时甚至导致网络不可用。

    解决方法举例:
    1、排查是否DDoS攻击,如果是,从预防攻击层面解决问题。

    2、清空会话表。

    重启iptables,会自动清空nf_conntrack table。注意,重启前先保存当前iptables配置(iptables-save > /etc/sysconfig/iptables ; service iptables restart)。

    3、应用程序正常关闭会话

    设计应用时,正常关闭会话很重要。

    4、加大表的上限(需要考虑内存的消耗)

    例举故障原因
    内核参数 net.nf_conntrack_max 系统默认值为”65536”,当nf_conntrack模块被装置且服务器上连接超过这个设定的值时,系统会主动丢掉新连接包,直到连接小于此设置值才会恢复。同时内核参数“net.netfilter.nf_conntrack_tcp_timeout_established”系统默认值为”432000”,代表nf_conntrack的TCP连接记录时间默认是5天,致使nf_conntrack的值减不下来,丢包持续时间长。

    nf_conntrack模块在首次装载或重新装载时,内核参数net.nf_conntrack_max会重新设置为默认值“65536”,并且不会调用sysctl设置为我们的预设值。

    触发nf_conntrack模块首次装载比较隐蔽,任何调用IPtable NAT功能的操作都会触发。当系统没有挂载nf_conntrack模块时,iptables 相关命令(iptables -L -t nat)就成触发nf_conntrack模块装置,致使net.nf_conntrack_max 重设为65536。

    触发nf_conntrack模块重新装载的操作很多,CentOS6 中“service iptables restart”,CentOS7中“systemctl restart iptables.service”都会触发设置重置,致使net.nf_conntrack_max 重设为65536。

    重要的几个配置文件
    nf_conntrack_max决定连接跟踪表的大小,当nf_conntrack模块被装置且服务器上连接超过这个设定的值时,系统会主动丢掉新连接包,直到连接小于此设置值才会恢复。
    nf_conntrack_buckets决定存储conntrack条目的哈希表大小,若是单方面修改nf_conntrack_max,而不修改nf_conntrack_buckets,只是影响查找速度,挂在不了桶上的新跟踪项目,会挂在到桶中的链表上(原理为hash表结构)。
    nf_conntrack_tcp_timeout_established系统默认值为”432000”,代表nf_conntrack的TCP连接记录时间默认是5天,致使nf_conntrack的值减不下来,丢包持续时间长。
    通过修改这两个值即可,但是nf_conntrack_buckets时个只读文件,无法进行修改。

    修改参数
    或通过sysctl命令进行修改:
    $ sysctl -w net.netfilter.nf_conntrack_max=1048576
    $ sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600
    $ sysctl -p #使生效
    或是直接永久性修改永久生效
    vi /etc/sysctl.conf
    net.netfilter.nf_conntrack_max=1048576
    net.netfilter.nf_conntrack_tcp_timeout_established=3600
    对于上述解决方案无法修改nf_conntrack_buckets的参数,因为此为只读文件,通过上述nf_conntrack-sysctl.txt文件可知知,可以通过模块加载的时候设置参数。此时可以采用下面方案进行修改:
    通过系统初始化脚本创建配置文件”/etc/modprobe.d/nf_conntrack.conf”, 内容为“options nf_conntrack hashsize=262144”,通过nf_conntrack模块挂接参数”hashsize”自动设置“net.nf_conntrack_max=2097152”(nf_conntrack_max=hashsize*8),保证后续新初始化服务器配置正确。

    通过自动化部署工具全网推送配置文件”/etc/modprobe.d/nf_conntrack.conf”, 内容为“options nf_conntrack hashsize=262144”,保证nf_conntrack模块在首次装载或重新装载时“net.nf_conntrack_max”内核参数设置为我们预期的“2097152”。

    更新系统初始化脚本,设置“net.netfilter.nf_conntrack_tcp_timeout_established=1800”,减少nf_conntrack的TCP连接记录时间。

    如果并不需要nf_conntrack及其相关模块可以在/etc/modprobe.d目录新建文件blacklist.conf ,文件中加入:install nf_conntrack /bin/false 这样做的副作用是无法再使用Iptables NAT相关功能。

    计算公式
    可以增大 conntrack 的条目(sessions, connection tracking entries) CONNTRACK_MAX 或者增加存储 conntrack 条目哈希表的大小 HASHSIZE
    默认情况下,CONNTRACK_MAX 和 HASHSIZE 会根据系统内存大小计算出一个比较合理的值:
    对于 CONNTRACK_MAX,其计算公式:
    CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (ARCH / 32)
    比如一个 64 位 48G 的机器可以同时处理 48*1024^3/16384/2 = 1572864 条 netfilter 连接。对于大于 1G 内存的系统,默认的 CONNTRACK_MAX 是 65535。

    对于 HASHSIZE,默认的有这样的转换关系:
    CONNTRACK_MAX = HASHSIZE * 8
    这表示每个链接列表里面平均有 8 个 conntrack 条目。其真正的计算公式如下:
    HASHSIZE = CONNTRACK_MAX / 8 = RAMSIZE (in bytes) / 131072 / (ARCH / 32)
    比如一个 64 位 48G 的机器可以存储 48*1024^3/131072/2 = 196608 的buckets(连接列表)。对于大于 1G 内存的系统,默认的 HASHSIZE 是 8192。

    展开全文
  • go-conntrack 这是go-conntrack ,它是用编写的。 它为的conntrack子系统提供了无绑定的API。 例子 func main () { nfct , err := ct . Open ( & ct. Config {}) if err != nil { fmt . Println ( "could not ...
  • Added conntrack support

    2020-12-02 09:50:07
    <div><p>This commit adds visualization and installation instructions of Netfilter Conntrack application that has been pulled recently: https://github.com/librenms/librenms-agent/pull/200</p> ...
  • conntrack-race-源码

    2021-05-02 17:48:52
    conntrack种族 讨论: : 重现 在建议的修补程序^^顶部应用 。 启用动态调试: echo -n 'file net/netfilter/nf_conntrack_core.c +p' > /sys/kernel/debug/dynamic_debug/control 。 编译并运行 : gcc server.c...
  • // Conntrack parameters and options: // -n, --src-nat ip source NAT ip // -g, --dst-nat ip destination NAT ip // -j, --any-nat ip source or destination NAT ip </code></pre> <p>This does not match...
  • 该软件包包含conntrack,conntrackd和nfct的补全。
  • conntrack-tools

    2013-06-13 11:55:40
    获取linux conntrack 的必备工具,很好用的。
  • And see strange dependency in ipt_netflow (nf_conntrack). Why it needed? As i known in heavy loaded relay server (that we have) conntrack is evil. Can we avoid this dep?</p><p>该提问来源于开源项目&#...
  • ctrmd-conntrack条目删除守护程序 ctrmd提供了一种使用iptables规则删除conntrack条目的机制。 由于不存在删除iptables中的conntrack条目的本机支持,因此使用以下方法: 数据包被发送到iptables中的专用NFLOG组 ...
  • conntrack: entry injection

    2020-12-27 10:23:45
    <div><p>Coleagues, does anyone plan to write a method to inject conntrack entries? If not, I would do that on the weekend.</p><p>该提问来源于开源项目:svinota/pyroute2</p></div>
  • <div><p>This PR allows populating per-connection packet and byte counts to ConntrackFlow object when nf_conntrack_acct is enabled.</p><p>该提问来源于开源项目:vishvananda/netlink</p></div>
  • conntrack系统介绍

    2011-10-02 17:08:17
    描述了netfile框架下的conntrack连接跟踪系统
  • increase the conntrack limit

    2020-12-29 16:01:28
    Increase the conntrack table limit <p>Fixes #3026 <p><strong>Special notes for your reviewer</strong>: <p><strong>Release note</strong>: <pre><code>release-note NONE </code></pre>该提问来源于开源项目...
  • <div><p>This adds more information to the conntrack lines ("packets" and "bytes") which breaks the line parser introduced in #2095: <pre><code> Error parsing dumped flow "tcp 6 9 ...
  • t have conntrack installed or conntrack tools enabled or something like that. I get this spammed to my log: <pre><code> <probe> ERRO: 2016/10/05 23:54:47.433553 conntrack error: EOF <probe>...
  • It issues a lot of <code>read()</code> calls to the<code>nf_conntrack</code> file on <code>procfs</code> and the collector agent "self-destructs (probably killed by <code>watchdog) while waiting ...
  • OVS Conntrack 指南

    千次阅读 2019-07-02 21:04:20
    OVS可与内核的连接跟踪系统(Connection tracking system)一同使用,借助Conntrack的功能,OpenFlow流可用于匹配TCP、UDP、ICMP等连接的状态。(连接跟踪系统支持跟踪有状态和无状态协议)。 本教程演示OVS如何使用...

    OVS可与内核的连接跟踪系统(Connection tracking system)一同使用,借助Conntrack的功能,OpenFlow流可用于匹配TCP、UDP、ICMP等连接的状态。(连接跟踪系统支持跟踪有状态和无状态协议)。

    本教程演示OVS如何使用连接跟踪系统。以匹配从连接建立到连接拆除的TCP报文段。将OVS与Linux内核模块一同作为此演示的数据路径。(在Linux内核中利用openvswitch模块执行的数据处理)。

    此演示在Open vSwitch的“master”分支进行了测试。

    定义

    conntrack:连接跟踪模块。用于有状态报文的检查。

    pipeline:报文处理管道。它是当报文遍历表时所经过的路径,报文需要与表中的某个流的匹配字段一致,并且执行此流中规定的动作。

    网络命名空间:是在单个Linux内核中,创建多个虚拟路由域的方法。每个网络命名空间都有自己的网络表实例(arp、路由),以及连接的特定接口。

    :本教程中使用的是OpenFlow流,它可以使用OpenFlow控制器或OVS命令行工具编程,如这里使用的ovs-ofctl工具。流具有匹配字段和动作字段。

    Conntrack 相关字段

    匹配字段

    OVS支持与Conntrack相关的以下匹配字段:

    1. ct_state:

    匹配报文的连接状态. 可能的值有:

    - *new*
    - *est*
    - *rel*
    - *rpl*
    - *inv*
    - *trk*
    - *snat*
    - *dnat*
    

    每个以"+“为前缀的标志,表示必须设置,或者以”-"为前缀的标志表示不能设置。还可以指定多个标志,例如ct_state=+trk+new。下面我们将看到其中一些标志的用法。详细的说明,请参阅OVS字段文档.

    1. ct_zone:区域是独立的连接跟踪上下文,可以通过CT动作设置。

    由最近的ct action(通过位于Conntrack条目上的OpenFlow 流)设置的16位ct_zone值可以用作另一个流量条目的匹配字段。

    1. ct_mark:由ct action的 exec参数中的action设置到当前报文所属的连接中的32位元数据。

    2. ct_label
      由exec参数内的操作提交到的128位标签CT动作,到当前数据包的连接属于。

    3. ct_label:
      由ct action的 exec参数中的action设置到当前报文所属的连接中的128位标签.

    4. ct_nw_src / ct_ipv6_src:
      匹配IPv4/IPv6连接跟踪原始方向元组的源地址。

    5. ct_nw_dst / ct_ipv6_dst:
      匹配IPv4/IPv6连接跟踪原始方向元组的目标地址。

    6. ct_nw_proto:
      匹配连接跟踪原始方向元组的IP协议类型。

    7. ct_tp_src:
      匹配连接跟踪原始方向的元组传输层源端口。

    8. ct_tp_dst:
      匹配连接跟踪原始方向的元组传输层目的端口。

    动作

    OVS支持与conntrack连接跟踪相关的"ct"动作。

    *ct([argument][,argument...])*
    

    ct action动作将报文送入连接跟踪器.

    支持以下的参数:

    1. commit:
      将连接提交到连接跟踪模块,该模块对此连接的存储超出报文在管道中的生命周期。

    2. force:
      除以上的commit标志外,还可以使用force标志来有效地终止现有连接并在当前方向开始新连接。

    3. table=number:
      管道处理一分为二。原始报文将继续以未跟踪数据包的形式处理当前动作action列表。报文的另一个实例将发送到连接跟踪程序,之后它将重新注入OpenFlow管道并继续在表number中处理,此时其已设置了ct_state状态和其它ct match匹配字段。

    4. zone=value 或 zone=src[start…end]:
      一个16位的上下文ID,可以将连接隔离在单独的域,允许在不同区域使用重叠的网络地址。如果未提供区域值,则默认为使用区域0。

    5. exec([action][,action…]):
      在连接跟踪上下文中执行受限制的动作集。在exec的动作列表中只接受修改ct_markct_label字段的动作。

    6. alg=<ftp/tftp>:
      指定alg(Application Layer Gateway 应用层网关)以跟踪特定连接类型。

    7. nat:
      指定所跟踪的连接的NAT翻译地址和端口。

    示例拓扑

    本教程使用以下拓扑来执行测试。

             +                                                       +
             |                                                       |
             |                       +-----+                         |
             |                       |     |                         |
             |                       |     |                         |
             |     +----------+      | OVS |     +----------+        |
             |     |   left   |      |     |     |  right   |        |
             |     | namespace|      |     |     |namespace |        |
             +-----+        A +------+     +-----+ B        +--------+
             |     |          |    A'|     | B'  |          |        |
             |     |          |      |     |     |          |        |
             |     +----------+      |     |     +----------+        |
             |                       |     |                         |
             |                       |     |                         |
             |                       |     |                         |
             |                       +-----+                         |
             |                                                       |
             |                                                       |
             +                                                       +
         192.168.0.X n/w                                          10.0.0.X n/w
    
         A  = veth_l1
         A' = veth_l0
         B  = veth_r1
         B' = veth_r0
    

    创建以上拓扑的步骤如下所述。

    创建 “left” 网络命名空间:

    $ ip netns add left
    

    创建 “right” 命名空间:

    $ ip netns add right
    

    创建第一对veth接口:

    $ ip link add veth_l0 type veth peer name veth_l1
    

    将 veth_l1 添加到 “left” 网络命名空间:

    $ ip link set veth_l1 netns left
    

    创建第二对veth接口:

    $ ip link add veth_r0 type veth peer name veth_r1
    

    将 veth_r1 添加到 “right” 网络命名空间:

    $ ip link set veth_r1 netns right
    

    创建网桥 br0:

    $ ovs-vsctl add-br br0
    

    将 veth_l0 和 veth_r0 接口添加到网桥 br0::

    $ ovs-vsctl add-port br0 veth_l0
    $ ovs-vsctl add-port br0 veth_r0
    

    在"left"网络命名空间生成的源/目的 IP地址分别为192.168.0.x / 10.0.0.x的数据包,以及在"right"网络命名空间生成的相反方向的数据包都将出现在OVS交换机中,就好像两个网络(192.168.0.X 和 10.0.0.X)中的主机在通信。

    这在基本上模拟了两个网络或子网中的主机之间通过中间的OVS进行通信的情况。

    注意
    一对veth接口即可实现两个网络命名空间之间的通信,本例仅是演示。

    生成TCP报文的工具

    可以使用scapy生成TCP报文。我们在Ubuntu 16.04上使用了scapy用于本测试中执行的步骤。(scapy的安装,不在本文讨论范围内)。

    你可以在每个名称空间上保持两个活动的scapy会话:

     $ sudo ip netns exec left sudo `which scapy`
    
     $ sudo ip netns exec right sudo `which scapy`
    

    注意: 如果你碰到以下的错误:

    ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",LOOPBACK_NAME))
    
    IOError: [Errno 99] Cannot assign requested address
    

    执行此命令:

    $ sudo ip netns exec <namespace> sudo ip link set lo up
    

    匹配TCP报文

    TCP连接建立

    在OVS中可以添加两个简单的流,这两个流将转发从"left"命名空间到"right"命名空间,以及从"right"到"left"的数据包:

     $ ovs-ofctl add-flow br0 \
              "table=0, priority=10, in_port=veth_l0, actions=veth_r0"
    
     $ ovs-ofctl add-flow br0 \
              "table=0, priority=10, in_port=veth_r0, actions=veth_l0"
    

    除了添加这两个流之外,我们还将添加与TCP报文的状态匹配的流。

    我们将发送TCP连接建立报文,即:位于"left"网络命名空间的主机192.168.0.2与位于"right"命名空间的主机10.0.0.2之间的syn, syn-ack 和 ack报文。

    首先,我们添加一个流来启动"tracking"跟踪OVS中接收到的报文。

    如何开始跟踪报文呢?

    要开始跟踪报文,首先需要匹配动作为"ct"的流。此动作发送报文到连接跟踪器。要确定报文是一个"untracked"未跟踪的报文,流匹配字段的ct_state必须设置为“-trk”,即其不是跟踪的报文。一旦报文被发送到连接跟踪器,那么我们唯一可知的就是其连接跟踪状态。(即,此报文是否代表一个新的连接或报文属于现有连接或格式不正确的报文等等。)

    我们添加下面的流:

     (flow #1)
     $ ovs-ofctl add-flow br0 \
        "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_l0, actions=ct(table=0)"
    

    从"left"命名空间发送的TCP SYN报文将与流#1匹配,因为数据包从veth_l0端口进入OVS,并且还没有被跟踪。(因为报文刚刚进入OVS。所有首次进入OVS的报文都是"untracked")。

    由于配置的"ct"动作,流将把报包发送到连接跟踪器。"ct"动作中的参数"table=0"将管道处理分为两部分。原始的报文实例将作为"untracked"报文继续处理当前动作列表。(由于在此之后没有任何动作,原始报文将被丢弃。)。

    另一个分叉的报文实例将发送到连接跟踪器,之后将重新注入到OpenFlow管道继续在指定的流表中处理,此时已设置了ct_state状态值和其它ct匹配字段。在以上的情况下,带有ct_state状态和其它ct匹配字段的报文将返回到表0。

    接下来,我们添加一个流来匹配从conntrack返回的报包:

    (flow #2)
    $ ovs-ofctl add-flow br0 \
        "table=0, priority=50, ct_state=+trk+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0"
    

    既然报文是从连接跟踪返回,ct_state状态值应设置了"trk"。

    此外,如果这是TCP连接的第一个报文,则ct_state状态也应设置了"new"标志。(正是当前的情况,因为不存在任何192.168.0.2和10.0.0.2之间的TCP连接)ct参数"commit"将把连接提交到连接跟踪模块。这一动作的意义在于连接信息将被存储在连接跟踪模块,并且将超出数据包在管道中的生存期限。

    我们使用scapy发送TCP SYN报文(位于"left"命名空间的scapy会话)(flags=0x02 is syn):

    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x02, seq=100), iface="veth_l1")
    

    此报文将匹配 flow #1 和 flow #2.

    连接跟踪模块conntrack将有此连接的项:

    $ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
    tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=SYN_SENT)
    

    注意:在这个阶段,如果重新传输TCP SYN报文,它将再次匹配流 #1(因为新报文总是未跟踪的),并且它也将匹配流 #2。它与流 #2匹配的原因是,尽管conntrack有关于此连接的信息,但它不处于"ESTABLISHED"状态,因此再次匹配"new"状态。

    接下来,对于来自相反/服务器方向的TCP SYN+ACK报文,我们需要以下的OVS流:

    (flow #3)
    $ ovs-ofctl add-flow br0 \
        "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_r0, actions=ct(table=0)"
    (flow #4)
    $ ovs-ofctl add-flow br0 \
        "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_r0, actions=veth_l0"
    

    flow #3 匹配未跟踪的由服务器(10.0.0.2)发回的报文,并且将此报文发送到conntrack. (另外, 我们可以将flow #1与flow #3合并,方法是去掉"in_port"匹配字段)

    TCP SYN+ACK报文经过conntrack处理后,其ct_state设置了"est"连接建立标志。

    注意:当conntrack看到双向流量后,将连接的ct_state设置为"est"状态,但它还没有看到客户端的第三个ACK报文,它在conntrack的此条目上配置一个短时的清除计时器。

    使用scapy发送TCP SYN+ACK报文(在"right"命名空间的scapy会话中)(标志=0x12为ACK和SYN):

    $ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0x12, seq=200, ack=101), iface="veth_r1")
    

    此报文将匹配 flow #3 和 flow #4.

    conntrack 条目:

     $ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
    
     tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=ESTABLISHED)
    

    在只接收到SYN和SYN ACK报文后,conntrack的状态成为"ESTABLISHED"。但此时,如果它没有收到第三个ACK报文(来自客户端),此连接很快会从conntrack中清除。

    接下来,对于来自客户端方向的TCP ACK报文,我们可以添加以下流匹配此报文:

    (flow #5)
    $ ovs-ofctl add-flow br0 \
        "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_l0, actions=veth_r0"
    

    使用scapy发送第三个TCP ACK报文(位于"left"命名空间的scapy会话)(flags=0x10 为 ACK):

    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=101, ack=201), iface="veth_l1")
    

    此报文将匹配 flow #1 和 flow #5.

    conntrack 条目:

    $ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
    
     tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048), \
         reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024), \
                                         protoinfo=(state=ESTABLISHED)
    

    conntrack状态保持在"ESTABLISHED"状态,但现在它已经收到来自客户端的ACK,即使没有接收此连接上的任何数据,其也将保持此状态很长时间。

    TCP 数据

    当携带一个字节载荷的TCP数据段从192.168.0.2发送到10.0.0.2时,携带该段数据的报文将匹配流 #1,和之后的流 #5。

    使用scapy发送一个字节的TCP报文段(位于"left"命名空间的scapy会话)(flags=0x10 is ack)::

    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=101, ack=201)/"X", iface="veth_l1")
    

    使用scapy发送以上报文段的ACK回复(位于"right"命名空间scapy会话)(flags=0x10 is ack)::

    $ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0X10, seq=201, ack=102), iface="veth_r1")
    

    数据报文的ACK回复应匹配 flow #3 and flow #4.

    TCP 连接拆除

    有不同的方法可以拆除TCP连接。我们通过从客户端发送"FIN"报文,服务器回复"FIN+ACK"报文,接着客户端发送最后的"ACK"报文的方式拆除连接。

    从客户端到服务器的所有报文都会匹配Flow #1和Flow #5。从服务器到客户端的所有报文都会匹配Flow #3和Flow #4。值得注意的一点是,即使TCP连接正在进行
    拆除,所有报文(实际上正在拆除连接)仍然匹配"+est"状态。一个报文,如果其conntrack条目是或者曾经是"ESTABLISHED"状态,应继续匹配OVS的ct_state的"+est"标志。

    注意:实际上,当conntrack连接状态为"TIME_WAIT"状态时(交换了所有TCP连接拆除所需的FIN和ACK报文后),一个重新传输的报文(从192.168.0.2->10.0.0.2),仍然命中流量 #1和 #5。

    使用scapy发送TCP FIN报文("left"命名空间的scapy会话)(flags=0x11 为 ACK 和 FIN):

    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x11, seq=102, ack=201), iface="veth_l1")
    

    此报文匹配 flow #1 和 flow #5.

    conntrack 条目:

    $ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
    
      tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=FIN_WAIT_1)
    

    使用scapy发送TCP FIN+ACK报文("right"命名空间scapy会话)(flags=0x11 为 ACK 和 FIN):

    $ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0X11, seq=201, ack=103), iface="veth_r1")
    

    此报文命中 flow #3 和 flow #4.

    conntrack 条目:

    $ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
    
      tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=LAST_ACK)
    

    使用scapy发送TCP ACK报文("left"命名空间scapy会话)(flags=0x10 为 ACK):

    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=103, ack=202), iface="veth_l1")
    

    此报文命中 flow #1 和 flow #5.

    conntrack 条目:

    $ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
    
      tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=TIME_WAIT)
    

    总结

    下表总结了TCP报文与流匹配字段的关系

      +-------------------------------------------------------+-------------------+
      |                     TCP Segment                       |ct_state(flow#)    |
      +=======================================================+===================+
      |                     **Connection Setup**              |                   |
      +-------------------------------------------------------+-------------------+
      |192.168.0.2 → 10.0.0.2 [SYN] Seq=0                     | -trk(#1) then     |
      |                                                       | +trk+new(#2)      |
      +-------------------------------------------------------+-------------------+
      |10.0.0.2 → 192.168.0.2 [SYN, ACK] Seq=0 Ack=1          | -trk(#3) then     |
      |                                                       | +trk+est(#4)      |
      +-------------------------------------------------------+-------------------+
      |192.168.0.2 → 10.0.0.2 [ACK] Seq=1 Ack=1               | -trk(#1) then     |
      |                                                       | +trk+est(#5)      |
      +-------------------------------------------------------+-------------------+
      |                     **Data Transfer**                 |                   |
      +-------------------------------------------------------+-------------------+
      |192.168.0.2 → 10.0.0.2 [ACK] Seq=1 Ack=1               | -trk(#1) then     |
      |                                                       | +trk+est(#5)      |
      +-------------------------------------------------------+-------------------+
      |10.0.0.2 → 192.168.0.2 [ACK] Seq=1 Ack=2               | -trk(#3) then     |
      |                                                       | +trk+est(#4)      |
      +-------------------------------------------------------+-------------------+
      |                     **Connection Teardown**           |                   |
      +-------------------------------------------------------+-------------------+
      |192.168.0.2 → 10.0.0.2 [FIN, ACK] Seq=2 Ack=1          | -trk(#1) then     |
      |                                                       | +trk+est(#5)      |
      +-------------------------------------------------------+-------------------+
      |10.0.0.2 → 192.168.0.2 [FIN, ACK] Seq=1 Ack=3          | -trk(#3) then     |
      |                                                       | +trk+est(#4)      |
      +-------------------------------------------------------+-------------------+
      |192.168.0.2 → 10.0.0.2 [ACK] Seq=3 Ack=2               | -trk(#1) then     |
      |                                                       | +trk+est(#5)      |
      +-------------------------------------------------------+-------------------+
    

    注意:tshark抓包显示的序号和确认序号都是相对的。

    流表

    
         (flow #1)
         $ ovs-ofctl add-flow br0 \
            "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_l0, actions=ct(table=0)"
    
        (flow #2)
        $ ovs-ofctl add-flow br0 \
            "table=0, priority=50, ct_state=+trk+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0"
    
        (flow #3)
        $ ovs-ofctl add-flow br0 \
            "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_r0, actions=ct(table=0)"
    
        (flow #4)
        $ ovs-ofctl add-flow br0 \
            "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_r0, actions=veth_l0"
    
        (flow #5)
        $ ovs-ofctl add-flow br0 \
            "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_l0, actions=veth_r0"
    
    展开全文
  • <div><p><code>nf_conntrack: table full, dropping packet</code> could be observed on busy hypervisors. While it is not exactly known what the breakdown of active sessions or root cause is, increasing ...
  • ERRO: 2016/03/07 12:21:21.338211 conntrack stderr:conntrack v1.4.3 (conntrack-tools): Operation failed: No buffer space available <probe> ERRO: 2016/03/07 12:21:21.338141 conntrack error: EOF &...
  • 增加nf_conntrack_max固然可以缓解这个问题,或者说减小conntrack表项占据内核内存的时间也可以缓解之,然而这种补救措施都是治标不治本的.注解:不要过度减小NEW以及TCP的establish的CT状态的timeout的原因 尽量...
    增加nf_conntrack_max固然可以缓解这个问题,或者说减小conntrack表项占据内核内存的时间也可以缓解之,然而这种补救措施都是治标不治本的.

    注解:不要过度减小NEW以及TCP的establish的CT状态的timeout的原因

    尽量不要减小NEW状态时间,因为对于某些恶劣的网络,一个数据包的来回确实需要很长时间,对于TCP而言,此时RTT还没有测量呢。如果NEW状态的conntrack保留时间过短,就会导致大量NEW状态的连接,而对于很多依赖ctstate的模块而言,这样就会有问题,比如iptables的filter表中使用ESTABLISH状态来放过前向包的返回包就会有问题,此时ip_conntrack很有可能由于NEW状态时间过短而将返回包作为NEW状态处理而不是ESTABLISH状态,如此一来,返回包就无法通过了。如下图所示:


    使用简单的实验可以很容易证实上面的图示,以简单的udp通信为例,编写一个udp-echo程序,服务器简单echo客户端送达的字符串:
        for(;;)     {      n = recvfrom(sd, msg, MAXLINE, 0, pcliaddr, &len);           sleep(5);           sendto(sd, msg, n, 0, pcliaddr, len);     }

    然后在客户端上执行echo $sec /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout
    其中sec要比服务器端的sleep参数更小即可。
    如此udp客户端将收不到服务器eho回来的字符串,因为客户端只是放行状态为establish的入流量,如果ip_conntrack_udp_timeout配置过于短暂,NEW状态的conntrack过早被释放,这样将不会有establish状态的流量了。对于UDP而言,由于它是不确认无连接允许丢包的,因此影响还不是很大,TCP也有类似的问题,那就是如果你连接一个很远的且网络状况很恶劣的TCP服务器,然后你把ip_conntrack_tcp_timeout_synsent设置很小,这样就几乎完不成三次握手了,更进一步,如果你把ip_conntrack_tcp_timeout_established设置过小,那么一旦三次握手建立连接之后,客户端和服务器之间很久不发包,当establish状态到期后,conntrack被释放,此时服务器端主动发来一个包,该包的conntrack状态会是什么呢?因此给予tcp的establish状态5天的时间,是可以理解的。需要注意的是,对于tcp而言,由于无法简单的控制服务器发送syn-ack的延时,因此需要在establish状态而不是new状态做文章了(实际上,ip_conntrack的establish状态映射成了tcp的多个状态,包括syn-ack,ack,established),试试看,效果和udp的一样。
            前面关于ip_conntrack扯的太远了,我们的首要问题是conntrack full的问题。实际上,如果深入思考这个conntrack full的问题,就会发现,并不是conntrack容量太小或者表项保留时间过长引发的full。现实中的万事万物都不是无限的,对于计算机资源而言,更应该节约使用,不能让无关人士浪费这种资源,另外既然内核默认了一个表项的存活时间,那肯定是经过测试的经验值,自有它的道理。因此本质问题在于很多不需要conntrack的包也被conntrack了,这样就会挤掉很多真正需要conntrack的流量。
            那么都是哪些流量需要conntrack呢?常用的就两个,一个是任何使用ctstate或者state这些match的iptables规则,另外一个就是所有的iptables的nat表中的规则,如果我们事先知道哪些流量需要使用iptables的[ct]state来控制,并且也知道哪些流量需要做NAT,那么余下的流量就都是和conntrack无关的流量了,可以不被ip_conntrack来跟踪。
            幸运的是,Linux的Netfilter在PREROUTING以及OUTPUT这两个HOOK的conntrack之前安插了一个优先级更高的table,那就是raw,通过它就可以分离出不需要被conntrack的流量。如果你确定只有某个网卡进来的流量才需要做NAT,那么就执行下面的规则:
    iptables -t raw -A PREROUTING ! –I $网卡 -j NOTRACK iptables –t raw –A OUTPUT –j NOTRACK
    这样一来,资源就不会浪费在无关人士身上了,性能也会有所提高,因为凡是NOTRACK的流量,都不会去查询conntrack的hash表,因为在ip(nf)_conntrack_in的内部的开始有一个判断:
    if ((*pskb)->nfct)     return NF_ACCEPT;
    而NOTRACK这个target的实现也很简单:
    (*pskb)->nfct = &ip_conntrack_untracked.info[IP_CT_NEW];
    事实上将一个占位者设置给skb的nfct,这样可以保持其它代码的一致性。
         可见,必要时同时采取三种方式比较有效:1.增大conntrack_max;2.减少状态保存时间;3.分离无关流量。然而除了第三种方式,其余两种方式在操作时必须给自己十足的理由那么做才行,对于1,比必须明白内核内存被占有的方式,对于2,看看本文的前半部分。
    iptables -A FORWARD -m state --state UNTRACKED -j ACCEPT

    最后有个提问:

    对于没有keepalive的TCP连接而言,试想服务器和客户端在establish状态之后5天内都没有互相通信,5天后的一天,服务器主动发送了一个数据包给客户端,然而此时防火墙/NAT设备上的conntrack状态已经过期被删除,此时该数据包将会被认为是NEW状态的数据包,被DROP,客户端永远收不到这个数据包,进而也不会发送ACK,服务器端不断重发,不断被防火墙DROP,当重发次数达到一定次数后,服务器RESET该连接,然而客户端如何得知,只有客户端主动发包才能打破这个僵局,然而谁能保证客户端一定会主动发包?这是不是Linux的ip_conntrack的一种缺陷,设计5天时间的establish状态是不是一种极限措施,然而谁又能保证5天内两端不断通信呢?



     本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1269007

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,163
精华内容 865
关键字:

conntrack