Port forwarding based on originating hostname/dynamic IP

Discussion in 'Tomato Firmware' started by plainoldchair, Apr 19, 2014.

  1. plainoldchair

    plainoldchair Connected Client Member

    I'm running Tomato on a WRT54GS without issue.

    What I'm trying to do is restrict access to certain ports on my home network to only certain source IP addresses, and that works fine using typical port forwarding rules, restricting them by source address.

    Problem is, one of the places I'm trying to allow access from doesn't have a static IP (it's a typical home network with an ISP-assigned dynamic IP address). As a result, when I'm there and trying to access my home network, sometimes I can't because their IP address has changed and no longer matches the source address in my port forwarding rules... and since I'm not at home and don't really feel like opening up Tomato's web config to the outside world, I can't change it.

    So, is there any particularly good solution to this? Could I just use a hostname from a dynamic DNS service as the source address? I've tried looking around for an answer, but almost all of what I'm finding is the opposite situation (forwarding to different ports based on destination hostname, not source hostname).
  2. jerrm

    jerrm Network Guru Member

    You can use a hostname in an iptables rule, but it resolves at the time the rule is added. You would need a cron job to delete and re-add the rule at some acceptable interval to pickup any ip address change.
  3. plainoldchair

    plainoldchair Connected Client Member

    Yeah, I was thinking I'd have to script something to re-add the rule on an interval, but I have pretty limited experience with Linux. Adding a cron job should be something I can figure out, although I'm not sure what exactly it would need to do to implement this.

    Also, would doing this require a restart of the router/firewall? I'm hoping for no downtime involved here. Thanks for the help.
  4. plainoldchair

    plainoldchair Connected Client Member

    Apologies for the double post, but at this point I've got an ssh session open with the router, and the results of iptables --list mostly makes sense to me, in that I see the active port forwarding rules in the wanin chain... except 1) they're given as hostnames here even though they're IP addresses in the Tomato GUI, and I don't quite understand why that's the case, and 2) custom external ports aren't listed there, only the internal ones.

    Am I still safe just setting up a cron job to replace the relevant rule with the exact same one, using the dynamic DNS hostname? And would this best be set up in the tomato GUI's Scheduler section, or somewhere else?

    EDIT: Okay, so it was giving me hostnames instead because I hadn't used the -n command-line switch, and the NAT table contains the rules for port redirection... so that's all fine. Still not sure exactly what I'll need to do exactly to get it to re-resolve a host. Relevant rules (relying on that dynamic source IP) seem to be in both the wanin chain in the filter table, and in the PREROUTING chain in the NAT table.
    Last edited: Apr 21, 2014
  5. koitsu

    koitsu Network Guru Member

    What you're trying to accomplish is both possible and difficult at the same time. The difficulty stems from whether or not the DNS servers used by the router itself properly honour TTL on DNS records. You'd be surprised how many don't. What this means is even if you were to use iptables -D to delete the rule + iptables -I (or -A, depending on context) in a cron job, it doesn't guarantee that the FQDN you give iptables will resolve to the "newest" IP. You're making the blind assumption that it will. Meaning: you are at the mercy of the DNS servers you're using. There is really nothing you can do about this (if it turns out to be true), I'm sorry to say. You can give it a try and hope for the best if you want.

    I tend to not recommend this approach because it's a complete nightmare, and because you're screwing around with iptables rules, it's possible for error conditions to cause, say, deletion of the wrong iptables rule which in turn can cause you all kinds of different havoc.

    Here's a better idea: get a list of the IP addresses you have commonly seen being used/assigned to whatever place it is that you're trying to allow access from (the ambiguity of this statement makes explanations difficult; I wish you'd say "my place of work" or "my girlfriend's house", etc.). You'll probably be surprised to find out that the IP addresses very likely fall within a very specific network range, such as a.b.c.0/24 or a.b.c.128/25 or a.b.0.0/16 or who knows what. You can determine what the range is by using a combination of ARIN and checking out what the netblock size is that's advertised on the Internet via BGP using resources like route-views.org. I can do this for you if you want (to make your life easier) + show you how to do it going forward. From that point, all you have to do is add a single static iptables rule that allows access from that that range of addresses. No messing around with DNS, no cronjobs, just a simple one-liner in Administration / Scripts / Firewall and you're done. It's a hell of a lot simpler and much less likely to break, mess up, and easy to manage/figure out how to deal with if something ever changes. KISS principle really matters here.

    I'll give you a real-world example: I'm on Comcast, which does use dynamic IPs (although it's well-established that the IP you get doesn't change 99.8% of the time, barring if the MAC address of your router changes, etc.). I run some servers on the Internet that I only want reachable from my IP via SSH, IMAP+SSL, and some other services. Rather than deal with some wonky cronjob on my servers that does DNS lookups for my dynamic DNS-based FQDN and risk making a big mess, over the course of a few months I figured out what the network ranges for Comcast's service in the Bay Area are (where I'm located) and added those statically. It's been this way for years and I've never had a single problem. Yes this means other Comcast customers in this region could reach my servers on those ports, but the chance of someone doing that is slim -- and even if they did, they'd still have to know login/passwords to get anywhere.

    In case you wonder how the "enterprise world" does it (ex. "what do we do about Bob who works remotely and is on a dynamic IP? How do we make sure our firewall always allows him through?", they do it like I just described.
    Last edited: Apr 21, 2014
  6. plainoldchair

    plainoldchair Connected Client Member

    It literally is both my place of work and my girlfriend's house, yeah, although it's only a problem in the latter case because we have a static IP address where I work.

    Well, to be fair, I do have control over which DNS servers I'm using in the first place; I pretty much never use the ISP's servers, since they're pretty trash. At the moment, I'm using, which I believe are Google's.

    You're probably right about not messing with iptables to accomplish this, though.

    I only have a couple data points regarding the dynamic IP in question so far, but I'm finding it likely enough for the IP address to fall within some small block, and I can always increase the range if necessary in the future.

    That's pretty new to me, but let's see...
    Looking up the one sample IP address I have available to me at the moment gives me a block of about 16,000 addresses (18-bit subnet) for that customer record, so I assume that's pretty much the broadest I'd have to be here, although I'd like it to be narrower.

    I'm on routeviews.org now (the one with a hyphen is a parked domain), although I'm not sure where to even begin with that.

    For what it's worth, I don't see why I'd need to mess with iptables directly at all, since Tomato lets you specify IP ranges/subnets in the port forwarding rules, making this approach that much simpler. Wouldn't that be sufficient?

    I work in IT, and yeah, it's kind of annoying how often I wind up thinking "there has to be a better way than this" about plenty of situations, hence my trying to figure out how to ensure connections are only allowed from very specific places. I have a tendency to avoid "good enough" or approximate solutions, and joke that it's a result of having taken too many math courses in college. Usually I'm able to hammer together some solution that satisfies that, but in this case I suppose I'm better off just conceding the point and going for the slightly-too-broad approach that actually works rather than the extremely fiddly solution that might break everything.
    Last edited: Apr 21, 2014
  7. koitsu

    koitsu Network Guru Member

    I haven't played with the "Src Address" field in the Tomato Port Forwarding GUI to know if that "truly" suffices or not (or if it even allows CIDR format there or not). You can experiment though I'm sure, but if you end up having to have many different ranges (very possible) then it's probably best to not use the GUI and instead just drop some lines into Administration / Scripts / Firewall. Or you can make a new iptables chain and add them all there, then insert reference to that chain into the relevant INPUT chain.

    As for using routeviews, it's pretty simple: telnet to route-views.routeviews.org (yes I assure you that is the name), log in as "rviews". What you're now sitting at is an extremely limited version of Cisco IOS, where you can enter show ip route a.b.c.d and see what's advertised on the Internet via BGP, pertaining to where that IP falls within what range. Yes, the interface is extremely slow -- this is intentional. This type of interface, by the way, is more commonly known as a "looking glass" -- lots of ISPs and backbone providers offer them (some via CLI/telnet, others via web). Example for my own connection:

    route-views>show ip route
    Routing entry for
      Known via "bgp 6447", distance 20, metric 6
      Tag 1668, type external
      Last update from 7w0d ago
      Routing Descriptor Blocks:
      *, from, 7w0d ago
          Route metric is 6, traffic share count is 1
          AS Hops 2
          Route tag 1668
    Some ISPs do stupid things like advertise excessive numbers of /24s (vs. advertising, say, a single /20 -- how they split things up internally has no bearing on whats announced via BGP), while others announce humongous sizes. Figuring how they've delegated/split things up internally is virtually impossible (and asking them will get you no where, I'm sure. "What's CIDR? What's a network block? You mean blocking network traffic? A firewall?"), so going off of what's in ARIN and/or what's announced via BGP is all you can do.

    As for your concerns over having an /18 permitted: referring to my own example/situation previously mentioned, because of points in aforementioned paragraph, below is what I ended up with. You can clearly see I didn't allow a in my below list, but instead allowed Where did I get that? ARIN.

    # Comcast, Bay Area
    Yup, lots of very large blocks, but there isn't anything I can do about it.

    As for those ARIN results, by the way:

    NetRange: -
    NetName:        BAYAREA-CPE-23
    NetHandle:      NET-76-102-0-0-1
    Parent:         NET-76-96-0-0-1
    NetType:        Reassigned
    RegDate:        2007-04-20
    Updated:        2007-04-20
    Ref:            http://whois.arin.net/rest/net/NET-76-102-0-0-1
    CustName:       Comcast Cable Communications, Inc.
    Address:        1800 Bishops Gate Blvd
    City:           Mt Laurel
    StateProv:      NJ
    PostalCode:     08054
    Country:        US
    RegDate:        2007-04-20
    Updated:        2011-03-19
    Ref:            http://whois.arin.net/rest/customer/C01618413
  8. plainoldchair

    plainoldchair Connected Client Member

    It uses pretty much all reasonable formats in the examples and on the page itself:
    Src Address (optional) - Forward only if from this address. Ex: "", " -", "".
    ... So if that doesn't work, something's pretty wrong.

    Sidenote: It may be worth noting that Tomato lists my external IP's hostmask as (so a /22 subnet), although I'm not sure what this corresponds to... definitely not ARIN, which gives an /18 subnet, which I guess is just being subnetted further by the ISP.

    Routeviews is giving results for the /18... so I'm not entirely sure where the comes from.

    This should certainly give enough data to play around with, though.
  9. koitsu

    koitsu Network Guru Member

    My point was: how do you plan on dealing with more than one CIDR, ex. permitting both and The hyphen syntax isn't going to work (the range is not linear). The iptables/netfilter iprange module (ex. iptables -m iprange) will not help here either (again, the example address ranges are not linear). You'd need 2 iptables rules, which would be best managed through Administration / Scripts / Firewall. I'd actually end up putting all the permitted CIDRs in their own chain and then insert one single rule in the INPUT chain that references the accept-traffic-from-these-CIDRs chain -- it's easier to manage that way and minimises the chance of making a mistake when tinkering with the INPUT chain (which can have dire consequences as discussed earlier).

    It comes from your ISP; if you're using DHCP or PPPoE then it's handed to you as part of negotiation. They're simply choosing to use a /22 for network segregation on the customer/client-facing side. Internet-announced routes and the netmask/network size you get from your ISP do not have to match -- they are completely separate things.
    Last edited: Apr 22, 2014
  10. plainoldchair

    plainoldchair Connected Client Member

    Oh, that. I'd just add them as separate rules, which has worked fine for me before. If it turns into some kind of horrible mess, I'll do it differently, but I've used multiple rules for the same port before (to allow access to the same thing from multiple places) without any issues resulting.

    Yeah, pretty much what I figured... I just wasn't sure if there was something there I was missing, or if there was some other special significance to it.

    Thanks for the help, by the way! This should be more than enough information to set up something workable.
    koitsu likes this.
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice