
Q-Feeds를 NFtables 또는 IPtables에 직접 구현하는 스크립트
tip.qfeeds.com에서 무료 API 키를 발급받으세요.
git clone https://github.com/Q-Feeds/NFtables-IPtables-integration-script.git
cd NFtables-IPtables-integration-script
chmod +x qfeeds-installer.sh qfeeds-uninstaller.sh
sudo ./qfeeds-installer.sh
설치 프로그램은 다음을 수행합니다:
이제 서버가 보호됩니다. cron 작업은 20분마다(구성 가능) 업데이트를 확인하며, 실제 API 호출은 라이선스가 허용할 때만 발생합니다.
이 솔루션은 주기적으로 Q-Feeds에서 최신 위협 인텔리전스 피드를 다운로드하여 방화벽 규칙으로 적용합니다(단계별 가이드: NFtables/IPtables 설정). 이를 통해 다음을 수행할 수 있습니다:
설치 프로그램은 사용 가능한 방화벽 백엔드를 자동으로 감지합니다:
| 우선순위 | 감지 | 백엔드 |
|---|---|---|
| 1순위 | nft 명령어 발견 | nftables |
| 2순위 | iptables 명령어 발견 | iptables+ipset |
| — | 둘 다 없음 | 오류 (종료) |
감지된 백엔드는 구성 파일에 저장됩니다. 업데이터 및 제거 스크립트는 이를 사용하여 올바른 방화벽 명령을 실행합니다.
두 백엔드 모두 최대 성능을 위해 동일한 분할 세트 전략을 사용합니다:
nftables 백엔드:
┌─────────────────────────────────────────────────────────┐
│ table ip qfeeds │
│ │
│ ┌─────────────────────────┐ ┌───────────────────────┐ │
│ │ qfeeds_blacklist_v4 │ │ qfeeds_blacklist_v4 │ │
│ │ (hash set) │ │ _nets (interval set) │ │
│ │ │ │ │ │
│ │ Individual IPs │ │ CIDR ranges │ │
│ │ ~99% of entries │ │ ~1% of entries │ │
│ │ O(1) lookup & insert │ │ O(log n) lookup │ │
│ └─────────────────────────┘ └───────────────────────┘ │
│ │
│ ┌─────────────────────────┐ │
│ │ qfeeds_whitelist_v4 │ │
│ │ (interval set) │ │
│ │ Your allowed IPs/CIDRs │ │
│ └─────────────────────────┘ │
│ │
│ chain input-chain (hook input, priority 0, accept) │
│ → ip saddr @qfeeds_whitelist_v4 accept │
│ → ip saddr @qfeeds_blacklist_v4 drop │
│ → ip saddr @qfeeds_blacklist_v4_nets drop │
│ │
│ chain output-chain (if enabled) │
│ → ip daddr @qfeeds_whitelist_v4 accept │
│ → ip daddr @qfeeds_blacklist_v4 drop │
│ → ip daddr @qfeeds_blacklist_v4_nets drop │
└─────────────────────────────────────────────────────────┘
iptables+ipset 백엔드:
┌──────────────────────────────────────────────────────────┐
│ ipset sets │
│ │
│ ┌─────────────────────────┐ ┌────────────────────────┐ │
│ │ qfeeds_blacklist_v4 │ │ qfeeds_blacklist_v4 │ │
│ │ (hash:ip) │ │ _nets (hash:net) │ │
│ │ maxelem 1000000 │ │ maxelem 65536 │ │
│ │ │ │ │ │
│ │ Individual IPs │ │ CIDR ranges │ │
│ └─────────────────────────┘ └────────────────────────┘ │
│ │
│ ┌─────────────────────────┐ │
│ │ qfeeds_whitelist_v4 │ │
│ │ (hash:net) │ │
│ └─────────────────────────┘ │
│ │
│ iptables: INPUT/OUTPUT jump to a dedicated chain │
│ (jump rule tagged -m comment "qfeeds"): │
│ │
│ chain QFEEDS_INPUT (rebuilt each run, in order): │
│ -m set --match-set whitelist_v4 src -j ACCEPT │
│ -m set --match-set blacklist_v4 src -j DROP │
│ -m set --match-set blacklist_v4_nets src -j DROP │
│ (QFEEDS_OUTPUT mirrors this with dst, if enabled) │
└──────────────────────────────────────────────────────────┘
IPv6에도 동일한 구조가 존재합니다(ip6 qfeeds 테이블 또는 ip6tables + family inet6 ipsets).
왜 두 가지 set 유형인가?
┌──────────────────────────────────────────────────────┐
│ 1. Check license schedule (licenses.php API) │
│ → Skip run if not yet time for next update │
│ 2. Determine sync mode (full or diff) │
│ 3. Fetch IPv4 feed (ipv6=0) and IPv6 feed │
│ (ipv6=only) separately │
│ 4. Separate IPs from CIDRs in awk │
│ 5. Batch-load into hash set (IPs) and net/interval │
│ set (CIDRs) │
│ 6. Update whitelist sets from config │
│ 7. Persist rules │
└──────────────────────────────────────────────────────┘
| 모드 | 시점 | 수행 작업 |
|---|---|---|
| 전체 동기화 | 최초 실행, 강제 업데이트, 차분 실패 후, 로컬 세트가 기준선을 잃었을 때(비어 있거나 예상보다 훨씬 작을 때), 또는 마지막 동기화가 FULL_SYNC_MAX_AGE(기본값 24시간)보다 오래된 경우 | 각 피드를 먼저 가져와 검증한 다음, 블랙리스트 세트를 비우고 다시 로드합니다. 유효한 데이터를 확보한 후에만 세트를 비우므로, 가져오기 실패로 인해 보호되지 않는 상태가 되는 일은 없습니다 |
| 차분 동기화 | 이후 실행(malware_ip 피드만 해당) 중 로컬 세트가 정상일 때 | 마지막 가져오기 이후의 추가(+) 및 제거(-) 항목만 가져옵니다 |
차분 동기화는 API 키별로 이루어집니다 — API는 마지막 성공적인 가져오기를 추적하며 그 이후의 변경 사항만 반환합니다. 차분 동기화가 실패하면 스크립트는 자동으로 전체 동기화로 폴백합니다.
자가 복구: 차분 업데이트는 기존 세트만 패치합니다. 해당 세트가 손실되거나 잘린 경우 — 예를 들어 방화벽 규칙이 유지되지 않은 재부팅, 수동 초기화, 또는 이전의 부분 동기화 — 업데이터는 누락된 기준선(실시간 요소 수가 0이거나 마지막으로 기록된 수보다 훨씬 낮음)을 감지하고 빈 세트에 차분을 적용하는 대신 전체 재구성을 강제합니다. 추가 안전망으로 주기적인 전체 동기화도 강제합니다(기본적으로 24시간마다,
FULL_SYNC_MAX_AGE를 통해).
업데이터는 매 실행 전에 Q-Feeds 라이선스 API(licenses.php)를 확인합니다. 라이선스의 next_update 타임스탬프에 아직 도달하지 않았다면, 스크립트는 불필요한 API 호출 없이 조기 종료합니다. cron 작업은 자주 실행되지만(기본값: 20분마다), 실제 업데이트는 라이선스가 허용할 때만 발생합니다.
설치하기 전에 다음 사항을 확인하세요:
api.qfeeds.com에 접속할 수 있어야 합니다