mirror of
https://github.com/mirage/qubes-mirage-firewall.git
synced 2025-04-06 14:03:48 -04:00
Merge pull request #54 from talex5/rule-examples
Allow naming hosts and add examples to rules.ml
This commit is contained in:
commit
a93bb954d7
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
Makefile
|
||||
/Makefile
|
||||
_build/
|
||||
log
|
||||
key_gen.ml
|
||||
|
23
README.md
23
README.md
@ -86,6 +86,29 @@ qvm-prefs --set my-app-vm netvm mirage-firewall
|
||||
|
||||
Alternatively, you can configure `mirage-firewall` to be your default firewall VM.
|
||||
|
||||
### Components
|
||||
|
||||
This diagram show the main components (each box corresponds to a source `.ml` file with the same name):
|
||||
|
||||
<p align='center'>
|
||||
<img src="./diagrams/components.svg"/>
|
||||
</p>
|
||||
|
||||
Ethernet frames arrives from client qubes (such as `work` or `personal`) or from `sys-net`.
|
||||
Internet (IP) packets are sent to `firewall`, which consults `rules` to decide what to do with the packet.
|
||||
If it should be sent on, it uses `router` to send it to the chosen destination.
|
||||
`client_net` watches the XenStore database provided by dom0
|
||||
to find out when clients need to be added or removed.
|
||||
|
||||
The boot process:
|
||||
|
||||
- `config.ml` describes the libraries used and static configuration settings (NAT table size).
|
||||
The `mirage` tool uses this to generate `main.ml`.
|
||||
- `main.ml` initialises the drivers selected by `config.ml`
|
||||
and calls the `start` function in `unikernel.ml`.
|
||||
- `unikernel.ml` connects the Qubes agents, sets up the networking components,
|
||||
and then waits for a shutdown request.
|
||||
|
||||
### Easy deployment for developers
|
||||
|
||||
For development, use the [test-mirage][] scripts to deploy the unikernel (`qubes_firewall.xen`) from your development AppVM.
|
||||
|
@ -5,5 +5,5 @@ docker build -t qubes-mirage-firewall .
|
||||
echo Building Firewall...
|
||||
docker run --rm -i -v `pwd`:/home/opam/qubes-mirage-firewall qubes-mirage-firewall
|
||||
echo "SHA2 of build: $(sha256sum qubes_firewall.xen)"
|
||||
echo "SHA2 last known: dbf7460fa628bea5d132a96fe7ba2cd832e3d9da7005ae74f6a124957f4848ea"
|
||||
echo "SHA2 last known: 888cfd66e54c14da75be2bc4272efdb74c2ec8f9f144979f508a09410121482e"
|
||||
echo "(hashes should match for released versions)"
|
||||
|
@ -56,7 +56,7 @@ let input_arp ~fixed_arp ~iface request =
|
||||
iface#writev `ARP (fun b -> Arp_packet.encode_into response b; Arp_packet.size)
|
||||
|
||||
(** Handle an IPv4 packet from the client. *)
|
||||
let input_ipv4 ~client_ip ~router packet =
|
||||
let input_ipv4 ~iface ~router packet =
|
||||
match Nat_packet.of_ipv4_packet packet with
|
||||
| Error e ->
|
||||
Log.warn (fun f -> f "Ignored unknown IPv4 message: %a" Nat_packet.pp_error e);
|
||||
@ -64,10 +64,10 @@ let input_ipv4 ~client_ip ~router packet =
|
||||
| Ok packet ->
|
||||
let `IPv4 (ip, _) = packet in
|
||||
let src = ip.Ipv4_packet.src in
|
||||
if src = client_ip then Firewall.ipv4_from_client router packet
|
||||
if src = iface#other_ip then Firewall.ipv4_from_client router ~src:iface packet
|
||||
else (
|
||||
Log.warn (fun f -> f "Incorrect source IP %a in IP packet from %a (dropping)"
|
||||
Ipaddr.V4.pp src Ipaddr.V4.pp client_ip);
|
||||
Ipaddr.V4.pp src Ipaddr.V4.pp iface#other_ip);
|
||||
return ()
|
||||
)
|
||||
|
||||
@ -94,7 +94,7 @@ let add_vif { Dao.ClientVif.domid; device_id } ~client_ip ~router ~cleanup_tasks
|
||||
| Ok (eth, payload) ->
|
||||
match eth.Ethernet_packet.ethertype with
|
||||
| `ARP -> input_arp ~fixed_arp ~iface payload
|
||||
| `IPv4 -> input_ipv4 ~client_ip ~router payload
|
||||
| `IPv4 -> input_ipv4 ~iface ~router payload
|
||||
| `IPv6 -> return () (* TODO: oh no! *)
|
||||
)
|
||||
>|= or_raise "Listen on client interface" Netback.pp_error
|
||||
|
6
diagrams/Makefile
Normal file
6
diagrams/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# Requires https://github.com/blampe/goat
|
||||
|
||||
all: components.svg
|
||||
|
||||
%.svg: %.txt
|
||||
goat $^ > $@
|
149
diagrams/components.svg
Normal file
149
diagrams/components.svg
Normal file
@ -0,0 +1,149 @@
|
||||
<svg class='diagram' xmlns='http://www.w3.org/2000/svg' version='1.1' height='329' width='600'>
|
||||
<g transform='translate(8,16)'>
|
||||
<path d='M 272,0 L 360,0' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,32 L 360,32' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 120,96 L 224,96' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,96 L 320,96' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 320,96 L 360,96' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 72,112 L 112,112' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 224,112 L 264,112' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 368,112 L 440,112' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,128 L 320,128' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 320,128 L 360,128' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 400,144 L 440,144' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 440,144 L 472,144' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 72,160 L 112,160' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 480,160 L 520,160' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 400,176 L 472,176' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,192 L 360,192' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 72,208 L 112,208' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 232,208 L 272,208' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 360,208 L 440,208' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 120,224 L 176,224' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 176,224 L 224,224' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,224 L 360,224' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 120,96 L 120,224' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 176,224 L 176,272' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 224,96 L 224,112' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 224,112 L 224,224' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,0 L 272,32' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,96 L 272,128' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,192 L 272,208' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 272,208 L 272,224' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 320,48 L 320,96' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 320,128 L 320,176' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 360,0 L 360,32' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 360,96 L 360,128' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 360,192 L 360,208' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 360,208 L 360,224' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 400,144 L 400,176' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 440,112 L 440,144' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 440,192 L 440,208' style='fill:none;stroke:#000;'></path>
|
||||
<path d='M 472,144 L 472,176' style='fill:none;stroke:#000;'></path>
|
||||
<polygon points='80.000000,112.000000 68.000000,106.400002 68.000000,117.599998' style='fill:#000' transform='rotate(180.000000, 72.000000, 112.000000)'></polygon>
|
||||
<polygon points='80.000000,160.000000 68.000000,154.399994 68.000000,165.600006' style='fill:#000' transform='rotate(180.000000, 72.000000, 160.000000)'></polygon>
|
||||
<polygon points='80.000000,208.000000 68.000000,202.399994 68.000000,213.600006' style='fill:#000' transform='rotate(180.000000, 72.000000, 208.000000)'></polygon>
|
||||
<polygon points='120.000000,112.000000 108.000000,106.400002 108.000000,117.599998' style='fill:#000' transform='rotate(0.000000, 112.000000, 112.000000)'></polygon>
|
||||
<polygon points='120.000000,160.000000 108.000000,154.399994 108.000000,165.600006' style='fill:#000' transform='rotate(0.000000, 112.000000, 160.000000)'></polygon>
|
||||
<polygon points='120.000000,208.000000 108.000000,202.399994 108.000000,213.600006' style='fill:#000' transform='rotate(0.000000, 112.000000, 208.000000)'></polygon>
|
||||
<polygon points='184.000000,272.000000 172.000000,266.399994 172.000000,277.600006' style='fill:#000' transform='rotate(90.000000, 176.000000, 272.000000)'></polygon>
|
||||
<polygon points='240.000000,208.000000 228.000000,202.399994 228.000000,213.600006' style='fill:#000' transform='rotate(180.000000, 232.000000, 208.000000)'></polygon>
|
||||
<polygon points='272.000000,112.000000 260.000000,106.400002 260.000000,117.599998' style='fill:#000' transform='rotate(0.000000, 264.000000, 112.000000)'></polygon>
|
||||
<path d='M 320,40 L 320,48' style='fill:none;stroke:#000;'></path>
|
||||
<polygon points='336.000000,48.000000 324.000000,42.400002 324.000000,53.599998' style='fill:#000' transform='rotate(270.000000, 320.000000, 48.000000)'></polygon>
|
||||
<path d='M 320,176 L 320,184' style='fill:none;stroke:#000;'></path>
|
||||
<polygon points='336.000000,176.000000 324.000000,170.399994 324.000000,181.600006' style='fill:#000' transform='rotate(90.000000, 320.000000, 176.000000)'></polygon>
|
||||
<polygon points='376.000000,112.000000 364.000000,106.400002 364.000000,117.599998' style='fill:#000' transform='rotate(180.000000, 368.000000, 112.000000)'></polygon>
|
||||
<path d='M 440,184 L 440,192' style='fill:none;stroke:#000;'></path>
|
||||
<polygon points='456.000000,192.000000 444.000000,186.399994 444.000000,197.600006' style='fill:#000' transform='rotate(270.000000, 440.000000, 192.000000)'></polygon>
|
||||
<polygon points='488.000000,160.000000 476.000000,154.399994 476.000000,165.600006' style='fill:#000' transform='rotate(180.000000, 480.000000, 160.000000)'></polygon>
|
||||
<polygon points='528.000000,160.000000 516.000000,154.399994 516.000000,165.600006' style='fill:#000' transform='rotate(0.000000, 520.000000, 160.000000)'></polygon>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='144' y='164' style='fill:#000;font-size:1em'>l</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='544' y='164' style='fill:#000;font-size:1em'>y</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='552' y='164' style='fill:#000;font-size:1em'>s</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='216' y='260' style='fill:#000;font-size:1em'>t</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='456' y='164' style='fill:#000;font-size:1em'>k</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='16' y='212' style='fill:#000;font-size:1em'>r</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='312' y='212' style='fill:#000;font-size:1em'>u</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='312' y='20' style='fill:#000;font-size:1em'>l</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='168' y='164' style='fill:#000;font-size:1em'>n</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='184' y='164' style='fill:#000;font-size:1em'>_</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='296' y='20' style='fill:#000;font-size:1em'>r</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='152' y='164' style='fill:#000;font-size:1em'>i</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='8' y='212' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='56' y='212' style='fill:#000;font-size:1em'>l</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='224' y='260' style='fill:#000;font-size:1em'>o</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='168' y='292' style='fill:#000;font-size:1em'>n</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='56' y='116' style='fill:#000;font-size:1em'>k</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='568' y='164' style='fill:#000;font-size:1em'>n</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='32' y='212' style='fill:#000;font-size:1em'>o</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='40' y='116' style='fill:#000;font-size:1em'>o</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='576' y='164' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='328' y='212' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='160' y='292' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='432' y='164' style='fill:#000;font-size:1em'>l</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='536' y='164' style='fill:#000;font-size:1em'>s</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='184' y='292' style='fill:#000;font-size:1em'>t</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='160' y='308' style='fill:#000;font-size:1em'>(</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='288' y='116' style='fill:#000;font-size:1em'>f</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='424' y='164' style='fill:#000;font-size:1em'>p</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='440' y='164' style='fill:#000;font-size:1em'>i</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='208' y='260' style='fill:#000;font-size:1em'>i</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='192' y='260' style='fill:#000;font-size:1em'>o</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='320' y='116' style='fill:#000;font-size:1em'>w</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='176' y='164' style='fill:#000;font-size:1em'>t</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='416' y='164' style='fill:#000;font-size:1em'>u</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='448' y='164' style='fill:#000;font-size:1em'>n</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='560' y='164' style='fill:#000;font-size:1em'>-</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='48' y='212' style='fill:#000;font-size:1em'>a</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='304' y='212' style='fill:#000;font-size:1em'>o</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='152' y='292' style='fill:#000;font-size:1em'>X</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='176' y='292' style='fill:#000;font-size:1em'>S</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='200' y='292' style='fill:#000;font-size:1em'>r</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='184' y='308' style='fill:#000;font-size:1em'>m</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='304' y='20' style='fill:#000;font-size:1em'>u</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='352' y='68' style='fill:#000;font-size:1em'>c</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='48' y='116' style='fill:#000;font-size:1em'>r</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='56' y='164' style='fill:#000;font-size:1em'>]</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='200' y='164' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='296' y='212' style='fill:#000;font-size:1em'>r</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='296' y='116' style='fill:#000;font-size:1em'>i</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='200' y='260' style='fill:#000;font-size:1em'>n</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='240' y='260' style='fill:#000;font-size:1em'>s</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='584' y='164' style='fill:#000;font-size:1em'>t</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='344' y='68' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='360' y='68' style='fill:#000;font-size:1em'>k</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='368' y='68' style='fill:#000;font-size:1em'>s</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='32' y='116' style='fill:#000;font-size:1em'>w</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='312' y='116' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='32' y='164' style='fill:#000;font-size:1em'>.</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='192' y='164' style='fill:#000;font-size:1em'>n</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='208' y='292' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='336' y='116' style='fill:#000;font-size:1em'>l</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='232' y='260' style='fill:#000;font-size:1em'>r</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='24' y='212' style='fill:#000;font-size:1em'>s</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='320' y='20' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='328' y='20' style='fill:#000;font-size:1em'>s</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='304' y='116' style='fill:#000;font-size:1em'>r</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='344' y='116' style='fill:#000;font-size:1em'>l</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='24' y='164' style='fill:#000;font-size:1em'>[</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='48' y='164' style='fill:#000;font-size:1em'>.</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='0' y='212' style='fill:#000;font-size:1em'>p</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='40' y='212' style='fill:#000;font-size:1em'>n</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='320' y='212' style='fill:#000;font-size:1em'>t</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='192' y='292' style='fill:#000;font-size:1em'>o</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='176' y='308' style='fill:#000;font-size:1em'>o</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='328' y='68' style='fill:#000;font-size:1em'>c</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='336' y='68' style='fill:#000;font-size:1em'>h</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='40' y='164' style='fill:#000;font-size:1em'>.</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='136' y='164' style='fill:#000;font-size:1em'>c</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='208' y='164' style='fill:#000;font-size:1em'>t</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='184' y='260' style='fill:#000;font-size:1em'>m</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='328' y='116' style='fill:#000;font-size:1em'>a</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='160' y='164' style='fill:#000;font-size:1em'>e</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='336' y='212' style='fill:#000;font-size:1em'>r</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='168' y='308' style='fill:#000;font-size:1em'>d</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='192' y='308' style='fill:#000;font-size:1em'>0</text>
|
||||
<text text-anchor='middle' font-family='Menlo,Lucida Console,monospace' x='200' y='308' style='fill:#000;font-size:1em'>)</text>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 16 KiB |
20
diagrams/components.txt
Normal file
20
diagrams/components.txt
Normal file
@ -0,0 +1,20 @@
|
||||
+----------+
|
||||
| rules |
|
||||
+----------+
|
||||
^
|
||||
|checks
|
||||
|
|
||||
+------------+ +-----+----+
|
||||
work <---->| +---->| firewall |<--------.
|
||||
| | +-----+----+ |
|
||||
| | | +----+---+
|
||||
[...] <---->| client_net | | | uplink |<----> sys-net
|
||||
| | v +--------+
|
||||
| | +----------+ ^
|
||||
personal <---->| |<----+ router +---------'
|
||||
+------+-----+ +----------+
|
||||
|
|
||||
|monitors
|
||||
v
|
||||
XenStore
|
||||
(dom0)
|
55
firewall.ml
55
firewall.ml
@ -48,8 +48,21 @@ let forward_ipv4 t packet =
|
||||
|
||||
(* Packet classification *)
|
||||
|
||||
let classify t packet =
|
||||
let `IPv4 (ip, transport) = packet in
|
||||
let parse_ips ips = List.map (fun (ip_str, id) -> (Ipaddr.of_string_exn ip_str, id)) ips
|
||||
|
||||
let clients = parse_ips Rules.clients
|
||||
let externals = parse_ips Rules.externals
|
||||
|
||||
let resolve_client client =
|
||||
`Client (try List.assoc (Ipaddr.V4 client#other_ip) clients with Not_found -> `Unknown)
|
||||
|
||||
let resolve_host = function
|
||||
| `Client c -> resolve_client c
|
||||
| `External ip -> `External (try List.assoc ip externals with Not_found -> `Unknown)
|
||||
| (`Client_gateway | `Firewall_uplink | `NetVM) as x -> x
|
||||
|
||||
let classify ~src ~dst packet =
|
||||
let `IPv4 (_ip, transport) = packet in
|
||||
let proto =
|
||||
match transport with
|
||||
| `TCP ({Tcp.Tcp_packet.src_port; dst_port; _}, _) -> `TCP {sport = src_port; dport = dst_port}
|
||||
@ -58,8 +71,8 @@ let classify t packet =
|
||||
in
|
||||
Some {
|
||||
packet;
|
||||
src = Router.classify t (Ipaddr.V4 ip.Ipv4_packet.src);
|
||||
dst = Router.classify t (Ipaddr.V4 ip.Ipv4_packet.dst);
|
||||
src;
|
||||
dst;
|
||||
proto;
|
||||
}
|
||||
|
||||
@ -80,7 +93,10 @@ let pp_proto fmt = function
|
||||
| `ICMP -> Format.pp_print_string fmt "ICMP"
|
||||
| `Unknown -> Format.pp_print_string fmt "UnknownProtocol"
|
||||
|
||||
let pp_packet fmt {src; dst; proto; packet = _} =
|
||||
let pp_packet t fmt {src = _; dst = _; proto; packet} =
|
||||
let `IPv4 (ip, _transport) = packet in
|
||||
let src = Router.classify t (Ipaddr.V4 ip.Ipv4_packet.src) in
|
||||
let dst = Router.classify t (Ipaddr.V4 ip.Ipv4_packet.dst) in
|
||||
Format.fprintf fmt "[src=%a dst=%a proto=%a]"
|
||||
pp_host src
|
||||
pp_host dst
|
||||
@ -125,18 +141,18 @@ let nat_to t ~host ~port packet =
|
||||
|
||||
(* Handle incoming packets *)
|
||||
|
||||
let apply_rules t rules info =
|
||||
let apply_rules t rules ~dst info =
|
||||
let packet = info.packet in
|
||||
match rules info, info.dst with
|
||||
match rules info, dst with
|
||||
| `Accept, `Client client_link -> transmit_ipv4 packet client_link
|
||||
| `Accept, (`External _ | `NetVM) -> transmit_ipv4 packet t.Router.uplink
|
||||
| `Accept, (`Firewall_uplink | `Client_gateway) ->
|
||||
Log.warn (fun f -> f "Bad rule: firewall can't accept packets %a" pp_packet info);
|
||||
Log.warn (fun f -> f "Bad rule: firewall can't accept packets %a" (pp_packet t) info);
|
||||
return ()
|
||||
| `NAT, _ -> add_nat_and_forward_ipv4 t packet
|
||||
| `NAT_to (host, port), _ -> nat_to t packet ~host ~port
|
||||
| `Drop reason, _ ->
|
||||
Log.info (fun f -> f "Dropped packet (%s) %a" reason pp_packet info);
|
||||
Log.info (fun f -> f "Dropped packet (%s) %a" reason (pp_packet t) info);
|
||||
return ()
|
||||
|
||||
let handle_low_memory t =
|
||||
@ -147,7 +163,7 @@ let handle_low_memory t =
|
||||
`Memory_critical
|
||||
| `Ok -> Lwt.return `Ok
|
||||
|
||||
let ipv4_from_client t packet =
|
||||
let ipv4_from_client t ~src packet =
|
||||
handle_low_memory t >>= function
|
||||
| `Memory_critical -> return ()
|
||||
| `Ok ->
|
||||
@ -156,23 +172,28 @@ let ipv4_from_client t packet =
|
||||
| Some frame -> forward_ipv4 t frame (* Some existing connection or redirect *)
|
||||
| None ->
|
||||
(* No existing NAT entry. Check the firewall rules. *)
|
||||
match classify t packet with
|
||||
let `IPv4 (ip, _transport) = packet in
|
||||
let dst = Router.classify t (Ipaddr.V4 ip.Ipv4_packet.dst) in
|
||||
match classify ~src:(resolve_client src) ~dst:(resolve_host dst) packet with
|
||||
| None -> return ()
|
||||
| Some info -> apply_rules t Rules.from_client info
|
||||
| Some info -> apply_rules t Rules.from_client ~dst info
|
||||
|
||||
let ipv4_from_netvm t packet =
|
||||
handle_low_memory t >>= function
|
||||
| `Memory_critical -> return ()
|
||||
| `Ok ->
|
||||
match classify t packet with
|
||||
let `IPv4 (ip, _transport) = packet in
|
||||
let src = Router.classify t (Ipaddr.V4 ip.Ipv4_packet.src) in
|
||||
let dst = Router.classify t (Ipaddr.V4 ip.Ipv4_packet.dst) in
|
||||
match classify ~src ~dst:(resolve_host dst) packet with
|
||||
| None -> return ()
|
||||
| Some info ->
|
||||
match info.src with
|
||||
match src with
|
||||
| `Client _ | `Firewall_uplink | `Client_gateway ->
|
||||
Log.warn (fun f -> f "Frame from NetVM has internal source IP address! %a" pp_packet info);
|
||||
Log.warn (fun f -> f "Frame from NetVM has internal source IP address! %a" (pp_packet t) info);
|
||||
return ()
|
||||
| `External _ | `NetVM ->
|
||||
| `External _ | `NetVM as src ->
|
||||
translate t packet >>= function
|
||||
| Some frame -> forward_ipv4 t frame
|
||||
| None ->
|
||||
apply_rules t Rules.from_netvm info
|
||||
apply_rules t Rules.from_netvm ~dst { info with src }
|
||||
|
@ -6,6 +6,6 @@
|
||||
val ipv4_from_netvm : Router.t -> Nat_packet.t -> unit Lwt.t
|
||||
(** Handle a packet from the outside world (this module will validate the source IP). *)
|
||||
|
||||
val ipv4_from_client : Router.t -> Nat_packet.t -> unit Lwt.t
|
||||
val ipv4_from_client : Router.t -> src:Fw_utils.client_link -> Nat_packet.t -> unit Lwt.t
|
||||
(** Handle a packet from a client. Caller must check the source IP matches the client's
|
||||
before calling this. *)
|
||||
|
22
packet.ml
22
packet.ml
@ -13,9 +13,25 @@ type ports = {
|
||||
type host =
|
||||
[ `Client of client_link | `Client_gateway | `Firewall_uplink | `NetVM | `External of Ipaddr.t ]
|
||||
|
||||
type info = {
|
||||
type ('src, 'dst) info = {
|
||||
packet : Nat_packet.t;
|
||||
src : host;
|
||||
dst : host;
|
||||
src : 'src;
|
||||
dst : 'dst;
|
||||
proto : [ `UDP of ports | `TCP of ports | `ICMP | `Unknown ];
|
||||
}
|
||||
|
||||
(* The first message in a TCP connection has SYN set and ACK clear. *)
|
||||
let is_tcp_start = function
|
||||
| `IPv4 (_ip, `TCP (hdr, _body)) -> Tcp.Tcp_packet.(hdr.syn && not hdr.ack)
|
||||
| _ -> false
|
||||
|
||||
(* The possible actions we can take for a packet: *)
|
||||
type action = [
|
||||
| `Accept (* Send the packet to its destination. *)
|
||||
| `NAT (* Rewrite the packet's source field so packet appears to
|
||||
have come from the firewall, via an unused port.
|
||||
Also, add NAT rules so related packets will be translated accordingly. *)
|
||||
| `NAT_to of host * port (* As for [`NAT], but also rewrite the packet's
|
||||
destination fields so it will be sent to [host:port]. *)
|
||||
| `Drop of string (* Drop the packet and log the given reason. *)
|
||||
]
|
||||
|
63
rules.ml
63
rules.ml
@ -1,39 +1,62 @@
|
||||
(* Copyright (C) 2015, Thomas Leonard <thomas.leonard@unikernel.com>
|
||||
See the README file for details. *)
|
||||
|
||||
(** Put your firewall rules here. *)
|
||||
(** Put your firewall rules in this file. *)
|
||||
|
||||
open Packet
|
||||
open Packet (* Allow us to use definitions in packet.ml *)
|
||||
|
||||
(* List your AppVM IP addresses here if you want to match on them in the rules below.
|
||||
Any client not listed here will appear as [`Client `Unknown]. *)
|
||||
let clients = [
|
||||
(*
|
||||
"10.137.0.12", `Dev;
|
||||
"10.137.0.14", `Untrusted;
|
||||
*)
|
||||
]
|
||||
|
||||
(* List your external (non-AppVM) IP addresses here if you want to match on them in the rules below.
|
||||
Any external machine not listed here will appear as [`External `Unknown]. *)
|
||||
let externals = [
|
||||
(*
|
||||
"8.8.8.8", `GoogleDNS;
|
||||
*)
|
||||
]
|
||||
|
||||
(* OCaml normally warns if you don't match all fields, but that's OK here. *)
|
||||
[@@@ocaml.warning "-9"]
|
||||
|
||||
(** {2 Actions}
|
||||
(** This function decides what to do with a packet from a client VM.
|
||||
|
||||
The possible actions are:
|
||||
It takes as input an argument [info] (of type [Packet.info]) describing the
|
||||
packet, and returns an action (of type [Packet.action]) to perform.
|
||||
|
||||
- [`Accept] : Send the packet to its destination.
|
||||
See packet.ml for the definitions of [info] and [action].
|
||||
|
||||
- [`NAT] : Rewrite the packet's source field so packet appears to
|
||||
have come from the firewall, via an unused port.
|
||||
Also, add NAT rules so related packets will be translated accordingly.
|
||||
|
||||
- [`NAT_to (host, port)] :
|
||||
As for [`NAT], but also rewrite the packet's destination fields so it
|
||||
will be sent to [host:port].
|
||||
|
||||
- [`Drop reason] drop the packet and log the reason.
|
||||
*)
|
||||
|
||||
(** Decide what to do with a packet from a client VM.
|
||||
Note: If the packet matched an existing NAT rule then this isn't called. *)
|
||||
let from_client = function
|
||||
let from_client (info : ([`Client of _], _) Packet.info) : Packet.action =
|
||||
match info with
|
||||
(* Examples (add your own rules here):
|
||||
|
||||
1. Allows Dev to send SSH packets to Untrusted.
|
||||
Note: responses are not covered by this!
|
||||
2. Allows Untrusted to reply to Dev.
|
||||
3. Blocks an external site.
|
||||
|
||||
In all cases, make sure you've added the VM name to [clients] or [externals] above, or it won't
|
||||
match anything! *)
|
||||
(*
|
||||
| { src = `Client `Dev; dst = `Client `Untrusted; proto = `TCP { dport = 22 } } -> `Accept
|
||||
| { src = `Client `Untrusted; dst = `Client `Dev; proto = `TCP _; packet }
|
||||
when not (is_tcp_start packet) -> `Accept
|
||||
| { dst = `External `GoogleDNS } -> `Drop "block Google DNS"
|
||||
*)
|
||||
| { dst = (`External _ | `NetVM) } -> `NAT
|
||||
| { dst = `Client_gateway; proto = `UDP { dport = 53 } } -> `NAT_to (`NetVM, 53)
|
||||
| { dst = (`Client_gateway | `Firewall_uplink) } -> `Drop "packet addressed to firewall itself"
|
||||
| { dst = `Client _ } -> `Drop "prevent communication between client VMs"
|
||||
| { dst = `Client _ } -> `Drop "prevent communication between client VMs by default"
|
||||
|
||||
(** Decide what to do with a packet received from the outside world.
|
||||
Note: If the packet matched an existing NAT rule then this isn't called. *)
|
||||
let from_netvm = function
|
||||
let from_netvm (info : ([`NetVM | `External of _], _) Packet.info) : Packet.action =
|
||||
match info with
|
||||
| _ -> `Drop "drop by default"
|
||||
|
Loading…
x
Reference in New Issue
Block a user