iptables port forwarding (prerouting port 80) and firewall not working together

26,543

After PREROUTING local packets go to the local filter where they get dropped (your case 2).

So you just need to allow incoming traffic to those ports in iptables:

iptables -A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT

iptables -A INPUT -p tcp -m tcp --dport 3000 -j ACCEPT

Since you are redirecting http(s) traffic from 80/443 to 8080/3000 is like the latter ports are open and exposed to the Internet anyways, so there's no difference from the outside wrorld and there are no further security implications.

Share:
26,543

Related videos on Youtube

paintedbicycle
Author by

paintedbicycle

Updated on September 18, 2022

Comments

  • paintedbicycle
    paintedbicycle over 1 year

    I have read many articles and answers on this topic and I have been in discussion with Linode support, but no one seems to be able to answer my exact problem.

    Seems easy - I'd like to use a iptables firewall to restrict access to all ports except 22, 80 and 443. Linode has a great write up here: https://library.linode.com/securing-your-server#sph_creating-a-firewall and I used their firewall rules as is. The firewall works well.

    I also want to preroute some ports, because this is a nodejs app. So I used:

    sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
    sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 3000
    

    These rules work if I do not have the firewall rules. In fact, I'm using them right now, but I've had to leave the firewall down.

    If I add the firewall rules, the PREROUTING stops working. If I save the active iptables rules into a file to view, both the firewall (filter rules) and the PREROUTING (nat rules) are present, but only the firewall rules work. See here:

    # Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
    *security
    :INPUT ACCEPT [1606:135329]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [1206:144815]
    COMMIT
    # Completed on Wed Mar 26 02:40:04 2014
    # Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
    *raw
    :PREROUTING ACCEPT [1620:139613]
    :OUTPUT ACCEPT [1206:144815]
    COMMIT
    # Completed on Wed Mar 26 02:40:04 2014
    # Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
    *nat
    :PREROUTING ACCEPT [4:248]
    :INPUT ACCEPT [6:376]
    :OUTPUT ACCEPT [12:728]
    :POSTROUTING ACCEPT [12:728]
    -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
    -A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 3000
    COMMIT
    # Completed on Wed Mar 26 02:40:04 2014
    # Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
    *mangle
    :PREROUTING ACCEPT [1620:139613]
    :INPUT ACCEPT [1606:135329]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [1206:144815]
    :POSTROUTING ACCEPT [1206:144815]
    COMMIT
    # Completed on Wed Mar 26 02:40:04 2014
    # Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    -A INPUT -i lo -j ACCEPT
    -A INPUT -d 127.0.0.0/8 -j REJECT --reject-with icmp-port-unreachable
    -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
    -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
    -A INPUT -p icmp -j ACCEPT
    -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
    -A INPUT -j DROP
    -A FORWARD -j DROP
    -A OUTPUT -j ACCEPT
    COMMIT
    # Completed on Wed Mar 26 02:40:04 2014 
    

    If I use iptables -F, it will flush the firewall (filter) rules only and the PREROUTING will start working again. So it's definitely a conflict. The order of the rule blocks doesn't seem to matter as this (above) is the standard output by iptables regardless of the order in which I saved the rules to iptables.

    To me, it seems like it's one of two things:

    1. PREROUTING ports that also have the ACCEPT rule could mean the prerouting is ignored
    2. that I'm PREROUTING to a port that is technically blocked (but I thought that's where the "PRE" came in)

    Anyone know?

    Thanks!

    Paul

    • LinuxDevOps
      LinuxDevOps about 10 years
      looks like case 2; after PREROUTING local packets go to the local filter where they get dropped in your case. The solution is to a) run 8080 and 3000 locally (so they are not exposed) and open those ports in iptables like 80 etc or b) add rule to allow those ports for traffic coming locally only
    • paintedbicycle
      paintedbicycle about 10 years
      @LinuxDevOps Makes sense. How do a) and b) different in your answer? I'm not sure how to accomplish either case exactly, but it does make sense that I'd have to open up 8080 and 3000 to local traffic if I want this to work. Do you have a link or example of how to do that? And is there any security concerns there? Thanks!
    • LinuxDevOps
      LinuxDevOps about 10 years
      Sorry for the confusion, I think you just need to open those ports -A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT (same for 3000) , if you are redirecting from 80/443 to 8080/3000 is like the latter ports are open and exposed to the Internet anyways, I'm supposing you want http(s) requests to go directly to Node and there's no proxy (apache etc) at the front before it.
    • paintedbicycle
      paintedbicycle about 10 years
      @LinuxDevOps Interesting! Yes, http(s) requests are going directly to Node. I had assumed opening 8080 and 3000 to the public would be an issue, but it sounds from your answer that there is literally no difference since I'm forwarding 80 and 443 there anyway. Thanks for the help!
    • LinuxDevOps
      LinuxDevOps about 10 years
      correct, there's no difference from the outside, if everything works now let me put it together in a cleaner answer
    • paintedbicycle
      paintedbicycle about 10 years
      @LinuxDevOps Yes, please do. I have added those rules and the PREROUTING is working as desired and all the firewall rules are present in the file. What's the easiest way to test if the firewall is blocking the other ports? I can see them, but just want to be sure. Ping, cURL, wget from terminal?
    • LinuxDevOps
      LinuxDevOps about 10 years
      Internally if you run netstat -tlpn and look at services that listen to Local Address 0.0.0.0 or ::: then those are the services that are exposed to the outside (unless you are blocking them which usually doesn't make sense). You can run internally the nmap scanner against all ports to be sure of what's open to the Internet (from outside you may want to ask for your ISP's permission). For a particular port you can use telnet or nc.
    • paintedbicycle
      paintedbicycle about 10 years
      @LinuxDevOps Perfect, thanks. Add your answer and I'll accept it as the one.
  • Arthur Corenzan
    Arthur Corenzan over 9 years
    For the sake of information, what if I want to explicitly block direct requests for port 3000 ? I.E. mysite.com is OK but mysite.com:3000 is NOT OK.
  • Xeoncross
    Xeoncross over 9 years
    @ArthurCorenzan if you are redirecting 80 traffic to 8080 - why not just run node on 80?