{{tag>linux router vpn wireguard Docker "qr code" QR}} =====Wireguard VPN access from WAN to LAN====== I use a Docker instance for my Wireguard server now. 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: 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 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''. [Interface] Address = 192.168.6.1/24 SaveConfig = true PrivateKey = ListenPort = 51914 [Peer] PublicKey = AllowedIPs = 192.168.6.2/32 [Peer] PublicKey = AllowedIPs = 192.168.6.3/32 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''| #!/usr/sbin/nft -f ++ | + nftables scripts need this shebang with the -f option to run++ \\ \\ # script variable definitions ++ | \\ + * 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. ++ \\ define wan = ppp1 #definition of wan device label\\ define modem = eno1 #definition of modem device label\\ define lan = br0 #definition of lan device label\\ define router_ip4 = 192.168.1.1 #definition of router IPv4 address\\ define modem_ip4 = 192.168.5.2 #definition of modem IPv4 address ++ | \\ + 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]].++\\ define http_server = 192.168.1.12 #definition of http server IPv4 address\\ define mail_server = 192.168.1.18 #definition of mail server IPv4 address\\ define wan_ip4 = 112.213.222.38 #definition of wan IPv4 address\\ define vpn = wg0 #definition of wireguard vpn device label\\ define vpn_ip = 192.168.6.0/24 #definition of wireguard IPv4 address range\\ define vpn_ip4 = 192.168.6.1 #definition of wireguard IPv4 server address\\ define vpn_port = 51914 #definition of wireguard server port\\ #define he_tunnel = he-ipv6 #\\ \\ # Clean out the current ruleset\\ flush ruleset ++ | \\ +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 [[https://www.netfilter.org/projects/nftables/manpage.html#lbAO|Ruleset]] for more information.++ \\ \\ table inet firewall { ++ | \\ +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 [[https://www.netfilter.org/projects/nftables/manpage.html#lbAP|Tables]] for more information. ++ \\ \\ # The set controllist is used to dynamically add IP address(es) to a timed drop list for LAN access control ++ | \\ + This has been separately described in detail at the following link: [[linux_router:nftables_control]], also see wiki.nftables on [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets| Names Sets]] & nft man page [[https://www.netfilter.org/projects/nftables/manpage.html#lbAS|Sets]]. ++ \\ set controllist {\\ type ipv4_addr\\ flags interval\\ flags timeout\\ }\\ \\ # Remember that the input and output chains only refer to this machine.\\ # The forward and nat chains refer to routing.\\ # open ports refers to ports to open for input to this machine.\\ # ssh is port 22 for SSH on both TCP and UDP, but we only use TCP!\\ # bootps, port 67 and bootpc, port 68 are for DHCP on both TCP and UDP, but we only use UDP!\\ # domain is port 53 for DNS requests on TCP & UDP.\\ # openvpn is port 1194 on both TCP and UDP, but we will not be using this antiquated protocol.\\ \\ set tcp_open_ports { ++ | \\ + 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 [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets| Names Sets]] & nft man page [[https://www.netfilter.org/projects/nftables/manpage.html#lbAS|Sets]]. ++ \\ type inet_service; flags interval;\\ elements = {\\ ssh,\\ domain\\ }\\ }\\ \\ set udp_open_ports { ++ | \\ + 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 [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets| Names Sets]] & nft man page [[https://www.netfilter.org/projects/nftables/manpage.html#lbAS|Sets]]. ++ \\ type inet_service; flags interval;\\ elements = {\\ domain,\\ $vpn_port, # Wireguard port\\ 60000-61000 # mosh port interval\\ }\\ }\\ \\ chain tcp_cek { ++ | \\ + 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 [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] & nft man page [[https://www.netfilter.org/projects/nftables/manpage.html#lbAQ|Chains]]for more information++ \\ # bad tcp -> avoid network scanning: \\ tcp flags & (fin|syn) == (fin|syn) counter drop\\ tcp flags & (syn|rst) == (syn|rst) counter drop\\ tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) counter drop\\ tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) counter drop\\ } \\ \\ chain icmp_cek {++ | \\ + 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 [[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.++ \\ # no ping floods\\ ip protocol icmp counter\\ ip protocol icmp limit rate over 2/second burst 5 packets counter drop ++ | + This limits the incoming rate of icmp packets handled ++\\ ip6 nexthdr ipv6-icmp counter\\ ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 2/second burst 5 packets counter drop ++ | + This limits the incoming rate of icmpv6 packets handled ++\\ \\ # allow icmp \\ ip protocol icmp icmp type { ++ | + This allows the icmp packets to be handled ++\\ echo-request, echo-reply, time-exceeded,\\ parameter-problem, destination-unreachable\\ } counter accept\\ \\ ip6 nexthdr icmpv6 icmpv6 type { ++ | + This allows the icmpv6 packets to be handled ++ \\ echo-request, echo-reply, time-exceeded,\\ parameter-problem, destination-unreachable,\\ packet-too-big, nd-router-advert, nd-router-solicit,\\ nd-neighbor-solicit, nd-neighbor-advert,\\ mld-listener-query\\ } counter accept\\ }\\ \\ chain input {++ | \\ + See wiki.nftables [[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.++ \\ type filter hook input priority 0; policy drop; ++ | \\ + 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 [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] for more information.++ \\ \\ # drop connections from blacklisted addresses \\ # ip saddr @blacklist counter drop \\ \\ # Cek valid tcp packet\\ ip protocol tcp jump tcp_cek ++ | + We use the jump statement as we want to return and continue to process chains after this statement.++\\ \\ # Cek valid icmp communications\\ jump icmp_cek ++ | + We use the jump statement as we want to return and continue to process chains after this statement.++\\ \\ #count all the wan SSH attemps\\ #iifname $wan tcp dport ssh counter \\ \\ # avoid brute force on ssh: (if using external ssh) \\ #tcp dport ssh limit rate over 8/minute counter drop ++ | \\ + 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.)++ \\ \\ # In general input filter drops and limits list should be placed above here here ++ | \\ + Position of rules is important in chains. Once a chain rule accepts, drops or rejects a packet subsequent chain rules are no longer processed!)++ \\ \\ # accept established connections ++ | \\ + 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. ++ \\ ct state established, related counter accept \\ \\ # drop invalid state packets ++ | \\ + 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.++ \\ ct state invalid counter drop\\ \\ # accept input from loopback interface ++ | \\ + It is generally accepted practice to accept all packets from the loopback interface.++ \\ iif lo counter accept\\ \\ # accept input from LAN ++ | \\ + 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.++ \\ iifname $lan counter accept # By port is a pain in the arse!\\ # iifname $lan tcp dport { ssh, domain, 667, 953 } counter accept ++ | + This is used to accept specific LAN tcp ports, required if not accepting all.++ \\ # iifname $lan udp dport { domain, bootps, bootpc, 667, 953} counter accept ++ | + This is used to accept specific LAN tcp ports, required if not accepting all.++ \\ \\ # accept input from VPN ++ | \\ + 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.++ \\ iifname $vpn counter accept # By port is a pain in the arse!\\ ip daddr $vpn_ip4 udp dport $vpn_port counter accept ++ | \\ + 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.++ \\ # iifname $wan udp dport $vpn_port ct state new counter accept\\ \\ # everything else reject port unreachable \\ ct state new counter reject ++ | \\ + 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 [[https://wiki.nftables.org/wiki-nftables/index.php/Rejecting_traffic| Rejecting traffic]] for more information. ++\\ }\\ \\ chain forward {++ | \\ + See wiki.nftables [[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.++ \\ type filter hook forward priority 0; policy accept; ++ | \\ + 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 [[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains| Configuring Chains]] for more information.++ \\ \\ #drop all IP addresses in the control list both source and destination ++ | \\ + This has been separately described in detail at the following link: [[linux_router:nftables_control]], also see wiki.nftables on [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets| Names Sets]] & nft man page [[https://www.netfilter.org/projects/nftables/manpage.html#lbAS|Sets]]. ++ \\ ip daddr @controllist counter drop\\ ip saddr @controllist counter drop\\ \\ #limit the IP address range bandwidth using WAN ++ | \\ + 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]] ++ \\ iifname $wan ip daddr { 192.168.1.100-192.168.1.254 } limit rate over 1300kbytes/second burst 3000kbytes counter drop\\ oifname $wan ip saddr { 192.168.1.100-192.168.1.254 } limit rate over 750kbytes/second burst 1200kbytes counter drop\\ \\ #oifname $wan tcp flags syn tcp option maxseg size set rt mtu\\ oifname $wan tcp flags syn tcp option maxseg size set 1452 counter\\ \\ # In general forward filter drops and limits list should be placed above here here ++ | \\ + Position of rules is important in chains. Once a chain rule accepts, drops or rejects a packet subsequent chain rules are no longer processed!)++ \\ \\ # accept established connections ++ | \\ + 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. ++ \\ ct state established, related counter accept\\ \\ # drop invalid state packets ++ | \\ + 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.++ \\ ct state invalid counter drop\\ \\ #All traffic from lan is accepted\\ iifname $lan counter accept # accept anything from the LAN, keep it simple.\\ \\ # Allow traffic coming from the vpn \\ iifname $vpn counter accept # accept anything from the VPN, keep it simple.\\ \\ # Allow new connections to internal servers, but only those that have had dnat performed. \\ # The server names can be used where host DNS resolves to IP address\\ ip daddr $http_server ct status dnat counter accept ++ | \\ + The incoming WAN packets that have been preroute dnat to the http server IP address to be accepted.++ \\ ip daddr $mail_server ct status dnat counter accept ++ | \\ + The incoming WAN packets that have been preroute dnat to the mail server IP address to be accepted.++ \\ #ip daddr $vpn_ip4 ct status dnat counter accept # required if VPN service is not on main router IP\\ # other option is perhaps more verbose, e.g.\\ #ip daddr $http_server tcp dport {http, https} counter accept\\ #ip daddr $mail_server tcp dport {http, https, pop3s, imaps, smtp} counter accept\\ #ip daddr $vpn_ip4 udp dport $vpn_port counter accept\\ \\ #Hurricane Electric IPv6 tunnel\\ #iifname $he_tunnel counter jump base_checks # not required as we do this for all connections above\\ #iifname $lan oifname $he_tunnel counter accept\\ \\ # drop and count everything else not accounted for,\\ # probably does not have much use on forward\\ counter drop\\ }\\ \\ chain output {\\ # We allow everything out \\ type filter hook output priority 0; policy accept;\\ \\ #counters for different devices, ip address, port, etc. place first\\ ip saddr $vpn_ip4 counter\\ \\ # In general output filter drops and limits list should be placed above here here ++ | \\ + Position of rules is important in chains. Once a chain rule accepts, drops or rejects a packet subsequent chain rules are no longer processed!)++ \\ \\ # Allow packets with existing state & count\\ ct state established,related counter accept\\ \\ # Allow all new packets on Router output & count\\ ct state new counter accept\\ \\ # Drop all invalid packet and count\\ ct state invalid counter drop\\ }\\ }\\ \\ table ip nat {\\ \\ #map tcp_nat_map { \\ # type inet_service : ipv4_addr \\ # elements = { http : 192.168.1.16, https : 192.168.1.16} \\ #} \\ \\ #map udp_nat_map { \\ # type inet_service : ipv4_addr \\ #} \\ \\ #chain wan_in { \\ # tcp dport { http, https} counter dnat to $http_server\\ # tcp dport { pop3s, imaps, smtp} counter dnat to $mail_server\\ # udp dport $vpn_port counter dnat to 192.168.6.1\\ # dnat tcp dport map @tcp_nat_map \\ # dnat udp dport map @udp_nat_map \\ #}\\ \\ chain prerouting { ++ | \\ + If we decalre postrouting nat we must also decalare prerouting nat, even if we do not need any rules in the prerouting chain.++\\ type nat hook prerouting priority 0; policy accept;\\ #iifname $wan jump wan_in\\ # dnat - direct allowed by port number wan incoming services to correct lan server ip.\\ ip daddr $wan_ip4 tcp dport {http, https} counter dnat to $http_server ++ | \\ + Incoming WAN packets to the http or https ports are preroute dnat to the webserver IP address.++\\ ip daddr $wan_ip4 tcp dport {pop3s, imaps, smtp} counter dnat to $mail_server ++ | \\ + Incoming WAN packets to the mail ports, pop3s, imaps or smtp ports are preroute dnat to the mail server IP address.++\\ ip daddr $wan_ip4 udp dport $vpn_port counter dnat to $vpn_ip4 ++ | \\ + Incoming WAN packets to the VPN port are preroute dnat to the VPN IP address.++\\ }\\ \\ chain postrouting {\\ type nat hook postrouting priority 0; policy accept;\\ \\ #Allow internal clients to correctly see external address "hairpin dnat" ++ | \\ + Hairpin nat is dicussed in greater death at [[https://wiki.kptree.net/doku.php?id=linux_router:nftables#hairpin_nat|hairpin nat]].++\\ ip saddr 192.168.1.0/24 ip daddr $http_server tcp dport {http, https} counter snat $router_ip4\\ ip saddr 192.168.1.0/24 ip daddr $mail_server tcp dport {http, https, pop3s, imaps, smtp} counter snat $router_ip4\\ \\ #Standard postrouting nat ++ | \\ + The examples below show different levels of granularity in control.++\\ #oifname $modem counter masquerade #needed with dynamic wan ip address\\ ip saddr $lan_ip4 oifname $modem counter snat $modem_ip\\ ip saddr $vpn_ip oifname $modem counter snat $modem_ip\\ #oifname $wan counter masquerade #needed with dynamic wan ip address\\ ip saddr $lan_ip4 oifname $wan counter snat $wan_ip4\\ ip saddr $vpn_ip oifname $wan counter snat $wan_ip4\\ #ip saddr { $lan_ip4, $vpn_ip4 }oifname $wan counter snat $wan_ip4 #with ip set\\ #oifname { $wan, $modem } counter masquerade #with device set \\ \\ }\\ }\\ \\ ++++ =====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'' : 14: wg0: 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 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'': 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. then\\ ''sudo ip a show wg0''7: wg0: mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000 link/none 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'': [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 ---- =====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'' [Interface] PrivateKey = [required] Address = 192.168.6.2/32 ListenPort = [optional, if not specified chosen randomly] MTU = [optional] DNS = 192.168.1.1 [Peer] PublicKey = Presharedkey = [optional] AllowedIPs = 0.0.0.0/0 Endpoint = kptree.net:51914 PersistentKeepalive = 25 ---- ====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 ^ linux_router:nmap|Next page ->