IP Filtering at the Gateway — Whitelists, Blacklists, and Geo-Blocking
In this tutorial, you'll learn about IP Filtering. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
IP filtering at the gateway blocks or allows traffic based on the client's IP address, providing a first line of defense against known malicious sources.
What You'll Learn
By the end of this lesson, you will implement IP whitelist and blacklist rules, CIDR range matching, geo-IP blocking, and dynamic IP reputation checks at the gateway level.
Why It Matters
IP filtering stops a significant portion of automated attacks and scrapers before they consume any backend resources, reducing load and improving security.
Real-World Use
Durga Antivirus Pro maintains a dynamic IP blacklist at its gateway that blocks known scanner IPs and allows traffic only from partner service IP ranges during maintenance Windows.
IP Filtering Architecture
flowchart LR
Client-->Gateway
Gateway-->IPCheck{IP Check}
IPCheck-->|Whitelisted|Pass[Allow]
IPCheck-->|Blacklisted|Block[403 Blocked]
IPCheck-->|Geo-Blocked|GeoBlock[403 Region Blocked]
IPCheck-->|Reputation Check|Rep[Reputation Score]
Rep-->|Low|Pass
Rep-->|High|Block
IP Rule Engine
A flexible IP filtering engine that supports whitelists, blacklists, and CIDR notation.
import ipaddress
from typing import List, Dict, Optional, Tuple
from datetime import datetime
class IPRuleEngine:
def __init__(self):
self.whitelist: List[ipaddress.IPv4Network] = []
self.blacklist: List[ipaddress.IPv4Network] = []
self.blocked_ips: set = set()
def add_whitelist(self, cidr: str):
self.whitelist.append(
ipaddress.IPv4Network(cidr)
)
def add_blacklist(self, cidr: str):
self.blacklist.append(
ipaddress.IPv4Network(cidr)
)
def block_ip(self, ip_str: str):
self.blocked_ips.add(ip_str)
def check_ip(self, ip_str: str) -> Tuple[bool, str]:
try:
ip = ipaddress.IPv4Address(ip_str)
except ipaddress.AddressValueError:
return False, "Invalid IP address"
if ip_str in self.blocked_ips:
return False, "IP blocked"
if self.whitelist:
for network in self.whitelist:
if ip in network:
return True, "Allowed by whitelist"
return False, "Not in whitelist"
for network in self.blacklist:
if ip in network:
return False, "Blacklisted"
return True, "Allowed"
def get_blocked_count(self) -> int:
return len(self.blocked_ips)
engine = IPRuleEngine()
engine.add_whitelist("10.0.0.0/8")
engine.add_blacklist("203.0.113.0/24")
result = engine.check_ip("10.0.0.5")
print(f"Whitelisted IP: {result}")
result = engine.check_ip("203.0.113.42")
print(f"Blacklisted IP: {result}")
result = engine.check_ip("198.51.100.1")
print(f"Unknown IP: {result}")
Geo-IP Blocking
Block traffic from specific countries or regions at the gateway.
from typing import Dict, List, Optional, Tuple
class GeoIPBlocker:
def __init__(self):
self.blocked_countries: set = set()
self.allowed_countries: set = set()
self.ip_to_country: Dict[str, str] = {}
def load_geoip_db(self, ip_country_map: Dict[str, str]):
self.ip_to_country = ip_country_map
def block_country(self, country_code: str):
self.blocked_countries.add(country_code.upper())
def allow_only_countries(self, countries: List[str]):
self.allowed_countries = {
c.upper() for c in countries
}
def check_ip(self, ip_str: str
) -> Tuple[bool, Optional[str]]:
country = self.ip_to_country.get(ip_str)
if not country:
return True, None
if self.allowed_countries:
if country not in self.allowed_countries:
return False, country
return True, country
if country in self.blocked_countries:
return False, country
return True, country
def get_blocked_countries(self) -> list:
return sorted(self.blocked_countries)
geo = GeoIPBlocker()
geo.load_geoip_db({
"203.0.113.1": "US",
"198.51.100.1": "CN",
"192.0.2.1": "RU",
})
geo.block_country("CN")
geo.block_country("RU")
allowed, country = geo.check_ip("203.0.113.1")
print(f"US IP: allowed={allowed}, country={country}")
allowed, country = geo.check_ip("198.51.100.1")
print(f"CN IP: allowed={allowed}, country={country}")
Dynamic IP Reputation
Check IP addresses against a dynamic reputation database.
from typing import Dict, Tuple, Optional
from collections import defaultdict
import time
class IPReputationChecker:
def __init__(self, threshold: float = 0.8):
self.threshold = threshold
self.reputation: Dict[str, float] = {}
self.failed_attempts: Dict[str, list] = defaultdict(list)
self.report_sources: list = []
def add_report_source(self, source: str):
self.report_sources.append(source)
def record_failure(self, ip_str: str):
now = time.time()
self.failed_attempts[ip_str].append(now)
cutoff = now - 300
self.failed_attempts[ip_str] = [
t for t in self.failed_attempts[ip_str]
if t > cutoff
]
failure_count = len(self.failed_attempts[ip_str])
if failure_count > 20:
self.reputation[ip_str] = 1.0
elif failure_count > 10:
self.reputation[ip_str] = 0.6
elif failure_count > 5:
self.reputation[ip_str] = 0.3
def get_score(self, ip_str: str) -> float:
score = self.reputation.get(ip_str, 0.0)
failures = len(self.failed_attempts.get(ip_str, []))
score += min(failures * 0.05, 0.5)
return min(score, 1.0)
def is_blocked(self, ip_str: str) -> Tuple[bool, float]:
score = self.get_score(ip_str)
return score >= self.threshold, score
reputation = IPReputationChecker(threshold=0.7)
for _ in range(15):
reputation.record_failure("203.0.113.42")
blocked, score = reputation.is_blocked("203.0.113.42")
print(f"Blocked: {blocked}, score: {score:.2f}")
Common Mistakes
Mistake 1: Relying Only on IP Filtering
IP addresses can be spoofed or changed. IP filtering is a complement to, not a replacement for, authentication.
Mistake 2: Using X-Forwarded-For Without Validation
Trusting the X-Forwarded-For header without verifying the upstream proxy allows IP spoofing.
Mistake 3: Blocking Too Aggressively
Overly strict IP blocking can lock out legitimate users from shared IPs or cloud services.
Mistake 4: Not Handling IPv6
Modern clients increasingly use IPv6. Ensure your filtering engine handles both IPv4 and IPv6.
Mistake 5: Static Rules Without Monitoring
IP threats change constantly. Update rules based on attack patterns and review blocked traffic regularly.
Practice Questions
- How does CIDR notation work for IP filtering?
- What is the difference between a whitelist and a blacklist approach?
- Why should you validate the X-Forwarded-For header?
- How does geo-IP blocking determine a client's location?
- What is IP reputation and how is it calculated?
Challenge
Build an IP filtering middleware for the gateway that supports CIDR whitelist and blacklist, geo-IP blocking using a provided country map, a dynamic reputation system that blocks IPs with more than 10 failed attempts in 5 minutes, and returns proper 403 responses with reason codes.
FAQ
Mini Project
Build an IP filtering module that supports whitelist and blacklist with CIDR notation, integrates with a MaxMind GeoLite2 database for country blocking, implements a Sliding Window failure tracker that automatically blocks IPs with more than 10 failed auth attempts in 5 minutes, and returns 403 with a X-Block-Reason header.
What's Next
Learn about Rate Limiting to control request volume, or explore Gateway Security for comprehensive gateway protection strategies.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro