GitHub

M-Abozaid/esp32-c3-adblock — Pi-hole-class DNS ad-blocker on a $2 ESP32-C3 (no PSRAM): 537k domains as 40-bit FNV-1a hashes in flash, binary-searched. UDP DNS sinkhole + web dashboard. https://youtube.com/shorts/RaxszOUMi8E?feature=share

2달러 ESP32-C3에서 실행하는 DNS 광고 차단기 — 40비트 해시를 플래시에 저장해 53만 7천 도메인 처리

ESP32-C3에서 실행하는 Pi-hole 스타일 DNS 차단기입니다. 도메인 문자열 대신 정렬한 40비트 FNV-1a 해시를 플래시에 저장하고 이진 탐색해, PSRAM 없이도 약 5만 KB RAM으로 차단 목록을 조회합니다. 보안 인증, 웹 대시보드, Wi-Fi 업데이트 기능도 제공합니다.

AI 요약

M-Abozaid의 esp32-c3-adblock은 2달러 수준의 ESP32-C3 보드에서 실행하는 DNS 광고 차단기입니다. 일반적인 임베디드 차단기가 도메인 문자열 목록을 RAM에 올리는 방식과 달리, 도메인마다 5바이트짜리 40비트 FNV-1a 해시를 계산해 정렬한 뒤 플래시에 저장합니다. DNS 요청이 들어오면 질의 도메인과 상위 도메인 접미사의 해시를 만들어 플래시 테이블을 이진 탐색합니다. 목록에 있으면 0.0.0.0으로 응답하고, 없으면 상위 DNS 리졸버에 전달한 뒤 응답을 돌려줍니다.

해시를 플래시에 저장하는 방식

README의 비교에 따르면 14만 1천 개 도메인을 문자열로 저장할 때 RAM 약 2.5MB가 필요하지만, 해시 테이블은 플래시 약 0.67MB를 차지하고 RAM은 약 50KB를 씁니다. 조회에는 플래시를 약 18회 읽으며, Wi-Fi 왕복 시간을 포함해 약 10ms가 걸립니다. 해시 충돌은 생일 역설을 따릅니다. 14만 1천 개에서는 거의 없고 53만 7천 개에서는 약 1개가 예상됩니다. 32비트로 줄이면 25만 개에서 충돌 약 7개가 예상되고, 64비트는 도메인마다 3바이트를 더 쓰므로 프로젝트는 40비트를 선택했습니다.

ESP32-C3 SuperMini와 플래시 4MB를 기본 대상으로 삼으며, PSRAM은 필요하지 않습니다. 클래식 ESP32 DevKit과 WROOM도 빌드 대상에 포함하지만, README는 C3를 실제 테스트한 대상으로 구분합니다. 16MB ESP32-S3에서는 해시 테이블로 약 270만 도메인을 담을 수 있다고 설명합니다.

목록 생성과 DNS 동작

목록 생성 도구는 hosts 파일, 한 줄에 도메인 하나를 적은 파일, AdGuard·Adblock 기본 규칙을 입력으로 받습니다. ||ads.example.com^ 형식은 차단하고 @@||ok.example.com^는 해당 도메인을 목록에서 제외합니다. 차단 도메인의 하위 도메인도 차단하지만, 정규식·와일드카드·$ 수정자·화장 규칙은 해시 목록으로 처리하지 않아 건너뜁니다. 예외 규칙은 정확히 일치하는 항목만 해제하므로 차단한 상위 도메인 아래 특정 하위 도메인만 예외로 두지는 못합니다. 목록 다운로드가 실패하면 작은 목록으로 조용히 대체하지 않고 빌드를 중단합니다.

기본 목록은 StevenBlack 기본 목록과 Hagezi Light를 합친 약 10만 항목입니다. 53만 7천 개짜리 목록도 제공하지만, 플래시 4MB 구성에서는 펌웨어 OTA용 앱 슬롯 두 개를 확보하면 목록 공간이 약 1.3MB로 줄어 최대 약 25만 도메인만 담깁니다. 더 큰 목록은 펌웨어 OTA를 지원하지 않는 단일 앱 파티션 구성이 필요합니다.

설정과 업데이트

초기에는 USB로 펌웨어와 목록 파일을 한 번 올립니다. 이후 웹 대시보드에서 목록 파일을 업로드하거나 원격 목록 URL과 갱신 일정을 설정할 수 있습니다. 기본 목록은 GitHub Actions가 매주 월요일 새로 빌드해 배포합니다. 펌웨어도 대시보드에서 OTA로 올리거나 PlatformIO 명령으로 Wi-Fi를 통해 업데이트합니다. Wi-Fi 정보를 설정하지 않았거나 연결에 실패하면 기기가 개방형 액세스 포인트와 캡티브 포털을 띄워 네트워크 정보를 받습니다.

인증과 네트워크 보안

대시보드의 조회 화면은 공개 상태지만, 차단·허용 목록 변경, 업로드, 업데이트 등 상태를 바꾸는 엔드포인트에는 HTTP Basic Auth가 필요합니다. 네트워크 OTA에도 별도 암호를 설정해야 합니다. 브라우저가 저장한 Basic Auth 인증 정보를 다른 페이지가 요청에 붙여 보내는 CSRF 문제를 막기 위해, 변경 요청에는 X-Requested-With: c3-adblock 헤더도 요구합니다. 사용자 지정 차단 도메인은 대시보드에 표시하기 전에 HTML 이스케이프 처리합니다.

다만 통신은 80번 포트의 평문 HTTP입니다. Basic Auth 정보도 암호화되지 않아 같은 네트워크에서 트래픽을 엿보는 공격자를 막지는 못합니다. 인증은 인증 정보 없이 LAN에서 API를 호출하는 상황을 막는 경계로 설명합니다. 기본 암호를 예제 파일 값 그대로 두면 누구나 알 수 있으므로 실제 값을 설정해야 합니다. 초기 Wi-Fi 설정용 액세스 포인트는 암호화되지 않은 상태로 열리며, 포털에서 입력하는 Wi-Fi 암호는 설정 중 무선 구간의 보안에 의존합니다.

원문: GitHub / 번역·요약: Trawling