다음은 /var/log/messages 의 내용이다. Netfilter의 conntrack 하나당 228 byte가 필요하고 최대 32760개가 가능하다는 것이다. (약 10M)
Oct 7 15:15:22 host kernel: ip_conntrack version 2.4 (4095 buckets, 32760 max) – 228 bytes per conntrack
만약 32760이 넘으면 어떻게 될까? 다음과 같이 패킷이 drop이 된다.
Oct 7 15:16:42 host kernel: ip_conntrack: table full, dropping packet.
이런 문제는 웹 서버와 같이 동시에 수 많은 connection을 처리해야 하는 경우에 발생할 수 있고 ab와 같은 stress 발생기를 사용하는 경우에도 발생할 수 있다. 이 문제에 대한 해결책은?
- netfilter를 사용하지 않는다.
- conntrack를 최대 개수를 늘린다.
- iptables raw table를 이용해서 특정 패킷은 conntrack을 하지 않는다.
- TCP 연결과 같이 각 상태별 TTL 값을 조절해서 볼 일이 끝난 연결은 빨리빨리 conntrack에서 제거한다.
각 경우에 대해서 좀 더 자세히 알아보자.
1. netfilter를 사용하지 않는다.
보안을 신경쓰지 않아도 된다면 그래도 좋다.
#service iptables stop
2. conntrack의 최대 개수를 늘린다.
아래와 같이 하면 가능하다.
echo “100000″ > /proc/sys/net/ipv4/ip_conntrack_max
3. NOTRACK
다음은 웹 서버(80)로 오가는 패킷은 conntrack 하지 않도록 하는 규칙이다. 들어오고 나가는 패킷 모두에 대해서 규칙을 넣어주어야 한다는 사실에 주의하시길.
# input packet to server iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK # output packet from server iptables -t raw -A OUTPUT -p tcp --sport 80 -j NOTRACK
“cat /proc/net/ip_conntrack”이나 iptstate를 실행해도 이제 더 이상 80번 포트로 오가는 패킷을 기록되지 않게 된다. 당연히 NAT는 할 수 없고 “-m state –state NEW” 와 같은 stateful inspection 규칙은 사용할 수 없게 된다. raw table은 conntrack이나 filter 앞에 위치하며 packet의 내부 정보에 UNTRACKED를 표시해 둔다. 이 정보는 -m state –state UNTRACKED 의 규칙을 사용해서 filter에서 이용할 수 있다. NOTRACK을 했다고 해서 그 이후의 filter 규칙을 무시하는 것은 아니다. 단지 stateful inspection을 사용할 수 없을 뿐이다.
이렇게 NOTRACK을 한 패킷을 filter에서 통과시키기 위해서는 다음과 같이 명시적으로 해 줄 수도 있다. 물론 -p tcp –dport 와 같은 IP 헤더 정보를 이용한 filtering도 가능하다.
# iptables -I INPUT -m state –state UNTRACKED -j ACCEPT
# iptables -I OUTPUT -m state –state UNTRACKED -j ACCEPT
4. TIMEOUT 값 변경
Netfilter와 관련해서 변경가능한 값은 아래와 같다. Timeout과 관련한 값을 변경해서 conntrack에 자리 잡고 있는 시간을 조절할 수 있다. 특히 timout_established 의 경우에는 5일이나 된다. 물론 TCP 연결이 종료된 경우에는 그에 부응하여 TTL 값이 줄기는 하지만 만약에 연결이 된 상태에서 클라이언트가 죽는 경우와 같은 경우에는 계속 상태를 잡고 있을 가능성이 있다.
Conntrack related status : /proc/sys/net/ipv4/ip_conntrack_max:32760 /proc/sys/net/ipv4/netfilter/ip_conntrack_buckets:4095 /proc/sys/net/ipv4/netfilter/ip_conntrack_checksum:1 /proc/sys/net/ipv4/netfilter/ip_conntrack_count:3 /proc/sys/net/ipv4/netfilter/ip_conntrack_generic_timeout:600 /proc/sys/net/ipv4/netfilter/ip_conntrack_icmp_timeout:30 /proc/sys/net/ipv4/netfilter/ip_conntrack_log_invalid:0 /proc/sys/net/ipv4/netfilter/ip_conntrack_max:32760 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal:0 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_loose:1 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_max_retrans:3 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_close:10 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_close_wait:60 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established:432000 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_fin_wait:120 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_last_ack:30 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_max_retrans:300 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_syn_recv:60 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_syn_sent:120 /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_time_wait:120 /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout:30 /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream:180
현재 conntrack 개수 빨리 알기
ip_conntrack_count 값을 읽으면 빨리 알 수 있다. 전체 리스트를 읽는 것은 시간이 오래 걸릴 뿐만이 아니라 전체 시스템 반응에도 심각한 영향을 줄 수 있다.
[root /proc/sys/net/ipv4/netfilter]# cat ip_conntrack_count 4887
[root /proc/sys/net/ipv4/netfilter]# wc -l /proc/net/ip_conntrack 4887 /proc/net/ip_conntrack
CONNTRACK_MAX는 커널 메모리 상에서 netfilter가 동시에 처리하는 세션의 수를 이야기 하는 것이며 HASHSIZE는 CONTRACK 엔트리의 리스트를 저장할 해쉬 테이블의 사이즈를 지칭하는 것이었다.
i386 아키텍쳐에서는 CONNTRACK_MAX = RAMSIZE(단위: byte) / 16384 일때 가장 이상적인 사이즈이며, HASHSIZE는 CONNTRACK_MAX = HASHSIZE * 8이 성립될때 가장 이상적인 사이즈가 된다.
더 정확하게는
HASHSIZE = CONNTRAK_MAX / 8 = RAMSIZE(단위: byte) / 131072 / (x / 32)
이다. 여기서 x의 값은 32비트 머신일 경우 32, 64비트 머신일 경우 64가 된다.
리눅스 머신에서는 1GB이상의 메모리일 경우 디폴트로 CONNTRACK_MAX가 65536이 세팅이 되고, HASHSIZE는 8192가 세팅이 된다.
아래의 명령으로 현재 세팅된 CONTRACK_MAX의 값을 알 수 있다.
# cat /proc/sys/net/ipv4/ip_conntrack_max
Linux kernel version 2.4.23 (Linux 2.6 포함) 이후의 버전:
# cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
(/proc/sys/net/ipv4/ip_conntrack_max는 더이상 사용하지 않음)
값을 변경하는 법은 위의 설정된 파일들의 숫자를 변경하면 되는데 vi나 에디터를 사용하여 변경을 시도하면 이미 읽고 있는 파일이라 저장이 되지 않을 것이다.
아래와 같이 타이핑하면 CONTRACK_MAX의 값을 변경 할 수 있다.
# echo $CONNTRACK_MAX > /proc/sys/net/ipv4/ip_conntrack_max
Linux kernel version 2.4.23 (Linux 2.6 포함) 이후의 버전:
# echo $CONNTRACK_MAX > /proc/sys/net/ipv4/netfilter/ip_conntrack_max
커널 버전 2.4.21 이전에서는 HASHSIZE의 값이 소수이고 홀수여야만 하며 최적화된 값이 이미 세팅되어 있는 상태이므로 크기의 변경을 추천하지 않는다. 하지만 그 이후의 버전에서는 해쉬 알고리즘의 변경으로 이러한 제약조건이 없어졌다. 그러나 HASHSIZE가 2의 배수일 경우 최대의 효율을 나타낸다고 되어있다.
만일 netfilter contrack가 커널에 static하게 컴파일 되어 있을 경우는 컴파일 시에 값을 변경하거나 부트 옵션에
를 넣어주면 된다.
모듈로 컴파일 되어 있을 경우는 모듈을 인서트할때 옵션을 주면 된다.
커널 버전 2.6.14부터는 런타임에 해쉬사이즈를 변경하는 것이 가능해졌다.
커널 버전 2.6.20에서는
# echo $HASHSIZE > /sys/module/nf_conntrack/parameters/hashsize
출처 : http://o5o5o.dyndns.org/
댓글