> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# IP Filter

> IP whitelist and blacklist middleware for access control.

## Overview

The `ipfilter` middleware filters requests based on client IP addresses. Use it to allow or deny access from specific IPs or IP ranges (CIDR notation).

Use it when you need:

* Whitelist access to admin panels
* Block known malicious IPs
* Restrict access to internal networks
* Geo-blocking based on IP ranges

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/ipfilter"
```

## Quick Start

```go theme={null}
app := mizu.New()

// Allow only specific IPs
app.Use(ipfilter.Allow("192.168.1.0/24", "10.0.0.1"))

// Block specific IPs
app.Use(ipfilter.Deny("192.168.1.100", "10.0.0.0/8"))
```

## Configuration

### Options

| Option          | Type                    | Default | Description               |
| --------------- | ----------------------- | ------- | ------------------------- |
| `AllowList`     | `[]string`              | -       | IPs/CIDRs to allow        |
| `DenyList`      | `[]string`              | -       | IPs/CIDRs to deny         |
| `DenyByDefault` | `bool`                  | `false` | Deny unless in allow list |
| `TrustProxy`    | `bool`                  | `false` | Use X-Forwarded-For       |
| `ErrorHandler`  | `func(*mizu.Ctx) error` | -       | Custom denial handler     |

## Examples

### Whitelist Mode

Only allow specific IPs, deny everything else:

```go theme={null}
app.Use(ipfilter.Allow(
    "192.168.1.0/24",  // Office network
    "10.0.0.5",        // Specific server
    "203.0.113.50",    // Remote developer
))
```

### Blacklist Mode

Allow everything except specific IPs:

```go theme={null}
app.Use(ipfilter.Deny(
    "192.168.1.100",   // Blocked user
    "10.0.0.0/8",      // Blocked network
))
```

### Combined Allow and Deny

```go theme={null}
app.Use(ipfilter.New(ipfilter.Options{
    AllowList: []string{"192.168.1.0/24"},
    DenyList:  []string{"192.168.1.100"},  // Even within allowed range
}))
```

### Localhost Only

```go theme={null}
// Only allow localhost connections
app.Use(ipfilter.Localhost())
```

### Private Networks Only

```go theme={null}
// Only allow private network IPs
app.Use(ipfilter.Private())
```

### Behind a Proxy

```go theme={null}
app.Use(ipfilter.New(ipfilter.Options{
    AllowList:  []string{"203.0.113.0/24"},
    TrustProxy: true, // Use X-Forwarded-For header
}))
```

### Custom Error Handler

```go theme={null}
app.Use(ipfilter.New(ipfilter.Options{
    AllowList:     []string{"192.168.1.0/24"},
    DenyByDefault: true,
    ErrorHandler: func(c *mizu.Ctx) error {
        return c.JSON(403, map[string]string{
            "error": "Access denied from your location",
            "ip":    c.ClientIP(),
        })
    },
}))
```

### Route-Specific Filtering

```go theme={null}
// Public routes
app.Get("/", publicHandler)
app.Get("/api", apiHandler)

// Admin routes - localhost only
adminFilter := ipfilter.Localhost()
app.Get("/admin", adminHandler, adminFilter)
app.Post("/admin/config", configHandler, adminFilter)
```

### Group Filtering

```go theme={null}
admin := app.Group("/admin")
admin.Use(ipfilter.Allow("192.168.1.0/24"))

admin.Get("/", adminDashboard)
admin.Get("/users", listUsers)
```

### Dynamic IP List

```go theme={null}
func dynamicFilter() mizu.Middleware {
    var blockedIPs sync.Map

    // Background goroutine to update blocked IPs
    go func() {
        for {
            ips := fetchBlockedIPs() // From database/API
            for _, ip := range ips {
                blockedIPs.Store(ip, true)
            }
            time.Sleep(5 * time.Minute)
        }
    }()

    return func(next mizu.Handler) mizu.Handler {
        return func(c *mizu.Ctx) error {
            if _, blocked := blockedIPs.Load(c.ClientIP()); blocked {
                return c.Text(403, "Forbidden")
            }
            return next(c)
        }
    }
}
```

## API Reference

### Functions

```go theme={null}
// Allow creates whitelist middleware (deny by default)
func Allow(ips ...string) mizu.Middleware

// Deny creates blacklist middleware
func Deny(ips ...string) mizu.Middleware

// New creates middleware with full options
func New(opts Options) mizu.Middleware

// Private allows only private network IPs
func Private() mizu.Middleware

// Localhost allows only localhost
func Localhost() mizu.Middleware
```

## CIDR Notation

The middleware supports both single IPs and CIDR notation:

| Format    | Description   | Example          |
| --------- | ------------- | ---------------- |
| Single IP | Exact match   | `192.168.1.100`  |
| IPv4 CIDR | Network range | `192.168.1.0/24` |
| IPv6      | IPv6 address  | `::1`            |
| IPv6 CIDR | IPv6 range    | `fc00::/7`       |

### Common CIDR Blocks

```go theme={null}
"10.0.0.0/8"       // 10.x.x.x (Class A private)
"172.16.0.0/12"    // 172.16-31.x.x (Class B private)
"192.168.0.0/16"   // 192.168.x.x (Class C private)
"127.0.0.0/8"      // Localhost
"0.0.0.0/0"        // All IPv4
"::/0"             // All IPv6
```

## Technical Details

### Implementation Overview

The ipfilter middleware uses Go's `net` package to parse and match IP addresses and CIDR ranges efficiently. The implementation follows these key principles:

1. **Network Parsing**: IP addresses and CIDR blocks are parsed at initialization time using `parseNetworks()`, converting them to `*net.IPNet` structures for efficient matching.

2. **IP Extraction**: Client IPs are extracted using one of two methods:
   * Direct extraction from `RemoteAddr` using `extractIP()` when not behind a proxy
   * Using `c.ClientIP()` when `TrustProxy` is enabled (reads X-Forwarded-For header)

3. **Filtering Logic**: The middleware applies a two-phase filtering process:
   * **Phase 1 - Deny List Check**: First checks if the IP is in the deny list. If found, immediately denies access.
   * **Phase 2 - Allow List Check**: If `DenyByDefault` is true, verifies the IP is in the allow list. Denies if not found.

4. **Single IP Normalization**: Single IP addresses are automatically converted to CIDR notation:
   * IPv4 addresses: converted to `/32` (e.g., `192.168.1.100/32`)
   * IPv6 addresses: converted to `/128` (e.g., `::1/128`)

5. **Error Handling**: Uses a custom `handleDenied()` function that either calls the user-provided `ErrorHandler` or returns a default 403 Forbidden response.

### Performance Considerations

* IP parsing happens once during middleware initialization, not on every request
* Network matching uses efficient `net.IPNet.Contains()` method
* Deny list is checked before allow list to fail fast on blocked IPs
* No regex or string manipulation on hot path

## Security Considerations

1. **Proxy Headers** - Only enable `TrustProxy` if behind a trusted proxy
2. **IP Spoofing** - X-Forwarded-For can be spoofed if not behind trusted proxy
3. **IPv6** - Consider both IPv4 and IPv6 addresses
4. **VPNs/Proxies** - Users may bypass IP restrictions using VPNs

## Best Practices

* Use CIDR notation for ranges to simplify management
* Enable `TrustProxy` only behind trusted load balancers
* Combine with other authentication for sensitive areas
* Log denied attempts for security monitoring

## Testing

The ipfilter middleware includes comprehensive test coverage for all filtering scenarios:

| Test Case                            | Description                                                                 | Expected Behavior                             |
| ------------------------------------ | --------------------------------------------------------------------------- | --------------------------------------------- |
| `TestAllow/allows listed IP`         | Request from IP within allowed CIDR range (192.168.1.100 in 192.168.1.0/24) | Returns 200 OK                                |
| `TestAllow/allows specific IP`       | Request from specific allowed IP (10.0.0.1)                                 | Returns 200 OK                                |
| `TestAllow/denies unlisted IP`       | Request from IP not in allow list (203.0.113.1)                             | Returns 403 Forbidden                         |
| `TestDeny/denies listed IP`          | Request from IP in deny list CIDR range (192.168.1.100 in 192.168.1.0/24)   | Returns 403 Forbidden                         |
| `TestDeny/allows unlisted IP`        | Request from IP not in deny list (10.0.0.1)                                 | Returns 200 OK                                |
| `TestNew_DenyTakesPrecedence`        | IP present in both allow and deny lists (192.168.1.100)                     | Returns 403 Forbidden (deny wins)             |
| `TestNew_TrustProxy`                 | Request with X-Forwarded-For header when TrustProxy enabled                 | Uses X-Forwarded-For IP for filtering         |
| `TestNew_ErrorHandler`               | Custom error handler when IP is blocked                                     | Calls custom error handler with JSON response |
| `TestPrivate` (192.168.1.1)          | Request from private network IP (Class C)                                   | Returns 200 OK                                |
| `TestPrivate` (10.0.0.1)             | Request from private network IP (Class A)                                   | Returns 200 OK                                |
| `TestPrivate` (172.16.0.1)           | Request from private network IP (Class B)                                   | Returns 200 OK                                |
| `TestPrivate` (127.0.0.1)            | Request from localhost                                                      | Returns 200 OK                                |
| `TestPrivate` (8.8.8.8)              | Request from public IP                                                      | Returns 403 Forbidden                         |
| `TestLocalhost/allows localhost`     | Request from 127.0.0.1                                                      | Returns 200 OK                                |
| `TestLocalhost/denies non-localhost` | Request from non-localhost IP (192.168.1.1)                                 | Returns 403 Forbidden                         |

## Related Middlewares

* [ratelimit](/middlewares/ratelimit) - Rate limiting by IP
* [honeypot](/middlewares/honeypot) - Detect malicious IPs
* [realip](/middlewares/realip) - Extract real client IP
