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

내 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


답변

간단히 이야기하자면 소켓이 누구에게도 속하지 않았을 때 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연결을 위한 패킷이 없습니다 .


답변

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

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

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