VPN: Include default iptables rule for tun0 or at least optional

  • Hi there,

    first of all I want to provide the solution to this Issue in form of a feature request:

    Please add those VPN tun0 rules as default into your iptables (for the non-considered regular user like me and others):

    Code
    iptables -F
    iptables -A INPUT -i tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -i tun0 -j DROP

    These rules will filter only the tun0 interface in case an OpenVPN connection is established to a VPN provider (remote Server, which is not in your control) for overcoming geo-blocking or for IP anonymization etc. So only requested data will get to you (IPTV and scraping media coverarts will all work with that). All local connections (lcdproc, yatse, webserver, samba) will remain untouched by this.

    [hr]
    Now here's the long shot of the story as explanation why this is a concern of massive consequences:

    As nowadays many LibreELEC users consume not only local content, but also streaming content, they might use one of a lot of VPN Providers on the market to overcome geo-blocking or simply to mask their own IP Address to be anonymous during media scraping like Coverarts etc.

    Because of the demand to use VPN connections on LibreELEC, LibreELEC team reincluded OpenVPN and the user zomboided developed a mighty and very awesome addon VPN Manager for OpenVPN as well as lrusak provided his own one before. So the demand got heard :)

    The Problem with LibreELEC is that it was not meant to be used outside of the own LAN, thus no iptables rules are set as default and there is also no GUI for that or any addon that could provide you this. But fortunately iptables is integrated, so anybody can add his own rules, if he knows that they are mandatory on his setup. So this issue potentially exposes your entire local area network to the internet.

    BUT here's the massive security issue with some VPN Providers in combination with LibreELECs default setup:
    I can speak for my VPN Provider "PureVPN": PureVPN and probably many other VPN services assign an external IP to my/your LibreELEC device whenever you connect to one of their servers. The shocking point here is:
    Knowing this IP, everybody is able to access your LibreELEC system and bypassing the routers firewall as well as all its closed ports. This is an unbelievably massive security issue, because all ports are open (including SSH 22)!

    Obviously this is exactly how a VPN connection is working and why it was invented originally: People wanted an encrypted connection from workplaces or from vacation to their Network at home. So far so good, but the use case of overcoming geo-blocking or using VPNs to anonymize your own IP is differnt here: You are paying for a tunnel, of which you have only control on your own side (LAN), but not of the other side (VPN Providers remote Servers). That means that a mean employee at your VPN Provider sees the IP assigned to you upon establishing the connection and gets access to your LibreELEC machine, and in an extreme situation to your whole LAN, although you have set up a quite secure Router-Firewall and NAT (everything gets bypassed).

    I was naive and didn't ever consider that a big VPN-Provider like PureVPN (and some others are doing the same) assign not shared IPs upon established VPN connection, but real 1:1 for every single VPN tunnel. I thought that it would be like NAT: Every unrequested connection coming from outside will be simply rejected. But that's not the case. PureVPN and some other providers simply route every single connection from outside to your client. So whenever you are surfing or streaming or so through their tunnel, every content provider or website logs your PureVPN IP, which points directly to your machine bypassing your router. They can simply type in this IP into a browser and access your Webserver at Port 8080, or access through SSH.
    Comparison: If using a private VPN connection for connecting the home network to the working place network (vice versa), then you know the other side and have probably control of the server at the other end, also there might be a software firewall which does its part to security (Windows firewall doesn't help you, if established an OpenVPN tunnel). But here you don't know what is on the other side and you certainly don't want to be accessed without asking while you simply use netflix USA from Europe or so.

    And this is the frightening result of it:

    • Establish a OpenVPN connection with PureVPN
    • determine your external VPN IP: curl ifconfig.co --> Lets say you get this IP: 136.0.5.198
    • Everybody can SSH into your system now, just knowing your IP: 136.0.5.198:22 with root/libreelec (provided you have SSH activated with password)
    • Everybody can access your webserver at 136.0.5.198:8080, if you don't have set a password for it (default: not set). Even with password, it won't be hard for an attacker to breach it, I think.
    • You can be pinged with ping 136.0.5.198
    • This way everybody could also access your Samba shares and simply everything that is connected to your local network. Even if the routers firewall secures everything, the VPN tunnels from some of those VPN services, are really dangerous for not so well informed people like me and many others. Anybody on the other side simply needs to guess or to read the IP and then they can get directly into your network no matter what router security configuration you have.
    • As this is a VPN tunnel IP, it passes through my WAN router and bypasses also all the closed ports of it


    The worst thing in case of LibreELEC is that the SSH user/pass are hardcoded: root/libereelec, so anybody who has SSH activated and did not deactivate the password, is accessable due to this shit of some VPN providers from all over the world with root/libreelec.

    The thing is that I was concerned about security before using VPNs for this purpose. And whenever you search for "VPN+security", it tells you that it is kind of safe. Even if I search now for keywords with the current knowledge, it is nowhere mentioned, that those services don't close all ports in your direction by default. So a normal user like I am, would simply assume that only connections established by me will cause inbound traffic. Just like it is if you are using a Windows computer with a browser: The Firewall or routers NAT will block everything that I did not request by typing it in into the URL bar.
    And anyways... I can't even think of any use case where somebody would like to have opened ports in his direction from remote servers, where he is not sitting (if the other side is not his own LAN).

    So.. What I want to say is: VPN Providers like PureVPN, IPVanish, PIA are nowadays (especially on MediaCenters like LibreELEC) not to be seen as a regular VPN tunnel, which is commonly known for secure connections between workplaces and your homenetwork. After discovering this issue, I had the explanation why I had suddenly about 15000 infected files (by an ancient trojan) on my external harddrive some months ago, which is always connected to my Odroid C2, and no other system at home had this infection.

    Using another VPN Provider named PIA is also kind of strange: Mostly you land on a foreign computer (noticed because ssh user/pass didn't work). So it is also similar to PureVPN, except the IP is kind of random to many computers (real NAT would reject those access attempts).

    Quick workaround for those who encounter the same or who can successful access their webserver via External-VPN-IP:8080 :

    • create an autostart.sh in: storage/.config/autostart.sh
    • with this content:
      Bash
      #!/bin/sh
      iptables -F
      iptables -A INPUT -i tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT
      iptables -A INPUT -i tun0 -j DROP
    • make it executable: chmod +x storage/.config/autostart.sh
    • Reboot the system and check whether the new rules are set in SSH: iptables -L
    • Then try again to ping your computer or accress ssh via port 22. It should time out.


    Sorry for the long post :/. But I already brang this topic up in the german kodinerds forum and many users tried to explain me that this is what VPN is for... but they didn't want to understand that this geo-unblocking usecase is a different matter in terms of VPN usage. And then some other users tested it and found out that they have the same issue with their VPN Providers and didn't notice that their network was exposed the whole time because of this.

    Edited once, last by infinity85 (November 19, 2016 at 12:54 AM).

  • Thank you for bringing up an important topic.

    It should be understood by everyone that wants to punch a hole in their router/firewall (using VPN, SOCKS, reverse SSH tunnel, port forwarding, etc) that there are massive security implication by doing so. You have laid it out very well here.

    Just so people are aware what you are doing, by using iptables you are dropping all packets (accept ESTABLISHED,RELATED) on the interface tun0 (which is the tunnel interface). This effectively mitigates any incoming traffic.

  • I agree completely to your post :)
    And thanks for adding the explanation for the mentioned iptables rules.

    Further example: Using these rulest the tunnel will only allow transfers to you, if you request them. So if you turn on ITPV, this is a requested URL and the stream will be started without any delay. If you search and download subtitles, this will also work as before through the tunnel.
    But if somebody got your tunnels IP, lets say a bad guy at the IPTV provider that is streaming to you, then his attempt to connect to your machine will be blocked, because you did not open personally an additional connection besides the stream itself.

    @lrusak or Team LibreELEC
    Don't you think it would be reasonable to include an on/off switch for iptables (with at least these 3 rules) to the first boot installation wizard? Currently there is only a switch for SMB and SSH.

    I'm a bit persistent here because this entire "issue" is not really prominently placed or mentioned anywhere. Also here in this forum, nobody will pay attention to it or notice that it is extremely dangerous to use a VPN for geo-unblocking, whenever somebody is going to set up OpenVPN on LibreELEC for the first time, because LibreELEC simply does not have any firewall rules set in default config. This is in some kind of contrast to LibreELECs philosophy where you choose LibreELEC because it is so easy to set up and simply running perfectly and lightweight. If you would be an advanced user who knows everything about linux, then you would take a distro like Ubuntu or whatever and you would know, that you need to set iptables, because you would use the machine for many different tasks and those persons would probably know a bit more about security or so.

    Edited once, last by infinity85 (November 20, 2016 at 9:38 PM).

  • Code
    iptables -F
    iptables -A INPUT -i tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -i tun0 -j DROP

    No need for the -F (flush) as there are no rules to begin with. Even if there was, you probably wouldn't want to flush them.

    It's a good idea to filter unrelated packets if a one-directional VPN is what you want, but there might be people that don't want this too. In any case, this can be implemented in the addon itself as a per-VPN option. Definitely does not belong in the first run wizard.

    Edited once, last by escalade (November 21, 2016 at 9:29 AM).

  • You're right. I thought I would leave the -F rule in case that somebody has already manipulated the rules somewhere in the system, so -F would flush them and set my own rules to override the hidden ones. On the other hand this -F rule could be also deleted by an attacker haha.

    I think having this included in the VPN addon itself would be the neatest solution. How would that be done the best? I mean... I do it by introducing an autostart.sh and adding these lines to it. But actually my autostart.sh contains also other lines which could get lost, if some addon starts to mess around with existing autostart.sh.
    Do you have a suggestion fo a more safe solution without editing an autostart.sh, is there some other already present routine in LibreELEC for such things? (I'm no programmer unfortunately, but I see directories like: /storage/.config/system.d/ with *.samples which imply that there are more ways to achieve something during boot/after start without autostart.sh. Would that also count for iptables?

    I'd like to provide these tips respectively this thread to the VPN Manager Addon developer, so perhaps he will be willing to think about implementing it.

    Edited once, last by infinity85 (November 21, 2016 at 3:22 PM).

  • Probably best done with a check-box in the provider setup dialog and then an ip-up script in the generated OpenVPN config file. I don't use any VPN addons myself so that's just a suggestion, there are a number of ways it could be done.

    I don't see why an addon would throw away your autostart.sh, that would make a lot of people angry. It should be fine to use that. You can use tun+ instead of tun0 if you happen to have more than one VPN at a time as well. Yes, systemd is another way of running scripts during start.


  • Probably best done with a check-box in the provider setup dialog and then an ip-up script in the generated OpenVPN config file. I don't use any VPN addons myself so that's just a suggestion, there are a number of ways it could be done.

    I don't see why an addon would throw away your autostart.sh, that would make a lot of people angry. It should be fine to use that. You can use tun+ instead of tun0 if you happen to have more than one VPN at a time as well. Yes, systemd is another way of running scripts during start.

    Very, very useful tips! especially the tun+ hint is awesome, thanks!

  • Okay, I've been digging a bit in a systemd manual... and I'd be glad if you could give your 2cents about pro's and con's to this :/.

    Here's my preliminary solution:

    • Create a file (iptables.rules) containing the rules in: /storage/.config/iptables.rules

      Code
      # perform "systemctl restart iptables.service" after editing rules
      # tun+ will filter all tunnels. Change to tun0, tun1, tunX if wanted otherwise
      iptables -F
      iptables -A INPUT -i tun+ -m state --state ESTABLISHED,RELATED -j ACCEPT
      iptables -A INPUT -i tun+ -j DROP


      Remark to iptables -F:
      This line iptables -F is necessary, otherwise the rules will be aggregated upon manual restart of service

    • Create the systemd service (iptables.service) in: /storage/.config/system.d/iptables.service

    • Enable this systemd service with following command systemctl enable iptables.service
      (This command will create a symlink in /storage/.config/system.d/kodi.target.wants/iptables.service)
    • Now start the service with: systemctl start iptables.service
    • Check if rules were set sucessfully with: iptables -nvL
      Output should look like this:



    [hr]

    Preceding thoughts:

    At first I used the service with Type=forking:


    I chose "forking" because I could define Restart=on-failure, as I thought it is good for a security related service like this to be restarted upon failure.
    I'm not sure if that does make sense. Perhaps I'm wrong here and this parameter does not have any effect practically. That is because I'm not sure whether forking is some kind of daemon, which is running the whole time in background and notices whenever it gets killed, to be restarted with "Restart=on-failure" in that case. If that is the case, then I don't understand why "ExecStop" in combination with "forking" does not activate the rules. May be I'm missing some other paramter? Or is forking just invoking the rules once and then closes automatically, that would mean that Restart=on-failure is just working for the boot, but not if the service has a failure somewhen later during watching content or so.


    Then I made this first Type=oneshot approach:


    • The advantage of this was that you could also stop the service on demand with systemctl stop iptables.service and it would then flush the rules thanks to ExecStop=/usr/sbin/iptables -F
    • The downside was that you could not use Restart=on-failure in combination with oneshot and,...(see next point)
    • If I understand it correctly, oneshot with RemainAfterExit=yes would keep up the service the entire time consuming ressources, wouldn't it? And if it crashes, the service wouldn't restart automatically because of missing Restart=on-failure. So in worst case the rules would vanish until next reboot and you wouldn't notice that your network is exposed again. Unfortunately Restart=on-failure does not work with oneshot.


    Finally I sticked to the short "oneshot" version without the ExecStop and RemainAfterExit=yes options to not having the service running the whole time. If I make systemctl stop iptables.service the service would ignore this I think, but the iptables rules will remain active until you invoke iptables -F

    Sorry that this post is so long again -_-. However I'd really appreciate if somebody could say which one of the three services would be the best. Or how oneshot or forking handles the situation if something kills the service.

    Edited once, last by infinity85 (November 22, 2016 at 5:01 PM).


  • Why not just do it like other distributions have it?

    svntogit/packages.git - Git clone of the 'packages' repository


    Thanks for pointing to it lrusak!

    Well... a rather more embarrassing reason why I didn't do it like they do! I didn't know how other distros do it and somehow I didn't manage to find this template. Apparently I was using the wrong keywords :/

    I tried iptables-restore once, but it gave me errors... and now I understood that my iptables.rules synax must be adapted for suiting the iptables-restore command. The wrong syntax was the reason it did not work before, and I thought it was because LibreELEC is a bit differently (I thought the error messages arise because of the read-only-filesystem).

    Now I adapted the script to suit the template from your arch link:
    iptables.service:

    And I solved the errors by modifying the iptables.rules files syntax:

    Code
    # perform "systemctl restart iptables.service" after editing rules
    *filter
    -A INPUT -i tun+ -m state --state ESTABLISHED,RELATED -j ACCEPT
    -A INPUT -i tun+ -j DROP
    COMMIT

    And finally the following commands work correctly now:

    • systemctl start iptables.service : starts the service (but does it at boot anyway, once it was enabled with systemctl enable iptables.service)
    • systemctl stop iptables.service : stops the service and flushes the rules=turns off filtering (reverting to LibreELEC default settings)
    • systemctl reload iptables.service : reloads/restarts the rules after one might have modified them or added new ones
    • systemctl restart iptables.service : apparently does the same as "reload" above

    Do you think this is a good solution? Also performance wise? oneshot should not eat any ressources, right? It is just once invoking the command and then closes again without having a process/service running in background as far as I understood.

    Edited once, last by infinity85 (November 30, 2016 at 2:28 PM).

  • absolutely no need for asking for permission! There is no intellectual property in what I did haha, as I just tested and adapted escalades and lrusaks tips. Sure, I'd be glad if you did this :)

    Do you mind if I send this thread to zomboided, who made the vpn manager addon so that he could integrate your work (or work with you) into his addon? In the long run it would be great anyway, if there is a standalone addon and one part which is integrated into a vpn addon, so that only the vpn related rules are present where they belong: In a VPN addon, right there, where you set up a vpn connection.

    And on the other hand there could be a dedicated iptables addon (like you intend to make one), which can be developed for further options and more customizable or so :)

    So may I send it to him also? He'll remember that we had a discussion about this potential issue some months ago via email.


    EDIT
    Ah and does anybody happen to know whether:

    Code
    [Install]
    WantedBy=multi-user.target


    or

    Code
    [Install]
    WantedBy=kodi.target


    is the better solution? I think if multi-user.target works, that that would be a better solution in terms of security/reliability, right? But is it consistent with LibreELECs approach of singleuser / root / readonly philosopy? Is there any conflict or so like "multi-user.target" is invoked later or prior or too early, to late etc.?

    Edited once, last by infinity85 (November 24, 2016 at 1:50 AM).

  • Thanks for the email Mr Infinity. Let's have the conversation here so I better understand. I don't have my LibreELEC boxes handy right now.

    Regardless of the approach that's used, I think the requirement is to update the iptable before establishing a VPN with the following two commands?

    Code
    iptables -A INPUT -i tun+ -m state --state ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -i tun+ -j DROP

    If a VPN is disconnected, what effect do these commands have? I think they'll be redundant, correct (ie, my router firewall will do the right thing as I don't have a VPN punching a hole, plus I can still ping, etc from the local network)? And therefore there's no need to remove them.

    If they are redundant why is there a requirement to switch it on and off? I think any integration with VPN Manager (which seems like a good idea, with it turned on by default), would be just to ensure these commands are sent, with an option to not do this for users that want to create their own special rules and go down a path of a systemd task that does magical things at boot?

    Edited once, last by zomboided (November 29, 2016 at 12:16 PM).


  • Thanks for the email Mr Infinity. Let's have the conversation here so I better understand. I don't have my LibreELEC boxes handy right now.

    Regardless of the approach that's used, I think the requirement is to update the iptable before establishing a VPN with the following two commands?

    Code
    iptables -A INPUT -i tun+ -m state --state ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -i tun+ -j DROP

    If a VPN is disconnected, what effect do these commands have? I think they'll be redundant, correct? And therefore there's no need to remove them.

    If they are redundant why is there a requirement to switch it on and off? I think any integration with VPN Manager (which seems like a good idea, with it turned on by default), would be just to ensure these commands are sent, with an option to not do this for users that want to create their own special rules and go down a path of a systemd task that does magical things at boot?


    Exactly. I can only speak for myself at first: My intention to have a "turn off" option was to ensure that users, who use your addon with their own VPN server (no PureVPN or IPVanish or similar), have the option to have control over this setting (or at least they would take notice that VPN Manager for OpenVPN is setting up iptables rules). If it wasn't an option in the addons GUI, then nobody would know why his private VPN (from lets say his vacation location to his home-router) isn't working as expected, although this person did not set up any firewall rules to be responsible for this. They'd probably wrap LibreELEC inside out to find the reason :D

    From developers point of view lrusak, you and awiouy do certainly have a better overview and basis to discuss pro's and con's for this :)

    Edited once, last by infinity85 (November 29, 2016 at 12:23 PM).

  • As mentioned, I think it would be a better idea to use an ip-up script (--up) in the per-VPN OpenVPN configuration. Then you add rules for the specific tunnel interface (passed as $dev to the --up script). Likely there are users with more than one VPN and perhaps don't want to limit inbound connections. Perhaps a good idea to create a dedicated chain for the addon which then can be flushed etc without disturbing other potential rules under INPUT.

    Edited once, last by escalade (November 29, 2016 at 12:30 PM).

  • Sorry @escalade that I did not go your way at first. I couldn't find an easy way to realize it (no experience at all for this), but instead I had the templates for systemd services in LibreELECs .config folder. Your solution sounds kind of perfect in terms of flexibility, when reading it now after you explained it a bit further :)

    @zomboided
    Do you think that it would also be possible to take user defined into account? I'm using PureVPN, but I'm using custom *.ovpn files for it with your User Defined option, because this way I can specify also direct connections to the Servers IP-addresses behind their DNS names.

    Like
    DNS: usny1-ovpn-udp.pointtoserver.com
    Corresponding IP-Adresses after resolution: 23.236.155.35 and 172.245.48.125 and 172.94.41.130 etc.

    Doing this method, because sometimes the servers are overloaded and slow and then I can cherry pick them by choosing different *.ovpn's to find a server that is kind of less used at the moment.

    Edited once, last by infinity85 (November 29, 2016 at 1:15 PM).