diff options
author | Ethel Morgan <eth@ethulhu.co.uk> | 2020-07-06 18:23:10 +0100 |
---|---|---|
committer | Ethel Morgan <eth@ethulhu.co.uk> | 2020-07-06 18:23:10 +0100 |
commit | b1e6491f77421ae4623391a7f53af7f3e6c13f34 (patch) | |
tree | acc4ce7ae214b92dbf2c269c70e94b68dac1d640 /src/wifi.thrust | |
parent | 04be5845dbaa6f8dec45a80dbe199861608b96f2 (diff) |
import website from previous repo
Diffstat (limited to 'src/wifi.thrust')
-rw-r--r-- | src/wifi.thrust | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/src/wifi.thrust b/src/wifi.thrust new file mode 100644 index 0000000..26cbdc7 --- /dev/null +++ b/src/wifi.thrust @@ -0,0 +1,350 @@ +--- +title: home WiFi setup +configs: + router: + /etc/systemd/network/wan.network: | + [Match] + # enp1s0 is the name of my router's WAN interface. + Name=enp1s0 + + [Network] + # take a IP from my ISP's modem over DHCP. + DHCP=yes + + # use Google's public DNS servers. + DNS=8.8.8.8 + DNS=8.8.4.4 + + # prefer DNS-over-TLS if available. + DNSOverTLS=opportunistic + + # forward packets from this interface to other interfaces. + IPForward=yes + + [DHCP] + # some ISPs' DNS invent A records, so don't use them. + UseDNS=no + + /etc/systemd/network/bridge.netdev: | + [NetDev] + Name=br0 + Kind=bridge + + /etc/systemd/network/lan.network: | + [Match] + Name=enp2s0 enp3s0 + + [Network] + Bridge=br0 + + /etc/systemd/network/bridge.network: | + [Match] + Name=br0 + + [Network] + # the router's LAN IP. + Address=192.168.16.1/24 + + # run a DHCP server. + DHCPServer=yes + + # forward packets from this interface to other interfaces. + IPForward=yes + + # make forwarded packets appear to come from this device, + # a.k.a. enable NAT. + IPMasquerade=yes + + [DHCPServer] + DefaultLeaseTimeSec=600 + + # LAN DNS & Stubby DNS-over-TLS bridge. + DNS=192.168.16.1 + + # fallback DNS. + DNS=8.8.8.8 + DNS=8.8.4.4 + + bouncer: + /etc/systemd/network/bridge.netdev: | + [NetDev] + Name=br0 + Kind=bridge + + /etc/systemd/network/wired.network: | + [Match] + Name=eth0 + + [Network] + Bridge=br0 + + /etc/systemd/network/bridge.network: | + [Match] + Name=br0 + + [Network] + DHCP=yes + DNSOverTLS=opportunistic + + shared: + /etc/hostapd/hostapd.conf: | + bridge=br0 + interface=wlan0 + driver=nl80211 + ssid=something-witty + + # select a channel automatically + # using the ACS survey-based algorithm, + # instead of setting a channel manually. + channel=0 + country_code=GB + ieee80211d=1 + + # hw_mode=g for 802.11n, hw_mode=a for 802.11ac. + hw_mode=g + + # 802.11n support. + ieee80211n=1 + wmm_enabled=1 + + # WPA2 encryption settings. + # note that wpa_key_mgmt also has FT-PSK for 802.11r. + wpa=2 + wpa_passphrase=something-secret + wpa_key_mgmt=WPA-PSK FT-PSK + wpa_pairwise=TKIP + rsn_pairwise=CCMP + + # 802.11i support. + rsn_preauth=1 + rsn_preauth_interfaces=br0 + + # 802.11r support. + # mobility_domain must be shared across APs. + # nas_identifier must be different between APs. + mobility_domain=19fc + nas_identifier=8e71540f0467 + ft_psk_generate_local=1 +diagram: | + <svg xmlns='http://www.w3.org/2000/svg' + viewBox='0.00 0.00 466.59 106.00' + width='467pt' height='106pt' + style='font-family: "Times New Roman", Times, serif; font-size: 12pt; font-weight: lighter;'> + <g id='graph0' class='graph' transform='scale(1 1) rotate(0) translate(4 102)'> + <title>home network diagram</title> + <g id='home-network-diagram/internet' class='node'> + <title>internet</title> + <polygon fill='none' points='43.19,-8.05 45.61,-8.15 48.01,-8.3 50.37,-8.49 52.69,-8.74 54.96,-9.03 57.16,-9.36 59.29,-9.75 61.34,-10.18 63.31,-10.65 65.18,-11.16 66.95,-11.71 68.61,-12.31 70.17,-12.94 71.6,-13.61 72.92,-14.31 74.11,-15.04 75.18,-15.8 76.11,-16.59 76.92,-17.41 77.6,-18.25 78.15,-19.11 78.57,-19.99 78.87,-20.89 79.04,-21.8 79.08,-22.72 79.01,-23.65 78.81,-24.59 78.51,-25.53 78.1,-26.47 77.58,-27.41 76.96,-28.35 76.25,-29.28 75.46,-30.2 74.57,-31.11 73.61,-32.01 72.58,-32.89 71.47,-33.75 70.31,-34.59 69.09,-35.41 67.81,-36.2 66.49,-36.96 65.13,-37.69 63.73,-38.39 62.29,-39.06 60.83,-39.69 59.33,-40.29 57.82,-40.84 56.28,-41.35 54.73,-41.82 53.16,-42.25 51.58,-42.64 49.99,-42.97 48.4,-43.26 46.79,-43.51 45.18,-43.7 43.57,-43.85 41.95,-43.95 40.34,-44 38.72,-44 37.1,-43.95 35.48,-43.85 33.87,-43.7 32.26,-43.51 30.66,-43.26 29.06,-42.97 27.47,-42.64 25.89,-42.25 24.32,-41.82 22.77,-41.35 21.24,-40.84 19.72,-40.29 18.23,-39.69 16.76,-39.06 15.33,-38.39 13.92,-37.69 12.56,-36.96 11.24,-36.2 9.97,-35.41 8.74,-34.59 7.58,-33.75 6.48,-32.89 5.44,-32.01 4.48,-31.11 3.6,-30.2 2.8,-29.28 2.09,-28.35 1.47,-27.41 0.96,-26.47 0.54,-25.53 0.24,-24.59 0.05,-23.65 -0.03,-22.72 0.02,-21.8 0.19,-20.89 0.48,-19.99 0.9,-19.11 1.45,-18.25 2.13,-17.41 2.94,-16.59 3.88,-15.8 4.94,-15.04 6.14,-14.31 7.45,-13.61 8.89,-12.94 10.44,-12.31 12.1,-11.71 13.88,-11.16 15.75,-10.65 17.71,-10.18 19.76,-9.75 21.89,-9.36 24.1,-9.03 26.36,-8.74 28.68,-8.49 31.05,-8.3 33.44,-8.15 35.87,-8.05 38.31,-8 40.75,-8 43.19,-8.05'/> + <text text-anchor='middle' x='39.53' y='-21.8'>internet</text> + </g> + <g id='home-network-diagram/router' class='node'> + <title>router</title> + <polygon fill='none' points='170.05,-44 116.05,-44 116.05,-8 170.05,-8 170.05,-44'/> + <text text-anchor='middle' x='143.05' y='-21.8'>router</text> + </g> + <g id='edge1' class='edge'> + <title>internet -- router</title> + <path fill='none' d='M78.33,-26C90.85,-26 104.49,-26 115.93,-26'/> + </g> + <g id='node3' class='node'> + <title>kitchen</title> + <polygon fill='none' points='327.91,-78 270.49,-78 270.49,-42 327.91,-42 327.91,-78'/> + <text text-anchor='middle' x='299.2' y='-55.8'>kitchen</text> + </g> + <g id='edge2' class='edge'> + <title>router -- kitchen</title> + <path d='M170.2,-31.77C198.03,-37.91 241.9,-47.58 270.36,-53.86'/> + <text text-anchor='middle' x='220.33' y='-51.8'>powerline</text> + </g> + <g id='node4' class='node'> + <title>laptop</title> + <text text-anchor='middle' x='425.31' y='-13.8'>laptop</text> + </g> + <g id='edge3' class='edge'> + <title>router -- laptop</title> + <path fill='none' stroke-dasharray='5,2' d='M170.21,-24.18C195.79,-22.49 235.85,-20.07 270.6,-19 315.41,-17.62 367.61,-17.62 398.19,-17.78'/> + <text text-anchor='middle' x='299.2' y='-21.8'>WiFi</text> + </g> + <g id='edge4' class='edge'> + <title>kitchen -- laptop</title> + <path stroke-dasharray='5,2' d='M328.05,-50.57C349.07,-43.46 377.69,-33.78 398.25,-26.82'/> + <text text-anchor='middle' x='359.92' y='-45.8'>WiFi</text> + </g> + <g id='node5' class='node'> + <title>bulb</title> + <text text-anchor='middle' x='425.31' y='-75.8'>lightbulb</text> + </g> + <g id='edge5' class='edge'> + <title>kitchen -- bulb</title> + <path stroke-dasharray='5,2' d='M328.05,-64.49C347.06,-67.55 372.3,-71.62 392.17,-74.82'/> + <text text-anchor='middle' x='359.92' y='-73.8'>WiFi</text> + </g> + </g> + </svg> +--- +{% extends 'templates/base.html' %} +{% block body %} + <nav> + <a href='/projects'>> projects</a> + </nav> + + + <article> + <h1>{{ title }}</h1> + +{% macro file(d, path) %} +<pre><code>$ cat {{ path }} +{{ d[path] }}</code></pre> +{% endmacro %} + +{% markdown %} +<details markdown='1'> +<summary>contents…</summary> +<div markdown='block'> + +[TOC] + +</div> +</details> + +There are two Access Points (APs) in my house: one in the living room, and one in the kitchen. +They are connected via LAN-over-powerline, and have WiFi Roaming set up for a seamless connection throughout. + +{{ diagram | safe }} + +## Roaming + +WiFi Roaming allows a client device (e.g. a phone) to transparently switch from one AP to another. +Unlike "repeaters" or "boosters", which create a second WiFi network that the client needs to disconnect from and reconnect to, Roaming is _the same network_ across APs and allows for a seamless experience. + +This is implemented with two extensions of the WiFi spec, _802.11i_ and _802.11r_: + +- _802.11i_ is pre-authentication, which allows clients to start associating to a new AP while still connected to the previous one. +- _802.11r_ is Fast Transition (FT), where APs can share keys with each other. + On large networks (e.g. corporate ones) this is done properly where the APs communicate and use intermediate keys and the like, but for a home network with a Pre-Shared Key (PSK), the APs can derive all the keys themselves. + +<details markdown='1'> +<summary>How does 802.11r actually work?</summary> +<div markdown='block'> +In a given roaming connection, there are 3 keys: + +- Master Session Key (MSK). +- R0, a key derived from the MSK. +- R1, a key derived from R0. + +There are 3 players: + +- The client. +- R0KH, the R0 Key Handler, may or may not be an AP. +- R1KH, the R1 Key Handler, an AP. + +In "pull mode": + +1. The client connects to the first AP. +2. The client is given a key and an R0KH-ID (the _NAS Identifier_, named for [RADIUS'](https://en.wikipedia.org/wiki/RADIUS) [Network Access Server](https://en.wikipedia.org/wiki/Network_access_server)). +3. The client connects to the second AP. +4. The client gives R0KH-ID to the second AP. +5. The second AP, now R1KH, contacts R0KH using the ID and its own R1KH-ID. +6. R0KH sends R1KH a key R1 derived from R0 and R1KH-ID. +7. R1KH, gives the client R1. + +In "push mode": + +1. R0KH knows all its APs. +2. R0KH sends each AP a unique R1 derived from R0 and the AP's R1KH-ID. +3. the client connects normally. + +For PSK mode, the MSK is the PSK, so any AP can generate R0 and R1 for any NAS Identifier. +</div> +</details> + +## Router configuration { #router } + +My router is a [PC Engines APU 1d4](https://www.pcengines.ch/apu1d4.htm), which has: + +- 3 ethernet ports. +- 1 wifi card. + +One of the ethernet ports is for WAN, and the other two and wifi card are LAN. +The LAN interfaces are joined with a bridge, `br0`. + +### WAN { #router/wan } + +This is a fairly normal [`systemd-networkd`](https://wiki.archlinux.org/index.php/Systemd-networkd) client config, with the addition of `IPForward=yes`: + +{{ file( configs.router, '/etc/systemd/network/wan.network' ) }} + +### LAN { #router/lan } + +The LAN is controlled with `systemd-networkd` where possible, and the wifi is managed by `hostapd`. +There are three parts to the `networkd` configuration: + +- Create a bridge network device. +- Connect the LAN ethernet ports to it. +- Configure the bridge to be a DHCP server & NAT gateway. + +First, create a bridge `br0`: + +{{ file( configs.router, '/etc/systemd/network/bridge.netdev' ) }} + +Connect the LAN ethernet ports to the bridge: + +{{ file( configs.router, '/etc/systemd/network/lan.network' ) }} + +Finally, configure the local network on the bridge itself. + +- `systemd-networkd` includes a minimal DHCP server, so also enable that. +- Note the addition of both `IPForward=yes` and `IPMasquerade=yes` to set up NAT. + +{{ file( configs.router, '/etc/systemd/network/bridge.network' ) }} + +### WiFi { #router/wifi } + +Because `hostapd` has its own bridge management, it isn't included in the `systemd-networkd` configuration. + +This configuration: + +- Uses our bridge `br0`. +- Uses the standard Linux WiFi driver set (others exist for other chipsets). +- Automatically selects a channel at start. +- Enables 802.11n (`hostapd` also supports 802.11ac). +- Enables WPA2 with a Pre-Shared Key (PSK). +- Enables pre-authentication (802.11i) on our bridge `br0`. +- Enables roaming (802.11r): + - `nas_identifier` must be 6 bytes, and different between APs. I use the interface MAC. + - `mobility_domain` must be 2 bytes, and is shared between APs. + +{{ file( configs.shared, '/etc/hostapd/hostapd.conf' ) }} + +## Kitchen + +The WiFi in the kitchen is provided by a [Raspberry Pi 2B](https://www.raspberrypi.org/products/raspberry-pi-2-model-b/) and a USB WiFi adapter that supports _host mode_. +I chose this hardware because I already owned it. + +### LAN { #kitchen/lan } + +This is a simpler version of the [Router's LAN configuration](#router/lan), but with only two steps: + +- Create a bridge network device. +- Connect the LAN ethernet ports to it. + +As before, create a bridge `br0`: + +{{ file( configs.bouncer, '/etc/systemd/network/bridge.netdev' ) }} + +Connect the ethernet port to the bridge: + +{{ file( configs.bouncer, '/etc/systemd/network/wired.network' ) }} + +Configure the local network on the bridge itself. +Because this is not the primary router, it can be just another DHCP client: + +{{ file( configs.bouncer, '/etc/systemd/network/bridge.network' ) }} + + +### WiFi { #kitchen/wifi } + +This is basically the same as the [Router's WiFi configuration](#router/wifi), although remember to change the `nas_identifier`! +{% endmarkdown %} + </article> +{% endblock %} |