-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathblock_fb.py
More file actions
96 lines (79 loc) · 3.09 KB
/
Copy pathblock_fb.py
File metadata and controls
96 lines (79 loc) · 3.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# -*- coding: utf-8 -*-
import asyncio
import logging
import sys
# 1. Safety Check: Ensure we are using Python 3.7+
if sys.version_info < (3, 7):
print("❌ Error: This script requires Python 3.7 or higher for 'asyncio' features.")
sys.exit(1)
# Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
logger = logging.getLogger("DNS-Filter")
# --- CONFIGURATION ---
UPSTREAM_DNS = "8.8.8.8"
UPSTREAM_PORT = 53
LISTEN_ADDR = "0.0.0.0"
LISTEN_PORT = 53
# Domains to block (Case-insensitive check)
BLOCKLIST = ["facebook.com", "fb.com", "fbcdn.net", "messenger.com"]
def extract_domain(data):
"""Helper to parse the domain name from the DNS binary packet."""
try:
parts = []
i = 12 # DNS header is 12 bytes long
while True:
length = data[i]
if length == 0: break
i += 1
parts.append(data[i:i+length].decode('ascii'))
i += length
return ".".join(parts).lower()
except Exception:
return "unknown"
class DNSProxyProtocol(asyncio.DatagramProtocol):
def __init__(self):
self.transport = None
self.sessions = {} # Mapping Transaction ID to Client Address
def connection_made(self, transport):
self.transport = transport
def datagram_received(self, data, addr):
tx_id = data[:2] # First 2 bytes are the Transaction ID
# A. Handle Response from Google/Upstream
if addr == (UPSTREAM_DNS, UPSTREAM_PORT):
client_addr = self.sessions.pop(tx_id, None)
if client_addr:
self.transport.sendto(data, client_addr)
# B. Handle Request from Client (your PC/Device)
else:
domain = extract_domain(data)
# --- BLOCKING LOGIC ---
if any(blocked in domain for blocked in BLOCKLIST):
logger.warning(f"🚫 BLOCKED: {addr[0]} tried to access [{domain}]")
# We simply return and do NOT forward the packet to the upstream server.
# The client will eventually "Time Out."
return
# Store the request ID and forward to Google
self.sessions[tx_id] = addr
logger.info(f"🔍 Forwarding: {addr[0]} -> [{domain}]")
self.transport.sendto(data, (UPSTREAM_DNS, UPSTREAM_PORT))
async def main():
logger.info(f"🚀 Starting DNS Filter on {LISTEN_ADDR}:{LISTEN_PORT}")
logger.info(f"🛡️ Blocking: {', '.join(BLOCKLIST)}")
loop = asyncio.get_running_loop()
try:
transport, protocol = await loop.create_datagram_endpoint(
lambda: DNSProxyProtocol(),
local_addr=(LISTEN_ADDR, LISTEN_PORT)
)
except PermissionError:
logger.error("❌ Permission Denied: Run with 'sudo python3' to use port 53.")
return
try:
await asyncio.Future() # Keep running
finally:
transport.close()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logger.info("\n🛑 Server stopped by user.")