# IP and country rules

> Allow or block single addresses, CIDR ranges and countries at the edge, for a whole zone or only for some of its names.

IP and country rules are edge rules of kind `ip` and `geo`. They apply in every [WAF mode](https://developers.openwaf.dev/waf/modes-and-levels/#modes), before rate limits and the WAF.

## IP rules

| Field | Value |
|---|---|
| `ip` | An IPv4 or IPv6 address (`203.0.113.7`, `2001:db8::1`) or a CIDR range (`203.0.113.0/24`, `2001:db8::/32`). Stored in canonical form. |
| `action` | `block`: answer 403. `allow`: skip [threat feeds](https://developers.openwaf.dev/waf/threat-feeds/) and country rules for this address. |

An `allow` rule does **not** skip rate limits, the WAF, the shields or AI Crawl Control. Avoid overlapping rules with different actions for the same address.

## Country rules

| Field | Value |
|---|---|
| `country_code` | ISO 3166-1 alpha-2 code, e.g. `RU`. Stored in upper case. |
| `action` | `block`: answer 403 to visitors from that country. `allow`: never block that country with a country rule. |

A country rule only acts on the country it names: an `allow` rule does not block the other countries. To keep a site to a few countries, add `block` rules for the countries you don't want. Visitors whose country can't be determined are never blocked by a country rule.

## Add a rule

**Dashboard**

Domain → **Security → Firewall → Rules**: **IP rules → Add IP rule** or **Countries → Add country rule**. Choose the **Action**, optionally the names it **Applies to**, and a **Note**.
**CLI**

```sh
openwaf-cloud ctl rules add example.com kind=ip ip=203.0.113.0/24 action=block note="Scanner" --reason "Block scanner network"
openwaf-cloud ctl rules add example.com kind=geo country_code=KP action=block --reason "No customers there"
openwaf-cloud ctl rules add example.com kind=ip ip=198.51.100.10 action=allow hosts:='["admin.example.com"]' --reason "Office IP"
openwaf-cloud ctl rules list example.com
openwaf-cloud ctl rules rm example.com 42 --reason "Scanner gone"
```
**API**

```sh
curl -sS -X POST "https://dash.openwaf.dev/v1/orgs/$ORG/zones/example.com/rules" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Block scanner network" \
  -H "Content-Type: application/json" \
  -d '{"kind": "ip", "ip": "203.0.113.0/24", "action": "block", "note": "Scanner"}'
```
Remove a rule with `DELETE /v1/orgs/{org}/zones/{zone}/rules/{rule}` and the same `X-Change-Reason` header.
**MCP**

`add_rule` with `{"zone": "example.com", "kind": "ip", "ip": "203.0.113.0/24", "action": "block", "reason": "…"}`; `list_rules` shows the ids and `remove_rule` deletes one. Both simulate first.


Blocked requests appear in [security events](https://developers.openwaf.dev/analytics/security-events/) as `IP Rule` or `Geo Block`.
