I’m working on a personal project and I’d like to add a feature where you can deny/allow access based on IP.

I’m not sure that the way I’m thinking about it is good enough.

The user would be able to specify multiple deny and allow ranges as IP[/CIDR] and then I would:

  • Go through all the “deny” ranges and if any of them matches reject access.
  • Go through all the “allow” ranges and if any of them matches permit access.
  • If nothing matches the final decision is taken by a default fallback policy that can be set to allow or deny.

Would this be good enough or are there scenarios that can’t be expressed this way?

PS: fwiw I did have a look at how other projects achieve this. Some let you define ranges and combine them with boolean logic in any manner, pseudo-programatically; that’s a bit too complex for mine. Some let you draw up a list where order matters and the first matching range “wins”; I’m not sure if that’s more capable than my way, and having order matter would complicate things for my code.

Appreciate any help. If you can link me to something that talks about this, that’s good too.

  • litchralee@sh.itjust.works
    link
    fedilink
    English
    arrow-up
    3
    ·
    10 days ago

    I’m personally weary of software that tries to do IP-level allow/deny, because it’s effort spent on a feature that either is rarely used (ie most users’ threat model presume the LAN is safe) or it would get heavily used and its performance becomes a limiting factor (eg WAN exposed service). There isn’t really much of an in-between here, and so I generally ignore such features and would use a proper software firewall to reject at the network level. A firewall can also do rate limiting, and other things like permitting blocked IPs to have another go after a cool-down time.

    But supposing you still want to proceed, what you’ve described would cover the simplest case, yes. But consider that firewall rules often allow you to have ordered rules, such as: block by default, but allow anyone from 2001:db8::/32, but reject from 2001:db8:69::/64, except that 2001:db8:69::420/128 is cool and should be allowed. Here, that would be four rules for a firewall like Linux nftables or FreeBSD pf.

    In your case, how many entries would it take to convey the same intent, where there are “enclaves” to the allowlist? This is the sort of complexity that firewalls have already solved, and if it’s a matter of integrating a dynamic block feature into your app, you could just have your app tie into the OS firewall. Any firewall worth its salt will have APIs to do that, such as pf’s in-memory “tables” that are a list of all IPs that are grouped together to apply a rule. These are expressly designed to be added to/remove from frequently and efficiently. The rule doesn’t change, but the table of IPs affected would be updated by your app.

    • lemmyvore@feddit.nlOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      10 days ago

      You raise some very good points. I will have to think whether I really need to deal with that responsibility in my app. The performance implications are also something I hadn’t considered.

      There is possibly one case where doing the rules in the app would make sense: if they’re contingent on knowledge that only exists inside the app. I’ll have to see if I need something like that.

      In your case, how many entries would it take to convey the same intent, where there are “enclaves” to the allowlist?

      Yep that’s one case I can’t reproduce with my algorithm, unless I use the inverse of the deny netmask or something. I guess processing the rules in order is the superior algorithm.