1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

iptables and Tomato firewall script

Discussion in 'Tomato Firmware' started by tjfriese, Sep 2, 2013.

  1. tjfriese

    tjfriese Addicted to LI Member

    Please bear with me, this could be slightly lengthy...

    I have an AppleTV3 sitting behind a Tomato router. A while ago someone figured out how to run Plex (a home theatre program similar to XBMC off of the AppleTV by forwarding the traffic to Apple's trailer app. I have a QNAP NAS box that serves as my media server.

    I was able tog et this setup and working properly by modifying my tomato router using the following settings:

    DHCP/DNS:

    address=/trailers.apple.com/192.168.1.1
    address=/atv.plexconnect/192.168.1.1

    This sends all the traffic for trailers.apple.com to my router.

    Someone else came up with this firewall script (run from the firewall section of admin in Tomato):

    iptables -t nat -A PREROUTING -s 192.168.1.9 -d 192.168.1.1 -p tcp -m multiport --dports 80,443 -j DNAT --to-destination 192.168.1.8:8090

    This is where the QNAP comes in. It seems to make use of port 80, and so I needed a way to forward the traffic around the QNAP. In this setup .1 is my router, .9 is the AppleTV, and .8 is my QNAP (media server).

    This all worked wonderfully for a few weeks, and then Apple modified it so that port 443 was also used. I now need a separate (second) firewall script that will forward port 443 to a different port (8091 for example) in the same way that the above script would forward either port 80 or 443 to port 8090. The QNAP also makes use of port 443 (and won't give it up easily).

    I am unsure as to how to write these two separate scripts/rules. I have tried the following (unsuccessfully):

    iptables -t nat -A PREROUTING -s 192.168.1.9 -d 192.168.1.1 -p tcp -m --dport 80 -j DNAT --to-destination 192.168.1.8:8090
    iptables -t nat -A PREROUTING -s 192.168.1.9 -d 192.168.1.1 -p tcp -m --dport 443 -j DNAT --to-destination 192.168.1.8:8091

    Can the firewall section handle something like this? How would I go about setting this up? Any help would be greatly appreciated.
     
  2. mstombs

    mstombs Network Guru Member

    I suspect router doing what you want - but 443 implies https, I wonder what response the TV is expecting?
     
  3. tjfriese

    tjfriese Addicted to LI Member

    I am not convinced that the router is doing what I want. I have had everything working when I was able to disable the use of port 80 and port 443 by the QNAP. It has since decided to overrule me and take those ports back.

    I know that the first rule worked (before Apple updated the AppleTV).

    What I am concerned about is if my two separate rules (based off the first rule) will work?

    I removed the multiports and changed --dports to --dport.
    I left in the -m as I didn't know what purpose it served.

    My questions are:

    Will the two rules that I made based off of the initial one rule work as I intend them to? That is, will they make sure that connections on port 80 from the AppleTV (.9) are sent to the router (.1) and then sent to the media server (.8) on port 8090 and that connections on port 443 from the AppleTV (.9) are sent to the router (.1) and then sent to the media server (.8) on port 8091?

    Will the firewall script handle the two rules or do I need to add them in the router somewhere else?

    The AppleTV is indeed making use of both ports (80 and 443) and so I need to handle them separately.
     
  4. koitsu

    koitsu Network Guru Member

    Some iptables help for you -- just to clarify some concerns/confusions you had (understandably);

    1a. You can safely remove the -m. This flag is used to cause netfilter/iptables to load a netfilter/iptables module on-the-fly for use (ex. -m string), which enables other command-line flags and features. However, in your above syntax, there is no module name specified after the -m, which syntactically is incorrect. (iptables should be returning usage syntax/syntax error for this, but doesn't, and this is a bug in iptables)

    1b. -j XXX can also enable certain features (keep reading).

    2. All the flags you're using (-s, -d, -p, and --dport) are supported natively within iptables on Tomato (at least the firmware version I use (tomato-K26USB-1.28.0502.8MIPSR2Toastman-RT-N-Ext.trx)), with no extra modules needed. It looks to me like someone meant to say -m multiport (except that isn't needed here), and they simply made a mistake removing it fully.

    3. The --to-destination flag becomes enabled only when using -j DNAT. For example, if you were to run iptables -h (to get a list of commands), you would not see --to-destination listed, however if you were to say iptables -j DNAT -h you would see extra arguments (look carefully).

    Basically, the flags available can dynamically be changed depending on what modules or features you've specified up to that point. Thus, you should always specify -h last on the command line (ex. compare output between iptables -j DNAT -h and iptables -h -j DNAT). Each module (via -m) and each chain feature (via -j) can change the help/usage output; same goes for iptables -m multiport -h (just as an example); this is how netfilter modules work. I know, it's a bit confusing, but once people are taught the above it becomes more clear.

    Hope this helps. I cannot help otherwise.
     
    darkknight93 likes this.
  5. tjfriese

    tjfriese Addicted to LI Member

    Thanks for everyone's help so far. I have tried the following two scripts in the Firewall section of Admin with no luck:

    iptables -t nat -A PREROUTING -s 192.168.1.9 -d 192.168.1.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.8:8090
    iptables -t nat -A PREROUTING -s 192.168.1.9 -d 192.168.1.1 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.8:8091

    Does anyone have any idea why they wouldn't work?
     
  6. koitsu

    koitsu Network Guru Member

    Yes, I have a fairly certain idea why what you're doing doesn't work, but where you're testing from actually matters too.

    However, I've read your initial post -- twice now -- and I cannot for the life of me understand the topology of what's going on, and the way it's all written is not concise/clear. I'm sorry that I can't phrase this eloquently while being terse, but you really need to describe the topology, with IPs and source and destination ports and everything defined per-device and what you want to accomplish more clearly. That's the short/terse version, and I'm sorry that I can't (rather, don't want to be) more verbose in that.
     
  7. tjfriese

    tjfriese Addicted to LI Member

    I'll try to clarify.

    I have three devices:

    A Tomato router (192.168.1.1)
    An AppleTV (192.168.1.9)
    A QNAP NAS (192.168.1.8)

    The QNAP NAS is running Plex Media Server as well as a program called PlexConnect which gives access to Plex from the AppleTV by redirecting Apple's Trailers app.

    What I am trying to do is have my Tomato router forward ports 80 and 443 from the AppleTV to the QNAP NAS PlexConnect program as the QNAP NAS seems to have programs that are hardcoded to make use of ports 80 and 443.

    I am also using the Tomato router to handle the DNS forwarding that the PlexConnect program normally does. The usual setup for PlexConnect is to change the APpleTV DNS to the IP address where PlexConnect is running. I have left the AppleTV DNS as the router IP and used the router to forward any requests for trailers.apple.com to the router.

    I then want the router to pass the traffic from the router to the QNAP NAS on a different port than the port on which it originated (as the originating ports are used by the QNAP NAS).

    This all used to run over port 80 and so I was able to use the initial iptables command that I listed in the first post (iptables -t nat -A PREROUTING -s 192.168.1.9 -d 192.168.1.1 -p tcp -m multiport --dports 80,443 -j DNAT --to-destination 192.168.1.8:8090). I did not write the command. I believe the author set it up to use multiport in order to handle connections on either of port 80 or port 443.

    So here's what is happening now:

    The AppleTV is sending out traffic on ports 80 and 443. Tha traffic needs to be intercepted by the QNAP NAS running PlexConnect. I would like to use the router to stop the traffic from leaving my network and send it to the QNAP NAS on different ports (while keeping the initial port separation).

    Does this make things any clearer?
     
  8. koitsu

    koitsu Network Guru Member

    What you're describing may or may not be doable.

    Let's start with this:

    1. What destination IP address is the AppleTV (192.168.1.9) device talking to at present? Is it somewhere on the Internet?

    2. What source port number(s) does the AppleTV (192.168.1.9) device use, or are they dynamic? (If you don't understand what this means, then this indicates you should probably learn a bit about IP networking -- specifically, when two endpoints talk, there is a source IP and source port, and a destination IP and destination port)

    3. What destination port number(s) does the AppleTV (192.168.1.9) device talk to?

    You can't just say "port 80 and 443", because the direction matters, and what/where the device is talking to (if it's on the Internet or on the LAN) actually matters. If the traffic is internet-bound, having packet captures would really, really help.

    Let's blindly assume the traffic (at present) is Internet-bound -- meaning 192.168.1.9 with a source port of {something random} talks to {some Internet IP} with destination TCP port 80 or 443. But instead of it talking to {some Internet IP}, you want it to talk to 192.168.1.8 (QNAP NAS) using the same destination port (either 80 or 443).

    If that's what you want, this is called packet rewriting -- specifically you (the router) rewrite the destination IP of the packet to 192.168.1.8 (instead of wherever it was going on the Internet). However, often it's not that easy, especially if the packets are true HTTP (port 443 is just HTTP with SSL encapsulation, the encrypted packets are still HTTP) and things like HTTP Host: headers are used. Rewriting those is very very painful, and in most cases use of an HTTP proxy server to do the task is best.

    BTW, don't the QNAP NAS units have an administrative web GUI that listens on port 80 or 443? If so, by "redirecting" AppleTV packets to that port, you would be causing massive mayhem and probably upsetting the QNAP NAS webserver. I simply don't know though; I have used none of these devices.

    Finding out what is actually flowing across the wire is what matters, hence the need for packet captures. I have posted elsewhere on this forum small "tutorials" of sorts on how to use tcpdump on a Tomato router to monitor packets going out the WAN interface, so you can look through my past posts if you want to learn how to do that. You won't be able to monitor machine-to-machine (i.e. 192.168.1.8 <-> 192.168.1.9) traffic, but you can watch Internet traffic (outbound or inbound).

    The amount of time proper reverse-engineering of this would take is fairly high, specifically if being done by someone who does not have familiarity with networking at this level. Unless someone online has actually done exactly what you're wanting, you're either going to have to learn a lot about IP networking, or probably hire someone to sit down with you (in person) and reverse-engineer the flow and figure it out. This is something that can be done remotely, but very very very painfully because it requires one skilled engineer to be on the telephone directing another person to do things like "turn the AppleTV device on" while simultaneously issuing commands. It's a lot easier to do in person.

    Once the details of the packet flow can be determined, and the contents of the packets can be analysed, then someone can try to come up with some iptables rules that might work. I'm wondering if the mangle table would be used for this; the destination address has to get rewritten and then the packet forwarded back (across the LAN) to another LAN device and so on. So like I said, packet captures would help.
     
  9. tjfriese

    tjfriese Addicted to LI Member

    I should have mentioned that PlexConnect is a Plex client. It is a collection of Python scripts that serves Javascript through the AppleTV's Trailers app. Currently it is running on my QNAP NAS at the same time as the Plex Media Server.

    >>1. What destination IP address is the AppleTV (192.168.1.9) device talking to at present? Is it somewhere >>on the Internet?
    The AppleTV iwll talk to trailers.appel.com. The PlexConnect application redirects (intercepts) requests to trailers.apple.com and replies with the Javascript PlexConnect client (currently running on 192.168.1.8).

    >>2. What source port number(s) does the AppleTV (192.168.1.9) device use, or are they dynamic? (If you >>don't understand what this means, then this indicates you should probably learn a bit about IP networking -- >>specifically, when two endpoints talk, there is a source IP and source port, and a destination IP and >>destination port)
    I believe they are dynamic. Plexconnect is only concerned with traffic being sent to trailers.apple.com regardless of what port is used to send it. That is why I have the DHCP/DNS lines referenced in the first post (
    address=/trailers.apple.com/192.168.1.1
    address=/atv.plexconnect/192.168.1.1)

    >>3. What destination port number(s) does the AppleTV (192.168.1.9) device talk to?
    No traffic ever actually leaves the internal network. Normally the Apple TV Trailers app would wait for traffic on 80 and 443. That is why I need PlexConnect to be able to listen on those ports. The reason why I need to forward around those ports is that I have a QNAP NAS that still listens on those ports even though I have told it not to listen on those ports.

    >>BTW, don't the QNAP NAS units have an administrative web GUI that listens on port 80 or 443? If so, by >>"redirecting" AppleTV packets to that port, you would be causing massive mayhem and probably upsetting >>the QNAP NAS webserver. I simply don't know though; I have used none of these devices.
    The QNAP WebUI runs on port 8080. It also has a webserver running (either Apache or Qhttpd) that by default runs on port 80. I have modified that to use port 81. I have done the same for the HTTPS portion (changed port 443 to port 444). These changes have not been enough to get the device to stop listening on those ports.

    In the first post I referenced this iptables command:

    iptables -t nat -A PREROUTING -s 192.168.1.9 -d 192.168.1.1 -p tcp -m multiport --dports 80,443 -j DNAT --to-destination 192.168.1.8:8090
    That command in conjunction with the DHCP/DNS rules was enough to have PlexConnect working when the AppleTV was only looking for content to be sent to it on port 80. The command should have worked equally well written as:

    iptables -t nat -A PREROUTING -s 192.168.1.9 -d 192.168.1.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.8:8090

    as the AppleTV wsa only ever anticipating traffic on port 80. The author of the original command set it up in case traffic was ever expected on either of ports 80 or 443, but not both.

    Now that the AppleTV is looking for traffic on both ports separately, the initial command will not work. I wonder if the reason that the two separate comamnds don't work is because there is seemingly no way to prioritze them. I should try reversing the order of the commands to see if that has any impact.

    I hope this is clearer.
     
  10. koitsu

    koitsu Network Guru Member

    Sort of, but not really. I'm just not getting the information I really need here.

    From what I can discern, this is the situation:

    192.168.1.9 (AppleTV) normally talks to whatever atv.plexconnect or trailers.apple.com resolves to. It speaks on TCP port 80 or TCP port 443. You've used dnsmasq to falsify DNS A record lookups so that resolution of those two FQDNs return an IP address of 192.168.1.1 (router)

    You then want 192.168.1.1 to essentially "punt/forward" the aforementioned packets to 192.168.1.8 on TCP port 8090.

    I can assure you the AppleTV device is expecting HTTP+SSL on port 443. You cannot have a webserver that answers on a single port for both protocols (HTTP and HTTP+SSL). Yes, there is an RFC that lets you do this (RFC 2817; it allows a plaintext HTTP connection to be "upgraded" to SSL via TLS), but I doubt that is how the AppleTV device is designed. So, I can tell you right now that redirecting port 80 and 443 to 192.168.1.8 on port 8090 will probably not work. You're going to need two daemons on 192.168.1.8 -- one that understands plaintext (say on port 8090) and one that handles SSL (say on port 8091). I will also admit that I am having to make assumptions about this model, because without packet captures and actual payload I cannot guarantee this is the case, but it sure looks like it to me.

    That said, back to the matter at hand...

    Essentially what you're wanting to do is have 192.168.1.1 forward TCP packets coming from 192.168.1.9:{anyport} to 192.168.1.1:{80,443} to 192.168.1.8:8090.

    Your router's administrative GUI lives on 192.168.1.1:80, and there are known problems/caveats if you move it to a different port (there's a semi-recent thread about that which I commented in; some of the "automatic refreshes" and HTTP redirects do not take the changed port number into consideration). However, it's probably unlikely your AppleTV device is ever going to want to talk to 192.168.1.1:80 or 192.168.1.1:443, so as long as we filter off of source address we should be okay.

    I can replicate this exact condition/scenario without "special devices". So here's my test that shows it works:

    192.168.1.1 = Asus RT-N16, running tomato-K26USB-1.28.0502.8MIPSR2Toastman-RT-N-Ext.trx
    192.168.1.50 = Windows XP workstation, listening on TCP port 3389 (MSTSC/Remote Desktop) (think of this as your QNAP thing)
    192.168.1.51 = FreeBSD machine (think of this as your AppleTV client)

    Goal: I want TCP packets with a source address of 192.168.1.51:{anyport} destined to 192.168.1.1:12345 to get forwarded to 192.168.1.50:113. Short version: 192.168.1.51 should be able to connect to 192.168.1.1:12345 but be actually speaking with 192.168.1.50:113. The traffic needs to flow bidirectionally as well (a TCP socket connection should suffice for that, due to the 3-way handshake nature of TCP), but the daemon listening on 192.168.1.50:113 will return some text to act as a validator.

    So let's try it. First, my existing PREROUTING table:

    Code:
    root@gw:/tmp/home/root# iptables -t nat -L PREROUTING -n -v --line-numbers
    Chain PREROUTING (policy ACCEPT 61 packets, 5057 bytes)
    num  pkts bytes target  prot opt in  out  source  destination
    1  0  0 DROP  all  --  vlan2  *  0.0.0.0/0  192.168.1.0/24
    2  278K  26M WANPREROUTING  all  --  *  *  0.0.0.0/0  76.102.14.35
    3  260K  25M upnp  all  --  *  *  0.0.0.0/0  76.102.14.35
    
    
    Now we add the rule and verify what it looks like:

    Code:
    root@gw:/tmp/home/root# iptables -t nat -A PREROUTING -i br0 -p tcp --syn -s 192.168.1.51 -d 192.168.1.1 --dport 12345 -j DNAT --to-destination 192.168.1.50:113
    
    root@gw:/tmp/home/root# iptables -t nat -L PREROUTING -n -v --line-numbers
    Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
    num  pkts bytes target  prot opt in  out  source  destination
    1  0  0 DROP  all  --  vlan2  *  0.0.0.0/0  192.168.1.0/24
    2  278K  26M WANPREROUTING  all  --  *  *  0.0.0.0/0  76.102.14.35
    3  260K  25M upnp  all  --  *  *  0.0.0.0/0  76.102.14.35
    4  0  0 DNAT  tcp  --  br0  *  192.168.1.51  192.168.1.1  tcp dpt:12345 flags:0x17/0x02 to:192.168.1.50:113
    
    There it is, entry 4 at the bottom. Now let's test from the FreeBSD box (192.168.1.51) and see what happens:

    Code:
    $ telnet 192.168.1.1 12345
    Trying 192.168.1.1...
    Connected to 192.168.1.1.
    Escape character is '^]'.
    2,4
    2, 4 : USERID : UNIX : no
    Connection closed by foreign host.
    
    I entered the string "2,4" and pressed Enter, and the daemon (an RFC931/1413 service) responded with the relevant text and closed the socket. To triple check that things aren't happening due to magic voodoo, let's look at the packet counter on that iptables rule we added:

    Code:
    root@gw:/tmp/home/root# iptables -t nat -L PREROUTING -n -v --line-numbers
    Chain PREROUTING (policy ACCEPT 30 packets, 2116 bytes)
    num  pkts bytes target  prot opt in  out  source  destination
    1  0  0 DROP  all  --  vlan2  *  0.0.0.0/0  192.168.1.0/24
    2  278K  26M WANPREROUTING  all  --  *  *  0.0.0.0/0  76.102.14.35
    3  260K  25M upnp  all  --  *  *  0.0.0.0/0  76.102.14.35
    4  1  60 DNAT  tcp  --  br0  *  192.168.1.51  192.168.1.1  tcp dpt:12345 flags:0x17/0x02 to:192.168.1.50:113
    
    Yep, I see 1 packet (60 bytes). You might think "shouldn't there be more bytes/packets due to the text/etc. in the payload?" No -- only the initial packet is forwarded, the rest is pure two-way communication between 192.168.1.51 and 192.168.1.50. The router stays completely out of the picture once the packet is forwarded.

    Now let's delete the rule and see what happens if we try the connection...

    Code:
    root@gw:/tmp/home/root# iptables -t nat -D PREROUTING 4
    
    ...and over on the FreeBSD box...
    
    $ telnet 192.168.1.1 12345
    Trying 192.168.1.1...
    telnet: connect to address 192.168.1.1: Connection refused
    telnet: Unable to connect to remote host
    
    Yup, fails as it should.

    If you manage to get all of this accomplished/done and it "doesn't work", then chances are what you're not understanding is the underlying layer 7 protocol (the actual HTTP packets themselves) and how that works. The AppleTV device could be attempting to talk to some other FQDN (which dnsmasq would resolve publicly of course), or alternately, it could be including specific things in the client HTTP headers which causes the daemon on your QNAP box to behave erroneously.

    My point here is that the iptables method I just showed you above for forwarding ports across the LAN does in fact work. If you have actual protocol-level problems or "how do I reverse engineer this damn AppleTV protocol" issues, those I cannot help with, and you're on your own with that. :) You're going to need to do packet captures on the router looking at the br0 (LAN) interface, as well as packet captures on the WAN interface (that's vlan2 on my router, but check your NVRAM variable wan_iface), and start trying to reverse engineer it all. I can assure you it's going to take you a lot of effort to figure out if it's a layer 7 issue. And I absolutely will not assist with that, simply because that would suck up an immense amount of time (consider hiring someone if it's outside of your skillset).

    Good luck!
     
  11. tjfriese

    tjfriese Addicted to LI Member

    First of all I want to thank you for all of your help. I was able to get it working because of your patience with me.

    Here is what I had to do to get it working:

    I used these two iptables commands:

    iptables -t nat -A PREROUTING -i br0 -p tcp --syn -s 192.168.1.9 -d 192.168.1.1 --dport 80 -j DNAT --to-destination 192.168.1.8:8090
    iptables -t nat -A PREROUTING -i br0 -p tcp --syn -s 192.168.1.9 -d 192.168.1.1 --dport 443 -j DNAT --to-destination 192.168.1.8:8091

    However, when I ran "iptables -t nat -L PREROUTING -n -v --line-numbers" I received the following back from the router:

    Chain PREROUTING (policy ACCEPT 112K packets, 19M bytes)
    num pkts bytes target prot opt in out source destination
    1 888 63307 WANPREROUTING all -- * * 0.0.0.0/0 192.168.0.12
    2 0 0 DROP all -- vlan2 * 0.0.0.0/0 192.168.1.0/24
    3 160 10240 DNAT tcp -- * * 192.168.1.9 192.168.1.1 tcp dpt:80 to:192.168.1.8:8091
    4 9 576 DNAT tcp -- * * 192.168.1.9 192.168.1.1 tcp dpt:443 to:192.168.1.8:8092

    I immediately noticed that the destination was listed as ports 8091 and 8092 instead of 8090 and 8091. I modified the PlexConnect configuration to reflect the changed ports and everything worked as it had before.

    Is there any way to find out why 8091 and 8092 are being used instead of 8090 and 8091?
     
  12. koitsu

    koitsu Network Guru Member

    Yes -- you have "old rules" from playing around with things before, most likely. Otherwise, typos, etc..

    Reboot the router and do the same two above commands again.

    I can assure you with 100% reliability that the iptables/netfilter stack on Linux is not changing port numbers on you. It does what you tell it, so human error or leftovers from testing are the only explanations.

    It's fairly obvious your nat table PREROUTING rules are wrong/messed up and you tried to recreate them at some point (I could be wrong but that's what it looks like). Compare what you provided to what I provided (this is stock default):

    Code:
    Chain PREROUTING (policy ACCEPT 22337 packets, 1738K bytes)
    num  pkts bytes target  prot opt in  out  source  destination
    1  0  0 DROP  all  --  vlan2  *  0.0.0.0/0  192.168.1.0/24
    2  285K  27M WANPREROUTING  all  --  *  *  0.0.0.0/0  76.102.14.35
    3  264K  25M upnp  all  --  *  *  0.0.0.0/0  76.102.14.35
    
    You have UPnP disabled, so the 3rd rule for you doesn't apply.

    But look closely at rule 1 and rule 2 above, then compare to yours. Yours are in the opposite order, which to me would indicate you've been poking about. The order of these rules matters and is incredibly important for security, and even more so, I notice that your rule for sending traffic to the WANPREROUTING chain has a destination IP that is 192.168.0.12, which makes no sense to me. Are you doing NAT behind NAT? Are you using VLANs? Etc. etc. etc.. I would expect to see a public Internet IP there.

    Actually, you know what, never mind my last few questions -- they aren't relevant and I really do not want to spend hours trying to reverse engineer your network topology. You obviously know it better than I do, so if it works, but you're on your own in that regard. All I can tell you is that iptables/netfilter always does what you tell it, it does not change numbers around on you.
     
    Last edited: Sep 7, 2013

Share This Page