Skip to content

Commit f9b630d

Browse files
docs: update docs for fqdn support
Signed-off-by: saiaunghlyanhtet <saiaunghlyanhtet2003@gmail.com>
1 parent 680caa7 commit f9b630d

3 files changed

Lines changed: 81 additions & 41 deletions

File tree

POLICY.md

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ rules:
1414
protocol: tcp|udp|icmp|any
1515
direction: ingress|egress|both
1616
description: Optional description
17+
18+
# FQDN rule (domain instead of ip)
19+
- name: block_ads
20+
domain: "*.ads.example.com"
21+
action: drop
22+
direction: both
1723
```
1824
1925
### JSON Format
@@ -40,7 +46,8 @@ rules:
4046
### Rule Object
4147

4248
- **name** (required): Unique identifier for the rule
43-
- **ip** (required): IPv4 address to match (e.g., "192.168.1.1" or "192.168.0.0/24")
49+
- **ip** (required unless `domain` is set): IPv4 address to match (e.g., "192.168.1.1" or "192.168.0.0/24")
50+
- **domain** (optional): Domain name for FQDN-based rules (e.g., "ads.example.com" or "*.tracking.com"). When set, `ip` should be omitted — IPs are resolved dynamically from DNS responses.
4451
- **action** (required): Action to take. Valid values:
4552
- Allow: `allow`, `pass`, `accept`
4653
- Drop: `drop`, `deny`, `block`
@@ -57,17 +64,29 @@ rules:
5764
- **dst_port** (optional): Destination port to match (0 or omit for any)
5865
- **description** (optional): Human-readable description of the rule
5966

67+
> **Note:** Each rule must specify either `ip` or `domain`, but not both.
68+
6069
## Validation Rules
6170

6271
1. Each rule must have a unique name
63-
2. IP addresses must be valid IPv4 format or CIDR notation
64-
3. Actions must be one of the allowed values
65-
4. Protocols must be tcp, udp, icmp, or any
66-
5. Directions must be ingress, egress, or both
67-
6. Policy file must contain at least one rule
72+
2. Each rule must specify either `ip` or `domain`, but not both
73+
3. IP addresses must be valid IPv4 format or CIDR notation
74+
4. Domain names must be non-empty; wildcards use `*.` prefix (e.g., `*.example.com`)
75+
5. Actions must be one of the allowed values
76+
6. Protocols must be tcp, udp, icmp, or any
77+
7. Directions must be ingress, egress, or both
78+
8. Policy file must contain at least one rule
6879

6980
## Important Notes
7081

82+
### FQDN (Domain-Based) Rules
83+
- FQDN rules use passive DNS sniffing to resolve domain names to IP addresses
84+
- When a DNS response is seen for a matching domain, firebee automatically installs BPF rules for the resolved IPs
85+
- Resolved IP rules are named `fqdn:<domain>:<ip>` and are automatically removed when the DNS TTL expires
86+
- Wildcard domains are supported: `*.example.com` matches `sub.example.com`, `deep.sub.example.com`, and `example.com` itself
87+
- FQDN rules require the XDP/TC programs to be loaded (via `firebee run` or `firebee add --attach`)
88+
- A minimum TTL floor of 30 seconds is applied to prevent excessive rule churn
89+
7190
### Direction Field
7291
- **XDP Limitation**: The current XDP implementation only processes ingress (incoming) traffic
7392
- Rules with `direction: egress` will be stored but won't match traffic until TC-BPF egress support is added

README.md

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ An eBPF-based network firewall for Linux that uses XDP (eXpress Data Path) for h
77
- **XDP ingress filtering** — Drops or allows packets at the earliest point in the network stack, before the kernel allocates an `sk_buff`, for near line-rate performance.
88
- **TC-BPF egress filtering** — Filters outgoing traffic using the Linux Traffic Control subsystem.
99
- **IPv4 and IPv6 support** — Rules can target individual IPs or CIDR ranges for both address families.
10+
- **FQDN domain-based rules** — Block or allow traffic by domain name (e.g., `*.ads.example.com`). Firebee passively sniffs DNS responses via BPF, resolves domains to IPs, and dynamically installs/removes BPF rules with TTL-based expiry.
1011
- **Protocol and port matching** — Filter by TCP, UDP, ICMP, or any protocol, with optional source/destination port constraints.
1112
- **Declarative policy files** — Define rules in YAML or JSON; firebee validates and loads them.
1213
- **Per-rule statistics** — Track packet and byte counts per rule in real time.
@@ -41,36 +42,36 @@ This runs `cargo build --release` (compiles the Rust userspace binary) and `carg
4142
## Architecture
4243

4344
```
44-
┌──────────────────────────────────────────────────────────┐
45-
│ Userspace (Rust) │
46-
│ │
47-
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
48-
│ │ CLI │ │ Policy │ │ State │ │ TUI │ │
49-
│ │ (clap) │ │ Parser & │ │ Manager │ │(ratatui)│ │
50-
│ │ │ │Validator │ │ │ │ │ │
51-
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────────┘ │
52-
│ │ │ │
53-
│ └──────────────┴─────┬──────┴──────────────
54-
55-
│ ┌───────▼────────┐
56-
│ │ BPF Loader │
57-
│ │ & Maps API │
58-
│ └───────┬────────┘
59-
└────────────────────────────┼─────────────────────────────┘
60-
│ libbpf-rs
61-
┌─────────▼──────────┐
62-
│ Pinned BPF Maps │
63-
│ /sys/fs/bpf/firebee│
64-
└─────────┬──────────┘
65-
66-
┌────────────────────────────────┐
67-
68-
┌────────▼──────┐ ┌─────▼──────┐ ┌─────────────┐
69-
│ XDP Program │ │ TC Egress │ │ Ring Buffer
70-
│ (ingress) │ │ Program │ │ (log_events)
71-
│ firebee.bpf.c│ │firebee_ │ │
72-
│ │ │egress.bpf.c│ │ │
73-
└───────────────┘ └────────────┘ └──────────────┘
45+
┌──────────────────────────────────────────────────────────────
46+
Userspace (Rust)
47+
48+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
49+
│ │ CLI │ │ Policy │ │ State │ │ TUI │ │
50+
│ │ (clap) │ │ Parser & │ │ Manager │ │ (ratatui) │ │
51+
│ │ │ │Validator │ │ │ │ │ │
52+
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬──────┘ │
53+
│ │ │ │
54+
│ └──────────────┴─────┬──────┴───────────────┘
55+
56+
│ ┌───────▼────────┐ ┌────────────────┐
57+
│ │ BPF Loader │ DNS Monitor
58+
│ │ & Maps API │ (FQDN → BPF) │
59+
│ └───────┬────────┘ └───────┬────────┘
60+
└────────────────────────────┼───────────────────┼────────────┘
61+
│ libbpf-rs
62+
┌─────────▼──────────┐
63+
│ Pinned BPF Maps │◄───────┘
64+
│ /sys/fs/bpf/firebee│
65+
└─────────┬──────────┘
66+
67+
┌────────────────────┼────────────────────┐
68+
69+
┌────────▼──────┐ ┌─────────▼────────┐ ┌────────▼────────┐
70+
│ XDP Program │ │ TC Egress │ │ Ring Buffers
71+
│ (ingress) │ │ Program │ │ log_events
72+
│ firebee.bpf.c│ │firebee_egress │ │ dns_events
73+
│ │ │ .bpf.c │ │
74+
└───────────────┘ └──────────────────┘ └─────────────────┘
7475
Kernel space (eBPF)
7576
```
7677

@@ -95,7 +96,7 @@ The entry point. Uses [clap](https://docs.rs/clap) to expose these subcommands:
9596
- **`firebee.bpf.c`** — The XDP program (`xdp_firewall`). Attached to a network interface, it inspects every incoming packet: parses Ethernet/IP/IPv6 headers, extracts protocol and ports, iterates through the rules array map to find a match (with CIDR, protocol, port, and direction checks), logs the decision to a ring buffer, and returns `XDP_DROP` or `XDP_PASS`.
9697
- **`firebee_egress.bpf.c`** — The TC-BPF program (`tc_egress_firewall`). Attached via the Traffic Control egress hook, it performs the same matching logic on outgoing packets, returning `TC_ACT_SHOT` (drop) or `TC_ACT_OK` (pass).
9798
- **`firebee_common.h`** — Shared struct definitions (`rule_entry`, `rule_entry_v6`, `rule_metadata`, `log_event`, `rule_stats`) used by both kernel and userspace.
98-
- **`firebee_helpers.h`** — BPF helper functions for port extraction, rule matching, and IPv6 prefix comparison.
99+
- **`firebee_helpers.h`** — BPF helper functions for port extraction, rule matching, IPv6 prefix comparison, and DNS response capture.
99100
- **`firebee_test.bpf.c`** — Kernel-side BPF unit tests using Cilium-style `CHECK`/`TEST` macros.
100101

101102
BPF maps used:
@@ -107,6 +108,7 @@ BPF maps used:
107108
| `rule_metadata_map` | Hash | Human-readable metadata (name, description) keyed by index |
108109
| `rule_stats_map` | Array | Per-rule packet/byte counters |
109110
| `log_events` | Ring Buffer | Real-time packet log events sent to userspace |
111+
| `dns_events` | Ring Buffer | DNS response payloads captured for FQDN resolution |
110112

111113
#### 3. BPF Userspace Layer (`src/bpf_user/`)
112114

@@ -116,14 +118,28 @@ BPF maps used:
116118

117119
#### 4. Policy Engine (`src/policy/`)
118120

119-
- **`parser.rs`** — Reads a `.yaml`/`.yml` or `.json` file, deserialises it into a `PolicyFile` containing a list of `PolicyRule` structs. Supports IPv4, IPv6, CIDR notation, protocol, direction, and port fields.
120-
- **`validator.rs`** — Validates the parsed policy: checks for non-empty rules, unique names, valid IP addresses, valid actions (`allow`/`pass`/`accept`/`drop`/`deny`/`block`), and valid protocols/directions.
121+
- **`parser.rs`** — Reads a `.yaml`/`.yml` or `.json` file, deserialises it into a `PolicyFile` containing a list of `PolicyRule` structs. Supports IPv4, IPv6, CIDR notation, protocol, direction, port fields, and FQDN domain rules.
122+
- **`validator.rs`** — Validates the parsed policy: checks for non-empty rules, unique names, valid IP addresses or domains, valid actions (`allow`/`pass`/`accept`/`drop`/`deny`/`block`), and valid protocols/directions.
121123

122-
#### 5. State Manager (`src/state.rs`)
124+
#### 5. DNS Monitor (`src/dns/`)
125+
126+
Implements passive DNS sniffing for FQDN-based firewall rules (Cilium-style approach):
127+
128+
- **`parser.rs`** — Parses DNS wire format responses: extracts query names and A/AAAA answer records with IPs and TTLs. Handles DNS label compression pointers.
129+
- **`cache.rs`** — TTL-aware cache mapping domain names to resolved IP addresses. Tracks per-IP expiry and supports sweep operations to clean up stale entries.
130+
- **`monitor.rs`** — The orchestrator: polls the `dns_events` BPF ring buffer, parses each captured DNS response, matches against FQDN rules (exact or wildcard), and dynamically installs/removes BPF rules via `RulesState`. Rules are named `fqdn:<domain>:<ip>` for tracking and cleanup.
131+
132+
**How it works:**
133+
1. BPF programs (XDP + TC) detect UDP packets with source port 53 (DNS responses) and copy the DNS payload into the `dns_events` ring buffer.
134+
2. The DNS monitor thread polls this ring buffer, parses each DNS response, and checks if the queried domain matches any FQDN rule.
135+
3. For matching domains, the resolved IP addresses are installed as concrete BPF rules with `/32` masks, inheriting the FQDN rule's action/protocol/direction.
136+
4. When DNS TTLs expire, the corresponding BPF rules are automatically removed.
137+
138+
#### 6. State Manager (`src/state.rs`)
123139

124140
`RulesState` bridges the policy layer and the BPF maps. It converts `PolicyRule` objects into kernel-level `Rule` structs and calls the maps API to add, get, delete, or list rules.
125141

126-
#### 6. Terminal UI (`src/ui/`)
142+
#### 7. Terminal UI (`src/ui/`)
127143

128144
Built with [ratatui](https://docs.rs/ratatui) and [crossterm](https://docs.rs/crossterm):
129145

example-policy.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,8 @@ rules:
4343
dst_port: 80
4444
direction: ingress
4545
description: Block HTTP traffic from specific IP
46+
47+
- name: block pornhub
48+
domain: "*.pornhub.com"
49+
action: drop
50+
direction: both

0 commit comments

Comments
 (0)