This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. {{tag>linux router vpn wireguard Docker "qr code" QR}} =====Wireguard VPN access from WAN to LAN====== <fc #ff0000>I use a Docker instance for my Wireguard server now.</fc> I use 2 forms of vpn (virtual private network) on my home server. - VPN to gain remote secure private access to my home LAN from the WAN (internet). //This is the one I am describing here.// - VPN to anonymize my public internet access, making it more difficult for others to track my online behavior. //This is where I describe this [[https://wiki.kptree.net/doku.php?id=tech_notes:docker-deluge#vpn_setup_including_nftable_force_vpn_usage|VPN setup including nftable force to anonymize WAN usage]]// WireGuard is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform (Windows, macOS, BSD, iOS, Android) and widely deployable. It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry. ===Linux Wireguard Setup links=== * [[https://www.wireguard.com/|WireGuard]] * xdeb.org [[https://xdeb.org/post/2019/09/26/setting-up-a-server-firewall-with-nftables-that-support-wireguard-vpn/|Setting up a server firewall with nftables that support WireGuard VPN]] * [[https://engineerworkshop.com/blog/how-to-set-up-a-wireguard-vpn-server-on-ubuntu-linux/|How To Set Up a WireGuard VPN Server on Ubuntu Linux]] * [[https://github.com/pirate/wireguard-docs|Some Unofficial WireGuard Documentation]] * [[https://securityespresso.org/tutorials/2019/03/22/vpn-server-using-wireguard-on-ubuntu/|How to setup your own VPN server using WireGuard on Ubuntu]] * [[https://wiki.archlinux.org/index.php/WireGuard|Archlinux Wireguard]] * [[https://www.ckn.io/blog/2017/11/14/wireguard-vpn-typical-setup/|Wireguard VPN: Typical Setup]] * [[https://try.popho.be/vpn.html|OpenVPN FAQ]] * [[https://www.linode.com/docs/security/firewalls/control-network-traffic-with-iptables/#insert-replace-or-delete-iptables-rules|A Tutorial for Controlling Network Traffic with iptables]] * [[https://www.cyberciti.biz/faq/how-to-set-up-wireguard-firewall-rules-in-linux/|How To Set Up WireGuard Firewall Rules in Linux]] * [[https://serversideup.net/courses/gain-flexibility-and-increase-privacy-with-wireguard-vpn/|Gain flexibility & increase privacy with WireGuard VPN]] ====My Setup==== I want to setup an access within my Linux router to allow external authorise only VPN access into the system. I proposed to use an entirely separate IP address range for this: * Main home LAN is on 192.168.1.0/24 * Access to my VDSL modem is on 192.168.5.0/24 * VPN (Wireguard) LAN range is 192.168.6.0/24 There seem to be a lot of methods to use the Wireguard interface, most of them do not align well with my requirements, specifically for firewall they reference iptables, or UFW, instead of nftables and do not in general seem well setup for router access, also some belabour use of variable IP address on domain names, whereas I have organised a static IP address for my domain, or are not setup to utilise a full manual setup Linux router, using OPNsense, pfsense, OpenWRT or consumer modem/router boxes, etc. ===Greatest Difficulties in Setting=== Wireguard is not chatty, this actually is a security feature. It is important that the setup information is done correctly, in particular the private and public keys. Also the allowed ips is important. On the server side it is set to the main VPN ip address. On the client side it needs to be set to include ip addresses that are allowed to be access on the client side. Some tools that help fault find: * On the server side: ''sudo tcpdump -i wan_device -c 5 port vpn_port'', where wan_device is the wan device, in my case ppp1 and vpn_port is the port number wireguard is set to, in my case 51914, the default is 51820. This lets you see if the packets are coming in to the wan. * The next is checking the firewall to see if the packets are being directed to the wireguard IP address *''sudo nft list table inet firewall -a'' will list my firewall settings. * ''ip daddr 192.168.6.1 udp dport 51914 counter packets 1 bytes 176 accept # handle 29'' of the router input indicates that the first packet was allowed to the wireguard vpn, 192.168.6.1:51914. After this the packets are captured stateful statement''ct state established,related counter packets 31276 bytes 9246975 accept # handle 24''. *''sudo nft list table ip nat -a'' will list my nat settings. *''ip daddr 112.213.222.38 udp dport 51914 counter packets 287 bytes 50512 dnat to 192.168.6.1'' prerouting shows the incoming wan packet on the vpn port are directed to the vpn server ip address. *''oifname "ppp1" counter packets 129181 bytes 22662174 masquerade # handle 13'' postrouting, the vpn packets from 192.168.6.1 are masqueraded onto the wan. ====Basic Wireguard Installation on Router==== Installation of Wireguard on Ubuntu 20.04 straight forwards: ''sudo apt install wireguard'' The ability to forward packets must be set / allowed, edit or add the following parameters in ''sudo vim /etc/sysctl.conf'': *net.ipv4.ip_forward = 1 *net.ipv4.conf.all.proxy_arp = 1 After applying these changes reboot or apply setting using ''sudo sysctl -p /etc/sysctl.conf'' Create some security keys: <code> sudo su cd /etc/wireguard umask 077 wg genkey | tee name_1_privatekey | wg pubkey > name_1_publickey wg genkey | tee name_2_privatekey | wg pubkey > name_2_publickey </code> Use ''exit'' to get out of root access. (I prefer to use sudo instead of going full root.) (In Australia English root has another less savoury meaning....) Clearly the private key needs to be kept private for security reasons. Also no need to unnecessarily flash around the pubic key in general public. The above keys are simple files that can be viewed as text using standard utilities, e.g. ''cat name_1_private_key'', etc. Example below (real, but not used): * privatekey: ''4G8wilxppYxxMibntzBL6lejypNOxU0NAAMi4/azAlY='' * publickey: ''n3xKCvYWyosT9yBPLTeCy5M8nWHp2mBJuAz79a4KPAo='' While still in ''/etc/wireguard'' in root create a wireguard server configuration file: ''vim wg0.conf'' or ''sudo vim /etc/wireguard/wg0.conf''. <code> [Interface] Address = 192.168.6.1/24 SaveConfig = true PrivateKey = <insert server_private_key> ListenPort = 51914 [Peer] PublicKey = <insert client_public_key> AllowedIPs = 192.168.6.2/32 [Peer] PublicKey = <insert client_public_key> AllowedIPs = 192.168.6.3/32 </code> Obviously the correct private and public key values need to be inserted. *To start/stop the Wireguard service: ''sudo systemctl start wg-quick@wg0'' *To enable/disable the Wireguard service: ''sudo systemctl enable wg-quick@wg0'' *To check status of the Wireguard service: ''sudo systemctl status wg-quick@wg0'' ====Router Firewall changes for Wireguard==== The Router (server) firewall configuration needs to be adjusted to allow Wireguard to function. - definitions - define wan = ppp1 - define lan = br0 - define router_ip4 = 192.168.1.1 - define wan_ip4 = 112.213.222.38 - define vpn = wg0 - define vpn_ip4 = 192.168.6.0/24 - define vpn_port = 51914 - From external (Internet) to router: - Pin hole fire wall and direct to Wireguard server: - sudo nft add rule ip nat prerouting ip daddr $wan_ip4 udp dport $vpn_port counter dnat to $vpn_ip4 - sudo nft add rule inet firewall input iifname $wan dport $vpn_port counter accept - Wireguard server to LAN - Forward from wireguard LAN to general LAN: - sudo nft add rule inet firewall forward iifname $vpn counter accept - sudo nft add rule inet firewall forward ip daddr $vpn_ip4 ct status dnat counter accept - sudo nft add rule inet firewall input iifname $vpn counter accept - From LAN to Wireguard - Forward from general LAN to Wireguard LAN: - sudo nft add rule inet firewall forward oifname $vpn counter accept - From router to to external (Internet) - Mangle or SNAT to internet - sudo nft add rule ip nat postrouting ip saddr $vpn_ip4 oifname $wan counter snat $wan_ip4 (not necessary is already have masquerade on oifname $wan ====Full NFTables Code=== ''sudo vim /etc/nftables.conf'' ++++ ''nftables router script''| <color blue>#!/usr/sbin/nft -f </color> ++ | + <color #202000/#F0F0E0> nftables scripts need this shebang with the -f option to run</color>++ \\ <tab3> \\ <tab3><color blue># script variable definitions</color> ++ | \\ +<color #202000/#F0F0E0> * Device definitions can be found using ''ip a'' \\ * IP address should also be able to be found using ''ip a''.\\ * Where services are on separate server, virtual, container, etc., the ''ip a'' may need to be run in on these servers.\\ * Another option would be to use ''sudo nmap -sn 192.168.1.0/24'' to find all the related active ip address ip range. </color>++ \\ <tab3>define <color red>wan = ppp1</color><color blue> #definition of wan device label</color>\\ <tab3>define <color red>modem = eno1</color><color blue> #definition of modem device label</color>\\ <tab3>define <color red>lan = br0</color><color blue> #definition of lan device label</color>\\ <tab3>define <color red>router_ip4 = 192.168.1.1</color><color blue> #definition of router IPv4 address</color>\\ <tab3>define <color red>modem_ip4 = 192.168.5.2</color><color blue> #definition of modem IPv4 address</color> ++ | \\ + <color #202000/#F0F0E0>The $modem router interface has been assigned the IP address 192.168.5.2, as the modem device IP address is 192.168.5.1, See [[https://wiki.kptree.net/doku.php?id=linux_router:network#ubuntu_network_-_interface_setup|network interface]].</color>++\\ <tab3>define <color red>http_server = 192.168.1.12</color><color blue> #definition of http server IPv4 address</color>\\ <tab3>define <color red>mail_server = 192.168.1.18</color><color blue> #definition of mail server IPv4 address</color>\\ <tab3>define <color red>wan_ip4 = 112.213.222.38</color><color blue> #definition of wan IPv4 address</color>\\ <tab3>define <color red>vpn = wg0</color><color blue> #definition of wireguard vpn device label</color>\\ <tab3>define <color red>vpn_ip = 192.168.6.0/24</color><color blue> #definition of wireguard IPv4 address range</color>\\ <tab3>define <color red>vpn_ip4 = 192.168.6.1</color><color blue> #definition of wireguard IPv4 server address</color>\\ <tab3>define <color red>vpn_port = 51914</color><color blue> #definition of wireguard server port</color>\\ <tab3><color #000060/#F0F0FF>#define</color> <color #060000/#FFF0F0>he_tunnel = he-ipv6</color><color blue> #</color>\\ <tab3> \\ <tab3><color blue> # Clean out the current ruleset</color>\\ <tab3> flush ruleset ++ | \\ +<color #202000/#F0F0E0>Clears the previous ruleset. This flushes out all the tables, chains and rules so we can start clean. This is not done automatically so without this, previously added rules would still be in effect. See nft man page <tab1> [[https://www.netfilter.org/projects/nftables/manpage.html#lbAO|Ruleset]] for more information.</color>++ \\ <tab3> \\ <tab3> table inet firewall { ++ | \\ +<color #202000/#F0F0E0>This defines a table. A table is a container for chains (and sets). This line defines a table with the family ''inet'' and name ''firewall''. ''inet'' is a family that encompasses both IPv4 and IPv6 internet protocols. I wanted a shared configuration between both so I chose this one, alternatively I could have restricted it to either by using ip or ip6. See nft man page <tab1> [[https://www.netfilter.org/projects/nftables/manpage.html#lbAP|Tables]] for more information.</color> ++ \\ <tab6> \\ <tab6><color blue> # The set controllist is used to dynamically add IP address(es) to a timed drop list for LAN access control </color> ++ | \\ +<color #202000/#F0F0E0> This has been separately described in detail at the following link: [[linux_router:nftables_control]], also see wiki.nftables on<tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets| Names Sets]] & nft man page <tab1> [[https://www.netfilter.org/projects/nftables/manpage.html#lbAS|Sets]].</color> ++ \\ <tab6> set controllist {\\ <tab9> type ipv4_addr\\ <tab9> flags interval\\ <tab9> flags timeout\\ <tab6> }\\ <tab2> \\ <tab6><color blue> # Remember that the input and output chains only refer to this machine.</color>\\ <tab6><color blue> # The forward and nat chains refer to routing.</color>\\ <tab6><color blue> # open ports refers to ports to open for input to this machine.</color>\\ <tab6><color blue> # ssh is port 22 for SSH on both TCP and UDP, but we only use TCP!</color>\\ <tab6><color blue> # bootps, port 67 and bootpc, port 68 are for DHCP on both TCP and UDP, but we only use UDP!</color>\\ <tab6><color blue> # domain is port 53 for DNS requests on TCP & UDP.</color>\\ <tab6><color blue> # openvpn is port 1194 on both TCP and UDP, but we will not be using this antiquated protocol.</color>\\ <tab6>\\ <tab6> set tcp_open_ports { ++ | \\ + <color #202000/#F0F0E0> This creates a set of type inet_service (port number or range). The flags interval directive enables port ranges to be used. After that, you just set elements to add members to the set. Having a set is a clean and efficient way to later reference all of these values in the rules. We can use port numbers, service names and port ranges.\\ Sets provide a performant way to use generic sets of data, that can be dynamically manipulated, so they are very suitable for tasks like IP blocking. More about sets on the nftables wiki page<tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets| Names Sets]] & nft man page <tab1> [[https://www.netfilter.org/projects/nftables/manpage.html#lbAS|Sets]]. </color>++ \\ <tab9> type inet_service; flags interval;\\ <tab9> elements = {\\ <tab12> ssh,\\ <tab12> domain\\ <tab9> }\\ <tab6> }\\ <tab6> \\ <tab6> set udp_open_ports { ++ | \\ + <color #202000/#F0F0E0> This creates a set of type inet_service (port number or range). The flags interval directive enables port ranges to be used. After that, you just set elements to add members to the set. Having a set is a clean and efficient way to later reference all of these values in the rules. We can use port numbers, service names and port ranges.\\ Sets provide a performant way to use generic sets of data, that can be dynamically manipulated, so they are very suitable for tasks like IP blocking. More about sets on the nftables wiki page<tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets| Names Sets]] & nft man page <tab1> [[https://www.netfilter.org/projects/nftables/manpage.html#lbAS|Sets]]. </color>++ \\ <tab9> type inet_service; flags interval;\\ <tab9> elements = {\\ <tab12> domain,\\ <tab12> <color red>$vpn_port</color>, <color blue># Wireguard port</color>\\ <tab12> 60000-61000 <color blue># mosh port interval</color>\\ <tab9> }\\ <tab6> }\\ <tab3>\\ <tab6> chain tcp_cek { ++ | \\ + <color #202000/#F0F0E0>A chain is a container for rules. This a regular (non-base) chain. As a regular chain does not define a type or hook it can only be called from another chain with a jump (or goto) statement. See wiki.nftables <tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] & nft man page <tab1> [[https://www.netfilter.org/projects/nftables/manpage.html#lbAQ|Chains]]for more information</color>++ \\ <tab9><color blue> # bad tcp -> avoid network scanning: </color>\\ <tab9> tcp flags & (fin|syn) == (fin|syn) counter drop\\ <tab9> tcp flags & (syn|rst) == (syn|rst) counter drop\\ <tab9> tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) counter drop\\ <tab9> tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) counter drop\\ <tab6> } \\ <tab3> \\ <tab6> chain icmp_cek {++ | \\ + <color #202000/#F0F0E0>A chain is a container for rules. This a regular (non-base) chain. As a regular chain does not define a type or hook it can only be called from another chain with a jump (or goto) statement. See wiki.nftables <tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] for more information.\\ More information on icmp can be seen at nftables man [[https://www.netfilter.org/projects/nftables/manpage.html#lbCG|ICMP Header Expression]].\\ Our table type is inet which means IPv4 or IPv6. However, ICMP is different to ICMPv6. This means that we have to do our checks with version specific directives. The ip and ip6 directives do that. After more version specific checks, we match the version specific types.</color>++ \\ <tab9><color blue> # no ping floods</color>\\ <tab9> ip protocol icmp counter\\ <tab9> ip protocol icmp limit rate over 2/second burst 5 packets counter drop ++ | + <color #202000/#F0F0E0> This limits the incoming rate of icmp packets handled </color>++\\ <tab9> ip6 nexthdr ipv6-icmp counter\\ <tab9> ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 2/second burst 5 packets counter drop ++ | + <color #202000/#F0F0E0> This limits the incoming rate of icmpv6 packets handled </color>++\\ <tab9> \\ <tab9><color blue> # allow icmp</color> \\ <tab9> ip protocol icmp icmp type { ++ | + <color #202000/#F0F0E0> This allows the icmp packets to be handled </color>++\\ <tab12> echo-request, echo-reply, time-exceeded,\\ <tab12> parameter-problem, destination-unreachable\\ <tab9> } counter accept\\ <tab9> \\ <tab9> ip6 nexthdr icmpv6 icmpv6 type { ++ | + <color #202000/#F0F0E0> This allows the icmpv6 packets to be handled </color>++ \\ <tab12> echo-request, echo-reply, time-exceeded,\\ <tab12> parameter-problem, destination-unreachable,\\ <tab12> packet-too-big, nd-router-advert, nd-router-solicit,\\ <tab12> nd-neighbor-solicit, nd-neighbor-advert,\\ <tab12> mld-listener-query\\ <tab9> } counter accept\\ <tab6> }\\ <tab6> \\ <tab6> chain input {++ | \\ + <color #202000/#F0F0E0> See wiki.nftables <tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] for more information. The name does not actually matter, but was chosen to align with iptables. This is a base chain, hence base chain type and base chain hook must be defined.</color>++ \\ <tab9> type filter hook input priority 0; policy drop; ++ | \\ + <color #202000/#F0F0E0> This statement defines the the base chain's: type (filter), hook (input), priority (0) and policy (drop), any packet that makes it way through all the table chain is at the end drop (nftable default policy is accept, hence it is necessary to set so). See wiki.nftables <tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] for more information.</color>++ \\ <tab9> \\ <tab9><color blue> # drop connections from blacklisted addresses</color> \\ <tab9><color blue> # ip saddr @blacklist counter drop</color> \\ <tab9>\\ <tab9><color blue> # Cek valid tcp packet</color>\\ <tab9> ip protocol tcp jump tcp_cek ++ | + <color #202000/#F0F0E0> We use the jump statement as we want to return and continue to process chains after this statement.</color>++\\ <tab9> \\ <tab9><color blue> # Cek valid icmp communications</color>\\ <tab9> jump icmp_cek ++ | + <color #202000/#F0F0E0> We use the jump statement as we want to return and continue to process chains after this statement.</color>++\\ <tab9>\\ <tab9><color blue> #count all the wan SSH attemps</color>\\ <tab9><color #000060/#F0F0FF> #iifname </color><color #060000/#FFF0F0>$wan</color><color #000060/#F0F0FF> tcp dport ssh counter</color> \\ <tab9>\\ <tab9><color blue> # avoid brute force on ssh: (if using external ssh)</color> \\ <tab9><color #000060/#F0F0FF> #tcp dport ssh limit rate over 8/minute counter drop</color> ++ | \\ + <color #202000/#F0F0E0>Rate limit and count WAN ssh attempts. As I only allow ssh locally on LAN or via VPN I drop all such incoming traffic. (Also probably would not work without NAT prerouting dnat.)</color>++ \\ <tab6>\\ <tab6><color blue> # In general input filter drops and limits list should be placed above here here</color> ++ | \\ + <color #202000/#F0F0E0>Position of rules is important in chains. Once a chain rule accepts, drops or rejects a packet subsequent chain rules are no longer processed!)</color>++ \\ <tab6>\\ <tab9><color blue> # accept established connections</color> ++ | \\ + <color #202000/#F0F0E0>This rule is to allow already established or related connections through. If the connection has already been established, it probably means it was already allowed by us earlier and we can just continue allowing it.\\ ''ct'' is used to tap into the connection tracking entry associated with the packet. In this case, we are accessing the state of the connection, and checking if it is in the set ''{established, related}''. If it is in the set, accept the packet, otherwise, continue to the next rule. </color>++ \\ <tab9> ct state established, related counter accept \\ <tab9> \\ <tab9><color blue> # drop invalid state packets</color> ++ | \\ + <color #202000/#F0F0E0>This is similar to the previous line, but this time, instead of checking if the state is within a set, we only check if the connection state is ''invalid'' and if so, we drop the packet. That is, we just ignore the packet as if it never came in. Otherwise continue on to the next rule.</color>++ \\ <tab9> ct state invalid counter drop\\ <tab9> \\ <tab9><color blue> # accept input from loopback interface</color> ++ | \\ + <color #202000/#F0F0E0>It is generally accepted practice to accept all packets from the loopback interface.</color>++ \\ <tab9> iif lo counter accept\\ <tab9> \\ <tab9><color blue> # accept input from LAN</color> ++ | \\ + <color #202000/#F0F0E0>Filtering of LAN incoming packets. It can be done by port or port sets, however in general all the LAN interface inputs can be accepted. Filtering by port probably does improve security, but any applications using ports not in the filter will be broken until added.</color>++ \\ <tab9> iifname <color red>$lan</color> counter accept <color blue># By port is a pain in the arse!</color>\\ <tab9><color #000060/#F0F0FF> # iifname </color><color #060000/#FFF0F0>$lan</color><color #000060/#F0F0FF> tcp dport { ssh, domain, 667, 953 } counter accept</color> ++ | + <color #202000/#F0F0E0>This is used to accept specific LAN tcp ports, required if not accepting all.</color>++ \\ <tab9><color #000060/#F0F0FF> # iifname </color><color #060000/#FFF0F0>$lan</color><color #000060/#F0F0FF> udp dport { domain, bootps, bootpc, 667, 953} counter accept</color> ++ | + <color #202000/#F0F0E0>This is used to accept specific LAN tcp ports, required if not accepting all.</color>++ \\ <tab9> \\ <tab9><color blue> # accept input from VPN</color> ++ | \\ + <color #202000/#F0F0E0>Filtering of VPN incoming packets. It can be done by port or port sets, however in general the all the VPN interface inputs can be accepted. Filtering by port probably does improve security, but any applications using ports not in the filter will be broken until added.</color>++ \\ <tab9> iifname <color red>$vpn</color> counter accept <color blue># By port is a pain in the arse!</color>\\ <tab9> ip daddr <color red>$vpn_ip4</color> udp dport <color red>$vpn_port</color> counter accept ++ | \\ + <color #202000/#F0F0E0> As the VPN is hosted on this local machine this chain allows packets that have been preroute dnat to the VPN IP address to be accepted.</color>++ \\ <tab9><color #000060/#F0F0FF> # iifname </color><color #060000/#FFF0F0>$wan</color><color #000060/#F0F0FF> udp dport </color><color #060000/#FFF0F0>$vpn_port</color><color #000060/#F0F0FF> ct state new counter accept</color>\\ <tab9>\\ <tab9><color blue> # everything else reject port unreachable</color> \\ <tab9> ct state new counter reject ++ | \\ + <color #202000/#F0F0E0> Any other new packets coming to the filter input are unknow and should be dropped or rejected. Dropped means the packet is simply ignored and not further proceesed. Reject means the packet is ignored and not further procees and a ICMP(v4 or v6) host-unreachable message is returned to the source. See wiki.nftables <tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Rejecting_traffic| Rejecting traffic]] for more information. </color>++\\ <tab6> }\\ <tab6>\\ <tab6> chain forward {++ | \\ + <color #202000/#F0F0E0> See wiki.nftables <tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] for more information. The name does not actually matter, but was chosen to align with iptables. This is a base chain, hence base chain type and base chain hook must be defined.</color>++ \\ <tab9> type filter hook forward priority 0; policy accept; ++ | \\ + <color #202000/#F0F0E0> This statement defines the the base chain's: type (filter), hook (forward), priority (0) and policy (accept), any packet that makes it way through all the table chain is at the end drop (nftable default policy is accept, hence it is necessary to set so). See wiki.nftables <tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] for more information.</color>++ \\ <tab9>\\ <tab9><color blue> #drop all IP addresses in the control list both source and destination</color> ++ | \\ +<color #202000/#F0F0E0> This has been separately described in detail at the following link: [[linux_router:nftables_control]], also see wiki.nftables on<tab1> [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets| Names Sets]] & nft man page <tab1> [[https://www.netfilter.org/projects/nftables/manpage.html#lbAS|Sets]].</color> ++ \\ <tab9> ip daddr @controllist counter drop\\ <tab9> ip saddr @controllist counter drop\\ <tab9>\\ <tab9><color blue> #limit the IP address range bandwidth using WAN</color> ++ | \\ +<color #202000/#F0F0E0> This is a simple form of traffic control. My DHCP / DNS place critical IP address in the 192.168.1.1 to 99 range, other equipment is automatically assigned in the 100-254 range. The chains below then limit traffic speed into / out of these IP addresses. This has been separately described in detail at the following link: [[linux_router:nftables_control#Limit Rate on IP Address Range]] </color> ++ \\ <tab9> iifname <color red>$wan</color> ip daddr { 192.168.1.100-192.168.1.254 } limit rate over 1300kbytes/second burst 3000kbytes counter drop\\ <tab9> oifname <color red>$wan</color> ip saddr { 192.168.1.100-192.168.1.254 } limit rate over 750kbytes/second burst 1200kbytes counter drop\\ <tab9>\\ <tab9><color #000060/#F0F0FF> #oifname </color><color #060000/#FFF0F0>$wan</color><color #000060/#F0F0FF> tcp flags syn tcp option maxseg size set rt mtu</color>\\ <tab9> oifname <color red>$wan</color> tcp flags syn tcp option maxseg size set 1452 counter\\ <tab6>\\ <tab6><color blue> # In general forward filter drops and limits list should be placed above here here</color> ++ | \\ + <color #202000/#F0F0E0>Position of rules is important in chains. Once a chain rule accepts, drops or rejects a packet subsequent chain rules are no longer processed!)</color>++ \\ <tab6>\\ <tab9><color blue> # accept established connections</color> ++ | \\ + <color #202000/#F0F0E0>This rule is to allow already established or related connections through. If the connection has already been established, it probably means it was already allowed by us earlier and we can just continue allowing it.\\ ''ct'' is used to tap into the connection tracking entry associated with the packet. In this case, we are accessing the state of the connection, and checking if it is in the set ''{established, related}''. If it is in the set, accept the packet, otherwise, continue to the next rule. </color>++ \\ <tab9> ct state established, related counter accept\\ <tab9>\\ <tab9><color blue> # drop invalid state packets</color> ++ | \\ + <color #202000/#F0F0E0>This is similar to the previous line, but this time, instead of checking if the state is within a set, we only check if the connection state is ''invalid'' and if so, we drop the connection. That is, we just ignore the packet as if it never came in. Otherwise continue on to the next rule.</color>++ \\ <tab9> ct state invalid counter drop\\ <tab9>\\ <tab9><color blue> #All traffic from lan is accepted</color>\\ <tab9> iifname <color red>$lan</color> counter accept <color blue># accept anything from the LAN, keep it simple.</color>\\ <tab9>\\ <tab9><color blue> # Allow traffic coming from the vpn</color> \\ <tab9> iifname <color red>$vpn</color> counter accept <color blue># accept anything from the VPN, keep it simple.</color>\\ <tab9>\\ <tab9><color blue> # Allow new connections to internal servers, but only those that have had dnat performed.</color> \\ <tab9><color blue> # The server names can be used where host DNS resolves to IP address</color>\\ <tab9> ip daddr <color red>$http_server</color> ct status dnat counter accept ++ | \\ + <color #202000/#F0F0E0> The incoming WAN packets that have been preroute dnat to the http server IP address to be accepted.</color>++ \\ <tab9> ip daddr <color red>$mail_server</color> ct status dnat counter accept ++ | \\ + <color #202000/#F0F0E0> The incoming WAN packets that have been preroute dnat to the mail server IP address to be accepted.</color>++ \\ <tab9><color #000060/#F0F0FF> #ip daddr </color><color #060000/#FFF0F0>$vpn_ip4</color><color #000060/#F0F0FF> ct status dnat counter accept # required if VPN service is not on main router IP</color>\\ <tab9><color blue> # other option is perhaps more verbose, e.g.</color>\\ <tab9><color #000060/#F0F0FF> #ip daddr </color><color #060000/#FFF0F0>$http_server</color><color #000060/#F0F0FF> tcp dport {http, https} counter accept</color>\\ <tab9><color #000060/#F0F0FF> #ip daddr </color><color #060000/#FFF0F0>$mail_server</color><color #000060/#F0F0FF> tcp dport {http, https, pop3s, imaps, smtp} counter accept</color>\\ <tab9><color #000060/#F0F0FF> #ip daddr </color><color #060000/#FFF0F0>$vpn_ip4</color><color #000060/#F0F0FF> udp dport </color><color #060000/#FFF0F0>$vpn_port</color><color #000060/#F0F0FF> counter accept</color>\\ <tab9>\\ <tab9><color blue> #Hurricane Electric IPv6 tunnel</color>\\ <tab9><color #000060/#F0F0FF> #iifname </color><color #060000/#FFF0F0>$he_tunnel</color><color #000060/#F0F0FF> counter jump base_checks # not required as we do this for all connections above</color>\\ <tab9><color #000060/#F0F0FF> #iifname </color><color #060000/#FFF0F0>$lan</color><color #000060/#F0F0FF> oifname </color><color #060000/#FFF0F0>$he_tunnel</color><color #000060/#F0F0FF> counter accept</color>\\ <tab9>\\ <tab9><color blue> # drop and count everything else not accounted for,</color>\\ <tab9><color blue> # probably does not have much use on forward</color>\\ <tab9> counter drop\\ <tab6> }\\ <tab6>\\ <tab6> chain output {\\ <tab9><color blue> # We allow everything out </color>\\ <tab9> type filter hook output priority 0; policy accept;\\ <tab9>\\ <tab9><color blue> #counters for different devices, ip address, port, etc. place first</color>\\ <tab9> ip saddr <color red>$vpn_ip4</color> counter\\ <tab6>\\ <tab6><color blue> # In general output filter drops and limits list should be placed above here here</color> ++ | \\ + <color #202000/#F0F0E0>Position of rules is important in chains. Once a chain rule accepts, drops or rejects a packet subsequent chain rules are no longer processed!)</color>++ \\ <tab6>\\ <tab9><color blue> # Allow packets with existing state & count</color>\\ <tab9> ct state established,related counter accept\\ <tab9>\\ <tab9><color blue> # Allow all new packets on Router output & count</color>\\ <tab9> ct state new counter accept\\ <tab9>\\ <tab9><color blue> # Drop all invalid packet and count</color>\\ <tab9> ct state invalid counter drop\\ <tab6> }\\ <tab3> }\\ <tab3>\\ <tab3> table ip nat {\\ <tab3>\\ <tab6><color #000060/#F0F0FF> #map tcp_nat_map { </color>\\ <tab9><color #000060/#F0F0FF> # type inet_service : ipv4_addr </color>\\ <tab9><color #000060/#F0F0FF> # elements = { http : 192.168.1.16, https : 192.168.1.16} </color>\\ <tab6><color #000060/#F0F0FF> #} </color>\\ <tab6>\\ <tab6><color #000060/#F0F0FF> #map udp_nat_map { </color>\\ <tab9><color #000060/#F0F0FF> # type inet_service : ipv4_addr </color>\\ <tab6><color #000060/#F0F0FF> #} </color>\\ <tab6>\\ <tab6><color #000060/#F0F0FF> #chain wan_in { </color>\\ <tab9><color #000060/#F0F0FF> # tcp dport { http, https} counter dnat to </color><color #060000/#FFF0F0>$http_server</color>\\ <tab9><color #000060/#F0F0FF> # tcp dport { pop3s, imaps, smtp} counter dnat to </color><color #060000/#FFF0F0>$mail_server</color>\\ <tab9><color #000060/#F0F0FF> # udp dport </color><color #060000/#FFF0F0>$vpn_port</color><color #000060/#F0F0FF> counter dnat to 192.168.6.1</color>\\ <tab9><color #000060/#F0F0FF> # dnat tcp dport map @tcp_nat_map </color>\\ <tab9><color #000060/#F0F0FF> # dnat udp dport map @udp_nat_map </color>\\ <tab6><color #000060/#F0F0FF> #}</color>\\ <tab6>\\ <tab6> chain prerouting { ++ | \\ + <color #202000/#F0F0E0> If we decalre postrouting nat we must also decalare prerouting nat, even if we do not need any rules in the prerouting chain.</color>++\\ <tab9> type nat hook prerouting priority 0; policy accept;\\ <tab9><color #000060/#F0F0FF> #iifname </color><color #060000/#FFF0F0>$wan</color><color #000060/#F0F0FF> jump wan_in</color>\\ <tab9><color blue> # dnat - direct allowed by port number wan incoming services to correct lan server ip.</color>\\ <tab9> ip daddr <color red>$wan_ip4</color> tcp dport {http, https} counter dnat to <color red>$http_server</color> ++ | \\ + <color #202000/#F0F0E0> Incoming WAN packets to the http or https ports are preroute dnat to the webserver IP address.</color>++\\ <tab9> ip daddr <color red>$wan_ip4</color> tcp dport {pop3s, imaps, smtp} counter dnat to <color red>$mail_server</color> ++ | \\ + <color #202000/#F0F0E0> Incoming WAN packets to the mail ports, pop3s, imaps or smtp ports are preroute dnat to the mail server IP address.</color>++\\ <tab9> ip daddr <color red>$wan_ip4</color> udp dport <color red>$vpn_port counter dnat to <color red>$vpn_ip4</color> ++ | \\ + <color #202000/#F0F0E0> Incoming WAN packets to the VPN port are preroute dnat to the VPN IP address.</color>++\\ <tab6> }\\ <tab6>\\ <tab6> chain postrouting {\\ <tab9> type nat hook postrouting priority 0; policy accept;\\ <tab9> \\ <tab9><color blue> #Allow internal clients to correctly see external address "hairpin dnat"</color> ++ | \\ + <color #202000/#F0F0E0> Hairpin nat is dicussed in greater death at [[https://wiki.kptree.net/doku.php?id=linux_router:nftables#hairpin_nat|hairpin nat]].</color>++\\ <tab9> ip saddr 192.168.1.0/24 ip daddr <color red>$http_server</color> tcp dport {http, https} counter snat <color red>$router_ip4</color>\\ <tab9> ip saddr 192.168.1.0/24 ip daddr <color red>$mail_server</color> tcp dport {http, https, pop3s, imaps, smtp} counter snat <color red>$router_ip4</color>\\ <tab9>\\ <tab9><color blue> #Standard postrouting nat</color> ++ | \\ + <color #202000/#F0F0E0> The examples below show different levels of granularity in control.</color>++\\ <tab9><color #000060/#F0F0FF> #oifname </color><color #060000/#FFF0F0>$modem</color><color #000060/#F0F0FF> counter masquerade #needed with dynamic wan ip address</color>\\ <tab9> ip saddr <color red>$lan_ip4</color> oifname <color red>$modem</color> counter snat <color red>$modem_ip</color>\\ <tab9> ip saddr <color red>$vpn_ip</color> oifname <color red>$modem</color> counter snat <color red>$modem_ip</color>\\ <tab9><color #000060/#F0F0FF> #oifname </color><color #060000/#FFF0F0>$wan</color><color #000060/#F0F0FF> counter masquerade #needed with dynamic wan ip address</color>\\ <tab9> ip saddr <color red>$lan_ip4</color> oifname $wan</color> counter snat $wan_ip4</color>\\ <tab9> ip saddr <color red>$vpn_ip</color> oifname $wan</color> counter snat $wan_ip4</color>\\ <tab9><color #000060/#F0F0FF> #ip saddr { </color><color #060000/#FFF0F0>$lan_ip4, $vpn_ip4 </color><color #000060/#F0F0FF>}oifname </color><color #060000/#FFF0F0>$wan</color><color #000060/#F0F0FF> counter snat </color><color #060000/#FFF0F0>$wan_ip4 #with ip set</color>\\ <tab9><color #000060/#F0F0FF> #oifname { </color><color #060000/#FFF0F0>$wan, $modem</color><color #000060/#F0F0FF> } counter masquerade #with device set</color> \\ <tab9>\\ <tab6> }\\ <tab3> }\\ <tab3>\\ ++++ =====Wireguard Trouble Shooting===== I have had a lot of difficulties getting Wireguard Running. These are some notes on troubleshooting this issue. - Make sure the public keys are properly shared and match the private keys. Wireguard will simply not respond to incorrect information! - Ensure the sure of counter in nftables setup to be able to see the actual packets counted by each nftables chain - Use of the nftables list to list the chains and actual counted packets and bytes - ''sudo nft list tables'' -> to list active nftables - ''sudo nft list table inet firewall -a'' -> to list contents of table - ''sudo nft list table ip nat -a'' - Use the tcpdump command to see the actual activity on each interface - ''sudo tcpdump -D'' to see a list the list interfaces - the interface ''any'' would look at all the interfaces - ''sudo tcpdump -i ppp1 -c 5 port 51914'' - where: - ''-i ppp1'' specifies specific use of interface ppp1 - ''-c 5'' limits the scan to 5 packets captured, ''^C'' can also exit the scan at any time - ''port 51914'' requires to listen only to port 51914 - ''sudo tcpdump -c 5 -i eno1 host 112.213.222.38 and port 51914'' to see on specific host I used my iPhone Wireguard app as the other end. It is important that the app is correctly configured. Also the Persistent keepalive is set a 1 second. As the Wireguard is not very chatty this can make it difficult to error check. The iOS app seems to send 20 keep alive packets waiting 5 seconds for a response after which it stops the keep alive attempts. The iOS VPN for Wireguard seems to immediately fall back from the VPN if a connection is not made. ''sudo ip a show wg0'' : <code>14: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000 link/none inet 192.168.6.1/24 scope global wg0 valid_lft forever preferred_lft forever</code> For some reason my system would not link the IP address even though the wg script was clearly running the commands, ''sudo systemctl status wg-quick@wg0'': <code>Jul 03 21:25:44 Router systemd[1]: Starting WireGuard via wg-quick(8) for wg0... Jul 03 21:25:44 Router wg-quick[3483]: [#] ip link add wg0 type wireguard Jul 03 21:25:44 Router wg-quick[3483]: [#] wg setconf wg0 /dev/fd/63 Jul 03 21:25:44 Router wg-quick[3483]: [#] ip -4 address add 192.168.6.1/24 dev wg0 Jul 03 21:25:44 Router wg-quick[3483]: [#] ip link set mtu 1420 up dev wg0 Jul 03 21:25:44 Router wg-quick[3483]: [#] ip -4 route add 192.168.6.3/32 dev wg0 Jul 03 21:25:44 Router wg-quick[3483]: [#] ip -4 route add 192.168.6.2/32 dev wg0 Jul 03 21:25:44 Router systemd[1]: Started WireGuard via wg-quick(8) for wg0.</code> then\\ ''sudo ip a show wg0''<code>7: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000 link/none </code> After updating to Debian 11 the following quick fix caused an error so I simply removed and rebooted. ''PostUp = ip -4 address add 192.168.6.1/24 dev wg0'' before PrivateKey to in ''/etc/wireguard/wg0.conf'': <code>[Interface] Address = 192.168.6.1/24 SaveConfig = true ListenPort = 51914 PrivateKey = censored= [Peer] PublicKey = censored= AllowedIPs = 192.168.6.2/32 Endpoint = 1.127.16.49:8898 [Peer] PublicKey = censored= AllowedIPs = 192.168.6.3/32 Endpoint = 192.168.1.34:63009 </code> ---- =====Client Setup===== My first setup was on my iPhone. There is a specific Wireguard application for the iPhone, which can be downloaded for free from the app store. This application can be manually setup. A private and public key can be made in the app and then the public keys manually transferred between the app to the server. This is where it can get clumsy. Phone interfaces are just not as nice to use as a proper full system with full size screen, keyboard and mouse. In fact, as noted above, this is where I got unstuck early in my tinkering with Wireguard. ''Interface_name'' <code> [Interface] PrivateKey = <insert server_private_key> [required] Address = 192.168.6.2/32 ListenPort = [optional, if not specified chosen randomly] MTU = [optional] DNS = 192.168.1.1 [Peer] PublicKey = <insert client_public_key> Presharedkey = [optional] AllowedIPs = 0.0.0.0/0 Endpoint = kptree.net:51914 PersistentKeepalive = 25 </code> ---- ====Linux security can be a pain in the arse sometime==== ===To work on Wireguard Configuration files=== * ''sudo chown root:baumkp -R /etc/wireguard'' * ''sudo chmod 770 -R /etc/wireguard'' With this I should be able to do all configurations without sudo. All setting the execution bit allows the operation of the qrencode utility. ===To Leave Wireguard Configuration files Secure, if I remember=== * ''sudo chown root:root -R /etc/wireguard'' * ''sudo chmod 600 -R /etc/wireguard'' ====QR codes==== The wireguard configuration file can be made into a QR code:\\ {{kptree_wiki.png}}\\ QR code for ''wiki.kptree.net'' can be created with ''qrencode -s 6 -l H -o "kptree_wiki.png" "%%https://wiki.kptree.net%%"'' A Wireguard configuration file can be printed to terminal screen with: ''sudo qrencode -t ansiutf8 </etc/wireguard/clients/kptree_router.mobile1'', where: * ''/etc/wireguard/clients/kptree_router.mobile1'' is a valid Wireguard configuration file * The permissions of the directory in which the file is located allow this. Similarly the output can be used to create a picture file: ''sudo qrencode -t ansiutf8 -o /etc/wireguard/clients/kptree_router.mobile1.png </etc/wireguard/clients/kptree_router.mobile1'' An online resource is Cloud Savey [[https://www.cloudsavvyit.com/8382/how-to-create-qr-codes-from-the-linux-command-line/|How To Create QR Codes From The Linux Command Line]]\\ Wikipedia [[https://en.wikipedia.org/wiki/QR_code|QR code]] =====Some NFTables and Wireguard Commands===== * to list table inet firewall with handles: ''sudo nft list table inet firewall -a'' * To list table ip nat with handles: ''sudo nft list table ip nat -a'' * To add a set tcp_open_ports in inet firewall: ''sudo nft add set inet firewall tcp_open_ports{type inet_service \; flags interval \;}'' * To add elements to set tcp_open_ports: ''sudo nft add element inet firewall tcp_open_ports{ssh, http, 60000-61000 }'' * To delete rule in ip nat postrouting: ''sudo nft delete rule ip nat postrouting handle 24'' * To add rule to inet firewall input, before handle 25: ''sudo nft add rule inet firewall input handle 25 ip saddr udp dport 51914 counter accept'' * To append new rule to end of inet firewall input: ''sudo nft add rule inet firewall input ip saddr udp dport 51914 counter accept'' * To restart wg0 interface: ''sudo systemctl restart wg-quick@wg0'' * To see status of wireguard: ''sudo wg'' * To see status of wireguard device ''wg0'': ''sudo wg show wg0'' ---- =====Docker Wireguard Setup===== *[[https://www.the-digital-life.com/wireguard-docker/|Create your own VPN server with WireGuard in Docker]] *[[https://www.linuxserver.io/|Building and maintaining community {Docker} images]] *[[https://hub.docker.com/r/linuxserver/wireguard|Dockerhub linuxserver.io wireguard]] <- linux_router:misc|Prev page ^ linux_router:start|Start page ^ -> ^ linux_router:nmap|Next page ->