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

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

내 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 입력 -p tcp --sport 81 -s $MYIP -m conntrack --ctstate 설립 -j 수락

나가는 포트 일치 사용자

## 사용자 계정의 나가는 포트 80
$IPTABLES -A 출력 --match owner --uid-owner useraccount -p tcp --dport 80 -m conntrack --ctstate 신규, 확립됨 --sport 1024:65535 -j accept
$IPTABLES -A 입력 -p tcp --sport 80 --dport 1024:65535 -d $MYIP -m conntrack --ctstate 설립 -j 수락

이렇게 하면 "useraccount" 계정만 포트 80을 사용할 수 있지만 TCP 트래픽에 대한 이러한 규칙에는 문제가 있습니다.

## 기본 발신 로그 + 차단 규칙
$IPTABLES -A 출력 -j log --log-prefix "BAD OUTGOING" --log-ip-options --log-tcp-options --log-uid
$IPTABLES -A 출력 -j 삭제

질문

위 작업이 작동하고 사용자 "useraccount"가 파일을 완벽하게 가져올 수 있습니다. 시스템의 다른 사용자는 포트 80으로 나가는 연결을 설정할 수 없습니다.

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

그러나 위의 wget은 내 시스템 로그에 x7 삭제된 항목을 남겼습니다.

Oct 18 02:00:35 xxxx 커널: 나가는 오류 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)에서 오는 것 같은데, 이해할 수 없습니다. 사용자 계정을 루트로 바꾸더라도.

conntrack이 3-way handshake의 3단계 이후에 연결 추적을 시작하기 때문에 ACK 패킷이 새 패킷으로 분류된다고 생각하는데 왜 삭제됩니까?

이러한 방울을 무시해도 안전합니까?

편집하다

그래서 나는 종종 나에게 잘 맞는 다음과 같은 규칙을 봅니다.

$IPTABLES -A 출력 -s $MYIP -p tcp -m tcp --dport 80 -m 상태 --신규, 확립됨 -j 수락
$IPTABLES -A 입력 -p tcp -m tcp --sport 80 -d $MYIP -m 상태 --상태 설정됨 -j 수락

상태 일치가 더 이상 사용되지 않기 때문에 "-m state --state"를 "-m conntrack --ctstate"로 대체했습니다.

보편적인 상태 추적 규칙을 갖는 것이 모범 사례입니까? 위의 규칙이 올바른 것으로 간주되지 않습니까?

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

$IPTABLES -A 입력 -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

답변1

간단히 말해서, 소켓이 누구에게도 속하지 않을 때 ACK가 전송됩니다. x사용자의 소켓에 속하는 패킷을 허용하는 대신 사용자의 소켓에 의해 시작된 연결에 속하는 패킷을 허용합니다 x.

이야기가 비교적 길어요.

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

존재하다

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

wgetcachefly.cachefly.netTCP 연결이 설정되면 " ()의 내용을 보내주십시오. 그런데 완료되면 연결()을 닫지 마십시오."라는 내용의 요청이 HTTP 프로토콜로 전송됩니다. 이렇게 하는 것은 서버가 동일한 IP 주소에서 URL 리디렉션으로 응답하면 연결을 재사용할 수 있기 때문입니다./10mb.testGET /10mb.test HTTP/1.1Connection: Keep-alive

이제 서버는 "요청한 데이터가 여기에 있습니다. 10MB 크기입니다( Content-Length: 10485760). 예, 알겠습니다. 연결을 계속 유지하겠습니다"라고 응답할 수 있습니다. 또는 데이터의 크기를 모르는 경우 "여기 데이터가 있습니다. 죄송합니다. 연결을 계속 열어 둘 수는 없지만 연결 끝을 닫아 데이터 다운로드를 중지할 수 있는 시기를 알려 드리겠습니다."

위의 URL에서는 첫 번째 상황에 있습니다.

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

기본적으로 wget10MB가 수신될 때까지 데이터를 읽고 종료하면 됩니다. 하지만 그때까지는 해야 할 일이 더 남아 있습니다. 서버는 어떻습니까? 연결을 열어두라는 지시를 받았습니다.

종료하기 전에 소켓의 파일 설명자를 wget닫습니다( 시스템 호출). close이 시점에서 close시스템은 서버가 보낸 데이터에 대한 승인을 완료하고 FIN"더 이상 데이터를 보내지 않겠습니다."라는 메시지를 보냅니다. 그런 다음 close돌아가서 wget종료하십시오. 더 이상 TCP 연결과 연관된 소켓이 없습니다(적어도 더 이상 어떤 사용자도 소유하지 않습니다). 그러나 아직 끝나지 않았습니다. 이 메시지를 받은 후 FINHTTP 서버는파일 끝클라이언트에서 다음 요청을 읽을 때. HTTP에서 이는 "더 이상 요청이 없습니다. 완료되었습니다"를 의미합니다. 그래서 "나도 아무것도 보내지 않고 연결이 끊어지고 있습니다"라는 FIN도 보냅니다.

FIN을 받은 후 클라이언트는 "ACK"를 보냅니다. 그러나 그 당시에는 wget이미 사라진 지 오래였으므로 ACK는 어떤 사용자로부터도 전송되지 않았습니다. 그래서 방화벽으로 막혀있습니다. 서버는 ACK를 수신하지 않기 때문에 포기하고 더 많은 ACK가 삭제될 때까지 FIN을 계속해서 보냅니다. 이는 또한 이러한 ACK를 삭제하면 상당 기간 동안 서버 리소스를 불필요하게 사용하게 된다는 의미입니다(소켓이 LAST-ACK 상태로 유지되어야 함).

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

이미 언급했듯이 연결 추적기를 사용하는 경우 모든 패킷이 ESTABLISHED 및 RELATED 상태로 통과되도록 하고 패킷에 대해서만 걱정하면 됩니다 NEW.

NEWuser 의 패킷은 허용 x하지만 user 의 패킷은 허용하지 않는 경우 y사용자가 설정한 연결의 다른 패킷은 x통과하고 사용자가 연결을 설정할 수 없으므로 ( 연결을 설정하는 패킷을 y차단했기 때문에 ) 모든 사용자 연결 패킷은 통과 하지 않습니다. .NEWy

답변2

이렇게 하면 "useraccount" 계정만 포트 80을 사용할 수 있습니다.

- 글쎄요, 적어도 당신이 보여준 규칙은 실제로 그런 의미는 아닙니다.

한 가지 더 제안합니다. 설정된 스트림에 대해 사용자 확인을 수행하지 말고 새 확인만 수행하세요. 또한 들어오는 ESTABLISHED를 확인할 때 소스 포트를 확인하는 요점이 표시되지 않습니다. 차이점이 무엇인지, conntrack의 PoV에서 이미 ESTABLISHED 상태에 있습니다. 방화벽은 최대한 단순하면서도 효율적이어야 합니다.오캄의 면도날방법이 가장 적절합니다.

관련 정보