Iptables : 나가는 트래픽을 conntrack 및 소유자와 일치시킵니다. 이상한 방울과 함께 작동


11

내 iptables 스크립트에서 가능한 한 세밀하게 규칙을 작성하는 실험을 해왔습니다. 나는 어느 사용자가 어떤 서비스를 사용할 수 있는지, 부분적으로 보안을 위해 그리고 부분적으로는 학습 연습으로 제한합니다.

3.6.2 커널을 실행하는 데비안 6.0.6에서 iptables v1.4.16.2 사용.

그러나 아직 이해하지 못하는 문제가 발생했습니다 ...

모든 사용자를위한 발신 포트

이것은 완벽하게 작동합니다. 일반적인 상태 추적 규칙이 없습니다.

## 발신 포트 81
$ IPTABLES -A OUTPUT -p tcp --dport 81 -m conntrack --ctstate NEW, 설립 됨 -j 수락
$ IPTABLES -A 입력 -p tcp --sport 81 -s $ MYIP -m conntrack --ctstate 설정 -j 수락

사용자가 일치하는 발신 포트

## 사용자 계정의 발신 포트 80
$ IPTABLES -A OUTPUT-소유자 일치 --uid- 소유자 사용자 계정 -p tcp --dport 80 -m conntrack --ctstate NEW, ESTABLISHED --sport 1024 : 65535 -j ACCEPT
$ IPTABLES -A 입력 -p tcp --sport 80 --dport 1024 : 65535 -d $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT

이렇게하면 "useraccount"계정에 대해서만 포트 80을 사용할 수 있지만 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이 내 syslog에서 항목을 삭제 한 상태로 둡니다.

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 서열 = 164520678 ACK = 3997126942 창 = 979 RES = 0x00 ACK URGP = 0  

UDP 트래픽과 유사한 규칙에 대해서는 이러한 하락을 얻지 못합니다. DNS 요청을 할 수있는 사용자를 제한하는 규칙이 이미 있습니다.

나가는 발신 ACK 패킷은 루트 계정 (URGP = 0)에서 오는 것으로 이해하지 못합니다. 사용자 계정을 루트로 바꾼 경우에도 마찬가지입니다.

conntrack이 3 방향 핸드 셰이크의 3 단계 후에 연결 추적을 시작하기 때문에 ACK 패킷이 새 패킷으로 분류된다고 생각하지만 그 이유는 무엇입니까?

이 방울들을 안전하게 무시할 수 있습니까?

편집하다

그래서 나는 종종 다음과 같은 규칙을 보았습니다.

$ IPTABLES -A OUTPUT -s $ MYIP -p tcp -m tcp --dport 80 -m state --state NEW, ESTABLISHED -j ACCEPT
$ IPTABLES -A 입력 -p tcp -m tcp --sport 80 -d $ MYIP -m state --state 설정 -j 수락

상태 일치가 더 이상 사용되지 않으므로 "-m state --state"를 "-m conntrack --ctstate"로 바꿨습니다.

일반적인 상태 추적 규칙을 사용하는 것이 가장 좋은 방법입니까? 위의 규칙이 올바른 것으로 간주되지 않습니까?

발신 사용자 연결을 엄격하게 제어하려면 이와 같은 것이 더 좋을까요?

$ IPTABLES-입력 -m conntrack --ctstate 설정 -j 수락
$ IPTABLES-출력 -m conntrack --ctstate 설립 -j 수락

$ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m 소유자 --uid-owner useraccount -j ACCEPT

$ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m 소유자 --uid-owner otheraccount -j ACCEPT

이 호스트가 LAN에서 트래픽을 라우팅하는 경우 FORWARD 체인 및 nat 테이블을 포함한 모든 규칙을 게시 할 수 있습니까?
8:20에

이 호스트는 라우팅을 수행하지 않으며 트래픽은 이러한 규칙을 사용하여 시스템에서 발생합니다. 특정 발신 트래픽에 대한 관련 규칙 만 게시했습니다.
arcX

답변:


16

간단히 이야기하자면 소켓이 누구에게도 속하지 않았을 때 ACK가 전송되었습니다. 사용자의 소켓에 관련된 패킷을 허용하는 대신 사용자 x의 소켓에 의해 시작된 연결에 관련된 패킷을 허용하십시오 x.

더 긴 이야기.

이 문제를 이해하려면 wget일반적으로 HTTP 요청이 작동 하는 방식을 이해하면 도움이됩니다 .

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

wget에 TCP 연결을 설정 cachefly.cachefly.net하고, 설립 후 것은 말한다 HTTP 프로토콜의 요청을 보냅니다 "나에게의 내용을 보내주세요 /10mb.test( GET /10mb.test HTTP/1.1당신이 (완료 후 가까운 연결을하지 기쁘게 수) 및 그런데 Connection: Keep-alive.) 그 이유를 서버가 동일한 IP 주소의 URL에 대한 리디렉션으로 응답하는 경우 연결을 재사용 할 수 있기 때문입니다.

이제 서버는 "요청한 데이터가 여기에 오면 10MB ( Content-Length: 10485760)이며 주의하십시오 . 연결을 열어 두겠습니다 "라고 응답 할 수 있습니다 . 또는 데이터의 크기를 모르는 경우 "데이터는 다음과 같습니다. 연결을 열어 둘 수는 없지만 연결 종료를 닫아서 데이터 다운로드를 중지 할 수있는 시점을 알려 드리겠습니다."

위의 URL에서 우리는 첫 번째 경우입니다.

따라서 wget응답의 헤더를 얻 자마자 10MB의 데이터를 다운로드하면 작업이 완료되었음을 알 수 있습니다.

기본적으로 wget10MB가 수신되고 종료 될 때까지 데이터를 읽습니다. 그러나 그 시점에서해야 할 일이 더 있습니다. 서버는 어떻습니까? 연결을 열린 상태로 두라는 메시지가 나타납니다.

종료하기 전에 소켓의 파일 디스크립터를 wget닫습니다 ( close시스템 호출). 에 close시스템은 서버가 전송 한 데이터의 확인을 마치고 FIN"더 이상 데이터를 보내지 않을 것" 이라는 메시지 를 보냅니다 . 그 시점에서 close돌아오고 wget나갑니다. 더 이상 TCP 연결과 관련된 소켓이 없습니다 (적어도 사용자가 소유하지 않은 소켓). 그러나 아직 끝나지 않았습니다. 이를 수신 FIN하면 HTTP 서버는 클라이언트에서 다음 요청을 읽을 때 파일 끝을 보게 됩니다. HTTP에서는 "더 이상 요청하지 않고 끝을 닫을 것"을 의미합니다. 따라서 FIN도 전송합니다. "어느 것도 보내지 않을 것입니다. 연결이 끊어집니다."

해당 FIN을 수신하면 클라이언트는 "ACK"를 보냅니다. 그러나 그 시점에서 wgetACK는 어떤 사용자의 것이 아니기 때문에 오랫동안 사라졌습니다. 이것이 방화벽에 의해 차단되는 이유입니다. 서버는 ACK를받지 않기 때문에 포기할 때까지 FIN을 계속해서 보내면 더 많은 ACK가 삭제됩니다. 또한 이러한 ACK를 삭제하면 서버 리소스 (LAST-ACK 상태에서 소켓을 유지해야 함)를 꽤 오랫동안 사용하고 있음을 의미합니다.

클라이언트가 "Keep-alive"를 요청하지 않았거나 서버가 "Keep-alive"로 응답하지 않으면 동작이 달라졌을 것입니다.

이미 언급했듯이 연결 추적기를 사용하는 경우 ESTABLISHED 및 RELATED 상태의 모든 패킷을 통과시키고 NEW패킷 만 걱정하면 됩니다.

NEWuser의 패킷은 허용 x하지만 user의 패킷은 허용 하지 않으면 y사용자 x가 설정 한 연결에 대한 다른 패킷 이 통과 하고 사용자 가 연결을 설정할 수 없기 때문에 y( 연결을 설정 하는 NEW패킷을 차단하기 때문에 ), 사용자 y연결을 위한 패킷이 없습니다 .


3

이것은 "useraccount"계정에 대해서만 포트 80을 허용합니다.

적어도, 당신이 보여준 규칙은 실제로 이것을 암시하지 않습니다.

조언을위한 여지가 있습니다. 사용자가 ESTABLISHED 스트림을 확인하지 말고 NEW를 확인하십시오. 또한 수신 ESTABLISHED를 확인할 때 소스 포트를 확인할 때 포인트가 보이지 않습니다. 포트의 차이점은 무엇입니까, 이미 conntrack의 PoV에서 ESTABLISHED 상태에 있습니다. 방화벽은 가능한 한 간단하지만 효율적이어야하므로 Occam의 면도기 접근 방식이 가장 적합합니다.


1
충고 감사합니다. 보통 나는 단순함을 위해 있지만이 특정 운동의 요점이 아닙니다.
arcX

1
@arcX,이 연습은 너무 복잡하고 일관성이 없어서 실패 할 수 있습니다.-IOW, netfilter 내부 (버그, 멍청이) 때문이 아니라 사용 방식에 따라 발생할 수 있습니다. 먼저 규칙 집합을 단순화 해보십시오.
poige
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.