Bash 스크립트 실행 속도 향상

Bash 스크립트 실행 속도 향상

큰 iptables 규칙 파일을 로드하는 bash 스크립트가 있습니다. 이러한 모든 iptable 규칙은 모든 미국 IP 주소를 차단하도록 설계되었습니다. 파일 크기는 약 9MB입니다. 실행하려고 하면 실행하는데 40분정도 소요됩니다.

이 스크립트의 실행 속도를 높이는 방법이 있습니까?

# head -n 4 iptables_block_usa.sh 

iptables -A INPUT -s 216.187.112.96/27 -j DROP
iptables -A INPUT -s 216.187.112.128/27 -j DROP
iptables -A INPUT -s 216.187.112.160/31 -j DROP
iptables -A INPUT -s 216.187.112.163/32 -j DROP

......

답변1

iptables는 개념상 한계가 있습니다. 언제iptables규칙을 어기면 실제로 일어나는 일은 다음과 같습니다.

  • iptables커널에 물어보세요모두규칙 세트
  • iptables(사용자 공간에서) 규칙 세트를 변경합니다. 일반적으로 다음을 추가합니다.하나입구
  • iptables커널로 돌아가기모두규칙 세트

따라서 100,000개의 규칙으로 구성된 규칙 집합에 규칙을 추가하면 많은 CPU가 낭비되므로 이런 일이 발생하지 않도록 해야 합니다.

또한 규칙은 선형적으로 작성되므로 각 패킷(이를 돕기 위해 상태 저장 규칙을 사용하는 경우 새 상태의 패킷일 수 있음)은 이 목록에 없습니다.모두규칙을 반복하여 일치하지 않는 규칙을 찾아 수락합니다. 따라서 패킷 조회는 목록의 크기에 비례하는데 이는 좋지 않습니다.

하지 말아야 할 일:

  • 여러 개를 병렬로 실행하려고 하지 마십시오 iptables. 커널 잠금이 없으면 결국 규칙을 잃게 됩니다. (사용자 공간) 잠금을 사용 iptables --wait하지만 더 이상 병렬이 아닙니다.

문제를 해결하려면 다음 중 하나를 수행하세요.

  • 사용iptables-restore전체 규칙 세트를 한 번에 로드합니다.

    bash 스크립트를 한 번 실행하고(그리고 기다려) 다음을 사용하여 최종 iptables-save결과를 덤프합니다.iptables-restoresed스크립트가 준비된 iptables-restore형식 파일을 가질 때까지 기다리십시오. 기본 필터 테이블인 경우 다음과 유사한 형식을 가져야 합니다.

    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    -A INPUT -s 216.187.112.96/27 -j DROP
    -A INPUT -s 216.187.112.128/27 -j DROP
    -A INPUT -s 216.187.112.160/31 -j DROP
    -A INPUT -s 216.187.112.163/32 -j DROP
    [...]
    -A INPUT -s 192.0.2.0/24 -j DROP
    COMMIT
    
  • 그렇지 않으면 직접 사용하지 마십시오.iptables주소 목록을 로드하려면 해당 컴패니언을 사용하세요.IP 세트iptables처럼 먼저 목록을 요청하는 대신 해시 테이블을 사용하고 커널에 추가할 항목만 푸시하여 이를 처리하도록 최적화되어 있습니다.

    네가 원한다면

    • 여러 IP 주소 또는 포트 번호를 저장하고 한 번에 iptables 컬렉션과 일치시킵니다.
    • IP 주소 또는 포트에 대한 iptables 규칙을 동적으로 업데이트합니다.성능 저하 없음;
    • 단일 iptables 규칙을 사용하여 복잡한 IP 주소 및 포트 기반 규칙 세트를 표현하고 IP 세트 속도의 이점을 누리세요.

    그렇다면 ipset이 귀하에게 적합한 도구일 수 있습니다.

    최대 요소 수를 정의해야 합니다(기본값은 "만" 65536임). 해시 크기는 ipset에 의해 동적으로 크기가 조정되므로 필요하지 않습니다(또는 hashsize 65536적어도 추가하는 것을 고려). 간단한 경우(소스 IP 네트워크만 해당) 다음을 수행할 수 있습니다.

    ipset create usa_ips hash:net maxelem 300000 hashsize 65536
    

    이제 루프를 사용하여 목록을 반복합니다 ipset. 목록은 usa_ips.txt다음과 같은 파일일 수 있습니다.

    216.187.112.96/27
    216.187.112.128/27
    216.187.112.160/31
    216.187.112.163/32
    [...]
    

    이러한 루프는 아래와 같이 10분 정도 걸릴 수 있습니다.

    while read net; do
        ipset add usa_ips $net
    done < usa_ips.txt
    

    끝에서 또는 끝나기 전에 목록의 크기를 확인할 수 있습니다. 예를 들면 다음과 같습니다.

    # ipset -t list usa_ips
    Name: usa_ips
    Type: hash:net
    Revision: 6
    Header: family inet hashsize 65536 maxelem 300000
    Size in memory: 3847384
    References: 0
    Number of entries: 131076
    

    이제 이 싱글과 일치하는 항목을 삭제할 수 있습니다.iptables규칙:

    iptables -A INPUT -m set --match-set usa_ips src -j DROP
    

    이 설정됩니다인용하다위의 항목은 iptables가 사용하고 있기 때문에 1입니다.

  • ipset save usa_ips > ipset_usa_ips.txt위에서 지정한 현재 설정을 사용하고 저장하고 다시 로드할 수 있습니다 ipset restore usa_ips < ipset_usa_ips.txt. 출력 형식을 보면 위와 같이 일회용 파일을 준비할 수도 있으며 훨씬 더 빠르다는 것을 알 수 있습니다.~130000개 항목을 로드하는 데 1초 미만 소요. 형식은 다음과 같습니다.

    업데이트: 실제로 세트가 현재 사용 중이므로 오류가 발생하므로 swap사용 가능한 명령이 있습니다.IP 세트. 해당 목록을 대체 세트에 로드하고 이전 세트와 교체해야 합니다.

    create usa_ips_new hash:net family inet hashsize 65536 maxelem 300000
    add usa_ips_new 216.187.112.96/27
    add usa_ips_new 216.187.112.128/27
    add usa_ips_new 216.187.112.160/31
    add usa_ips_new 216.187.112.163/32
    [...]
    

    이전에 생성된 컬렉션을 다음으로 대체합니다.

    # ipset restore < usa_ips_new.txt
    # ipset swap usa_ips usa_ips_new
    # ipset destroy usa_ips_new
    
  • 로 전환nftables또는 최소한 iptables-over-nftables API(Debian 10 및 RHEL 8/CentOS 8의 기본값)

    nftables이미 많은 버그를 해결하기 위해 만들어졌습니다.iptables. 규칙을 추가할 때 이 델타만 커널로 전송됩니다. 완료를 위해 전체 규칙 세트를 요청/편집/다시 보낼 필요가 없습니다.iptables. iptables-over-nftables 호환성 레이어는 nftables로 구현되기 때문에 동일한 작업을 수행합니다(주로 iptables의 특수 일치 및 타겟팅을 위한 호환성 레이어도 포함).IP 세트번역할 수 없습니다.)

    여기서 멈추고 운동은 여러분께 맡기겠습니다. 최근에야 알았어nftables최근 커널에서 사용되는 기능은 다음과 같습니다.네이티브 세트 지원와 함께 사용하면 flags interval( auto-merge중복을 피할 수도 있음) 다음을 사용하여 완전히 대체할 수 있습니다.IP 세트당신의 경우에.

답변2

구분 기호로 구분하여 여러 소스를 지정할 수 있습니다.,

바라보다iptables(8)

[!] -s, --소스 주소[/mask][,...] 소스 사양. 주소는 네트워크 이름, 호스트 이름, 네트워크 IP 주소(/mask 사용) 또는 일반 IP 주소일 수 있습니다. 호스트 이름은 규칙이 커널에 제출되기 전에 한 번만 확인됩니다. 원격 쿼리(예: DNS)를 사용하여 확인할 이름을 지정하는 것은 매우 나쁜 생각입니다. 마스크는 ipv4 넷마스크(iptables의 경우)이거나 넷마스크 왼쪽에 1의 수를 지정하는 일반 숫자일 수 있습니다. 따라서 iptables 마스크 24는 255.255.255.0과 동일합니다. 주소 지정 앞에 있는 "!" 인수는 주소의 의미를 반전시킵니다. --src 플래그는 이 옵션의 별칭입니다. 여러 주소를 지정할 수 있지만 이렇게 하면 여러 규칙으로 확장되거나(-A를 추가하는 경우) 여러 규칙이 제거됩니다(-D와 함께 사용하는 경우).

그런 다음 운영 체제에 따라 달라질 수 있는 bash 명령줄의 최대 길이로 제한됩니다. 궁극의 달리기를 찾아보세요

getconf ARG_MAX

이렇게 하면 iptables 명령을 여러 번 실행하지 않아도 됩니다.

질문의 예는 다음과 같습니다.

iptables -A INPUT -s 216.187.112.96/27,216.187.112.128/27,216.187.112.160/31,216.187.112.163/32 -j DROP

더 읽기 쉽게 만들려면 다음과 같이 줄을 나눌 수 있어야 합니다.

iptables -A INPUT -s\
  216.187.112.96/27,\
  216.187.112.128/27,\
  216.187.112.160/31,\
  216.187.112.163/32 \
  -j DROP

수학을 해보자:

  • 파일 크기는 9MB입니다. 행 수는 대략 48B 정도입니다. 이는 대략 9 * 1024^2 / 48 ≈ between 190000 and 200000적인 행 수입니다(1 행 = 1 iptables 호출).
  • 우분투에는 ARG_MAX 2097152가 있습니다. 9 * 1024^2 / 2097152 ≈ 5좋아요

관련 정보