
리눅스 데비안 북웜을 사용합니다.
문제
특정 국가에서 내 서버로 들어오는 모든 연결을 차단하고 싶습니다.
편집하다
누군가 의견에서 지적했듯이, 차단하는 IP 주소 목록이 관리할 수 없는 크기(예: 수천 개의 IP 주소)로 커지면 서버가 중단될 수 있으므로 iptables를 사용하여 이 작업을 수행해서는 안 됩니다. 대신 (전체 범위를 차단하려면)을 사용해야 합니다 ipset
. 문제는 정기적으로 다운로드해야 하는 목록에 따라 다르다는 것입니다. 나는 한 번 설정한 것을 원합니다(바람직하게는).
그렇다면 특정 국가의 연결을 어떻게 차단할 수 있나요?중국과 러시아에서 발생하는 트래픽(때로는 무차별 대입 공격)이 감당할 수 없을 정도로 늘어나고 있습니다. 그들은 정기적으로 내 서버를 무릎 꿇게 만듭니다. 이들은 robots.txt 파일을 준수하지 않고 매우 공격적으로 사이트를 크롤링합니다(수백, 때로는 수천 개의 동시 연결 사용). 정말 그만둬야 해요. 내 추측으로는 내 서버가 처리하는 모든 트래픽의 90% 이상이 악성/기형인 것으로 추정됩니다.
편집 2
온라인 튜토리얼을 찾았습니다(이 같은) 이를 수행하는 방법이 있지만 이 튜토리얼은 꽤 오래된 것 같습니다. 또한 일부 모듈을 다운로드하고 컴파일/설치해야 합니다. 이것이 향후에 문제가 발생하거나(다른 패키지 또는 배포판을 업데이트/업그레이드할 때) 향후 보안 위험이 될 수 있다는 점이 걱정됩니다. 나는 정기적으로 apt-get update / apt-get 업그레이드 / apt-get dist-upgrade를 실행하여 서버를 최신 상태로 유지합니다.
원본 메시지
간단히 말해서 매초 설정된 연결의 IP 주소 목록을 얻은 다음 geoiplookup을 사용하여 IP 주소의 국가를 얻는 스크립트를 온라인에서 찾았습니다. 국가가 차단하려는 국가 목록에 있으면 iptables를 사용하여 방화벽 필터에 IP 주소를 추가합니다. 나는 스크립트를 약간 변경했습니다(더 읽기 쉽게 만들고 이 스크립트가 IP 주소를 차단할 때마다 나에게 이메일을 보내는 데 관심이 없었기 때문에). 그런 다음 이 스크립트는 crontab을 통해 1분마다 실행됩니다.
#!/bin/bash
# Script found on lautenbacher.io"
end=$((SECONDS+55))
while [ $SECONDS -lt $end ]; do
echo $SECONDS
netstat -ant | egrep ':.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c > testcc.txt
sed 's/^[ t]*//' -i testcc.txt
sed '/^$/d' -i testcc.txt
while read c d; do
if [[ $c > "0" ]]; then
bGF1dGVuYmFjaGVyLmlv=$(geoiplookup $d | awk -v ip="$d" '{FS=" "} {if($4 == "RU," || $4 == "CN," || $4 == "BLR,") {print 1}}')
if [[ $bGF1dGVuYmFjaGVyLmlv = "1" ]]; then
echo "running geolookup"
echo checking ip $d
geoiplookup $d
isCloudflare=0
# The original script made an exception for CLOUDFLARE. I don't want that exception
# bGF1dGVuYmFjaGVyLmlX=$(whois $d)
# if [[ "$bGF1dGVuYmFjaGVyLmlX" == *"CLOUDFLARE "* ]]; then
# isCloudflare=1
# echo Cloudflare detected
# fi
if [[ "$isCloudflare" != 1 ]]; then
echo try to add ip $d to blocklist
sudo iptables -I INPUT -s $d -j DROP
### I would like to sever the connection here ###
fi
fi
fi
done < testcc.txt
sleep 1
:
done
그런데 스크립트 작성자가 왜 그렇게 이상한 변수 이름("bGF1dGVuYmFjaGVyLmlv")을 사용하는지 모르겠습니다.
어쨌든 문제는 금지된 국가의 IP 주소와의 연결을 발견할 때마다 실행된다는 것입니다.
sudo iptables -I INPUT -s $d -j DROP
IP 주소에. 모두 괜찮지만 이러한 연결의 대부분은 다소 지속적입니다. 즉, 잠시 후에 동일한 IP 주소가 발견되어 iptables를 사용하여 다시 추가됩니다. 무슨 일이 일어나는지 잘 모르겠지만(중복 규칙이 생성됩니까?) ipaddress가 iptables와 함께 추가된 후 즉시 연결을 끊고 싶습니다.
간단히 말해서, IP 주소가 있는 연결을 어떻게 끊을 수 있습니까?
답변1
몇 년 동안 Linux 커널에는 상태에 관계없이 기존 IP 소켓을 강제로 종료하는 API가 있었습니다. 그것은 다음과 같이 할 수 있습니다ss
명령 및 해당 필터 구문:
-K
,--kill
소켓을 강제로 닫으려고 시도합니다. 이 옵션은 성공적으로 닫힌 소켓을 표시하고 커널이 닫기를 지원하지 않는 소켓을 자동으로 건너뜁니다. IPv4 및 IPv6 소켓만 지원합니다.
다음을 대체할 수 있습니다.
### I would like to sever the connection here ###
와 함께:
ss --kill -n dst = "$d"
그만큼필터( dst = ...
)가 필요합니다. 명령이 표시되는 모든 소켓을 종료하기 때문입니다. 필터가 없으면 요청한 것 이상입니다. 로컬 프로세스는 소켓에서 ECONNABORTED
. 이를 방지하기 위해 OUTPUT 규칙도 (일시적으로) 추가되지 않는 한 원격 노드는 TCP RST로 알림을 받을 수 있습니다.
이 Q/A(내가 답변한 곳)도 참조하세요.Ubuntu에서 모든 TCP 연결(ESTABLISHED, RELATED)을 삭제합니다.여기서 OP는 다음을 사용하여 공격으로부터 보호하려고 시도합니다.IP세트(또한 오래된 연결 및 상태 저장 방화벽에 문제가 있습니다).