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
    ·
    2 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
      ·
      2 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.

  • laut_sprecher@feddit.org
    link
    fedilink
    English
    arrow-up
    2
    ·
    2 days ago

    On your algo: if the fallback is allow, you don’t need to check the allow list and the same for reject. First check what’s fallback, then check the exceptions of that default.

  • limelight79@lemmy.world
    link
    fedilink
    English
    arrow-up
    1
    ·
    2 days ago

    A firewall?

    Or is this a web app you’re building?

    If it’s the latter, note that the ip address would still have access to the web server, it’s just that the scripts won’t do whatever they would do for a valid user.

  • frongt@lemmy.zip
    link
    fedilink
    English
    arrow-up
    1
    arrow-down
    1
    ·
    2 days ago

    What kind of project? A web app, a network access controller, something else?

    There are probably existing libraries to do this exact thing. You could probably incorporate one to save yourself implementing all the logic.

    One question though, what happens in your two-list example when an address is on both lists?

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

      It’s a Node app. You’re probably right about existing libraries but I’d like to keep the dependencies minimal. It’s also a good exercise for me.

      what happens in your two-list example when an address is on both lists?

      It would encounter the deny rule first and not reach the allow rule. Basically resolve the conflict in the more restrictive way.

      • frongt@lemmy.zip
        link
        fedilink
        English
        arrow-up
        2
        arrow-down
        1
        ·
        2 days ago

        Okay so you’re doing the same ordering as a regular firewall list, just split. How do I block all of 10.0.0.0/8 but allow 10.34.99.0/24?

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

          Yeah it’s not suitable for all scenarios. I’ll have to consider if I either do ordered rules or give up the thing altogether and leave it to other layers (firewalls, proxies etc.)

          • Pomal@sh.itjust.works
            link
            fedilink
            English
            arrow-up
            2
            ·
            17 hours ago

            You are correct in identifying that trying to make fetch happen won’t work. There’s already a multitude of options for establishing network security native to any OS, or an open project that’s deviated in their own way.

            You could write a wrapper for everything, but unless that’s the intent of your app it may be scope creep.