Ubuntu 16.04 Full Stack Configuration (with Bonding Config): Difference between revisions

Back up to the Bonding Page
From AAISP Support Site
(clean up, typos fixed: ie. → i.e. , controled → controlled, eg: → e.g.:)
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<indicator name="Front">[[File:Menu-bonding.svg|link=:Category:Bonding|30px|Back up to the Bonding Page]]</indicator>

[[Category:Routers]]
[[Category:Routers]]
[[Category:Bonding Configuration]]
[[Category:3rd Party Routers]]
[[Category:3rd Party Routers]]
= Preface =
= Preface =
Line 80: Line 83:
linkname aa_wan1
linkname aa_wan1


Note the additional “unit” and “linkname” instructions from the linked guide, “unit” is in the index of the ppp connection created (ie. unit = 0 creates ppp0).
Note the additional “unit” and “linkname” instructions from the linked guide, “unit” is in the index of the ppp connection created (i.e. unit = 0 creates ppp0).


=== /etc/ppp/chap-secrets ===
=== /etc/ppp/chap-secrets ===
Line 268: Line 271:
# Accept established connections from AAISP Line 2 (Bonding only)
# Accept established connections from AAISP Line 2 (Bonding only)
iptables -A INPUT -i pppoe-AA_2 -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic" -j ACCEPT
iptables -A INPUT -i pppoe-AA_2 -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic" -j ACCEPT
# Allow related traffic from AAISP Modem Stats 1
# Reject anything else (not really needed as we will change default policy to drop later)
iptables -A INPUT -m comment --comment "Reject all remaining traffic" -j REJECT --reject-with icmp-port-unreachable
iptables -A INPUT -s 192.168.2.1/32 -i DEV_AA_WAN1_C -m state --state RELATED,ESTABLISHED -j ACCEPT
# Allow related traffic from AAISP Modem Stats 2 (Bonding only)
iptables -A INPUT -s 192.168.3.1/32 -i DEV_AA_WAN1_C -m state --state RELATED,ESTABLISHED -j ACCEPT
# AAISP Line 1 MSS Clamping
# AAISP Line 1 MSS Clamping
iptables -A FORWARD -o pppoe-AA_1 -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --
iptables -A FORWARD -o pppoe-AA_1 -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --
Line 304: Line 309:
iptables -t nat -A POSTROUTING -o DEV_AA_WAN2_C -m comment --comment NAT -j MASQUERADE
iptables -t nat -A POSTROUTING -o DEV_AA_WAN2_C -m comment --comment NAT -j MASQUERADE
# Default drop everything from outside
# Default drop everything from outside
# Note that these drops are *important* because we don't reject any traffic in the rules themselves, without these, stuff will be wide open
iptables -P FORWARD DROP
iptables -P FORWARD DROP
iptables -P INPUT DROP
iptables -P INPUT DROP
Line 581: Line 587:
START_DAEMON=1
START_DAEMON=1
# Define here the external interface connected to the WAN (eg: the public
# Define here the external interface connected to the WAN (e.g.: the public
# IP address NIC)
# IP address NIC)
MiniUPnPd_EXTERNAL_INTERFACE="pppoe-AA_1"
MiniUPnPd_EXTERNAL_INTERFACE="pppoe-AA_1"
Line 587: Line 593:
# IP that the daemon should listen on.
# IP that the daemon should listen on.
# Note that you do *not* want this to be 0.0.0.0, as you don't want
# Note that you do *not* want this to be 0.0.0.0, as you don't want
# your MiniUPnPd to be controled by anyone on the internet.
# your MiniUPnPd to be controlled by anyone on the internet.
MiniUPnPd_LISTENING_IP=”DEV_LAN”
MiniUPnPd_LISTENING_IP=”DEV_LAN”
Line 617: Line 623:
chmod 0755 /etc/ppp/ip-up.d/fix-upnp
chmod 0755 /etc/ppp/ip-up.d/fix-upnp
chmod +x /etc/ppp/ip-up.d/fix-upnp
chmod +x /etc/ppp/ip-up.d/fix-upnp

= Bonus: Run dslstats in Docker on Ubuntu =
I'll add this section because some people may find it useful if you either want dslstats for your own use directly or to submit to something like [https://www.mydslwebstats.co.uk/ MyDSLWebStats].

== Install Docker ==
Install Docker, we'll get a better version than what is in the normal repos:

apt-get install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# Assuming amd64
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update
apt-get install docker-ce

== Download & Run Container ==
Now we have docker, all we need to do is download and run the container, which can be done in a single command. This command will do the following:
* Names the container "dslstats_1"
* Opens a VNC server on 192.168.1.1:5900 (you should specifically set the router IP like I have to make sure it's only accessible privately)
* Opens a tcp listener on port 192.168.1.1:8080 - this won't actually do anything unless you enable the web server for dslstats
* Sets the password to login to VNC to "dslstats"
* Sets the path for the dslstats configurtion to be '''/etc/dslstats_1/''' on the '''host'''
* Mounts /etc/localtime from the host to use the correct timezone data
* Restarts the container as soon as the Docker daemon starts (should be on each reboot)

docker run -d \
--name=dslstats_1 \
-p 192.168.1.1:5900:5900 \
-p 198.168.1.1:8080:8080 \
-e "VNC_PASSWORD"="dslstats"
-v /etc/dslstats_1:/config \
-v /etc/localtime:/etc/localtime:ro \
--restart=always
rossallan/dslstats

Obviously if you are running 2 modems you wish to report stats for, you will need a second MyDSLWebStats account (if you are submitting there), and to modify this command for the second container to use different ports and configuration directory.

For more information about Docker installation, see [https://docs.docker.com/engine/installation/linux/ubuntu/#install-using-the-repository here], and for more information about the dslstats Docker container, see [https://hub.docker.com/r/rossallan/dslstats/ here].


= Bonus: Port based policy routing to a third WAN =
= Bonus: Port based policy routing to a third WAN =
I also have a third WAN connection (provided by Virgin Media) over which I route some traffic based on the destination port. It’s of course possible to route it based on destination IP, source IP or any combination of routing rules you can think of. It’s also possible to use it as a failover if your PPP connection dies as well (although this guide does not cover this).
Coming soon.

Moving forward though I’ll be making assumptions that the third connection is a VM connection (or an “equivalent”) provided by DHCP.

== Configure Interface ==
Edit /etc/network/interfaces and configure the interface for the connection, we give it a higher metric to make sure it doesn’t override any default routes we configured, we also provide a post-up script which we’ll cover later:

# VMEDIA
auto DEV_VM_WAN
iface DEV_VM_WAN inet dhcp
post-up /usr/local/sbin/fix_vm_policy
metric 100

== Fix Firewalling ==
We need to add some more iptables rules to allow this interface to NAT and receive related traffic etc., we won’t bother with IPv6 since we don’t get a v6 address:

iptables -A INPUT -i DEV_VM_WAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic" -j ACCEPT
iptables -A FORWARD -i DEV_LAN -o DEV_VM_WAN -m comment --comment "Allow traffic from LAN -> internet" -j ACCEPT
iptables -A FORWARD -i DEV_VM_WAN -o DEV_LAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic from internet -> LAN" -j ACCEPT
iptables -t nat -A POSTROUTING -o DEV_VM_WAN -m comment --comment NAT -j MASQUERADE

Don’t forget '''netfilter-persistent save && netfilter-persistent reload''' afterwards.

== Fix Routing ==
We need to add a new route table, it will be called VMEDIA.

echo “20 VMEDIA” >> /etc/iproute2/rt_tables

=== /usr/local/sbin/fix_vm_policy ===
Create the script mentioned in post-up earlier. This script does the following:
* Fetch the interface address (a /32 IPv4 in this case)
* Fetch the gateway address
* Check these look like valid IP addresses to avoid any blank routes
* Add a default route via the gateway to the routing table VMEDIA
* Adds a rule to mark traffic from LAN with a destination port of 563 with mark 10
* Adds a rule to source NAT traffic coming back on the interface to have the correct IP address (without this the external IP will not reply to pings for example)
* Adds a rule to send all traffic with mark 10 through the VMEDIA routing table
* Adds a rule to send all traffic destined for the /32 address associated with the connection through the VMEDIA routing table
* Flushes the route cache
* Loosens the return path filter on the interface in question

It’s important that you change the rule for port 563 to be your own rule(s) for policy routing. Notice that it is mentioned twice, the first checks if the rule exists, and the second actually adds the rule, so be sure to modify both.

#!/bin/bash
echo "IFACE: ${IFACE}"
echo "LOGICAL: ${LOGICAL}"
IFACE_ADDR=`ip addr show dev DEV_VM_WAN | grep "inet " | awk '{print $2}' | sed -E 's/\/[0-9]+$//'`
GWAY_ADDR=`ip route show dev DEV_VM_WAN | grep default | awk '{print $3}'`
(echo ${IFACE_ADDR} | grep -Eq "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$") && echo "VM-FIX IFACE matched" || exit
(echo ${GWAY_ADDR} | grep -Eq "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$") && echo "VM-FIX GWAY matched" || exit
ip route add default via ${GWAY_ADDR} dev DEV_VM_WAN table VMEDIA || true
IPT_CODE=`iptables -t mangle -C PREROUTING -p tcp --dport 563 -s 192.168.1.0/24 -j MARK --set-mark 10 2>&1 || true`
if [[ ! -z ${IPT_CODE// } ]]; then
echo "VM-FIX Adding rule 1"
iptables -t mangle -I PREROUTING 1 -p tcp --dport 563 -s 192.168.1.0/24 -j MARK --set-mark 10 || true
fi
IPT_CODE=`iptables -t nat -C POSTROUTING -o DEV_VM_WAN -j SNAT --to-source ${IFACE_ADDR} 2>&1 || true`
if [[ ! -z ${IPT_CODE// } ]]; then
echo "VM-FIX Adding rule 2"
iptables -t nat -I POSTROUTING 1 -o DEV_VM_WAN -j SNAT --to-source ${IFACE_ADDR} || true
fi
ip rule add fwmark 10 table VMEDIA || true
ip rule add from ${IFACE_ADDR}/32 table VMEDIA || true
ip route flush cache || true
if [ -f /proc/sys/net/ipv4/conf/DEV_VM_WAN/rp_filter ]; then
echo 2 > /proc/sys/net/ipv4/conf/DEV_VM_WAN/rp_filter
fi

Then:

chmod 0755 /usr/local/sbin/fix_vm_policy
chmod +x /usr/local/sbin/fix_vm_policy

You should now be able to bring up that interface and it should put all of its own routes in place. Traffic from the LAN should be routed appropriately.

Latest revision as of 00:22, 18 August 2018

Preface

These instructions are for setting up Ubuntu 16.04 specifically with an AAISP PPPoE (VDSL & ADSL) connection, and a functioning LAN, with additional instructions for bonding, a third WAN with policy based routing, and additional LAN services such as DHCP(v6) and RADVD. The instructions will likely be similar for other versions of Ubuntu and Debian, but may require some changes. These instructions were built at least partly on:

Initial System Setup

Make sure the system is up to date and install some essentials:

apt-get update
apt-get upgrade -y
apt-get install -y pppoe ppp iproute2 iptables ip6tables
sed -i 's/#net\.ipv4\.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sed -i 's/#net\.ipv6\.conf\.all\.forwarding=1/net.ipv6.conf.all.forwarding=1/' /etc/sysctl.conf
sysctl -p

Networking Interface Information

This is going to vary for everyone depending on how your “router” is setup. I’ll be referring to various network interfaces in the guide, and I’ll use the names defined here to reference them, where they are used, these names refer to the physical name of the device. You need to replace them with your own interface names in applicable config sections.

Interface Name Used Description
DEV_AA_WAN1 Plugged into port marked LAN1 on HG612 for Line 1 (bridged connection used for PPPoE)
DEV_AA_WAN1_C Plugged into port marked LAN2 on HG612 for Line 1 (HG612 has a static IP of 192.168.2.1 and subnet mask 255.255.255.0), used for accessing modem stats
DEV_AA_WAN2 Plugged into port marked LAN1 on HG612 for Line 2 (bridged connection used for PPPoE)
DEV_AA_WAN2_C Plugged into port marked LAN2 on HG612 for Line 2 (HG612 has a static IP of 192.168.3.1 and subnet mask 255.255.255.0), used for accessing modem stats
DEV_LAN The interface on which the LAN is connected
DEV_VM_WAN Plugged into Virgin Media modem in bridge mode

VLANs

Note that on Ubuntu, support for VLANs is not enabled by default, so if you are intending to use VLANs you will need to do the following:

modprobe 8021q
echo "8021q" >> /etc/modules

You will then need to add your VLANs for use by doing:

vconfig add INTERFACE VLAN

For example:

vconfig add eth0 10

You can then use the notation eth0.10 to reference this interface with VLAN.

Setting Up PPP Connection(s)

A lot of this part of the guide can be seen here: https://support.aa.net.uk/Router:Linux_-_Debian#Setting_up_pppd

First Connection

/etc/ppp/peers/aaisp_wan1

Edit this file with the following (don’t forget to replace DEV_AA_WAN1 with your interface over which PPP should be dialled):

user your-line1-username
plugin rp-pppoe.so DEV_AA_WAN1
noipdefault
defaultroute
hide-password
lcp-echo-interval 1
lcp-echo-failure 10
noauth
persist
maxfail 0
mtu 1492
noaccomp
default-asyncmap
+ipv6
ipv6cp-use-ipaddr
ifname pppoe-AA_1
unit 0
linkname aa_wan1

Note the additional “unit” and “linkname” instructions from the linked guide, “unit” is in the index of the ppp connection created (i.e. unit = 0 creates ppp0).

/etc/ppp/chap-secrets

Edit this file and input your username and password in the format specified below. If you have a second connection you can also add the credentials for this one while you are here:

# Secrets for authentication using CHAP
# client        server  secret                  IP addresses
line1-username  *       YourLine1Password
line2-username  *       YourLine2Password

Testing

Test you get some sort of response directly:

pppoe -I DEV_AA_WAN1 -A

If you do, then the connection will probably succeed, try firing up the connection:

pon aaisp_wan1

It should connect and you should get a default IPv4 route. Now that we know it’s working we can disable it again:

poff aaisp_wan1

Second Connection (for Bonding)

Only do this if you have a second PPPoE connection with AAISP for use for bonding. Make sure that your primary IPv4 address is routed to both lines, and make sure an IPv6 /64 block is routed to both lines. Multiple IPv4 addresses and IPv6 blocks are outside the scope of this guide.

/etc/ppp/peers/aaisp_wan2

Edit the file as shown for aaisp_wan1 but importantly, make sure the device is set to your DEV_AA_WAN2, and change the “ifname”, “unit” and “linkname” directives.

Testing

Again, you can test in the same way as with aaisp_wan1.

Further Config Changes

For bonding, it’s important now to go into both config files (/etc/ppp/peers/aaisp_wan1 & /etc/ppp/peers/aaisp_wan2), and to comment out the “defaultroute” directive. We don’t want either of these connections to become default routes as we will implement the bonding with a virtual interface later on.

Configuring Network Interfaces

Time to do some work on the network interfaces themselves, fire up your favourite text editor and edit the file /etc/network/interfaces

Most likely it’s populated with something like the following already:

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

auto enp0s20f0
iface enp0s20f0 inet dhcp

You’ll need to make sure that as you edit this file, you don’t define any interfaces a second time.

VLANs

Another note on VLANs, whenever you use one, you should always specify “vlan-raw-device” inside the interface definition, and there should always be a “manual” definition for the raw device itself as well. For example, assuming we have eth4, and the modem stats port is connected on VLAN 20, the definition would look like this:

auto eth4
iface eth4 inet manual

auto eth4.20
iface eth4.20 inet static
    vlan-raw-device eth4
    address 192.168.2.2
    netmask 255.255.255.0

You also need to make sure you have added this interface with vconfig as mentioned further up in the guide.

LAN

Firstly let’s define your LAN interface, this is where DHCP will operate and your LAN clients are connected to. Make sure to replace DEV_LAN with your physical device.

I’m using 192.168.1.0/24 as my LAN but feel free to use whatever you want.

For IPv6, assign the first address of your routed /64 block, so if your block is 2001:db8:b9:2041::/64, then assign 2001:db8:b9:2041::1.

# LAN Configuration
auto DEV_LAN
iface DEV_LAN inet static
    address 192.168.1.1
    netmask 255.255.255.0

iface DEV_LAN inet6 static
    address 2001:db8:b9:2041::1
    netmask 64

First Connection

We need to make 2 entries in the file for the connection, one for the physical interface itself and one to actually bring up PPP:

# AAISP WAN1
auto DEV_AA_WAN1
iface DEV_AA_WAN1 inet manual

# AAISP PPPoE 1
auto aa_wan1
iface aa_wan1 inet ppp
    pre-up /sbin/ip link set DEV_AA_WAN1 up
    provider aaisp_wan1

I am not sure the pre-up is strictly necessary but it seems to have helped for me.

Control Interface

If you have an HG612 with the IPs statically configured like I described, then you can also configure the modem stats interface:

# AAISP Modem Stats 1
auto DEV_AA_WAN1_C
iface DEV_AA_WAN1_C inet static
    address 192.168.2.2
    netmask 255.255.255.0

Second Connection (for Bonding)

Configure this exactly as described in “First Connection” but with the correct interfaces and provider name.

Testing

In theory now you can “ifup” all of the interfaces you just configured. The PPP interfaces should connect and get both an IPv4 address and an IPv6 link-local address.

If you are not bonding, a default IPv4 route should have been added and connectivity should work. You should also be able to statically assign yourself an IP address in the range you specified for LAN, connect on that interface and the router should respond to ping.

Fixing Routes

One Connection Only

If you are not bonding, then you should already get a default IPv4 route, and we simply need to make it so that an appropriate IPv6 route is added when the PPP interface comes up.

Create a new file /etc/ppp/ipv6-up.d/set-route with the following:

/sbin/ip -6 route add default dev $1

Then execute:

chmod 0755 /etc/ppp/ipv6-up.d/set-route
chmod +x /etc/ppp/ipv6-up.d/set-route

If you “ifdown” and “ifup” the interface, you should get an IPv6 default route now. You can check with “ip -6 route”.

Two (or more) Connections Bonded

If bonding, we need to enable the teql scheduler and set up some scripts to fix routing and bonding.

Enable the Scheduler

modprobe sch_teql
echo "sch_teql" >> /etc/modules

Fixing the Routing

Create a new file /etc/ppp/ip-up.d/fix-teql with the following contents (make sure to put in your IPv4 & first IPv6 address):

#!/bin/bash
/sbin/sysctl -w net.ipv4.conf.pppoe-AA_1.rp_filter=2
/sbin/sysctl -w net.ipv4.conf.pppoe-AA_2.rp_filter=2
/sbin/tc qdisc add dev pppoe-AA_1 root teql0
/sbin/tc qdisc add dev pppoe-AA_2 root teql0
/sbin/ip address add YOUR_IPV4_ADDRESS/32 dev teql0
/sbin/ip address add YOUR_FIRST_IPV6_ADDRESS/64 dev teql0
/sbin/ip link set teql0 up
/sbin/ip route replace default scope global dev teql0
/sbin/ip -6 route replace default scope global dev teql0

Then execute:

chmod 0755 /etc/ppp/ip-up.d/fix-teql
chmod +x /etc/ppp/ip-up.d/fix-teql

At this time, if your PPP connections are up from previous testing, you can manually run this script, and you should then get connectivity on both IPv4 & IPv6. You can also check “ip route” and “ip -6 route” and the teql0 device should be the default route for both.

Firewalling

You can use iptables to configure a firewall for your system and also to apply some features such as IPv4 NAT for LAN.

The rules are mostly taken from https://support.aa.net.uk/Router:Linux_-_Debian#Configuring_your_firewall and are commented so you can execute what you need. Also remember to replace your devices as before (although the PPP devices are named correctly if you followed the guide.

IPv4 Rules

Note that implementing these rules wipes your existing IPv4 rules if you have any.

# Wipe all existing rules
iptables -t filter -F
iptables -t nat -F
iptables -t mangle -F

iptables -t filter -X
iptables -t nat -X
iptables -t mangle -X

# Accept everything from localhost
iptables -A INPUT -i lo -m comment --comment "Accept all from localhost" -j ACCEPT
# Accept all ICMP
iptables -A INPUT -p icmp -m comment --comment "Accept all ICMP" -j ACCEPT
# Accept everything from LAN
iptables -A INPUT -i DEV_LAN -m comment --comment "Accept all from the LAN" -j ACCEPT
# Accept established connections from AAISP Line 1
iptables -A INPUT -i pppoe-AA_1 -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic" -j ACCEPT
# Accept established connections from AAISP Line 2 (Bonding only)
iptables -A INPUT -i pppoe-AA_2 -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic" -j ACCEPT
# Allow related traffic from AAISP Modem Stats 1
iptables -A INPUT -s 192.168.2.1/32 -i DEV_AA_WAN1_C -m state --state RELATED,ESTABLISHED -j ACCEPT
# Allow related traffic from AAISP Modem Stats 2 (Bonding only)
iptables -A INPUT -s 192.168.3.1/32 -i DEV_AA_WAN1_C -m state --state RELATED,ESTABLISHED -j ACCEPT
# AAISP Line 1 MSS Clamping
iptables -A FORWARD -o pppoe-AA_1 -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --
comment "Clamp MSS for traffic going via PPP" -j TCPMSS --clamp-mss-to-pmtu
# AAISP Line 2 MSS Clamping (Bonding only)
iptables -A FORWARD -o pppoe-AA_2 -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --comment "Clamp MSS for traffic going via PPP" -j TCPMSS --clamp-mss-to-pmtu
# Allow traffic from LAN to AAISP Line 1
iptables -A FORWARD -i DEV_LAN -o pppoe-AA_1 -m comment --comment "Allow traffic from LAN -> internet" -j ACCEPT
# Allow traffic from LAN to AAISP Line 2 (Bonding only)
iptables -A FORWARD -i DEV_LAN -o pppoe-AA_2 -m comment --comment "Allow traffic from LAN -> internet" -j ACCEPT
# Allow traffic from LAN to teql0 Bond (Bonding only)
iptables -A FORWARD -i DEV_LAN -o teql0 -m comment --comment "Allow traffic from LAN -> internet" -j ACCEPT
# Allow related traffic from AAISP Line 1 to LAN
iptables -A FORWARD -i pppoe-AA_1 -o DEV_LAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic from internet -> LAN" -j ACCEPT
# Allow related traffic from AAISP Line 2 to LAN (Bonding only)
iptables -A FORWARD -i pppoe-AA_2 -o DEV_LAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic from internet -> LAN" -j ACCEPT
# Allow traffic from LAN to AAISP Modem Stats 1
iptables -A FORWARD -i DEV_LAN -o DEV_AA_WAN1_C -m comment --comment "Allow traffic from LAN -> Control" -j ACCEPT
# Allow related traffic back from AAISP Modem Stats 1 to LAN
iptables -A FORWARD -I DEV_AA_WAN1_C -o DEV_LAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic from Control -> LAN" -j ACCEPT
# Allow traffic from LAN to AAISP Modem Stats 2 (Bonding only)
iptables -A FORWARD -i DEV_LAN -o DEV_AA_WAN2_C -m comment --comment "Allow traffic from LAN -> Control" -j ACCEPT
# Allow related traffic back from AAISP Modem Stats 2 to LAN (Bonding only)
iptables -A FORWARD -I DEV_AA_WAN2_C -o DEV_LAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic from Control -> LAN" -j ACCEPT
# Allow NAT on AAISP Line 1
iptables -t nat -A POSTROUTING -o pppoe-AA_1 -m comment --comment NAT -j MASQUERADE
# Allow NAT on AAISP Line 2 (Bonding only)
iptables -t nat -A POSTROUTING -o pppoe-AA_2 -m comment --comment NAT -j MASQUERADE
# Allow NAT on teql0 Bond (not sure this is necessary) (Bonding only)
iptables -t nat -A POSTROUTING -o teql0 -m comment --comment NAT -j MASQUERADE
# Allow NAT to get to AAISP Mode Stats Line 1
iptables -t nat -A POSTROUTING -o DEV_AA_WAN1_C -m comment --comment NAT -j MASQUERADE
# Allow NAT to get to AAISP Mode Stats Line 2 (Bonding only)
iptables -t nat -A POSTROUTING -o DEV_AA_WAN2_C -m comment --comment NAT -j MASQUERADE

# Default drop everything from outside 
# Note that these drops are *important* because we don't reject any traffic in the rules themselves, without these, stuff will be wide open
iptables -P FORWARD DROP
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -t nat -P OUTPUT ACCEPT
iptables -t nat -P PREROUTING ACCEPT
iptables -t nat -P POSTROUTING ACCEPT

IPv6 Rules

Note that implementing these rules wipes your existing IPv6 rules if you have any.

# Wipe all existing rules
ip6tables -F
ip6tables -X

# Accept everything from localhost
ip6tables  -A INPUT -i lo -m comment --comment "Accept all from localhost" -j ACCEPT
# Accept all ICMP
ip6tables  -A INPUT -p ipv6-icmp -m comment --comment "Accept all ICMP" -j ACCEPT
# Accept everything from LAN
ip6tables  -A INPUT -i DEV_LAN -m comment --comment "Accept all from LAN" -j ACCEPT
# Accept established connections from AAISP Line 1
ip6tables  -A INPUT -i pppoe-AA_1 -m state --state RELATED,ESTABLISHED -m comment --comment "Accept related & return traffic" -j ACCEPT
# Accept established connections from AAISP Line 2 (Bonding only)
ip6tables  -A INPUT -i pppoe-AA_2 -m state --state RELATED,ESTABLISHED -m comment --comment "Accept related & return traffic" -j ACCEPT
# Forward all ICMP
ip6tables  -A FORWARD -p ipv6-icmp -m comment --comment "Forward all ICMP" -j ACCEPT
# Allow traffic from LAN to AAISP Line 1
ip6tables  -A FORWARD -i DEV_LAN -o pppoe-AA_1 -m comment --comment "Allow LAN -> internet" -j ACCEPT
# Allow traffic from LAN to AAISP Line 2 (Bonding only)
ip6tables  -A FORWARD -i DEV_LAN -o pppoe-AA_2 -m comment --comment "Allow LAN -> internet" -j ACCEPT
# Allow traffic from LAN to teql0 Bond (Bonding only)
ip6tables  -A FORWARD -i DEV_LAN -o teql0 -m comment --comment "Allow LAN -> internet" -j ACCEPT
# Allow related traffic from AAISP Line 1 to LAN
ip6tables  -A FORWARD -i pppoe-AA_1 -o DEV_LAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow related & return traffic WAN -> LAN" -j ACCEPT
# Allow related traffic from AAISP Line 2 to LAN (Bonding only)
ip6tables  -A FORWARD -i pppoe-AA_2 -o DEV_LAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow related & return traffic WAN -> LAN" -j ACCEPT

# Default drop everything from outside
ip6tables -P FORWARD DROP
ip6tables -P INPUT DROP
ip6tables -P OUTPUT ACCEPT

Testing

You should now be able to statically assign a computer an address in your LAN subnet, connect to the LAN port on this router and you should have IPv4 connectivity to the internet at least at this point. If you wish you can also test IPv6 in this way by assigning an address from your block.

Final Steps

We now need to install iptables-persistent to save the rules across reboots:

apt-get install iptables-persistent

In the prompts select that you wish to save the rules now. Note that if you change rules manually in the future you will need to issue the following command to persist them (but note that it will also persist any rules added for things like UPnP):

netfilter-persistent save
netfilter-persistent reload

LAN Setup

This section deals with setting up services for your LAN network. We will cover the following:

  • BIND (DNS Forwarder with Caching)
  • DHCP
  • DHCPv6
  • RADVD
  • UPnP

BIND (DNS)

BIND is relatively simple to setup in this way, firstly install it:

apt-get install bind9

Now edit the file /etc/bind/named.conf.options and update it with the following. Note that you should replace 192.168.1.1 with the statically assigned IPv4 address on your LAN interface, and 2001:db8:b9:2041::1 with the statically assigned IPv6 address on your LAN.

acl goodclients {
    191.168.1.0/24;
    localhost;
    localnets;
};
options {
    directory "/var/cache/bind";

    recursion yes;
    allow-query { goodclients; };

    # Feel free to add your own DNS servers here
    forwarders {
        8.8.8.8;
        8.8.4.4;
    };

    dnssec-enable yes;
    dnssec-validation yes;

    auth-nxdomain no;
    listen-on-v6 { 2001:db8:b9:2041::1; ::1; };
    listen-on { 192.168.1.1; 127.0.0.1; };
};

Issue:

systemctl enable bind9
systemctl restart bind9

It should now be possible to issue DNS requests to the local system:

root@ubuntu-router:/# dig +noauthority aaisp.net A  @127.0.0.1

; <<>> DiG 9.10.3-P4-Ubuntu <<>> +noauthority aaisp.net A @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54288
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 13, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;aaisp.net.                     IN      A

;; ANSWER SECTION:
aaisp.net.              3420    IN      A       81.187.30.81

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed May 03 14:54:36 BST 2017
;; MSG SIZE  rcvd: 262

If you would like to force the local machine to use this caching server for lookups, but not change /etc/network/interfaces to do so, and also avoid messing with resolvconf, you can do the following, although it’s not the recommended method for doing so:

echo “nameserver 127.0.0.1” >> /etc/resolvconf/resolv.conf.d/head

DHCP

DHCP is relatively easy to setup for IPv4 but is going to require some manual tweaks for IPv6 (listed in the next section).

Install the ISC DHCP Server:

apt-get install isc-dhcp-server

Edit /etc/default/isc-dhcp-server and edit INTERFACES to add your LAN interface:

# Defaults for isc-dhcp-server initscript
# sourced by /etc/init.d/isc-dhcp-server
# installed at /etc/default/isc-dhcp-server by the maintainer scripts

#
# This is a POSIX shell fragment
#

# Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf).
#DHCPD_CONF=/etc/dhcp/dhcpd.conf

# Path to dhcpd's PID file (default: /var/run/dhcpd.pid).
#DHCPD_PID=/var/run/dhcpd.pid

# Additional options to start dhcpd with.
#       Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead
#OPTIONS=""

# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
#       Separate multiple interfaces with spaces, e.g. "eth0 eth1".
INTERFACES="DEV_LAN"

Now you can edit /etc/dhcp/dhcpd.conf and update it for your use, a sample config is shown below:

ddns-update-style none;
default-lease-time 600;
max-lease-time 7200;
log-facility local7;
subnet 192.168.1.0 netmask 255.255.255.0 {
    range 192.168.1.50 192.168.1.200;
    option routers 192.168.1.1;
    option domain-name-servers 192.168.1.1;
    option broadcast-address 192.168.1.255;
}

Once that’s done, you can issue the following:

systemctl enable isc-dhcp-server
systemctl restart isc-dhcp-server

This should give you working DHCP for IPv4 on your LAN.

DHCPv6

DHCPv6 is supported by isc-dhcp-server but requires us to make a new init script and change some configuration (credit: https://www.interlan.se/fix-isc-dhcp-server6-ubuntu-16-04/ ). I will assume you already did the DHCP setup mentioned previously.

Execute:

cp /etc/default/isc-dhcp-server /etc/default/isc-dhcp-server6

Edit /etc/default/isc-dhcp-server6 and change the options as follows:

# Defaults for isc-dhcp-server initscript
# sourced by /etc/init.d/isc-dhcp-server
# installed at /etc/default/isc-dhcp-server by the maintainer scripts

#
# This is a POSIX shell fragment
#

# Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf).
DHCPD_CONF=/etc/dhcp/dhcpd6.conf

# Path to dhcpd's PID file (default: /var/run/dhcpd.pid).
DHCPD_PID=/var/run/dhcpd6.pid

# Additional options to start dhcpd with.
#       Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead
OPTIONS="-6"

# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
#       Separate multiple interfaces with spaces, e.g. "eth0 eth1".
INTERFACES="DEV_LAN"

Edit /etc/dhcp/dhcpd6.conf and populate it with your /64 block and a suitable range, a sample config is:

default-lease-time 2592000;
preferred-lifetime 604800;
option dhcp-renewal-time 3600;
option dhcp-rebinding-time 7200;
allow leasequery;

option dhcp6.name-servers 2001:db8:b9:2041::1;
option dhcp6.info-refresh-time 21600;

subnet6 2001:db8:b9:2041::/64 {
    range6 2001:db8:b9:2041::100 2001:db8:b9:2041:ffff:ffff:ffff:ffff;
    range6 2001:db8:b9:2041::/64 temporary;
}

Execute:

cp /etc/init.d/isc-dhcp-server /etc/init.d/isc-dhcp-server6
sed -i s/isc-dhcp-server/isc-dhcp-server6/ /etc/init.d/isc-dhcp-server6
sed -i s/dhcpd.conf/dhcpd6.conf/ /etc/init.d/isc-dhcp-server6
sed -i s/dhcpd.pid/dhcpd6.pid/ /etc/init.d/isc-dhcp-server6
systemctl enable isc-dhcp-server6
systemctl start isc-dhcp-server6

You should now get an IPv6 address, although you may not, and if you do, depending on the OS, it may not actually work properly until you’ve gone to the next section and setup RADVD.

RADVD

RADVD config is actually very easy with a simple config. Just install RADVD first:

apt-get install radvd

Then edit /etc/radvd.conf and update it with your interface and prefix, here is a sample config:

interface DEV_LAN
{
    AdvSendAdvert on;
    prefix 2001:db8:b9:2041::/64 {
        AdvOnLink on;
        AdvAutonomous on;
    };
};

Once done, execute:

systemctl enable radvd
systemctl restart radvd

This should give your LAN clients IPv6 addresses and connectivity.

UPnP

UPnP is something I do have working, but for me it can be a little temperamental after a reboot, but usually starts working after a couple of minutes.

We will use miniupnpd for this, and the configuration options are really quite minimal.

Firstly, install miniupnpd:

apt-get install miniupnpd

Next, edit /etc/default/miniupnpd and update it as follows (notice the commenting out of the OTHER_OPTIONS”). If you need UPnP for IPv6, don’t forget to also set the last option to “yes”:

# Set to 1 to start the daemon. Desactivated by default, because
# you don't want the outside to control your UPnP router, and
# as a consequence MiniUPnPd_LISTENING_IP should be set to a
# reasonable value before enabling the daemon.
START_DAEMON=1

# Define here the external interface connected to the WAN (e.g.: the public
# IP address NIC)
MiniUPnPd_EXTERNAL_INTERFACE="pppoe-AA_1"

# IP that the daemon should listen on.
# Note that you do *not* want this to be 0.0.0.0, as you don't want
# your MiniUPnPd to be controlled by anyone on the internet.
MiniUPnPd_LISTENING_IP=”DEV_LAN”
 
# This defines other options which you might want to use when
# starting MiniUPnPd. Note that the -S option is important:
# -S sets "secure" mode : clients can only add mappings to their own ip
# (see man page)
#MiniUPnPd_OTHER_OPTIONS="-N -f /etc/miniupnpd/miniupnpd.conf"
MiniUPnPd_OTHER_OPTIONS=""

# If this option is defined, then the init script will initialize
# the ipv6 tables.
MiniUPnPd_ip6tables_enable=no

Once that’s done, you should be able to execute:

systemctl enable miniupnpd
systemctl start miniupnpd

We need to also restart miniupnpd when a PPP interface comes up or down. If we don’t do this, then miniupnpd will usually start at boot time before the PPP interface is connected, and this breaks the rules it puts in place.

Create a new file /etc/ppp/ip-up.d/fix-upnp with the following contents:

#!/bin/bash
/etc/init.d/miniupnpd restart

Then execute:

chmod 0755 /etc/ppp/ip-up.d/fix-upnp
chmod +x /etc/ppp/ip-up.d/fix-upnp

Bonus: Run dslstats in Docker on Ubuntu

I'll add this section because some people may find it useful if you either want dslstats for your own use directly or to submit to something like MyDSLWebStats.

Install Docker

Install Docker, we'll get a better version than what is in the normal repos:

apt-get install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# Assuming amd64
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update
apt-get install docker-ce

Download & Run Container

Now we have docker, all we need to do is download and run the container, which can be done in a single command. This command will do the following:

  • Names the container "dslstats_1"
  • Opens a VNC server on 192.168.1.1:5900 (you should specifically set the router IP like I have to make sure it's only accessible privately)
  • Opens a tcp listener on port 192.168.1.1:8080 - this won't actually do anything unless you enable the web server for dslstats
  • Sets the password to login to VNC to "dslstats"
  • Sets the path for the dslstats configurtion to be /etc/dslstats_1/ on the host
  • Mounts /etc/localtime from the host to use the correct timezone data
  • Restarts the container as soon as the Docker daemon starts (should be on each reboot)
docker run -d \
    --name=dslstats_1 \
    -p 192.168.1.1:5900:5900 \
    -p 198.168.1.1:8080:8080 \
    -e "VNC_PASSWORD"="dslstats"
    -v /etc/dslstats_1:/config \
    -v /etc/localtime:/etc/localtime:ro \
    --restart=always
    rossallan/dslstats

Obviously if you are running 2 modems you wish to report stats for, you will need a second MyDSLWebStats account (if you are submitting there), and to modify this command for the second container to use different ports and configuration directory.

For more information about Docker installation, see here, and for more information about the dslstats Docker container, see here.

Bonus: Port based policy routing to a third WAN

I also have a third WAN connection (provided by Virgin Media) over which I route some traffic based on the destination port. It’s of course possible to route it based on destination IP, source IP or any combination of routing rules you can think of. It’s also possible to use it as a failover if your PPP connection dies as well (although this guide does not cover this).

Moving forward though I’ll be making assumptions that the third connection is a VM connection (or an “equivalent”) provided by DHCP.

Configure Interface

Edit /etc/network/interfaces and configure the interface for the connection, we give it a higher metric to make sure it doesn’t override any default routes we configured, we also provide a post-up script which we’ll cover later:

# VMEDIA
auto DEV_VM_WAN
iface DEV_VM_WAN inet dhcp
        post-up /usr/local/sbin/fix_vm_policy
        metric 100

Fix Firewalling

We need to add some more iptables rules to allow this interface to NAT and receive related traffic etc., we won’t bother with IPv6 since we don’t get a v6 address:

iptables -A INPUT -i DEV_VM_WAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic" -j ACCEPT
iptables -A FORWARD -i DEV_LAN -o DEV_VM_WAN -m comment --comment "Allow traffic from LAN -> internet" -j ACCEPT
iptables -A FORWARD -i DEV_VM_WAN -o DEV_LAN -m state --state RELATED,ESTABLISHED -m comment --comment "Allow return traffic from internet -> LAN" -j ACCEPT
iptables -t nat -A POSTROUTING -o DEV_VM_WAN -m comment --comment NAT -j MASQUERADE

Don’t forget netfilter-persistent save && netfilter-persistent reload afterwards.

Fix Routing

We need to add a new route table, it will be called VMEDIA.

echo “20    VMEDIA” >> /etc/iproute2/rt_tables

/usr/local/sbin/fix_vm_policy

Create the script mentioned in post-up earlier. This script does the following:

  • Fetch the interface address (a /32 IPv4 in this case)
  • Fetch the gateway address
  • Check these look like valid IP addresses to avoid any blank routes
  • Add a default route via the gateway to the routing table VMEDIA
  • Adds a rule to mark traffic from LAN with a destination port of 563 with mark 10
  • Adds a rule to source NAT traffic coming back on the interface to have the correct IP address (without this the external IP will not reply to pings for example)
  • Adds a rule to send all traffic with mark 10 through the VMEDIA routing table
  • Adds a rule to send all traffic destined for the /32 address associated with the connection through the VMEDIA routing table
  • Flushes the route cache
  • Loosens the return path filter on the interface in question

It’s important that you change the rule for port 563 to be your own rule(s) for policy routing. Notice that it is mentioned twice, the first checks if the rule exists, and the second actually adds the rule, so be sure to modify both.

#!/bin/bash
echo "IFACE: ${IFACE}"
echo "LOGICAL: ${LOGICAL}"
IFACE_ADDR=`ip addr show dev DEV_VM_WAN | grep "inet " | awk '{print $2}' | sed -E 's/\/[0-9]+$//'`
GWAY_ADDR=`ip route show dev DEV_VM_WAN | grep default | awk '{print $3}'`
(echo ${IFACE_ADDR} | grep -Eq "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$") && echo "VM-FIX IFACE matched" || exit
(echo ${GWAY_ADDR} | grep -Eq "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$") && echo "VM-FIX GWAY matched" || exit
ip route add default via ${GWAY_ADDR} dev DEV_VM_WAN table VMEDIA || true
IPT_CODE=`iptables -t mangle -C PREROUTING -p tcp --dport 563 -s 192.168.1.0/24 -j MARK --set-mark 10 2>&1 || true`
if [[ ! -z ${IPT_CODE// } ]]; then
        echo "VM-FIX Adding rule 1"
        iptables -t mangle -I PREROUTING 1 -p tcp --dport 563 -s 192.168.1.0/24 -j MARK --set-mark 10 || true
fi
IPT_CODE=`iptables -t nat -C POSTROUTING -o DEV_VM_WAN -j SNAT --to-source ${IFACE_ADDR} 2>&1 || true`
if [[ ! -z ${IPT_CODE// } ]]; then
    echo "VM-FIX Adding rule 2"
    iptables -t nat -I POSTROUTING 1 -o DEV_VM_WAN -j SNAT --to-source ${IFACE_ADDR} || true
fi
ip rule add fwmark 10 table VMEDIA || true
ip rule add from ${IFACE_ADDR}/32 table VMEDIA || true
ip route flush cache || true
if [ -f /proc/sys/net/ipv4/conf/DEV_VM_WAN/rp_filter ]; then
    echo 2 > /proc/sys/net/ipv4/conf/DEV_VM_WAN/rp_filter
fi

Then:

chmod 0755 /usr/local/sbin/fix_vm_policy
chmod +x /usr/local/sbin/fix_vm_policy

You should now be able to bring up that interface and it should put all of its own routes in place. Traffic from the LAN should be routed appropriately.