mirage / qubes-mirage-firewall

A Mirage firewall VM for QubesOS
208 stars 28 forks source link

IP blocklist #168

Closed xbc5 closed 1 year ago

xbc5 commented 1 year ago

Is it feasible to to implement a self-updating IP/domain whitelist/blacklist?

Context: A self-updating blocklist manager.

Use case: Prevent/allow egress/ingress connections to single IPs and IP blocks. For example a country block, or blocks assigned to corporations. Additionally, resolve domain names to IPs (at time of use) to support domain blacklisting/whitelisting.

Requirements:

There are two possible approaches:

  1. internal: the firewall itself is exposed to third-party hosts
  2. external: another VM does the legwork, communicating the results to the firewall

Drawbacks:

Questions:

  1. Can QubesDB handle large rule sets? I remember there being an upper limit ~56KB, but I could be wrong.
  2. Would loading large rule sets via QubesDB on boot be a considerable performance impact?
  3. In both approaches, where could we cache the data? I know the mirage firewall doesn't have any permanent storage (that's probably a good thing)
xbc5 commented 1 year ago

I should note that I could write a daemon (in Go) for the external approach. I am just not sure how it would interface with the firewall exactly.

palainp commented 1 year ago

Hi, thanks for that suggestion. The Qubes security model is to have a white list rules and a default drop policy (and I see black list strategy lowering the security model as you can miss that your list is out of date). I think you can achieve your goal with qvm-firewall calls in dom0: you can create a script from an appvm, and upload it to dom0 to filter access of the firewall to appropriate IPs.

xbc5 commented 1 year ago

I think you can achieve your goal with qvm-firewall calls in dom0: you can create a script from an appvm, and upload it to dom0 to filter access of the firewall to appropriate IPs.

@palainp that is possible (and I do that myself) but it's very slow. It also requires pulling large lists into dom0, which is frowned upon by the Qubes team. It is probably possible to use a dedicated management VM and a disposable VM for that specific task alone, it's something I need to look into.

The Qubes security model is to have a white list rules and a default drop policy (and I see black list strategy lowering the security model as you can miss that your list is out of date).

That's my approach right now for domains that I want to lock down to a single service (e.g. IRC; although I am unaware of how to get a TLS resolver working). However, on more general systems (like untrusted) it doesn't make sense to do that.

I will likely research how to load large lists via management VM and QubesDB.

palainp commented 1 year ago

I'm not on my computer right now for testing so I may be wrong. In order to reduce the rules list, it may be possible to register your banned IPs with a drop action and at the end add a wildcard accept action? The online manpage seems to permit that.

xbc5 commented 1 year ago

Yeah that works, it won't reduce the size of the rule set thought.

The only issue I take with the Qubes firewall as it is, is performance and convenience. The current implementation is clunky, slow, and only useful for basic firewalling. I just thought some extra features in the firewall would be nice.

Perhaps this is a Qubes issue in fact. I should raise a ticket there instead.

palainp commented 1 year ago

The current implementation for filtering packets is O(n) with n the rules list size. With a really long list it's certainly slow :( I'm not sure how to improve that here, as the rules set is read only on startup or on updates, so the list is in memory when a packet arrives.

xbc5 commented 1 year ago

I see. I should ask these question on the Qubes dev forums/mailing list to be honest.

Would 1 million entries (~16MB) badly affect (runtime) filtering performance? (I am trying to gauge whether my effort will be worth it)

xbc5 commented 1 year ago

Closing this issue then.

palainp commented 1 year ago

I got my laptop back and now I guess I can imagine what you called slowiness :) I tried to create a list of drop rules and adding a wildcard accept at the end with the following script:

#!/bin/env sh

printf "#!/bin/env sh\n"

for b2 in `seq 16 31` ; do
    for b3 in `seq 0 255` ; do
        for b4 in `seq 0 4 255` ; do
            printf "qvm-firewall perso add drop 172.%d.%d.%d/30\n" $b2 $b3 $b4
        done
    done
done

printf "qvm-firewall perso add accept\n"

This should produce less than a million: 2^18 rules (it doesn't matter if the networks are in RFC 1918 as the firewall will check if a packet belong to any of those anyway), but I first tried with 500 rules and 2400 rules:

$ wc -l rules_list.sh 
578 rules_list.sh
$ time ./rules_list.sh 

real    1m15.999s
user    0m30.876s
sys 0m10.164s

The 2400 rules listing failed after 7 minutes before adding 2000 rules (I may have missed something here but haven't time for investigations :/) with Got empty response from qubesd. See journalctl in dom0 for details. and journalctl saying dom0 qubesd[2304]: request too long.

So now I still think the correct setup for that use case is using Qubes firewall ruleset but I wonder if Qubes support large rulesets. The other approach could be to create a separate specialised unikernel that takes a network list / file as argument and nat everything (not) included in that list (this can be independent from Qubes and take its roots from https://github.com/mirage/mirage-nat/tree/main/example).

xbc5 commented 1 year ago

The other approach could be to create a separate specialised unikernel that takes a network list / file as argument and nat everything (not) included in that list (this can be independent from Qubes and take its roots from https://github.com/mirage/mirage-nat/tree/main/example).

I'd love to, but I don't know OCaml or Mirage (yet; but it's on my TODO list). I will raise an issue with Qubes because it seems like the right place for such a feature request. I will come back to this thread one day with an answer.

Thanks for your help.