Add support for ipv6 subnet in ipStrategy
This commit is contained in:
parent
a398536688
commit
312ebb17ab
17 changed files with 544 additions and 12 deletions
|
@ -101,7 +101,7 @@ If none are set, the default is to use the `requestHost`.
|
||||||
|
|
||||||
#### `sourceCriterion.ipStrategy`
|
#### `sourceCriterion.ipStrategy`
|
||||||
|
|
||||||
The `ipStrategy` option defines two parameters that configures how Traefik determines the client IP: `depth`, and `excludedIPs`.
|
The `ipStrategy` option defines three parameters that configures how Traefik determines the client IP: `depth`, `excludedIPs` and `ipv6Subnet`.
|
||||||
|
|
||||||
!!! important "As a middleware, InFlightReq happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, i.e. after it has already passed through the middleware. Therefore, during InFlightReq, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be used and/or relied upon."
|
!!! important "As a middleware, InFlightReq happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, i.e. after it has already passed through the middleware. Therefore, during InFlightReq, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be used and/or relied upon."
|
||||||
|
|
||||||
|
@ -112,6 +112,9 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and select
|
||||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP is empty.
|
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP is empty.
|
||||||
- `depth` is ignored if its value is less than or equal to 0.
|
- `depth` is ignored if its value is less than or equal to 0.
|
||||||
|
|
||||||
|
If `ipStrategy.ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||||
|
See [ipStrategy.ipv6Subnet](#ipstrategyipv6subnet) for more details.
|
||||||
|
|
||||||
!!! example "Example of Depth & X-Forwarded-For"
|
!!! example "Example of Depth & X-Forwarded-For"
|
||||||
|
|
||||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used as the criterion is `"12.0.0.1"` (`depth=2`).
|
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used as the criterion is `"12.0.0.1"` (`depth=2`).
|
||||||
|
@ -218,6 +221,63 @@ http:
|
||||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### `ipStrategy.ipv6Subnet`
|
||||||
|
|
||||||
|
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||||
|
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||||
|
|
||||||
|
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||||
|
|
||||||
|
- `ipv6Subnet` is ignored if its value is outside of 0-128 interval
|
||||||
|
|
||||||
|
!!! example "Example of ipv6Subnet"
|
||||||
|
|
||||||
|
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||||
|
|
||||||
|
| `IP` | `ipv6Subnet` | clientIP |
|
||||||
|
|---------------------------|--------------|-----------------------|
|
||||||
|
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||||
|
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||||
|
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||||
|
|
||||||
|
```yaml tab="Docker & Swarm"
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: test-inflightreq
|
||||||
|
spec:
|
||||||
|
inFlightReq:
|
||||||
|
sourceCriterion:
|
||||||
|
ipStrategy:
|
||||||
|
ipv6Subnet: 64
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Consul Catalog"
|
||||||
|
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
test-inflightreq:
|
||||||
|
inFlightReq:
|
||||||
|
sourceCriterion:
|
||||||
|
ipStrategy:
|
||||||
|
ipv6Subnet: 64
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-inflightreq.inflightreq]
|
||||||
|
[http.middlewares.test-inflightreq.inFlightReq.sourceCriterion.ipStrategy]
|
||||||
|
ipv6Subnet = 64
|
||||||
|
```
|
||||||
|
|
||||||
#### `sourceCriterion.requestHeaderName`
|
#### `sourceCriterion.requestHeaderName`
|
||||||
|
|
||||||
Name of the header used to group incoming requests.
|
Name of the header used to group incoming requests.
|
||||||
|
|
|
@ -75,6 +75,9 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
|
||||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
||||||
- `depth` is ignored if its value is less than or equal to 0.
|
- `depth` is ignored if its value is less than or equal to 0.
|
||||||
|
|
||||||
|
If `ipStrategy.ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||||
|
See [ipStrategy.ipv6Subnet](#ipstrategyipv6subnet) for more details.
|
||||||
|
|
||||||
!!! example "Examples of Depth & X-Forwarded-For"
|
!!! example "Examples of Depth & X-Forwarded-For"
|
||||||
|
|
||||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used is `"12.0.0.1"` (`depth=2`).
|
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used is `"12.0.0.1"` (`depth=2`).
|
||||||
|
@ -204,3 +207,60 @@ http:
|
||||||
[http.middlewares.test-ipallowlist.ipAllowList.ipStrategy]
|
[http.middlewares.test-ipallowlist.ipAllowList.ipStrategy]
|
||||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `ipStrategy.ipv6Subnet`
|
||||||
|
|
||||||
|
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||||
|
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||||
|
|
||||||
|
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||||
|
|
||||||
|
- `ipv6Subnet` is ignored if its value is outside of 0-128 interval
|
||||||
|
|
||||||
|
!!! example "Example of ipv6Subnet"
|
||||||
|
|
||||||
|
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||||
|
|
||||||
|
| `IP` | `ipv6Subnet` | clientIP |
|
||||||
|
|---------------------------|--------------|-----------------------|
|
||||||
|
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||||
|
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||||
|
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||||
|
|
||||||
|
```yaml tab="Docker & Swarm"
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: test-ipallowlist
|
||||||
|
spec:
|
||||||
|
ipallowlist:
|
||||||
|
sourceCriterion:
|
||||||
|
ipStrategy:
|
||||||
|
ipv6Subnet: 64
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Consul Catalog"
|
||||||
|
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
test-ipallowlist:
|
||||||
|
ipallowlist:
|
||||||
|
sourceCriterion:
|
||||||
|
ipStrategy:
|
||||||
|
ipv6Subnet: 64
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-ipallowlist.ipallowlist]
|
||||||
|
[http.middlewares.test-ipallowlist.ipallowlist.sourceCriterion.ipStrategy]
|
||||||
|
ipv6Subnet = 64
|
||||||
|
```
|
||||||
|
|
|
@ -81,6 +81,9 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th
|
||||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP will be empty.
|
||||||
- `depth` is ignored if its value is less than or equal to 0.
|
- `depth` is ignored if its value is less than or equal to 0.
|
||||||
|
|
||||||
|
If `ipStrategy.ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||||
|
See [ipStrategy.ipv6Subnet](#ipstrategyipv6subnet) for more details.
|
||||||
|
|
||||||
!!! example "Examples of Depth & X-Forwarded-For"
|
!!! example "Examples of Depth & X-Forwarded-For"
|
||||||
|
|
||||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used for the whitelisting is `"12.0.0.1"` (`depth=2`).
|
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used for the whitelisting is `"12.0.0.1"` (`depth=2`).
|
||||||
|
@ -210,3 +213,60 @@ http:
|
||||||
[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
|
[http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy]
|
||||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `ipStrategy.ipv6Subnet`
|
||||||
|
|
||||||
|
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||||
|
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||||
|
|
||||||
|
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||||
|
|
||||||
|
- `ipv6Subnet` is ignored if its value is outside of 0-128 interval
|
||||||
|
|
||||||
|
!!! example "Example of ipv6Subnet"
|
||||||
|
|
||||||
|
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||||
|
|
||||||
|
| `IP` | `ipv6Subnet` | clientIP |
|
||||||
|
|---------------------------|--------------|-----------------------|
|
||||||
|
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||||
|
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||||
|
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||||
|
|
||||||
|
```yaml tab="Docker & Swarm"
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-ipWhiteList.ipWhiteList.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: test-ipWhiteList
|
||||||
|
spec:
|
||||||
|
ipWhiteList:
|
||||||
|
sourceCriterion:
|
||||||
|
ipStrategy:
|
||||||
|
ipv6Subnet: 64
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Consul Catalog"
|
||||||
|
- "traefik.http.middlewares.test-ipWhiteList.ipWhiteList.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
test-ipWhiteList:
|
||||||
|
ipWhiteList:
|
||||||
|
sourceCriterion:
|
||||||
|
ipStrategy:
|
||||||
|
ipv6Subnet: 64
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-ipWhiteList.ipWhiteList]
|
||||||
|
[http.middlewares.test-ipWhiteList.ipWhiteList.sourceCriterion.ipStrategy]
|
||||||
|
ipv6Subnet = 64
|
||||||
|
```
|
||||||
|
|
|
@ -211,7 +211,7 @@ If none are set, the default is to use the request's remote address field (as an
|
||||||
|
|
||||||
#### `sourceCriterion.ipStrategy`
|
#### `sourceCriterion.ipStrategy`
|
||||||
|
|
||||||
The `ipStrategy` option defines two parameters that configures how Traefik determines the client IP: `depth`, and `excludedIPs`.
|
The `ipStrategy` option defines three parameters that configures how Traefik determines the client IP: `depth`, `excludedIPs` and `ipv6Subnet`.
|
||||||
|
|
||||||
!!! important "As a middleware, rate-limiting happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, i.e. after it has already passed through rate-limiting. Therefore, during rate-limiting, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be found and/or relied upon."
|
!!! important "As a middleware, rate-limiting happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to `X-Forwarded-For` during the last stages of proxying, i.e. after it has already passed through rate-limiting. Therefore, during rate-limiting, as the previous network hop is not yet present in `X-Forwarded-For`, it cannot be found and/or relied upon."
|
||||||
|
|
||||||
|
@ -222,6 +222,9 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and select
|
||||||
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP is empty.
|
- If `depth` is greater than the total number of IPs in `X-Forwarded-For`, then the client IP is empty.
|
||||||
- `depth` is ignored if its value is less than or equal to 0.
|
- `depth` is ignored if its value is less than or equal to 0.
|
||||||
|
|
||||||
|
If `ipStrategy.ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||||
|
See [ipStrategy.ipv6Subnet](#ipstrategyipv6subnet) for more details.
|
||||||
|
|
||||||
!!! example "Example of Depth & X-Forwarded-For"
|
!!! example "Example of Depth & X-Forwarded-For"
|
||||||
|
|
||||||
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used as the criterion is `"12.0.0.1"` (`depth=2`).
|
If `depth` is set to 2, and the request `X-Forwarded-For` header is `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` then the "real" client IP is `"10.0.0.1"` (at depth 4) but the IP used as the criterion is `"12.0.0.1"` (`depth=2`).
|
||||||
|
@ -355,6 +358,63 @@ http:
|
||||||
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
excludedIPs = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### `ipStrategy.ipv6Subnet`
|
||||||
|
|
||||||
|
This strategy applies to `Depth` and `RemoteAddr` strategy only.
|
||||||
|
If `ipv6Subnet` is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to.
|
||||||
|
|
||||||
|
This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6.
|
||||||
|
|
||||||
|
- `ipv6Subnet` is ignored if its value is outside of 0-128 interval
|
||||||
|
|
||||||
|
!!! example "Example of ipv6Subnet"
|
||||||
|
|
||||||
|
If `ipv6Subnet` is provided, the IP is transformed in the following way.
|
||||||
|
|
||||||
|
| `IP` | `ipv6Subnet` | clientIP |
|
||||||
|
|---------------------------|--------------|-----------------------|
|
||||||
|
| `"::abcd:1111:2222:3333"` | `64` | `"::0:0:0:0"` |
|
||||||
|
| `"::abcd:1111:2222:3333"` | `80` | `"::abcd:0:0:0:0"` |
|
||||||
|
| `"::abcd:1111:2222:3333"` | `96` | `"::abcd:1111:0:0:0"` |
|
||||||
|
|
||||||
|
```yaml tab="Docker & Swarm"
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: test-ratelimit
|
||||||
|
spec:
|
||||||
|
ratelimit:
|
||||||
|
sourceCriterion:
|
||||||
|
ipStrategy:
|
||||||
|
ipv6Subnet: 64
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Consul Catalog"
|
||||||
|
- "traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.ipstrategy.ipv6Subnet=64"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
test-ratelimit:
|
||||||
|
ratelimit:
|
||||||
|
sourceCriterion:
|
||||||
|
ipStrategy:
|
||||||
|
ipv6Subnet: 64
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-ratelimit.ratelimit]
|
||||||
|
[http.middlewares.test-ratelimit.ratelimit.sourceCriterion.ipStrategy]
|
||||||
|
ipv6Subnet = 64
|
||||||
|
```
|
||||||
|
|
||||||
#### `sourceCriterion.requestHeaderName`
|
#### `sourceCriterion.requestHeaderName`
|
||||||
|
|
||||||
Name of the header used to group incoming requests.
|
Name of the header used to group incoming requests.
|
||||||
|
|
|
@ -85,15 +85,18 @@
|
||||||
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy=true"
|
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy=true"
|
||||||
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.depth=42"
|
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.depth=42"
|
||||||
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.excludedips=foobar, foobar"
|
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.excludedips=foobar, foobar"
|
||||||
|
- "traefik.http.middlewares.middleware13.ipallowlist.ipstrategy.ipv6subnet=42"
|
||||||
- "traefik.http.middlewares.middleware13.ipallowlist.rejectstatuscode=42"
|
- "traefik.http.middlewares.middleware13.ipallowlist.rejectstatuscode=42"
|
||||||
- "traefik.http.middlewares.middleware13.ipallowlist.sourcerange=foobar, foobar"
|
- "traefik.http.middlewares.middleware13.ipallowlist.sourcerange=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy=true"
|
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy=true"
|
||||||
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.depth=42"
|
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.depth=42"
|
||||||
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.excludedips=foobar, foobar"
|
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.excludedips=foobar, foobar"
|
||||||
|
- "traefik.http.middlewares.middleware14.ipwhitelist.ipstrategy.ipv6subnet=42"
|
||||||
- "traefik.http.middlewares.middleware14.ipwhitelist.sourcerange=foobar, foobar"
|
- "traefik.http.middlewares.middleware14.ipwhitelist.sourcerange=foobar, foobar"
|
||||||
- "traefik.http.middlewares.middleware15.inflightreq.amount=42"
|
- "traefik.http.middlewares.middleware15.inflightreq.amount=42"
|
||||||
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.depth=42"
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.depth=42"
|
||||||
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
||||||
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.ipstrategy.ipv6subnet=42"
|
||||||
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.requestheadername=foobar"
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.requestheadername=foobar"
|
||||||
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.requesthost=true"
|
- "traefik.http.middlewares.middleware15.inflightreq.sourcecriterion.requesthost=true"
|
||||||
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.commonname=true"
|
- "traefik.http.middlewares.middleware16.passtlsclientcert.info.issuer.commonname=true"
|
||||||
|
@ -125,6 +128,7 @@
|
||||||
- "traefik.http.middlewares.middleware18.ratelimit.period=42s"
|
- "traefik.http.middlewares.middleware18.ratelimit.period=42s"
|
||||||
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.depth=42"
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.depth=42"
|
||||||
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.excludedips=foobar, foobar"
|
||||||
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.ipstrategy.ipv6subnet=42"
|
||||||
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.requestheadername=foobar"
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.requestheadername=foobar"
|
||||||
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.requesthost=true"
|
- "traefik.http.middlewares.middleware18.ratelimit.sourcecriterion.requesthost=true"
|
||||||
- "traefik.http.middlewares.middleware19.redirectregex.permanent=true"
|
- "traefik.http.middlewares.middleware19.redirectregex.permanent=true"
|
||||||
|
|
|
@ -227,12 +227,14 @@
|
||||||
[http.middlewares.Middleware13.ipAllowList.ipStrategy]
|
[http.middlewares.Middleware13.ipAllowList.ipStrategy]
|
||||||
depth = 42
|
depth = 42
|
||||||
excludedIPs = ["foobar", "foobar"]
|
excludedIPs = ["foobar", "foobar"]
|
||||||
|
ipv6Subnet = 42
|
||||||
[http.middlewares.Middleware14]
|
[http.middlewares.Middleware14]
|
||||||
[http.middlewares.Middleware14.ipWhiteList]
|
[http.middlewares.Middleware14.ipWhiteList]
|
||||||
sourceRange = ["foobar", "foobar"]
|
sourceRange = ["foobar", "foobar"]
|
||||||
[http.middlewares.Middleware14.ipWhiteList.ipStrategy]
|
[http.middlewares.Middleware14.ipWhiteList.ipStrategy]
|
||||||
depth = 42
|
depth = 42
|
||||||
excludedIPs = ["foobar", "foobar"]
|
excludedIPs = ["foobar", "foobar"]
|
||||||
|
ipv6Subnet = 42
|
||||||
[http.middlewares.Middleware15]
|
[http.middlewares.Middleware15]
|
||||||
[http.middlewares.Middleware15.inFlightReq]
|
[http.middlewares.Middleware15.inFlightReq]
|
||||||
amount = 42
|
amount = 42
|
||||||
|
@ -242,6 +244,7 @@
|
||||||
[http.middlewares.Middleware15.inFlightReq.sourceCriterion.ipStrategy]
|
[http.middlewares.Middleware15.inFlightReq.sourceCriterion.ipStrategy]
|
||||||
depth = 42
|
depth = 42
|
||||||
excludedIPs = ["foobar", "foobar"]
|
excludedIPs = ["foobar", "foobar"]
|
||||||
|
ipv6Subnet = 42
|
||||||
[http.middlewares.Middleware16]
|
[http.middlewares.Middleware16]
|
||||||
[http.middlewares.Middleware16.passTLSClientCert]
|
[http.middlewares.Middleware16.passTLSClientCert]
|
||||||
pem = true
|
pem = true
|
||||||
|
@ -286,6 +289,7 @@
|
||||||
[http.middlewares.Middleware18.rateLimit.sourceCriterion.ipStrategy]
|
[http.middlewares.Middleware18.rateLimit.sourceCriterion.ipStrategy]
|
||||||
depth = 42
|
depth = 42
|
||||||
excludedIPs = ["foobar", "foobar"]
|
excludedIPs = ["foobar", "foobar"]
|
||||||
|
ipv6Subnet = 42
|
||||||
[http.middlewares.Middleware19]
|
[http.middlewares.Middleware19]
|
||||||
[http.middlewares.Middleware19.redirectRegex]
|
[http.middlewares.Middleware19.redirectRegex]
|
||||||
regex = "foobar"
|
regex = "foobar"
|
||||||
|
|
|
@ -267,6 +267,7 @@ http:
|
||||||
excludedIPs:
|
excludedIPs:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
|
ipv6Subnet: 42
|
||||||
rejectStatusCode: 42
|
rejectStatusCode: 42
|
||||||
Middleware14:
|
Middleware14:
|
||||||
ipWhiteList:
|
ipWhiteList:
|
||||||
|
@ -278,6 +279,7 @@ http:
|
||||||
excludedIPs:
|
excludedIPs:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
|
ipv6Subnet: 42
|
||||||
Middleware15:
|
Middleware15:
|
||||||
inFlightReq:
|
inFlightReq:
|
||||||
amount: 42
|
amount: 42
|
||||||
|
@ -287,6 +289,7 @@ http:
|
||||||
excludedIPs:
|
excludedIPs:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
|
ipv6Subnet: 42
|
||||||
requestHeaderName: foobar
|
requestHeaderName: foobar
|
||||||
requestHost: true
|
requestHost: true
|
||||||
Middleware16:
|
Middleware16:
|
||||||
|
@ -333,6 +336,7 @@ http:
|
||||||
excludedIPs:
|
excludedIPs:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
|
ipv6Subnet: 42
|
||||||
requestHeaderName: foobar
|
requestHeaderName: foobar
|
||||||
requestHost: true
|
requestHost: true
|
||||||
Middleware19:
|
Middleware19:
|
||||||
|
|
|
@ -1458,6 +1458,12 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider
|
||||||
|
all IPv6 addresses from the defined subnet as originating
|
||||||
|
from the same IP. Applies to RemoteAddrStrategy and
|
||||||
|
DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
requestHeaderName:
|
requestHeaderName:
|
||||||
description: RequestHeaderName defines the name of the header
|
description: RequestHeaderName defines the name of the header
|
||||||
|
@ -1491,6 +1497,11 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider all
|
||||||
|
IPv6 addresses from the defined subnet as originating from
|
||||||
|
the same IP. Applies to RemoteAddrStrategy and DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
rejectStatusCode:
|
rejectStatusCode:
|
||||||
description: |-
|
description: |-
|
||||||
|
@ -1523,6 +1534,11 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider all
|
||||||
|
IPv6 addresses from the defined subnet as originating from
|
||||||
|
the same IP. Applies to RemoteAddrStrategy and DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
sourceRange:
|
sourceRange:
|
||||||
description: SourceRange defines the set of allowed IPs (or ranges
|
description: SourceRange defines the set of allowed IPs (or ranges
|
||||||
|
@ -1691,6 +1707,12 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider
|
||||||
|
all IPv6 addresses from the defined subnet as originating
|
||||||
|
from the same IP. Applies to RemoteAddrStrategy and
|
||||||
|
DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
requestHeaderName:
|
requestHeaderName:
|
||||||
description: RequestHeaderName defines the name of the header
|
description: RequestHeaderName defines the name of the header
|
||||||
|
|
|
@ -103,18 +103,21 @@ THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/depth` | `42` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/depth` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/excludedIPs/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/excludedIPs/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/excludedIPs/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/excludedIPs/1` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware13/ipAllowList/ipStrategy/ipv6Subnet` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware13/ipAllowList/rejectStatusCode` | `42` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/rejectStatusCode` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware13/ipAllowList/sourceRange/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/sourceRange/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware13/ipAllowList/sourceRange/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware13/ipAllowList/sourceRange/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/depth` | `42` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/depth` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/excludedIPs/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/excludedIPs/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/excludedIPs/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/excludedIPs/1` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/ipStrategy/ipv6Subnet` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware14/ipWhiteList/sourceRange/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/sourceRange/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware14/ipWhiteList/sourceRange/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware14/ipWhiteList/sourceRange/1` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware15/inFlightReq/amount` | `42` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/amount` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/depth` | `42` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/depth` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/ipStrategy/ipv6Subnet` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/requestHeaderName` | `foobar` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/requestHeaderName` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/requestHost` | `true` |
|
| `traefik/http/middlewares/Middleware15/inFlightReq/sourceCriterion/requestHost` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/commonName` | `true` |
|
| `traefik/http/middlewares/Middleware16/passTLSClientCert/info/issuer/commonName` | `true` |
|
||||||
|
@ -147,6 +150,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/depth` | `42` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/depth` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/excludedIPs/0` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/excludedIPs/1` | `foobar` |
|
||||||
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/ipStrategy/ipv6Subnet` | `42` |
|
||||||
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/requestHeaderName` | `foobar` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/requestHeaderName` | `foobar` |
|
||||||
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/requestHost` | `true` |
|
| `traefik/http/middlewares/Middleware18/rateLimit/sourceCriterion/requestHost` | `true` |
|
||||||
| `traefik/http/middlewares/Middleware19/redirectRegex/permanent` | `true` |
|
| `traefik/http/middlewares/Middleware19/redirectRegex/permanent` | `true` |
|
||||||
|
|
|
@ -734,6 +734,12 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider
|
||||||
|
all IPv6 addresses from the defined subnet as originating
|
||||||
|
from the same IP. Applies to RemoteAddrStrategy and
|
||||||
|
DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
requestHeaderName:
|
requestHeaderName:
|
||||||
description: RequestHeaderName defines the name of the header
|
description: RequestHeaderName defines the name of the header
|
||||||
|
@ -767,6 +773,11 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider all
|
||||||
|
IPv6 addresses from the defined subnet as originating from
|
||||||
|
the same IP. Applies to RemoteAddrStrategy and DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
rejectStatusCode:
|
rejectStatusCode:
|
||||||
description: |-
|
description: |-
|
||||||
|
@ -799,6 +810,11 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider all
|
||||||
|
IPv6 addresses from the defined subnet as originating from
|
||||||
|
the same IP. Applies to RemoteAddrStrategy and DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
sourceRange:
|
sourceRange:
|
||||||
description: SourceRange defines the set of allowed IPs (or ranges
|
description: SourceRange defines the set of allowed IPs (or ranges
|
||||||
|
@ -967,6 +983,12 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider
|
||||||
|
all IPv6 addresses from the defined subnet as originating
|
||||||
|
from the same IP. Applies to RemoteAddrStrategy and
|
||||||
|
DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
requestHeaderName:
|
requestHeaderName:
|
||||||
description: RequestHeaderName defines the name of the header
|
description: RequestHeaderName defines the name of the header
|
||||||
|
|
|
@ -1458,6 +1458,12 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider
|
||||||
|
all IPv6 addresses from the defined subnet as originating
|
||||||
|
from the same IP. Applies to RemoteAddrStrategy and
|
||||||
|
DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
requestHeaderName:
|
requestHeaderName:
|
||||||
description: RequestHeaderName defines the name of the header
|
description: RequestHeaderName defines the name of the header
|
||||||
|
@ -1491,6 +1497,11 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider all
|
||||||
|
IPv6 addresses from the defined subnet as originating from
|
||||||
|
the same IP. Applies to RemoteAddrStrategy and DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
rejectStatusCode:
|
rejectStatusCode:
|
||||||
description: |-
|
description: |-
|
||||||
|
@ -1523,6 +1534,11 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider all
|
||||||
|
IPv6 addresses from the defined subnet as originating from
|
||||||
|
the same IP. Applies to RemoteAddrStrategy and DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
sourceRange:
|
sourceRange:
|
||||||
description: SourceRange defines the set of allowed IPs (or ranges
|
description: SourceRange defines the set of allowed IPs (or ranges
|
||||||
|
@ -1691,6 +1707,12 @@ spec:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
ipv6Subnet:
|
||||||
|
description: IPv6Subnet configures Traefik to consider
|
||||||
|
all IPv6 addresses from the defined subnet as originating
|
||||||
|
from the same IP. Applies to RemoteAddrStrategy and
|
||||||
|
DepthStrategy.
|
||||||
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
requestHeaderName:
|
requestHeaderName:
|
||||||
description: RequestHeaderName defines the name of the header
|
description: RequestHeaderName defines the name of the header
|
||||||
|
|
57
pkg/config/dynamic/middleware_test.go
Normal file
57
pkg/config/dynamic/middleware_test.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package dynamic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_GetStrategy_ipv6Subnet(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
expectError bool
|
||||||
|
ipv6Subnet *int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Nil subnet",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Zero subnet",
|
||||||
|
expectError: true,
|
||||||
|
ipv6Subnet: intPtr(0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Subnet greater that 128",
|
||||||
|
expectError: true,
|
||||||
|
ipv6Subnet: intPtr(129),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Valid subnet",
|
||||||
|
ipv6Subnet: intPtr(128),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
strategy := IPStrategy{
|
||||||
|
IPv6Subnet: test.ipv6Subnet,
|
||||||
|
}
|
||||||
|
|
||||||
|
get, err := strategy.Get()
|
||||||
|
if test.expectError {
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Nil(t, get)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotNil(t, get)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func intPtr(value int) *int {
|
||||||
|
return &value
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package dynamic
|
package dynamic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -405,6 +406,8 @@ type IPStrategy struct {
|
||||||
Depth int `json:"depth,omitempty" toml:"depth,omitempty" yaml:"depth,omitempty" export:"true"`
|
Depth int `json:"depth,omitempty" toml:"depth,omitempty" yaml:"depth,omitempty" export:"true"`
|
||||||
// ExcludedIPs configures Traefik to scan the X-Forwarded-For header and select the first IP not in the list.
|
// ExcludedIPs configures Traefik to scan the X-Forwarded-For header and select the first IP not in the list.
|
||||||
ExcludedIPs []string `json:"excludedIPs,omitempty" toml:"excludedIPs,omitempty" yaml:"excludedIPs,omitempty"`
|
ExcludedIPs []string `json:"excludedIPs,omitempty" toml:"excludedIPs,omitempty" yaml:"excludedIPs,omitempty"`
|
||||||
|
// IPv6Subnet configures Traefik to consider all IPv6 addresses from the defined subnet as originating from the same IP. Applies to RemoteAddrStrategy and DepthStrategy.
|
||||||
|
IPv6Subnet *int `json:"ipv6Subnet,omitempty" toml:"ipv6Subnet,omitempty" yaml:"ipv6Subnet,omitempty"`
|
||||||
// TODO(mpl): I think we should make RemoteAddr an explicit field. For one thing, it would yield better documentation.
|
// TODO(mpl): I think we should make RemoteAddr an explicit field. For one thing, it would yield better documentation.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,8 +421,13 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Depth > 0 {
|
if s.Depth > 0 {
|
||||||
|
if s.IPv6Subnet != nil && (*s.IPv6Subnet <= 0 || *s.IPv6Subnet > 128) {
|
||||||
|
return nil, fmt.Errorf("invalid IPv6 subnet %d value, should be greater to 0 and lower or equal to 128", *s.IPv6Subnet)
|
||||||
|
}
|
||||||
|
|
||||||
return &ip.DepthStrategy{
|
return &ip.DepthStrategy{
|
||||||
Depth: s.Depth,
|
Depth: s.Depth,
|
||||||
|
IPv6Subnet: s.IPv6Subnet,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +441,13 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ip.RemoteAddrStrategy{}, nil
|
if s.IPv6Subnet != nil && (*s.IPv6Subnet <= 0 || *s.IPv6Subnet > 128) {
|
||||||
|
return nil, fmt.Errorf("invalid IPv6 subnet %d value, should be greater to 0 and lower or equal to 128", *s.IPv6Subnet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ip.RemoteAddrStrategy{
|
||||||
|
IPv6Subnet: s.IPv6Subnet,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
|
@ -704,6 +704,11 @@ func (in *IPStrategy) DeepCopyInto(out *IPStrategy) {
|
||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
|
if in.IPv6Subnet != nil {
|
||||||
|
in, out := &in.IPv6Subnet, &out.IPv6Subnet
|
||||||
|
*out = new(int)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,10 +90,12 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
"traefik.http.middlewares.Middleware8.headers.stsseconds": "42",
|
"traefik.http.middlewares.Middleware8.headers.stsseconds": "42",
|
||||||
"traefik.http.middlewares.Middleware9.ipallowlist.ipstrategy.depth": "42",
|
"traefik.http.middlewares.Middleware9.ipallowlist.ipstrategy.depth": "42",
|
||||||
"traefik.http.middlewares.Middleware9.ipallowlist.ipstrategy.excludedips": "foobar, fiibar",
|
"traefik.http.middlewares.Middleware9.ipallowlist.ipstrategy.excludedips": "foobar, fiibar",
|
||||||
|
"traefik.http.middlewares.Middleware9.ipallowlist.ipstrategy.ipv6subnet": "42",
|
||||||
"traefik.http.middlewares.Middleware9.ipallowlist.sourcerange": "foobar, fiibar",
|
"traefik.http.middlewares.Middleware9.ipallowlist.sourcerange": "foobar, fiibar",
|
||||||
"traefik.http.middlewares.Middleware10.inflightreq.amount": "42",
|
"traefik.http.middlewares.Middleware10.inflightreq.amount": "42",
|
||||||
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.ipstrategy.depth": "42",
|
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.ipstrategy.depth": "42",
|
||||||
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.ipstrategy.excludedips": "foobar, fiibar",
|
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.ipstrategy.excludedips": "foobar, fiibar",
|
||||||
|
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.ipstrategy.ipv6subnet": "42",
|
||||||
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.requestheadername": "foobar",
|
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.requestheadername": "foobar",
|
||||||
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.requesthost": "true",
|
"traefik.http.middlewares.Middleware10.inflightreq.sourcecriterion.requesthost": "true",
|
||||||
"traefik.http.middlewares.Middleware11.passtlsclientcert.info.notafter": "true",
|
"traefik.http.middlewares.Middleware11.passtlsclientcert.info.notafter": "true",
|
||||||
|
@ -123,6 +125,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
"traefik.http.middlewares.Middleware12.ratelimit.sourcecriterion.requesthost": "true",
|
"traefik.http.middlewares.Middleware12.ratelimit.sourcecriterion.requesthost": "true",
|
||||||
"traefik.http.middlewares.Middleware12.ratelimit.sourcecriterion.ipstrategy.depth": "42",
|
"traefik.http.middlewares.Middleware12.ratelimit.sourcecriterion.ipstrategy.depth": "42",
|
||||||
"traefik.http.middlewares.Middleware12.ratelimit.sourcecriterion.ipstrategy.excludedips": "foobar, foobar",
|
"traefik.http.middlewares.Middleware12.ratelimit.sourcecriterion.ipstrategy.excludedips": "foobar, foobar",
|
||||||
|
"traefik.http.middlewares.Middleware12.ratelimit.sourcecriterion.ipstrategy.ipv6subnet": "42",
|
||||||
"traefik.http.middlewares.Middleware13.redirectregex.permanent": "true",
|
"traefik.http.middlewares.Middleware13.redirectregex.permanent": "true",
|
||||||
"traefik.http.middlewares.Middleware13.redirectregex.regex": "foobar",
|
"traefik.http.middlewares.Middleware13.redirectregex.regex": "foobar",
|
||||||
"traefik.http.middlewares.Middleware13.redirectregex.replacement": "foobar",
|
"traefik.http.middlewares.Middleware13.redirectregex.replacement": "foobar",
|
||||||
|
@ -392,6 +395,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
IPStrategy: &dynamic.IPStrategy{
|
IPStrategy: &dynamic.IPStrategy{
|
||||||
Depth: 42,
|
Depth: 42,
|
||||||
ExcludedIPs: []string{"foobar", "fiibar"},
|
ExcludedIPs: []string{"foobar", "fiibar"},
|
||||||
|
IPv6Subnet: intPtr(42),
|
||||||
},
|
},
|
||||||
RequestHeaderName: "foobar",
|
RequestHeaderName: "foobar",
|
||||||
RequestHost: true,
|
RequestHost: true,
|
||||||
|
@ -437,6 +441,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
IPStrategy: &dynamic.IPStrategy{
|
IPStrategy: &dynamic.IPStrategy{
|
||||||
Depth: 42,
|
Depth: 42,
|
||||||
ExcludedIPs: []string{"foobar", "foobar"},
|
ExcludedIPs: []string{"foobar", "foobar"},
|
||||||
|
IPv6Subnet: intPtr(42),
|
||||||
},
|
},
|
||||||
RequestHeaderName: "foobar",
|
RequestHeaderName: "foobar",
|
||||||
RequestHost: true,
|
RequestHost: true,
|
||||||
|
@ -648,6 +653,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
"foobar",
|
"foobar",
|
||||||
"fiibar",
|
"fiibar",
|
||||||
},
|
},
|
||||||
|
IPv6Subnet: intPtr(42),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -913,6 +919,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
IPStrategy: &dynamic.IPStrategy{
|
IPStrategy: &dynamic.IPStrategy{
|
||||||
Depth: 42,
|
Depth: 42,
|
||||||
ExcludedIPs: []string{"foobar", "fiibar"},
|
ExcludedIPs: []string{"foobar", "fiibar"},
|
||||||
|
IPv6Subnet: intPtr(42),
|
||||||
},
|
},
|
||||||
RequestHeaderName: "foobar",
|
RequestHeaderName: "foobar",
|
||||||
RequestHost: true,
|
RequestHost: true,
|
||||||
|
@ -957,6 +964,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
IPStrategy: &dynamic.IPStrategy{
|
IPStrategy: &dynamic.IPStrategy{
|
||||||
Depth: 42,
|
Depth: 42,
|
||||||
ExcludedIPs: []string{"foobar", "foobar"},
|
ExcludedIPs: []string{"foobar", "foobar"},
|
||||||
|
IPv6Subnet: intPtr(42),
|
||||||
},
|
},
|
||||||
RequestHeaderName: "foobar",
|
RequestHeaderName: "foobar",
|
||||||
RequestHost: true,
|
RequestHost: true,
|
||||||
|
@ -1176,6 +1184,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
"foobar",
|
"foobar",
|
||||||
"fiibar",
|
"fiibar",
|
||||||
},
|
},
|
||||||
|
IPv6Subnet: intPtr(42),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1338,11 +1347,13 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
"traefik.HTTP.Middlewares.Middleware8.Headers.STSSeconds": "42",
|
"traefik.HTTP.Middlewares.Middleware8.Headers.STSSeconds": "42",
|
||||||
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.IPStrategy.Depth": "42",
|
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.IPStrategy.Depth": "42",
|
||||||
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.IPStrategy.ExcludedIPs": "foobar, fiibar",
|
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.IPStrategy.ExcludedIPs": "foobar, fiibar",
|
||||||
|
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.IPStrategy.IPv6Subnet": "42",
|
||||||
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.RejectStatusCode": "0",
|
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.RejectStatusCode": "0",
|
||||||
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.SourceRange": "foobar, fiibar",
|
"traefik.HTTP.Middlewares.Middleware9.IPAllowList.SourceRange": "foobar, fiibar",
|
||||||
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.Amount": "42",
|
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.Amount": "42",
|
||||||
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.IPStrategy.Depth": "42",
|
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.IPStrategy.Depth": "42",
|
||||||
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.IPStrategy.ExcludedIPs": "foobar, fiibar",
|
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.IPStrategy.ExcludedIPs": "foobar, fiibar",
|
||||||
|
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.IPStrategy.IPv6Subnet": "42",
|
||||||
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.RequestHeaderName": "foobar",
|
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.RequestHeaderName": "foobar",
|
||||||
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.RequestHost": "true",
|
"traefik.HTTP.Middlewares.Middleware10.InFlightReq.SourceCriterion.RequestHost": "true",
|
||||||
"traefik.HTTP.Middlewares.Middleware11.PassTLSClientCert.Info.NotAfter": "true",
|
"traefik.HTTP.Middlewares.Middleware11.PassTLSClientCert.Info.NotAfter": "true",
|
||||||
|
@ -1372,6 +1383,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
"traefik.HTTP.Middlewares.Middleware12.RateLimit.SourceCriterion.RequestHost": "true",
|
"traefik.HTTP.Middlewares.Middleware12.RateLimit.SourceCriterion.RequestHost": "true",
|
||||||
"traefik.HTTP.Middlewares.Middleware12.RateLimit.SourceCriterion.IPStrategy.Depth": "42",
|
"traefik.HTTP.Middlewares.Middleware12.RateLimit.SourceCriterion.IPStrategy.Depth": "42",
|
||||||
"traefik.HTTP.Middlewares.Middleware12.RateLimit.SourceCriterion.IPStrategy.ExcludedIPs": "foobar, foobar",
|
"traefik.HTTP.Middlewares.Middleware12.RateLimit.SourceCriterion.IPStrategy.ExcludedIPs": "foobar, foobar",
|
||||||
|
"traefik.HTTP.Middlewares.Middleware12.RateLimit.SourceCriterion.IPStrategy.IPv6Subnet": "42",
|
||||||
"traefik.HTTP.Middlewares.Middleware13.RedirectRegex.Regex": "foobar",
|
"traefik.HTTP.Middlewares.Middleware13.RedirectRegex.Regex": "foobar",
|
||||||
"traefik.HTTP.Middlewares.Middleware13.RedirectRegex.Replacement": "foobar",
|
"traefik.HTTP.Middlewares.Middleware13.RedirectRegex.Replacement": "foobar",
|
||||||
"traefik.HTTP.Middlewares.Middleware13.RedirectRegex.Permanent": "true",
|
"traefik.HTTP.Middlewares.Middleware13.RedirectRegex.Permanent": "true",
|
||||||
|
@ -1486,3 +1498,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected, labels)
|
assert.Equal(t, expected, labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func intPtr(value int) *int {
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ip
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,7 +17,10 @@ type Strategy interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteAddrStrategy a strategy that always return the remote address.
|
// RemoteAddrStrategy a strategy that always return the remote address.
|
||||||
type RemoteAddrStrategy struct{}
|
type RemoteAddrStrategy struct {
|
||||||
|
// IPv6Subnet instructs the strategy to return the first IP of the subnet where IP belongs.
|
||||||
|
IPv6Subnet *int
|
||||||
|
}
|
||||||
|
|
||||||
// GetIP returns the selected IP.
|
// GetIP returns the selected IP.
|
||||||
func (s *RemoteAddrStrategy) GetIP(req *http.Request) string {
|
func (s *RemoteAddrStrategy) GetIP(req *http.Request) string {
|
||||||
|
@ -24,15 +28,22 @@ func (s *RemoteAddrStrategy) GetIP(req *http.Request) string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return req.RemoteAddr
|
return req.RemoteAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.IPv6Subnet != nil {
|
||||||
|
return getIPv6SubnetIP(ip, *s.IPv6Subnet)
|
||||||
|
}
|
||||||
|
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
|
||||||
// DepthStrategy a strategy based on the depth inside the X-Forwarded-For from right to left.
|
// DepthStrategy a strategy based on the depth inside the X-Forwarded-For from right to left.
|
||||||
type DepthStrategy struct {
|
type DepthStrategy struct {
|
||||||
Depth int
|
Depth int
|
||||||
|
// IPv6Subnet instructs the strategy to return the first IP of the subnet where IP belongs.
|
||||||
|
IPv6Subnet *int
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIP return the selected IP.
|
// GetIP returns the selected IP.
|
||||||
func (s *DepthStrategy) GetIP(req *http.Request) string {
|
func (s *DepthStrategy) GetIP(req *http.Request) string {
|
||||||
xff := req.Header.Get(xForwardedFor)
|
xff := req.Header.Get(xForwardedFor)
|
||||||
xffs := strings.Split(xff, ",")
|
xffs := strings.Split(xff, ",")
|
||||||
|
@ -40,7 +51,14 @@ func (s *DepthStrategy) GetIP(req *http.Request) string {
|
||||||
if len(xffs) < s.Depth {
|
if len(xffs) < s.Depth {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(xffs[len(xffs)-s.Depth])
|
|
||||||
|
ip := strings.TrimSpace(xffs[len(xffs)-s.Depth])
|
||||||
|
|
||||||
|
if s.IPv6Subnet != nil {
|
||||||
|
return getIPv6SubnetIP(ip, *s.IPv6Subnet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip
|
||||||
}
|
}
|
||||||
|
|
||||||
// PoolStrategy is a strategy based on an IP Checker.
|
// PoolStrategy is a strategy based on an IP Checker.
|
||||||
|
@ -72,3 +90,23 @@ func (s *PoolStrategy) GetIP(req *http.Request) string {
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getIPv6SubnetIP returns the IPv6 subnet IP.
|
||||||
|
// It returns the original IP when it is not an IPv6, or if parsing the IP has failed with an error.
|
||||||
|
func getIPv6SubnetIP(ip string, ipv6Subnet int) string {
|
||||||
|
addr, err := netip.ParseAddr(ip)
|
||||||
|
if err != nil {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
if !addr.Is6() {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix, err := addr.Prefix(ipv6Subnet)
|
||||||
|
if err != nil {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix.Addr().String()
|
||||||
|
}
|
||||||
|
|
|
@ -9,23 +9,81 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ipv6Basic = "::abcd:ffff:c0a8:1"
|
||||||
|
ipv6BracketsPort = "[::abcd:ffff:c0a8:1]:80"
|
||||||
|
ipv6BracketsZonePort = "[::abcd:ffff:c0a8:1%1]:80"
|
||||||
|
)
|
||||||
|
|
||||||
func TestRemoteAddrStrategy_GetIP(t *testing.T) {
|
func TestRemoteAddrStrategy_GetIP(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
expected string
|
expected string
|
||||||
|
remoteAddr string
|
||||||
|
ipv6Subnet *int
|
||||||
}{
|
}{
|
||||||
|
// Valid IP format
|
||||||
{
|
{
|
||||||
desc: "Use RemoteAddr",
|
desc: "Use RemoteAddr, ipv4",
|
||||||
expected: "192.0.2.1",
|
expected: "192.0.2.1",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Use RemoteAddr, ipv6 brackets with port, no IPv6 subnet",
|
||||||
|
remoteAddr: ipv6BracketsPort,
|
||||||
|
expected: "::abcd:ffff:c0a8:1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Use RemoteAddr, ipv6 brackets with zone and port, no IPv6 subnet",
|
||||||
|
remoteAddr: ipv6BracketsZonePort,
|
||||||
|
expected: "::abcd:ffff:c0a8:1%1",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Invalid IPv6 format
|
||||||
|
{
|
||||||
|
desc: "Use RemoteAddr, ipv6 basic, missing brackets, no IPv6 subnet",
|
||||||
|
remoteAddr: ipv6Basic,
|
||||||
|
expected: ipv6Basic,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Valid IP format with subnet
|
||||||
|
{
|
||||||
|
desc: "Use RemoteAddr, ipv4, ignore subnet",
|
||||||
|
expected: "192.0.2.1",
|
||||||
|
ipv6Subnet: intPtr(24),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Use RemoteAddr, ipv6 brackets with port, subnet",
|
||||||
|
remoteAddr: ipv6BracketsPort,
|
||||||
|
expected: "::abcd:0:0:0",
|
||||||
|
ipv6Subnet: intPtr(80),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Use RemoteAddr, ipv6 brackets with zone and port, subnet",
|
||||||
|
remoteAddr: ipv6BracketsZonePort,
|
||||||
|
expected: "::abcd:0:0:0",
|
||||||
|
ipv6Subnet: intPtr(80),
|
||||||
|
},
|
||||||
|
|
||||||
|
// Valid IP, invalid subnet
|
||||||
|
{
|
||||||
|
desc: "Use RemoteAddr, ipv6 brackets with port, invalid subnet",
|
||||||
|
remoteAddr: ipv6BracketsPort,
|
||||||
|
expected: "::abcd:ffff:c0a8:1",
|
||||||
|
ipv6Subnet: intPtr(500),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
strategy := RemoteAddrStrategy{}
|
strategy := RemoteAddrStrategy{
|
||||||
|
IPv6Subnet: test.ipv6Subnet,
|
||||||
|
}
|
||||||
req := httptest.NewRequest(http.MethodGet, "http://127.0.0.1", nil)
|
req := httptest.NewRequest(http.MethodGet, "http://127.0.0.1", nil)
|
||||||
|
if test.remoteAddr != "" {
|
||||||
|
req.RemoteAddr = test.remoteAddr
|
||||||
|
}
|
||||||
actual := strategy.GetIP(req)
|
actual := strategy.GetIP(req)
|
||||||
assert.Equal(t, test.expected, actual)
|
assert.Equal(t, test.expected, actual)
|
||||||
})
|
})
|
||||||
|
@ -38,6 +96,7 @@ func TestDepthStrategy_GetIP(t *testing.T) {
|
||||||
depth int
|
depth int
|
||||||
xForwardedFor string
|
xForwardedFor string
|
||||||
expected string
|
expected string
|
||||||
|
ipv6Subnet *int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Use depth",
|
desc: "Use depth",
|
||||||
|
@ -57,13 +116,30 @@ func TestDepthStrategy_GetIP(t *testing.T) {
|
||||||
xForwardedFor: "10.0.0.2,10.0.0.1",
|
xForwardedFor: "10.0.0.2,10.0.0.1",
|
||||||
expected: "10.0.0.2",
|
expected: "10.0.0.2",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Use depth with IPv4 subnet",
|
||||||
|
depth: 2,
|
||||||
|
xForwardedFor: "10.0.0.3,10.0.0.2,10.0.0.1",
|
||||||
|
expected: "10.0.0.2",
|
||||||
|
ipv6Subnet: intPtr(80),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Use depth with IPv6 subnet",
|
||||||
|
depth: 2,
|
||||||
|
xForwardedFor: "10.0.0.3," + ipv6Basic + ",10.0.0.1",
|
||||||
|
expected: "::abcd:0:0:0",
|
||||||
|
ipv6Subnet: intPtr(80),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
strategy := DepthStrategy{Depth: test.depth}
|
strategy := DepthStrategy{
|
||||||
|
Depth: test.depth,
|
||||||
|
IPv6Subnet: test.ipv6Subnet,
|
||||||
|
}
|
||||||
req := httptest.NewRequest(http.MethodGet, "http://127.0.0.1", nil)
|
req := httptest.NewRequest(http.MethodGet, "http://127.0.0.1", nil)
|
||||||
req.Header.Set(xForwardedFor, test.xForwardedFor)
|
req.Header.Set(xForwardedFor, test.xForwardedFor)
|
||||||
actual := strategy.GetIP(req)
|
actual := strategy.GetIP(req)
|
||||||
|
@ -121,3 +197,7 @@ func TestTrustedIPsStrategy_GetIP(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func intPtr(value int) *int {
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue