Home Network, a novice Design
May 16, 2017
I’ve written before about network hardware selection, where I surmise that Ubiquiti’s EdgeMax products are what I typically rely on when building out a network. Here I’ll lay out what I think is a good design for a home network using some of the inexpensive EdgeMax and Unifi products. It might seem silly that I would include Unifi in a discussion of implementation with EdgeMax, but really you don’t have a better choice for wireless access point than what Unifi offers. Furthermore, I chose EdgeMax for this implementation because it will help to solidify understanding of the standards better than if one would use the software defined networking approach of Unifi.
We make some assumptions before proceeding:
- you can acquire the listed hardware, or alternatives
- you have some networking basics
- you can read peripheral direction from the manufacture (e.g. firmware update process)
- your service providers modem uses DHCP (static isn’t a huge change but isn’t written in the document)
- you’re using a single switch and don’t need to muck with things like STP
Design & Standards #
As I’ve dug into more projects that require knowledge of network design I’ve begun to truly appreciate the artful nature of network composition. With a small home network you’ll likely never appreciate all of the available design choices and the craft associated expressing a design that addresses needs and anticipates growth vectors. However, you can use a small home network to get some exposure into the standards that ground all of these things. With a project like this you’re going to get exposure to a bunch of standard from the Internet Protocol Suite which typically developed as a series of RFC that eventually become documented as standards by a standards body, in this case it is IEEE 802.
When you’re wanting to understand something via discussion, or seach, it’s important to be able to layer these standards in your mind so that you understand the context you should be searching within. There are also other standards than the Internet Protocol Suite such as the OSI Stack that are incredibly useful as conceptual bounds for your exploration.
At first all these things might seem overwhelming and tedious, but if you take the time to examine them you’ll see that smart people have gone before you and created wonderful foundations for you to build upon. One that I like to have new people read is the IEEE 802.1Q because it really highlights how much work has to go into something as simple as adding a frame header to a switched packet, and how it can be designed to operate elegantly.
Design #
You should always write out your plan before you begin.
our network goals:
- a border router with a strong implementation of firewall
- two sub-networks, one for the home users, another for guests
- isolation of traffic between those sub-networks
- wireless access for both home and guest users off the same access point
- a bastion host that we can use as a hardened proxy to get back into our network
- use of fiber modules (because fiber is cool)
our networking kit:
- EdgeRouter X-SFP : ~80USD
- EdgeSwitch 8 : ~200USD
- UF-MM-1G : ~20USD
- Armored LC-LC Patch Cable : ~10USD
- Unifi AP-AC-Lite : ~90USD
- Odroid C2 : ~50USD
You can change out pretty much everything in this for other things that you wan based on your needs. I typically purchase the ES-24-Lite because its the least expensive managed switch that I can easily drop into environments. For the purposes of the write up I’ll assume the following kit so that I can use interface numbers to indicate wiring.
Fiber is also something you can choose to drop, Ethernet over the distances in a typical home is certainty adequate. I personally like to get people to play around with Fiber because I want them to realize its a technology that they can use today, which might make them more interested in municipal broadband and other things that would break up the monstrous trusts that control our countries internet today. For Fiber I typically purchase all of my accessories from FiberStore due to them being so inexpensive, but you need to know what you’re looking for. In a project like this you’d just need Multi Mode SFP modules, no need for SFP+ because you’re using gigabit interfaces. You’ll need LC-LC fiber, and I typically prefer to purchase the armored version from FiberStore because I’m less likely to damage it. Another alternative to fiber that allows you to use the SFP form factor is Direct Attached Copper (DAC) which allow you to use SFP over relatively short distances without the downsides of fiber (e.g. worrying about termination cleanliness).
our layer 1 topology:
Pardon the terrible drawing, but here is the topology:
- modem -> EdgeRouter eth0
- EdgeRouter eth5 (fiber) -> EdgeSwitch eth9
- EdgeSwitch eth8 -> AP-AC-Lite
- EdgeSwitch eth7 -> Odroid C2
EdgeRouter X-SFP
+---------------------+
| + +--------> diagnostic
+--|------------------+
|
+-------------------------+
EdgeSwitch 8 |
+----------------------------|--+
| v |
| +-+ +-+ |
+-------------|------|----------+
| |
OdroidC2 | | AP-AC-Lite
+-----------v-+ +v------------+
| | | |
| | | |
+-------------+ +-------------+
our layer 2 and 3 topology:
We will utilize Virtual LANs via 802.1Q to segment our home and guest networks. We will also create a sub-network on the interface of our router as a diagnostic backup for whenever something might go wrong, allowing you to plug right into the router to diagnose issues.
- 172.16.16.0/24 : DIAG : diagnostic network on eth4 of router
- 172.16.0.0/24 : HOME : where we want to hang out with all of our protected stuff
- 172.16.1.0/24 : ILPR : where we want guests to go when they authenticate to wireless
For 172.16.0.0/24
and 172.16.1.0/24
we will use VLAN ID 7
and VLAN ID 14
respectively. I’ve chosen these arbitrarily, but you’ll see them consistently throughout the write up, so if you want to change because you have numbers you like better… make sure you’re consistent.
our final prep:
- wire everything up as it should be
- hard reset the devices, ensure that you’ve not affected some configuration change on them before beginning
- update the firmware of both the router and switch, reboot them
Routing #
We’re going to get away from the GUI as soon as we can because there are a lot of cases where the GUI presents information in a way that isn’t clear, or actually sets values on the system in a way we do not want. This is much more prevalent in the EdgeSwitch, but it is preferred to learn what’s under the hood on both EdgeSwith and EdgeRouter.
- Get connected (
eth0
) and use the GUI to set up the settings tab:
hostname: router
timezone: Americas:United States:Eastern (or wherever you are)
nameserver: 127.0.0.1
domainname: your.domain.name
ntp: enabled
ssh: enabled, port 8888
ubntdiscovery: disabled
- Use the GUI to make changes to the interfaces on the main screen:
eth0 rename to WAN, leave alone for now (must configure DIAG)
eth1 disable
eth2 disable
eth3 disable
eth4 rename to DIAG, set static address of 172.16.16.1/24
eth5 rename to TRNK
- Now move yourself over to
eth4
, set a static address of172.16.16.2
, and get back into the router at172.16.16.1
. Seteth0
to DHCP, and if your modem is functioning you should now see it pull an address. - Now set up a username for yourself, log out, log back in, delete the ubnt user.
- Now
scp
your public key into the router:scp -P 8888 key.pub 172.16.16.1:key.pub
- Now
ssh
into the router and we will begin running through our configuration. First we load the key-file.
ssh -p 8888 <user>@172.16.16.1
configure
loadkey <user> key.pub
save
You should exit back out and ssh
back in to verify the key load works.
Once back in it is always nice to set a cool login banner, generate them here:
set system login banner pre-login "\n\n ___ __ __ ___ ___\n |__ |__) | |__) |__| \ / | |__\n |___ | | | | | | | |___\n\n [email protected]\n\n"
commit;save;
Which results in:
___ __ __ ___ ___
|__ |__) | |__) |__| \ / | |__
|___ | | | | | | | |___
[email protected]
We’ll now do several things at once, and I’ll explain them below:
configure
set service dhcp-server use-dnsmasq enable
set service dns forwarding name-server 1.1.1.1
set service dns forwarding name-server 1.0.0.1
set service dns forwarding cache-size 512
set service dhcp-server shared-network-name DIAG authoritative enable
set service dhcp-server shared-network-name DIAG subnet 172.16.16.0/24 default-router 172.16.16.1
set service dhcp-server shared-network-name DIAG subnet 172.16.16.0/24 dns-server 172.16.16.1
set service dhcp-server shared-network-name DIAG subnet 172.16.16.0/24 domain-name diag.domain.name
set service dhcp-server shared-network-name DIAG subnet 172.16.16.0/24 lease 360
set service dhcp-server shared-network-name DIAG subnet 172.16.16.0/24 start 172.16.16.10
set service dhcp-server shared-network-name DIAG subnet 172.16.16.0/24 start 172.16.16.10 stop 172.16.16.20
set service dns forwarding listen-on eth4
set interfaces ethernet eth5 vif 7 address 172.16.0.1/24
set interfaces ethernet eth5 vif 7 description HOME
set service dhcp-server shared-network-name HOME authoritative enable
set service dhcp-server shared-network-name HOME subnet 172.16.0.0/24
set service dhcp-server shared-network-name HOME subnet 172.16.0.0/24 default-router 172.16.0.1
set service dhcp-server shared-network-name HOME subnet 172.16.0.0/24 dns-server 172.16.0.1
set service dhcp-server shared-network-name HOME subnet 172.16.0.0/24 domain-name home.domain.name
set service dhcp-server shared-network-name HOME subnet 172.16.0.0/24 lease 86400
set service dhcp-server shared-network-name HOME subnet 172.16.0.0/24 start 172.16.0.100
set service dhcp-server shared-network-name HOME subnet 172.16.0.0/24 start 172.16.0.100 stop 172.16.0.200
set service dns forwarding listen-on eth5.7
set interfaces ethernet eth5 vif 14 address 172.16.1.1/24
set interfaces ethernet eth5 vif 14 description ILPR
set service dhcp-server shared-network-name ILPR authoritative enable
set service dhcp-server shared-network-name ILPR subnet 172.16.1.0/24
set service dhcp-server shared-network-name ILPR subnet 172.16.1.0/24 default-router 172.16.1.1
set service dhcp-server shared-network-name ILPR subnet 172.16.1.0/24 dns-server 172.16.1.1
set service dhcp-server shared-network-name ILPR subnet 172.16.1.0/24 domain-name guest.domain.name
set service dhcp-server shared-network-name ILPR subnet 172.16.1.0/24 lease 360
set service dhcp-server shared-network-name ILPR subnet 172.16.1.0/24 start 172.16.1.100
set service dhcp-server shared-network-name ILPR subnet 172.16.1.0/24 start 172.16.1.100 stop 172.16.1.110
set service dns forwarding listen-on eth5.14
commit;save;
In the above we:
- set the DHCP server to use dnsmasq, which has more features than the default ISC implementation
- set our DNS forwarders to Cloudflare DNS at
1.1.1.1
and1.0.0.1
(alternatively you could set it to use opendns, quad9, or another resolver you prefer (maybe run your own)). - created a DHCP server called
DIAG
- set our dns forwarder to listen on the interface we want
DIAG
to be a part of - created a
VLAN
oneth5
with theVLAN ID 7
, and assigned an address in ourHOME
sub-network - created a DHCP server called
HOME
- created a
VLAN
oneth5
with theVLAN ID 14
, and assigned an address in ourILPR
sub-network - created a DHCP server called
ILPR
Now that our addresses are in place we are going to restrict the GUI and ssh
to listen only to the DIAG
and HOME
sub-networks:
configure
set service ssh disable-password-authentication
set service ssh listen-address 172.16.16.1
set service ssh listen-address 172.16.0.1
set service gui listen-address 172.16.16.1
set service ssh listen-address 172.16.0.1
set service gui older-ciphers disable
commit;save;
We now set up our NAT masquerade
configure
set service nat rule 5000 outbound-interface eth0
set service nat rule 5000 type masquerade
commit;save;
With that we’re pretty much ready to connect devices to all of our LANs, but we have no firewall in place. So let’s build a firewall to protect us from WAN connections:
configure
set firewall name WAN_IN default-action drop
set firewall name WAN_IN description "packets from WAN through router to LAN"
set firewall name WAN_IN enable-default-log
set firewall name WAN_IN rule 1 action accept
set firewall name WAN_IN rule 1 description "allow established sessions"
set firewall name WAN_IN rule 1 log disable
set firewall name WAN_IN rule 1 protocol all
set firewall name WAN_IN rule 1 state established enable
set firewall name WAN_IN rule 1 state invalid disable
set firewall name WAN_IN rule 1 state new disable
set firewall name WAN_IN rule 1 state related enable
set firewall name WAN_IN rule 2 action drop
set firewall name WAN_IN rule 2 description "drop invalid state"
set firewall name WAN_IN rule 2 log enable
set firewall name WAN_IN rule 2 protocol all
set firewall name WAN_IN rule 2 state invalid enable
set firewall name WAN_LOCAL default-action drop
set firewall name WAN_LOCAL description "packets from WAN to router"
set firewall name WAN_LOCAL enable-default-log
set firewall name WAN_LOCAL rule 1 action accept
set firewall name WAN_LOCAL rule 1 description "allow established sessions"
set firewall name WAN_LOCAL rule 1 log disable
set firewall name WAN_LOCAL rule 1 protocol all
set firewall name WAN_LOCAL rule 1 state established enable
set firewall name WAN_LOCAL rule 1 state invalid disable
set firewall name WAN_LOCAL rule 1 state new disable
set firewall name WAN_LOCAL rule 1 state related enable
set firewall name WAN_LOCAL rule 2 action drop
set firewall name WAN_LOCAL rule 2 description "drop invalid state"
set firewall name WAN_LOCAL rule 2 log enable
set firewall name WAN_LOCAL rule 2 protocol all
set firewall name WAN_LOCAL rule 2 state invalid enable
set interfaces ethernet eth0 firewall in name WAN_IN
set interfaces ethernet eth0 firewall local name WAN_LOCAL
commit;save;
You’ll notice that at the end we applied these two new rules WAN_IN
and WAN_LOCAL
to our eth0
interfaces. To understand the IN
and LOCAL
directives you’d need to read up on the evaluation chain within iptables, or documentation straight from Ubiquiti, but I’ll try with an explanation here:
- WAN_IN: traffic from the internet, through the router, and onward to the LAN.
- WAN_OUT: traffic that has been forwarded through the router and is about to exit the interface
- WAN_LOCAL: traffic destined for the router (e.g. ssh, or the gui)
I’ve spent a lot of time reading about these ideas, this was another good post about the evaluation order and firewall composition. Above is something fairly simple, but you can get quite complex with what you do in these firewalls, and the order in which you evaluate things can have tremendous performance impact.
Although the edgeswitch line claims to have layer3 switching the limitations can be hit pretty quickly. We’ll instead route the traffic between vlans through the router.
The most efficient way to construct rules is to always drop packets as close to their origination as possible. We will build our inter-vlan routing rules based on this principle. Our objective is to:
- allow
HOME
to get out to the internet - allow
HOME
to get into theILPR
subnet - allow
ILPR
to get out to the ineternet - not-allow
ILPR
to get into theHOME
subnet
We’ll start with a chain for HOME
configure
set firewall name HOME_IN default-action reject
set firewall name HOME_IN description 'IN from HOME, VLAN 7, 172.16.0.0/24'
set firewall name HOME_IN rule 10 action accept
set firewall name HOME_IN rule 10 description 'allow related and established'
set firewall name HOME_IN rule 10 protocol all
set firewall name HOME_IN rule 10 state established enable
set firewall name HOME_IN rule 10 state related enable
set firewall name HOME_IN rule 100 action accept
set firewall name HOME_IN rule 100 description 'allow initiation to any of the local networks'
set firewall name HOME_IN rule 100 destination address 172.16.0.0/12
set firewall name HOME_IN rule 100 source address 172.16.0.0/24
set firewall name HOME_IN rule 200 action accept
set firewall name HOME_IN rule 200 description 'allow all outbound activity'
set firewall name HOME_IN rule 200 destination address !172.16.0.0/12
set firewall name HOME_IN rule 200 source address 172.16.0.0/24
set interfaces ethernet eth5 vif 7 firewall in name HOME_IN
This chain:
- rejects as a default action
- accepts related and established (rule 10)
- accepts
172.16.0.0/24
initiating to anything within172.16.0.0/12
(rule 100) - accepts all traffic not bound to
172.16.0.0/12
(rule 200)
The last rule (rule 200) is a negation match !172.16.0.0/12
, which is a hack to match all packets that are destined to not our local networks, which should, in essence, be the internet.
We’ll then build a chain for ILPR
:
set firewall name ILPR_IN default-action reject
set firewall name ILPR_IN description 'IN from ILPR, VLAN 14, 172.16.1.0/24'
set firewall name ILPR_IN rule 10 action accept
set firewall name ILPR_IN rule 10 description 'allow related and established'
set firewall name ILPR_IN rule 10 protocol all
set firewall name ILPR_IN rule 10 state established enable
set firewall name ILPR_IN rule 10 state related enable
set firewall name ILPR_IN rule 200 action accept
set firewall name ILPR_IN rule 200 description 'allow all outbound activity'
set firewall name ILPR_IN rule 200 destination address !172.16.0.0/12
set firewall name ILPR_IN rule 200 source address 172.16.1.0/24
set interfaces ethernet eth5 vif 14 firewall in name ILPR_IN
This chain:
- rejects as a default action
- accepts related and established (rule 10)
- accepts all traffic not bound to
172.16.0.0/12
(rule 200)
It might be considered an overlook to not create a DIAG_IN
chain, but we’re relying on that interface in the event that things go truely wrong so convoluting it would be a mistake.
We will force both of our sub-networks to use our internal DNS via a NAT destination rewrite:
set service nat rule 7 description "captive DNS for HOME vlan"
set service nat rule 7 destination port 53
set service nat rule 7 inbound-interface eth5.7
set service nat rule 7 inside-address address 172.16.0.1
set service nat rule 7 protocol tcp_udp
set service nat rule 7 type destination
set service nat rule 14 description "captive DNS for ILPR vlan"
set service nat rule 14 destination port 53
set service nat rule 14 inbound-interface eth5.14
set service nat rule 14 inside-address address 172.16.1.1
set service nat rule 14 protocol tcp_udp
set service nat rule 14 type destination
We will also do some level of “protection” for the router on from ILPR
via the LOCAL
directive:
set firewall name ILPR_LOCAL description "rules for traffic LOCAL from VLANs"
set firewall name ILPR_LOCAL default-action drop
set firewall name ILPR_LOCAL rule 1 action accept
set firewall name ILPR_LOCAL rule 1 description "allow related and established"
set firewall name ILPR_LOCAL rule 1 log disable
set firewall name ILPR_LOCAL rule 1 protocol all
set firewall name ILPR_LOCAL rule 1 state established enable
set firewall name ILPR_LOCAL rule 1 state related enable
set firewall name ILPR_LOCAL rule 2 action accept
set firewall name ILPR_LOCAL rule 2 description "allow DNS"
set firewall name ILPR_LOCAL rule 2 log disable
set firewall name ILPR_LOCAL rule 2 protocol tcp_udp
set firewall name ILPR_LOCAL rule 2 destination port 53
set firewall name ILPR_LOCAL rule 3 action accept
set firewall name ILPR_LOCAL rule 3 description "allow DHCP"
set firewall name ILPR_LOCAL rule 3 log disable
set firewall name ILPR_LOCAL rule 3 protocol udp
set firewall name ILPR_LOCAL rule 3 destination port 67
set interfaces ethernet eth5 vif 14 firewall local name ILPR_LOCAL
Note if you’d apply this ILPR_LOCAL
policy to your HOME
you’d no longer be able to use ssh
with the router. You’d need to create a separate HOME_LOCAL
type chain for HOME
if you wanted to get really restrictive, in this case I’m assuming you trust those who are allowed into the HOME
sub-network. We’ve written ILPR_LOCAL
so that you can apply it to multiple networks that can be treated similarly to ILPR
.
Switching #
Remember before that we have two VLAN
s that we need switched, for HOME
and ILPR
we’ll need VLAN ID 7
and VLAN ID 14
respectively. The switches are more fickle devices initially than the routers. You will need to do a bootstrap sequence by plugging directly into the switch and using the GUI to coax it onto the management VLAN
:
- connect your machine to any port of the switch, I typically choose eth0
- assign a static address of
192.168.1.5
- navigate to
192.168.1.2
via your browser - add the
VLAN ID
to theVLAN
database that you want to use for management, in this case7
. - above the
VLAN
database you’ll see trunking, select eth9 as a trunk - navigate to system->connectivity->ipv4 and set the management
VLAN
to7
Once you click submit on that management VLAN
the device will cease to respond to you, it is no longer listening for management control via the default VLAN
, which on EdgeSwitch is 1
. You will now need to plug into the diagnostic port that we set up earlier, eth4
, from here you should get DHCP
‘ed an address in the 172.16.16.0/24 sub-network, and then log into the router GUI (as GUI is easier for examining DHCP
leases).
Once in the router, navigate to services, then select the HOME
DHCP
server and view leases. You should see a new lease from the EdgeSwitch. Now you should be able to navigate to that new address and save the configuration of the switch (as its been in unsaved mode since we made our changes). In the router you should static map the switch to an address that you’d like it to use. Some will say you should static your devices from their own configuration, but if you ever want to move devices it’s easier to do that from a central location so I personally favor using DHCP. You should then log into the gui and save the configuration so that the switch will continue to use 7
as the management vlan.
Once rebooted, it should go to the new address, then you should log in do the final preparation work to take it over via ssh
:
- create yourself a user account
- navigate to system->management->ssh and generate both ssh keys, turn off
v1
, and set the port you’d like to use
Now we can ssh into the switch, we’ll assume that its at 172.16.0.2
with port 8888
, we’ll first take back over the VLAN
database:
ssh -p 8888 172.16.0.2
en
hostname 172.16.0.2
no network ipv6 enable
vlan database
vlan 7,14
vlan name 7 "HOME"
vlan name 14 "ILPR"
show vlan
configure
no username "ubnt"
spanning-tree mst priority 0 0
interface 0/1-0/10
vlan participation auto 7
interface 3/1-3/6
vlan participation auto 7
interface 0/9
description 'trunk to router'
switchport mode trunk
switchport trunk allowed vlan 7,14
exit
exit
write memory
This is doing several key things:
- setting the hostname, and prompt, to
172.16.0.2
so that you know what device you’re in. This becomes important if you add several more switches. - setting ipv6 off, as we’re only using ipv4 in this design
- setting up
7,14
in your vlan database and giving them descriptive names - disabling the default
ubnt
account - setting this switch as the stp root bridge. This becomes important if you add several more switches.
- cleaning up the
vlan
notation that the gui set when we added vlan7
in the initial bootstrapping (for both interfaces and link aggregate channels). - setting the one arm link to the router as a trunk and only allowing vlan
7,14
to pass on the trunk.
We’ll now set up the HOME
ports as well as our wireless port:
exit
interface 0/10
shutdown
exit
interface 0/8
description 'wireless'
switchport mode trunk
switchport trunk native vlan 7
switchport trunk allowed vlan 7,14
exit
interface 0/1-0/7
description 'participating in HOME'
switchport mode access
switchport access vlan 7
spanning-tree edgeport
spanning-tree bpdufilter
port-security
port-security max-dynamic 1
exit
exit
write memory
This does the following:
- shuts off port
0/9
, which you’re not currently using - sets up the wireless interface as a trunk, sets the native vlan (which is important for your access point to be managed on your
HOME
network) - sets the
switchport mode
toaccess
and theaccess vlan
toHOME
on interfaces0/1-0/7
- sets up spanning tree protections on those access ports, more discussion here and here
- sets up port security for only a single MAC on each port
At this time you should be able to plug into port 0/1
through 0/7
and pull an address in the 172.16.0.0/24
sub-network.
Wireless #
With wireless I’ll assume you can run the software from your management machine, an alternative is to purchase a Unifi Cloud Key or run the Unifi software on your Odroid.
If you run the interface from a machine in the HOME
sub-network you will see your wireless access point listed under devices. You can then select to provision the device.
All of the necessary settings, for now, are located in the Settings->Wireless Networks section of the interface. You’ll want to create a HOME
and GUEST
network, using whatever names you like. Just make sure that you set the VLAN ID
properly in the advanced settings.
You should now connect to each wireless network and observe that you get DHCP
‘ed into the proper sub-network. When you are in the GUEST
sub-network you should try to see if you can navigate to something in the HOME
sub-network to verify that your router is preventing inter-vlan routing as we designed it.
Jump Host #
We have an odroidc2 running archlinuxarm at 172.16.0.8. We need to modify the router to forward the port to this host:
ssh -p 8888 172.16.0.1
configure
set port-forward auto-firewall enable
set port-forward harpin-nat enable
set port-forward lan-interface eth5.7
set port forward rule 1 description 'arbiter'
set port-forward rule 1 forward-to address 172.16.0.8
set port-forward rule 1 forward-to port 8888
set port-forward rule 1 original-port 8888
set port-forward rule 1 protocol tcp
set port-forward wan-interface eth0
commit;save;
Ideally you would never punch a hole in your firewall without having a known source. If you had a server set up in the cloud with a static address you could chain Jump Hosts and set a limitation of source on your port forward.
Now you should be able to utilize this host as a Jump Host, which I write about here. You can do a simple VPN over ssh
with sshuttle.