Skip to content

IP Filtering at the Gateway — Whitelists, Blacklists, and Geo-Blocking

DodaTech Updated 2026-06-28 5 min read

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

  1. How does CIDR notation work for IP filtering?
  2. What is the difference between a whitelist and a blacklist approach?
  3. Why should you validate the X-Forwarded-For header?
  4. How does geo-IP blocking determine a client's location?
  5. 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

What is the difference between whitelist and blacklist IP filtering?

Whitelist allows only specified IPs and blocks everything else. Blacklist blocks specified IPs and allows everything else. Whitelist is more restrictive.

How accurate is geo-IP blocking?

Geo-IP databases are approximately 99 percent accurate at the country level but less accurate at the city level. Use country-level blocking for security, not enforcement.

Can IP filtering prevent DDoS attacks?

IP filtering can block known attack sources but cannot prevent large-scale DDoS. Use dedicated DDoS protection services for volumetric attacks.

How do you handle IP filtering for CDN traffic?

Configure the CDN to forward the real client IP in a trusted header. The gateway should only trust this header from known CDN IP ranges.

What is the performance impact of IP filtering?

IP filtering is extremely fast. CIDR matching uses binary prefix lookup and completes in microseconds for thousands of rules.

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