# Your first rules

> Write a first moat ruleset for a web server: bogon sources, a SYN flood rate limit per /24 and a ban list, then check and format it with moat check and moat fmt.

Source: https://moatfw.dev/docs/first-rules

A moat file is a list of declarations: the language version, the default
verdict, constants, sets and rules. Rules are checked against every
packet in order; the first rule that decides the packet's fate wins.

```moat
version 1
default pass

use std.bogons

set banned addresses ttl 10m

rule known_bad { when ip.src in banned then drop }

# one /24 opening connections too fast
rule syn_flood {
    when tcp.dport in {80, 443} and tcp.flags == {syn}
    then limit 100/s per ip.src/24 burst 200
        on exceed add ip.src to banned, drop
}
```

## Reading it

- `default pass` lets through every packet no rule decides.
- `use std.bogons` drops sources that are never valid on the wire.
- `banned` is a set of addresses that forget each entry after ten minutes.
- `syn_flood` lets each /24 open 100 connections a second, with room for
  200 at once. Above that, the source goes into `banned` and the packet
  is dropped, and from then on `known_bad` drops everything it sends.

## Check and format

```sh
$ moat check web.moat
$ moat fmt -w web.moat
```

`moat check` prints errors and warnings with the line and column, and a
hint when a field name is misspelled. It also warns about rules that can
never match because an earlier rule already decides every packet they
would see. It exits with 1 when there are errors; with `--deny-warnings`
warnings fail too, which is useful in CI. `moat fmt -w` rewrites the file
in its canonical form; in CI, `moat fmt --check *.moat` fails when a file
is not formatted.

Before loading anything, [test the rules](https://moatfw.dev/docs/testing).

Already filtering with iptables or nftables? Import your rules from
[iptables](https://moatfw.dev/docs/import-iptables) or [nftables](https://moatfw.dev/docs/import-nftables)
instead of starting from an empty file.
