Initial import of Hugo site to Forgejo
This commit is contained in:
commit
cb1ba0317f
1259 changed files with 236349 additions and 0 deletions
685
static/sources/posts/house_upgrade.md
Normal file
685
static/sources/posts/house_upgrade.md
Normal file
|
|
@ -0,0 +1,685 @@
|
|||
---
|
||||
title: "I Beat My 8-Device Wi-Fi Limit with a Raspberry Pi (and Made an IoT Village)"
|
||||
date: 2025-11-23
|
||||
draft: false
|
||||
tags: ["raspberry pi", "wifi", "iot", "networking", "hostapd", "dnsmasq"]
|
||||
description: "Real-world guide: hardware choices, reasons, setup details, performance, and how many devices you can realistically support."
|
||||
author: "Iman Alipour"
|
||||
ShowToc: true
|
||||
TocOpen: true
|
||||
---
|
||||
|
||||
## The Day My Wi-Fi Said “Eight Is Enough”
|
||||
|
||||
My apartment Wi-Fi (ASK4) has a hard cap of **8 devices**. That’s adorable until you own a phone, a laptop, a tablet, a TV, a smart speaker, and even a couple of smart plugs. My solution: put **all the IoT stuff behind a Raspberry Pi** that shows up as **one** device to the building’s network, but acts like a full-blown Wi-Fi for everything else I own.
|
||||
|
||||
This post is everything I did—no corporate firewall access, no exotic gear—just a Pi, a USB Wi-Fi adapter, and a little patience.
|
||||
|
||||
---
|
||||
|
||||
## Hardware: what I picked and why
|
||||
|
||||
- **Raspberry Pi 4 (4GB)**
|
||||
It has enough CPU to route/NAT comfortably, USB 3 for fast Wi-Fi dongles, and solid Linux support. A Pi 3 works in a pinch, but the 4 stays cooler and handles bursts better.
|
||||
|
||||
- **ALFA AWUS036ACHM (USB Wi-Fi)**
|
||||
Reliable, **AP-mode** friendly on Linux, and happy with `hostapd`. I used it to **broadcast** my IoT network (2.4 GHz, 20 MHz channel) while the Pi’s built-in Wi-Fi connects upstream. For better range, use a short **USB 3 extension** so the antenna sits away from the Pi (USB 3 noise can hurt 2.4 GHz).
|
||||
|
||||
- **Fast USB-C power supply** (official Pi 4 or 5V/3A equivalent)
|
||||
Wi-Fi spikes current draw; brown-outs cause random gremlins.
|
||||
|
||||
- **16–32 GB microSD**, **heatsinks**, **ventilated case**
|
||||
The Pi 4 appreciates a bit of airflow.
|
||||
|
||||
- **(Optional) Ethernet cable**
|
||||
If you can wire the Pi to the wall/router for upstream instead of using onboard Wi-Fi, do it. Wired upstream = higher, steadier throughput and frees the onboard radio.
|
||||
|
||||
---
|
||||
|
||||
## What this setup actually does
|
||||
|
||||
- The Pi connects to the building’s **ASK4 Wi-Fi** as a **client** (`wlan0`).
|
||||
- The ALFA dongle creates a new access point called **`IoT_hub`** (`wlx…` interface) with password `Iman8118`.
|
||||
- Devices join `IoT_hub`. The Pi does **NAT**, so upstream sees **one MAC address** (the Pi), not dozens of gadgets. Device limit: defeated.
|
||||
- **Avahi mDNS reflector** lets services like **AirPlay/HomeKit** be discoverable across the two subnets without touching the managed router.
|
||||
- If I’m on the building Wi-Fi and want to control IoT gear without switching, I can also use an optional overlay (e.g., **Tailscale**) to reach `192.168.50.0/24` from anywhere.
|
||||
|
||||
---
|
||||
|
||||
## Setup details (the friendly version)
|
||||
|
||||
### 1) Access point with hostapd
|
||||
I broadcast a simple WPA2 network on **2.4 GHz** (best compatibility). Channel **1/6/11**—pick the cleanest. 20 MHz channel width keeps legacy and low-power devices happy.
|
||||
|
||||
```ini
|
||||
interface=wlx00c0cab7ab29
|
||||
ssid=<A_NICE_SSID>
|
||||
country_code=DE
|
||||
hw_mode=g
|
||||
channel=6
|
||||
ieee80211n=1
|
||||
wmm_enabled=1
|
||||
# Don't require HT or you'll reject some tiny IoT clients:
|
||||
require_ht=0
|
||||
wpa=2
|
||||
wpa_key_mgmt=WPA-PSK
|
||||
rsn_pairwise=CCMP
|
||||
wpa_passphrase=<STRONG_PASSWORD>
|
||||
```
|
||||
|
||||
### 2) DHCP on the IoT side (dnsmasq)
|
||||
Give out addresses on 192.168.50.0/24 and let systemd-resolved handle DNS to the internet.
|
||||
|
||||
```bash
|
||||
interface=wlx00c0cab7ab29
|
||||
bind-interfaces
|
||||
dhcp-range=192.168.50.100,192.168.50.240,255.255.255.0,12h
|
||||
dhcp-option=3,192.168.50.1
|
||||
dhcp-option=6,1.1.1.1,8.8.8.8
|
||||
port=0 # leave port 53 to systemd-resolved
|
||||
log-dhcp
|
||||
```
|
||||
|
||||
### 3) Routing + NAT (nftables)
|
||||
This makes every downstream device appear as the Pi upstream:
|
||||
|
||||
```bash
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority filter; policy accept;
|
||||
ct state established,related accept
|
||||
iif "lo" accept
|
||||
iif "wlan0" accept
|
||||
iif "wlx00c0cab7ab29" accept
|
||||
udp dport 5353 accept # mDNS
|
||||
counter drop
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy accept;
|
||||
ct state established,related accept
|
||||
iif "wlx00c0cab7ab29" oif "wlan0" accept
|
||||
iif "wlan0" oif "wlx00c0cab7ab29" accept
|
||||
}
|
||||
chain output { type filter hook output priority filter; policy accept; }
|
||||
}
|
||||
table ip nat {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority srcnat; policy accept;
|
||||
oif "wlan0" masquerade
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4) mDNS across subnets (Avahi)
|
||||
The reflector bridges Bonjour so AirPlay/HomeKit can find each other across IoT and ASK4:
|
||||
|
||||
```bash
|
||||
[server]
|
||||
allow-interfaces=wlan0,wlx00c0cab7ab29
|
||||
[reflector]
|
||||
enable-reflector=yes
|
||||
```
|
||||
|
||||
I wanted to be able to control my homepod without switching networks, but without setting a custom route on ASK4 WiFi it was not possible, hence the reason I chose Tailscale
|
||||
|
||||
Iet up Tailscale, advertise 192.168.50.0/24 from the Pi. Now I can log in with a passkey from my devices and control my homepod without switching networks, well, kinda. Boom! Secure access to IoT without leaving ASK4.
|
||||
|
||||
Now some random questions that I looked up in internet:
|
||||
|
||||
1. How many devices can this really support?
|
||||
|
||||
Short answer: a lot—for IoT.
|
||||
Long answer: the DHCP pool here has 141 IPs (.100 to .240). Wi-Fi airtime is the real limit, not IPs. With a 2.4 GHz AP and mostly low-bandwidth gadgets (sensors, plugs, bulbs, ESPs), 50–70 devices is completely reasonable. The ALFA’s radio and hostapd handle concurrent associations fine; I’ve watched dozens attach, chatter, and renew leases without drama.
|
||||
|
||||
If you plan camera-heavy traffic or bulk transfers, either split heavy gear onto 5 GHz or wire those devices. For small, chatty IoT traffic, this Pi/AP combo is very comfortable.
|
||||
|
||||
2. What speeds should I expect?
|
||||
|
||||
- LAN (IoT device ↔ Pi) on 2.4 GHz, 20 MHz channel, WPA2:
|
||||
~20–60 Mbps real throughput per device is typical. IoT stuff barely needs 1 Mbps, so I'm golden! ^^
|
||||
|
||||
- Internet (IoT device → upstream via Pi):
|
||||
If the Pi’s upstream is Wi-Fi, which in my case is, the bottleneck is that link; expect ~30–70 Mbps stable. If upstream is Ethernet, the Pi 4 can NAT hundreds of Mbps, and my AP radio becomes the limit.
|
||||
|
||||
- Latency: Adding one NAT hop adds a little delay (a few ms). For HomePod/AirPlay, mDNS reflection + local Wi-Fi keeps it snappy.
|
||||
|
||||
3. Why these choices?
|
||||
- 2.4 GHz is where tiny IoT radios live (bulbs, plugs, ESP/ESP32). It trades speed for range and compatibility.
|
||||
|
||||
- WPA2-PSK keeps things simple; WPA3 is fine if all your clients support it.
|
||||
|
||||
- 20 MHz channel prevents older or power-saving devices from flaking out.
|
||||
|
||||
- Avahi reflector avoids any changes to the building’s router and still lets discovery work.
|
||||
|
||||
- NAT collapses dozens of gadgets into a single upstream “seat,” sidestepping the 8-device limit entirely.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- `hostapd` **masked/disabled** →
|
||||
```bash
|
||||
sudo systemctl unmask hostapd && sudo systemctl enable --now hostapd
|
||||
```
|
||||
|
||||
- `dnsmasq` can’t start because of **port 53** →
|
||||
set `port=0` in `/etc/dnsmasq.d/*.conf` and let systemd-resolved keep DNS.
|
||||
|
||||
- **“Station does not support mandatory HT PHY”** in `hostapd` logs →
|
||||
add `require_ht=0` (and keep `ieee80211n=1`) in your `hostapd.conf`.
|
||||
|
||||
- AirPlay/HomeKit don’t show up across subnets →
|
||||
ensure Avahi reflector is enabled and UDP/5353 (mDNS) is allowed:
|
||||
- `/etc/avahi/avahi-daemon.conf` has:
|
||||
```bash
|
||||
[server]
|
||||
allow-interfaces=wlan0,wlx00c0cab7ab29
|
||||
[reflector]
|
||||
enable-reflector=yes
|
||||
```
|
||||
- firewall allows:
|
||||
```bash
|
||||
udp dport 5353 accept
|
||||
```
|
||||
|
||||
- Weak signal / flaky joins →
|
||||
use a short **USB 3 extension** to move the ALFA away from the Pi and cables;
|
||||
scan and switch to a cleaner **2.4 GHz** channel (1/6/11), keep width at **20 MHz**.
|
||||
|
||||
- Clients connect but no internet →
|
||||
verify IP forward & NAT:
|
||||
```bash
|
||||
sudo sysctl net.ipv4.ip_forward
|
||||
```
|
||||
|
||||
If it's 0, enable it permanently and reload
|
||||
```bash
|
||||
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-iot.conf
|
||||
sudo sysctl --system
|
||||
```
|
||||
|
||||
Verify the nftables NAT rule exists (masquerade out via wlan0)
|
||||
```bash
|
||||
sudo nft list ruleset | sed -n '/table ip nat/,$p' | sed -n '1,80p'
|
||||
```
|
||||
|
||||
Add it if missing
|
||||
```bash
|
||||
sudo nft add table ip nat
|
||||
sudo nft 'add chain ip nat postrouting { type nat hook postrouting priority srcnat; policy accept; }'
|
||||
sudo nft 'add rule ip nat postrouting oif "wlan0" masquerade'
|
||||
```
|
||||
|
||||
Persist nftables (Ubuntu)
|
||||
```bash
|
||||
sudo sh -c 'nft list ruleset > /etc/nftables.conf'
|
||||
sudo systemctl enable --now nftables
|
||||
```
|
||||
|
||||
|
||||
## Quick service sanity checks
|
||||
|
||||
### hostapd (AP)
|
||||
```bash
|
||||
sudo systemctl status hostapd --no-pager
|
||||
sudo journalctl -u hostapd -n 60 --no-pager
|
||||
iw dev wlx00c0cab7ab29 info
|
||||
iw dev wlx00c0cab7ab29 station dump
|
||||
```
|
||||
|
||||
### dnsmasq (DHCP on IoT side)
|
||||
```bash
|
||||
sudo systemctl status dnsmasq --no-pager
|
||||
sudo journalctl -u dnsmasq -n 80 --no-pager
|
||||
grep -E 'interface=|dhcp-range' /etc/dnsmasq.d/*.conf || true
|
||||
tail -n 50 /var/lib/misc/dnsmasq.leases
|
||||
```
|
||||
|
||||
### Avahi (mDNS reflector)
|
||||
```bash
|
||||
grep -E 'enable-reflector|allow-interfaces' /etc/avahi/avahi-daemon.conf
|
||||
sudo systemctl status avahi-daemon --no-pager
|
||||
sudo journalctl -u avahi-daemon -n 60 --no-pager
|
||||
```
|
||||
|
||||
|
||||
## Basic connectivity tests from a client on IoT_hub
|
||||
|
||||
### got DHCP?
|
||||
```bash
|
||||
ip addr show
|
||||
ip route
|
||||
cat /etc/resolv.conf
|
||||
```
|
||||
|
||||
### can you reach the Pi and the internet?
|
||||
```bash
|
||||
ping -c 3 192.168.50.1
|
||||
ping -c 3 1.1.1.1
|
||||
ping -c 3 google.com
|
||||
```
|
||||
|
||||
### DNS works end-to-end?
|
||||
```bash
|
||||
|
||||
dig +short _airplay._tcp.local @224.0.0.251 -p 5353
|
||||
```
|
||||
(Or use a Bonjour browser app to confirm the HomePod is discoverable.)
|
||||
|
||||
|
||||
## If AirPlay/HomeKit discovery is flaky across subnets
|
||||
|
||||
### make sure mDNS is allowed both directions on the Pi
|
||||
```bash
|
||||
|
||||
sudo nft add rule inet filter input udp dport 5353 accept
|
||||
sudo nft add rule inet filter forward udp dport 5353 accept
|
||||
sudo sh -c 'nft list ruleset > /etc/nftables.conf'
|
||||
```
|
||||
|
||||
### restart Avahi cleanly and re-announce
|
||||
```bash
|
||||
sudo systemctl restart avahi-daemon
|
||||
sudo journalctl -u avahi-daemon -n 40 --no-pager
|
||||
```
|
||||
|
||||
### from the Pi, watch mDNS traffic on both sides (you should see queries/answers)
|
||||
```bash
|
||||
sudo tcpdump -ni wlx00c0cab7ab29 udp port 5353 -vvv
|
||||
```
|
||||
|
||||
(in another terminal:)
|
||||
```bash
|
||||
sudo tcpdump -ni wlan0 udp port 5353 -vvv
|
||||
```
|
||||
|
||||
|
||||
## Throughput + airtime sanity (optional)
|
||||
|
||||
### simple iperf3 (install on Pi and a client)
|
||||
```bash
|
||||
sudo apt-get update && sudo apt-get install -y iperf3
|
||||
```
|
||||
(on the Pi:) `iperf3 -s`
|
||||
(on a client:) `iperf3 -c 192.168.50.1 -P 3 -t 10`
|
||||
|
||||
### check channel utilization/interference (from Pi)
|
||||
```bash
|
||||
sudo iw dev wlx00c0cab7ab29 survey dump | sed -n '1,200p'
|
||||
```
|
||||
(if busy, try channel 1 or 11 in hostapd.conf and restart hostapd)
|
||||
|
||||
|
||||
## Scaling tips (lots of tiny IoT devices)
|
||||
|
||||
### hostapd tweaks (add to hostapd.conf, then restart)
|
||||
(reduce management overhead slightly; keep conservative for compatibility)
|
||||
```bash
|
||||
beacon_int=100
|
||||
dtim_period=2
|
||||
wmm_enabled=1
|
||||
ap_isolate=0
|
||||
max_num_sta=256 # logical cap; real limit is airtime/driver
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl restart hostapd
|
||||
```
|
||||
|
||||
### if some ESP/low-power clients are sticky or nap too hard:
|
||||
(device-side) disable aggressive power saving if supported
|
||||
(AP-side) keep channel width at 20 MHz and `require_ht=0` for legacy clients
|
||||
|
||||
|
||||
## “Clients connect but no internet” quick checklist
|
||||
|
||||
### Pi has a default route via upstream?
|
||||
```bash
|
||||
ip route | grep default
|
||||
```
|
||||
|
||||
### NAT counters are increasing when clients surf?
|
||||
```bash
|
||||
sudo nft list chain ip nat postrouting -a
|
||||
```
|
||||
|
||||
### connections tracked?
|
||||
```bash
|
||||
sudo conntrack -L -o extended | head -n 40
|
||||
```
|
||||
|
||||
### last resort: bounce the pieces
|
||||
```bash
|
||||
sudo systemctl restart hostapd dnsmasq avahi-daemon
|
||||
sudo systemctl restart NetworkManager || true
|
||||
sudo systemctl restart nftables
|
||||
```
|
||||
|
||||
## Network Traffic (embedded from captures)
|
||||
|
||||
For fun, and curiousity!
|
||||
|
||||
### 1) DHCP leases (who joined the IoT network)
|
||||
```bash
|
||||
1763936213 6a:12:f6:62:40:88 192.168.50.216 * 01:6a:12:f6:62:40:88
|
||||
1763935691 72:00:a6:33:e5:7a 192.168.50.222 * 01:72:00:a6:33:e5:7a
|
||||
1763935629 e8:06:90:69:66:7c 192.168.50.189 Aidot 01:e8:06:90:69:66:7c
|
||||
1763936452 ac:bc:b5:e5:38:29 192.168.50.202 Main-Bedroom-2 01:ac:bc:b5:e5:38:29
|
||||
1763935618 e8:06:90:68:06:2c 192.168.50.196 * 01:e8:06:90:68:06:2c
|
||||
1763935618 48:e1:e9:bc:f6:91 192.168.50.131 * *
|
||||
1763935618 48:e1:e9:bd:08:0d 192.168.50.118 * *
|
||||
1763935615 48:e1:e9:bd:0b:a7 192.168.50.233 * *
|
||||
1763935618 7c:f1:7e:ff:e1:b0 192.168.50.104 KH100 *
|
||||
1763935607 cc:b5:d1:31:a4:cc 192.168.50.134 espressif 01:cc:b5:d1:31:a4:cc
|
||||
```
|
||||
|
||||
### 2) Top talkers by bytes (hosts table)
|
||||
```bash
|
||||
192.168.50.233,7346
|
||||
192.168.50.118,7216
|
||||
192.168.50.131,7216
|
||||
17.253.53.203,7040
|
||||
54.217.122.41,6271
|
||||
192.168.50.216,5392
|
||||
192.168.50.104,3058
|
||||
192.168.50.189,2278
|
||||
17.242.218.132,1802
|
||||
192.168.50.134,1750
|
||||
192.168.50.196,1653
|
||||
3.122.71.119,639
|
||||
18.196.19.65,570
|
||||
161.117.178.131,391
|
||||
17.253.53.201,148
|
||||
17.57.146.25,90
|
||||
10.172.72.196,66
|
||||
224.0.0.251,0
|
||||
224.0.0.2,0
|
||||
255.255.255.255,0
|
||||
```
|
||||
|
||||
### 3) Heaviest flows (src, dst, proto, dport, bytes)
|
||||
```bash
|
||||
192.168.50.202,192.168.50.131,TCP,59903,402
|
||||
192.168.50.202,192.168.50.118,TCP,59807,402
|
||||
161.117.178.131,192.168.50.134,TCP,58246,391
|
||||
192.168.50.216,192.168.50.202,UDP,5353,336
|
||||
192.168.50.202,192.168.50.189,UDP,5353,312
|
||||
192.168.50.202,192.168.50.196,UDP,5353,234
|
||||
17.253.53.203,192.168.50.202,TCP,64726,222
|
||||
192.168.50.216,17.57.146.25,TCP,5223,172
|
||||
192.168.50.216,192.168.50.233,UDP,5353,162
|
||||
192.168.50.202,192.168.50.104,UDP,5353,156
|
||||
17.253.53.201,192.168.50.202,TCP,64727,148
|
||||
192.168.50.202,17.253.53.201,TCP,443,132
|
||||
192.168.50.216,224.0.0.251,IP,0,92
|
||||
192.168.50.216,224.0.0.2,IP,0,92
|
||||
17.57.146.25,192.168.50.216,TCP,64544,90
|
||||
192.168.50.216,192.168.50.118,UDP,5353,75
|
||||
192.168.50.216,192.168.50.131,UDP,5353,75
|
||||
192.168.50.216,192.168.50.134,UDP,5353,75
|
||||
192.168.50.216,10.172.72.196,TCP,59593,70
|
||||
10.172.72.196,192.168.50.216,TCP,51638,66
|
||||
```
|
||||
|
||||
### 4) Conntrack snapshot (active connections inventory)
|
||||
```bash
|
||||
ipv4 2 tcp 6 48 TIME_WAIT src=10.172.71.98 dst=185.125.190.39 sport=55012 dport=80 src=185.125.190.39 dst=10.172.71.98 sport=80 dport=55012 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 100 src=10.172.71.98 dst=185.40.234.113 sport=41641 dport=3478 src=185.40.234.113 dst=10.172.71.98 sport=3478 dport=41641 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431665 ESTABLISHED src=192.168.50.216 dst=17.57.146.25 sport=64544 dport=5223 src=17.57.146.25 dst=10.172.71.98 sport=5223 dport=64544 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 27 src=10.172.72.205 dst=224.0.0.251 sport=5353 dport=5353 [UNREPLIED] src=224.0.0.251 dst=10.172.72.205 sport=5353 dport=5353 mark=0 use=1
|
||||
ipv4 2 udp 17 17 src=10.172.72.196 dst=10.172.79.255 sport=137 dport=137 [UNREPLIED] src=10.172.79.255 dst=10.172.72.196 sport=137 dport=137 mark=0 use=1
|
||||
ipv4 2 tcp 6 431999 ESTABLISHED src=192.168.50.196 dst=18.196.19.65 sport=55164 dport=8883 src=18.196.19.65 dst=10.172.71.98 sport=8883 dport=55164 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 16 src=127.0.0.1 dst=127.0.0.53 sport=41796 dport=53 src=127.0.0.53 dst=127.0.0.1 sport=53 dport=41796 mark=0 use=1
|
||||
ipv4 2 unknown 2 265 src=192.168.50.216 dst=224.0.0.251 [UNREPLIED] src=224.0.0.251 dst=192.168.50.216 mark=0 use=1
|
||||
ipv4 2 udp 17 5 src=192.168.50.104 dst=1.1.1.1 sport=23791 dport=53 src=1.1.1.1 dst=10.172.71.98 sport=53 dport=23791 mark=0 use=1
|
||||
ipv4 2 udp 17 119 src=10.172.72.205 dst=10.172.71.98 sport=41641 dport=41641 src=10.172.71.98 dst=10.172.72.205 sport=41641 dport=41641 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 27 src=10.172.71.98 dst=224.0.0.251 sport=5353 dport=5353 [UNREPLIED] src=224.0.0.251 dst=10.172.71.98 sport=5353 dport=5353 mark=0 use=1
|
||||
ipv4 2 tcp 6 431946 ESTABLISHED src=192.168.50.202 dst=17.242.218.132 sport=64686 dport=5223 src=17.242.218.132 dst=10.172.71.98 sport=5223 dport=64686 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 10 src=10.172.71.98 dst=239.255.255.250 sport=40234 dport=1900 [UNREPLIED] src=239.255.255.250 dst=10.172.71.98 sport=1900 dport=40234 mark=0 use=1
|
||||
ipv4 2 tcp 6 96 TIME_WAIT src=192.168.50.104 dst=3.217.113.91 sport=49707 dport=443 src=3.217.113.91 dst=10.172.71.98 sport=443 dport=49707 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 10 src=10.172.71.98 dst=10.172.64.1 sport=40234 dport=1900 [UNREPLIED] src=10.172.64.1 dst=10.172.71.98 sport=1900 dport=40234 mark=0 use=1
|
||||
ipv4 2 tcp 6 431812 ESTABLISHED src=100.69.238.103 dst=192.168.50.202 sport=55514 dport=49395 src=192.168.50.202 dst=192.168.50.1 sport=49395 dport=55514 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431666 ESTABLISHED src=192.168.50.216 dst=10.172.72.196 sport=51638 dport=59593 src=10.172.72.196 dst=10.172.71.98 sport=59593 dport=51638 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431998 ESTABLISHED src=100.69.238.103 dst=192.168.50.202 sport=55510 dport=7000 src=192.168.50.202 dst=192.168.50.1 sport=7000 dport=55510 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 14 src=192.168.50.131 dst=224.0.0.251 sport=5353 dport=5353 [UNREPLIED] src=224.0.0.251 dst=192.168.50.131 sport=5353 dport=5353 mark=0 use=1
|
||||
ipv4 2 unknown 2 596 src=10.172.72.205 dst=224.0.0.251 [UNREPLIED] src=224.0.0.251 dst=10.172.72.205 mark=0 use=1
|
||||
ipv4 2 udp 17 27 src=192.168.50.1 dst=224.0.0.251 sport=5353 dport=5353 [UNREPLIED] src=224.0.0.251 dst=192.168.50.1 sport=5353 dport=5353 mark=0 use=8
|
||||
ipv4 2 udp 17 27 src=10.172.72.205 dst=10.172.71.98 sport=5353 dport=5353 [UNREPLIED] src=10.172.71.98 dst=10.172.72.205 sport=5353 dport=5353 mark=0 use=1
|
||||
ipv4 2 udp 17 15 src=192.168.50.118 dst=224.0.0.251 sport=5353 dport=5353 [UNREPLIED] src=224.0.0.251 dst=192.168.50.118 sport=5353 dport=5353 mark=0 use=1
|
||||
ipv4 2 udp 17 88 src=10.172.71.98 dst=109.43.114.250 sport=41641 dport=41641 src=109.43.114.250 dst=10.172.71.98 sport=41641 dport=41641 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431997 ESTABLISHED src=192.168.50.104 dst=18.234.9.109 sport=49700 dport=443 src=18.234.9.109 dst=10.172.71.98 sport=443 dport=49700 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431998 ESTABLISHED src=10.172.71.98 dst=199.165.136.101 sport=45248 dport=443 src=199.165.136.101 dst=10.172.71.98 sport=443 dport=45248 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431992 ESTABLISHED src=10.172.72.196 dst=10.172.71.98 sport=63953 dport=22 src=10.172.71.98 dst=10.172.72.196 sport=22 dport=63953 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431995 ESTABLISHED src=192.168.50.189 dst=3.122.71.119 sport=50422 dport=8883 src=3.122.71.119 dst=10.172.71.98 sport=8883 dport=50422 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 100 src=10.172.71.98 dst=176.58.90.104 sport=41641 dport=3478 src=176.58.90.104 dst=10.172.71.98 sport=3478 dport=41641 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 107 TIME_WAIT src=10.172.71.98 dst=185.125.190.36 sport=50914 dport=80 src=185.125.190.36 dst=10.172.71.98 sport=80 dport=50914 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 26 src=192.168.50.202 dst=192.168.50.1 sport=5353 dport=5353 [UNREPLIED] src=192.168.50.1 dst=192.168.50.202 sport=5353 dport=5353 mark=0 use=1
|
||||
ipv4 2 udp 17 16 src=127.0.0.1 dst=127.0.0.53 sport=33321 dport=53 src=127.0.0.53 dst=127.0.0.1 sport=53 dport=33321 mark=0 use=1
|
||||
ipv4 2 tcp 6 431975 ESTABLISHED src=192.168.50.134 dst=161.117.178.131 sport=58246 dport=11883 src=161.117.178.131 dst=10.172.71.98 sport=11883 dport=58246 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 16 src=10.172.71.98 dst=10.172.64.1 sport=35510 dport=53 src=10.172.64.1 dst=10.172.71.98 sport=53 dport=35510 mark=0 use=1
|
||||
ipv4 2 udp 17 100 src=10.172.71.98 dst=176.58.93.154 sport=41641 dport=3478 src=176.58.93.154 dst=10.172.71.98 sport=3478 dport=41641 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431652 ESTABLISHED src=100.69.238.103 dst=192.168.50.202 sport=55513 dport=49394 src=192.168.50.202 dst=192.168.50.1 sport=49394 dport=55513 [ASSURED] mark=0 use=1
|
||||
ipv4 2 udp 17 23 src=192.168.50.104 dst=255.255.255.255 sport=21112 dport=20002 [UNREPLIED] src=255.255.255.255 dst=192.168.50.104 sport=20002 dport=21112 mark=0 use=1
|
||||
ipv4 2 udp 17 10 src=10.172.71.98 dst=10.172.64.1 sport=40234 dport=5351 [UNREPLIED] src=10.172.64.1 dst=10.172.71.98 sport=5351 dport=40234 mark=0 use=1
|
||||
ipv4 2 udp 17 10 src=10.172.71.98 dst=10.172.64.1 sport=34331 dport=5351 [UNREPLIED] src=10.172.64.1 dst=10.172.71.98 sport=5351 dport=34331 mark=0 use=1
|
||||
ipv4 2 tcp 6 431975 ESTABLISHED src=10.172.71.98 dst=192.200.0.115 sport=48100 dport=443 src=192.200.0.115 dst=10.172.71.98 sport=443 dport=48100 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431999 ESTABLISHED src=10.172.71.98 dst=176.58.93.154 sport=58128 dport=443 src=176.58.93.154 dst=10.172.71.98 sport=443 dport=58128 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 431997 ESTABLISHED src=100.69.238.103 dst=192.168.50.202 sport=55515 dport=49154 src=192.168.50.202 dst=192.168.50.1 sport=49154 dport=55515 [ASSURED] mark=0 use=1
|
||||
ipv4 2 tcp 6 118 TIME_WAIT src=192.168.50.104 dst=3.217.113.91 sport=49708 dport=443 src=3.217.113.91 dst=10.172.71.98 sport=443 dport=49708 [ASSURED] mark=0 use=1
|
||||
```
|
||||
|
||||
### 5) Part of Raw packet capture
|
||||
|
||||
- What’s inside?
|
||||
```bash
|
||||
tshark -r iot_ap_120s.pcap -q -z io,stat,60
|
||||
|
||||
|
||||
==================================
|
||||
| IO Statistics |
|
||||
| |
|
||||
| Duration: 119.773534 secs |
|
||||
| Interval: 60 secs |
|
||||
| |
|
||||
| Col 1: Frames and bytes |
|
||||
|--------------------------------|
|
||||
| |1 |
|
||||
| Interval | Frames | Bytes |
|
||||
|--------------------------------|
|
||||
| 0 <> 60 | 400 | 60449 |
|
||||
| 60 <> Dur | 24672 | 30179911 |
|
||||
==================================
|
||||
```
|
||||
|
||||
- Protocol hierarchy (what kinds of traffic?)
|
||||
```bash
|
||||
❯ tshark -r iot_ap_120s.pcap -q -z io,phs
|
||||
|
||||
===================================================================
|
||||
Protocol Hierarchy Statistics
|
||||
Filter:
|
||||
|
||||
eth frames:25072 bytes:30240360
|
||||
ip frames:24706 bytes:30195993
|
||||
udp frames:349 bytes:94583
|
||||
mdns frames:241 bytes:60693
|
||||
data frames:32 bytes:2240
|
||||
quic frames:76 bytes:31650
|
||||
quic frames:2 bytes:2484
|
||||
tcp frames:24353 bytes:30101226
|
||||
tls frames:2413 bytes:3493680
|
||||
tcp.segments frames:2256 bytes:3378795
|
||||
tls frames:2222 bytes:3353799
|
||||
data frames:147 bytes:71717
|
||||
tcp.segments frames:5 bytes:7550
|
||||
igmp frames:4 bytes:184
|
||||
arp frames:150 bytes:6300
|
||||
ipv6 frames:216 bytes:38067
|
||||
icmpv6 frames:124 bytes:10704
|
||||
udp frames:79 bytes:25415
|
||||
data frames:2 bytes:132
|
||||
mdns frames:77 bytes:25283
|
||||
tcp frames:13 bytes:1948
|
||||
data frames:1 bytes:90
|
||||
===================================================================
|
||||
```
|
||||
|
||||
- Top IP conversations (who talked to whom?)
|
||||
```bash
|
||||
❯ tshark -r iot_ap_120s.pcap -q -z conv,ip
|
||||
================================================================================
|
||||
IPv4 Conversations
|
||||
Filter:<No Filter>
|
||||
| <- | | -> | | Total | Relative | Duration |
|
||||
| Frames Bytes | | Frames Bytes | | Frames Bytes | Start | |
|
||||
192.168.50.202 <-> 17.253.37.195 19588 29 MB 3912 286 kB 23500 29 MB 72.555738000 21.8560
|
||||
192.168.50.1 <-> 192.168.50.202 239 74 kB 238 46 kB 477 120 kB 0.293866000 119.4797
|
||||
192.168.50.1 <-> 224.0.0.251 0 0 bytes 118 28 kB 118 28 kB 0.000000000 119.7310
|
||||
192.168.50.202 <-> 1.1.1.1 40 20 kB 36 10 kB 76 31 kB 72.033321000 30.3367
|
||||
192.168.50.202 <-> 2.19.120.151 47 44 kB 29 8,460 bytes 76 53 kB 72.062807000 14.8525
|
||||
192.168.50.202 <-> 17.56.138.35 27 7,602 bytes 33 13 kB 60 20 kB 72.107270000 15.0196
|
||||
192.168.50.202 <-> 17.253.53.203 17 7,040 bytes 23 9,256 bytes 40 16 kB 72.326823000 10.5130
|
||||
192.168.50.202 <-> 54.217.122.41 19 6,271 bytes 18 6,122 bytes 37 12 kB 102.352119000 0.3678
|
||||
192.168.50.202 <-> 17.253.53.202 19 22 kB 17 3,099 bytes 36 25 kB 81.940717000 0.3208
|
||||
192.168.50.202 <-> 23.58.105.122 19 9,936 bytes 16 5,759 bytes 35 15 kB 72.225431000 9.6434
|
||||
192.168.50.104 <-> 255.255.255.255 0 0 bytes 32 2,240 bytes 32 2,240 bytes 50.628126000 65.2664
|
||||
17.242.218.132 <-> 192.168.50.202 12 1,701 bytes 13 1,802 bytes 25 3,503 bytes 20.967857000 62.0463
|
||||
192.168.50.189 <-> 3.122.71.119 8 639 bytes 13 978 bytes 21 1,617 bytes 1.112174000 108.8174
|
||||
192.168.50.131 <-> 224.0.0.251 0 0 bytes 20 6,092 bytes 20 6,092 bytes 19.033978000 79.6932
|
||||
192.168.50.118 <-> 224.0.0.251 0 0 bytes 20 6,092 bytes 20 6,092 bytes 79.030835000 19.7664
|
||||
192.168.50.233 <-> 224.0.0.251 0 0 bytes 20 6,052 bytes 20 6,052 bytes 79.031250000 19.7814
|
||||
192.168.50.196 <-> 18.196.19.65 8 570 bytes 10 678 bytes 18 1,248 bytes 4.963201000 107.5242
|
||||
192.168.50.216 <-> 224.0.0.251 0 0 bytes 12 3,880 bytes 12 3,880 bytes 98.049857000 4.2949
|
||||
192.168.50.134 <-> 161.117.178.131 5 391 bytes 4 960 bytes 9 1,351 bytes 15.392290000 60.5936
|
||||
192.168.50.202 <-> 192.168.50.189 4 1,300 bytes 4 312 bytes 8 1,612 bytes 26.274469000 93.2919
|
||||
192.168.50.202 <-> 192.168.50.118 2 406 bytes 4 402 bytes 6 808 bytes 17.999757000 60.1593
|
||||
192.168.50.202 <-> 192.168.50.131 2 406 bytes 4 402 bytes 6 808 bytes 17.999812000 60.1593
|
||||
192.168.50.202 <-> 192.168.50.233 2 406 bytes 4 402 bytes 6 808 bytes 17.999825000 60.1592
|
||||
192.168.50.202 <-> 192.168.50.196 3 975 bytes 3 234 bytes 6 1,209 bytes 30.223646000 89.3442
|
||||
192.168.50.216 <-> 192.168.50.233 4 888 bytes 2 162 bytes 6 1,050 bytes 98.322145000 0.1456
|
||||
192.168.50.216 <-> 192.168.50.202 1 1,092 bytes 4 336 bytes 5 1,428 bytes 98.319211000 0.2939
|
||||
192.168.50.216 <-> 192.168.50.1 0 0 bytes 5 455 bytes 5 455 bytes 98.319329000 0.2505
|
||||
192.168.50.202 <-> 17.253.53.201 2 148 bytes 2 132 bytes 4 280 bytes 81.716483000 1.0465
|
||||
192.168.50.202 <-> 192.168.50.104 2 818 bytes 2 156 bytes 4 974 bytes 87.030561000 0.0107
|
||||
192.168.50.216 <-> 192.168.50.131 3 718 bytes 1 75 bytes 4 793 bytes 98.321918000 0.1421
|
||||
192.168.50.216 <-> 192.168.50.118 3 718 bytes 1 75 bytes 4 793 bytes 98.322266000 0.1420
|
||||
192.168.50.216 <-> 17.57.146.25 1 90 bytes 2 172 bytes 3 262 bytes 98.048979000 0.0384
|
||||
192.168.50.216 <-> 192.168.50.134 2 790 bytes 1 75 bytes 3 865 bytes 98.321779000 0.2550
|
||||
192.168.50.216 <-> 224.0.0.2 0 0 bytes 2 92 bytes 2 92 bytes 98.049757000 0.0001
|
||||
192.168.50.216 <-> 10.172.72.196 1 66 bytes 1 70 bytes 2 136 bytes 98.664295000 0.0060
|
||||
================================================================================
|
||||
```
|
||||
|
||||
- Fast “top talkers” table (by source IP)
|
||||
```bash
|
||||
❯ tshark -r iot_ap_120s.pcap -T fields -e ip.src -e frame.len \
|
||||
| awk 'NF==2{b[$1]+=$2} END{for (h in b) printf "%-16s %12d\n", h, b[h]}' \
|
||||
| sort -k2,2nr | head -n 20
|
||||
17.253.37.195 29540349
|
||||
192.168.50.202 422414
|
||||
192.168.50.1 75521
|
||||
2.19.120.151 44554
|
||||
17.253.53.202 22016
|
||||
1.1.1.1 20675
|
||||
23.58.105.122 9936
|
||||
17.56.138.35 7602
|
||||
192.168.50.233 7346
|
||||
192.168.50.118 7216
|
||||
192.168.50.131 7216
|
||||
17.253.53.203 7040
|
||||
54.217.122.41 6271
|
||||
192.168.50.216 5392
|
||||
192.168.50.104 3058
|
||||
192.168.50.189 2278
|
||||
17.242.218.132 1802
|
||||
192.168.50.134 1750
|
||||
192.168.50.196 1653
|
||||
3.122.71.119 639
|
||||
```
|
||||
|
||||
- DNS & mDNS highlights (what names show up?)
|
||||
```bash
|
||||
# DNS queries (unicast)
|
||||
❯ tshark -r iot_ap_120s.pcap -Y "dns.flags.response==0" \
|
||||
-T fields -e frame.time -e ip.src -e dns.qry.name | head -n 20
|
||||
Nov 23, 2025 11:48:38.131162000 CET 192.168.50.1 _hap._tcp.local,_rdlink._tcp.local,_companion-link._tcp.local,_hap._udp.local
|
||||
Nov 23, 2025 11:48:42.961690000 CET 192.168.50.1 _hap._tcp.local
|
||||
Nov 23, 2025 11:48:42.962245000 CET 192.168.50.1 _companion-link._tcp.local
|
||||
Nov 23, 2025 11:48:42.962911000 CET 192.168.50.1 _hap._udp.local,_rdlink._tcp.local
|
||||
Nov 23, 2025 11:48:43.098378000 CET 192.168.50.1 MSS110-f691._hap._tcp.local
|
||||
Nov 23, 2025 11:48:43.158641000 CET 192.168.50.1 Qingping Air Monitor Lite._hap._tcp.local
|
||||
Nov 23, 2025 11:48:43.201440000 CET 192.168.50.202 _companion-link._tcp.local
|
||||
Nov 23, 2025 11:48:43.532623000 CET 192.168.50.1 MSS110-080d._hap._tcp.local
|
||||
Nov 23, 2025 11:48:43.962673000 CET 192.168.50.1 _hap._tcp.local,MSS110-0ba7._hap._tcp.local,Main Bedroom (3)._companion-link._tcp.local,HomePodSensor 185277._hap._tcp.local,_rdlink._tcp.local,_companion-link._tcp.local,_hap._udp.local
|
||||
Nov 23, 2025 11:48:49.110167000 CET 192.168.50.1 _hap._tcp.local
|
||||
Nov 23, 2025 11:48:49.110760000 CET 192.168.50.1 _companion-link._tcp.local
|
||||
Nov 23, 2025 11:48:49.111395000 CET 192.168.50.1 _hap._udp.local,_rdlink._tcp.local
|
||||
Nov 23, 2025 11:48:49.272920000 CET 192.168.50.1 Qingping Air Monitor Lite._hap._tcp.local
|
||||
Nov 23, 2025 11:48:49.311002000 CET 192.168.50.1 MSS110-0ba7._hap._tcp.local
|
||||
Nov 23, 2025 11:48:49.619376000 CET 192.168.50.1 Main Bedroom (3)._companion-link._tcp.local,MSS110-f691._hap._tcp.local,MSS110-080d._hap._tcp.local,HomePodSensor 185277._hap._tcp.local
|
||||
Nov 23, 2025 11:48:50.115506000 CET 192.168.50.1 _hap._tcp.local,_rdlink._tcp.local,_companion-link._tcp.local,_hap._udp.local
|
||||
Nov 23, 2025 11:48:55.037844000 CET 192.168.50.1 _hap._tcp.local
|
||||
Nov 23, 2025 11:48:55.038380000 CET 192.168.50.1 _companion-link._tcp.local
|
||||
Nov 23, 2025 11:48:55.038926000 CET 192.168.50.1 _hap._udp.local,_rdlink._tcp.local
|
||||
Nov 23, 2025 11:48:55.060503000 CET 192.168.50.202 _companion-link._tcp.local
|
||||
|
||||
# mDNS service announcements (AirPlay/HomeKit live here)
|
||||
❯ tshark -r iot_ap_120s.pcap -Y "udp.port==5353 && dns" \
|
||||
-T fields -e frame.time -e ip.src -e dns.qry.name -e dns.ptr.domain_name \
|
||||
| head -n 30
|
||||
```
|
||||
|
||||
The latter had no output as I wasn't able to make that work with a static route and relied on Tailscale. (?)
|
||||
|
||||
- TLS SNI (which cloud endpoints?)
|
||||
```bash
|
||||
❯ tshark -r iot_ap_120s.pcap -Y "tls.handshake.extensions_server_name" \
|
||||
-T fields -e ip.dst -e tls.handshake.extensions_server_name \
|
||||
| sort | uniq -c | sort -k1,1nr | head -n 20
|
||||
1 1.1.1.1 one.one.one.one
|
||||
1 17.253.37.195 streamingaudio.itunes.apple.com
|
||||
1 17.253.53.202 pancake.apple.com
|
||||
1 17.253.53.203 radio-activity.itunes.apple.com
|
||||
1 17.56.138.35 cma.itunes.apple.com
|
||||
1 2.19.120.151 play.itunes.apple.com
|
||||
1 23.58.105.122 librarydaap.itunes.apple.com
|
||||
1 54.217.122.41 guzzoni.apple.com
|
||||
```
|
||||
|
||||
- Ports in use (quick heat check)
|
||||
```bash
|
||||
❯ tshark -r iot_ap_120s.pcap -T fields -e _ws.col.Protocol -e tcp.dstport -e udp.dstport \
|
||||
| awk '{for(i=1;i<=NF;i++) if($i~/^[0-9]+$/) p[$i]++} END{for(k in p) printf "%-8s %8d\n", k, p[k]}' \
|
||||
| sort -k2,2nr | head -n 20
|
||||
64725 19588
|
||||
443 4086
|
||||
5353 318
|
||||
49395 109
|
||||
7000 109
|
||||
55514 102
|
||||
55510 101
|
||||
64721 47
|
||||
54806 40
|
||||
20002 32
|
||||
64722 27
|
||||
8883 23
|
||||
49154 21
|
||||
55515 21
|
||||
64723 19
|
||||
64728 19
|
||||
64729 19
|
||||
5223 14
|
||||
64724 14
|
||||
64686 13
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Epilogue
|
||||
I've been having so so much trouble with setting up a iot-hub for my house where I can connect all my IoT devices to, and without putting a phone on hotspot. Now I finally did it, and I even treated myself by allowing mDNS routing! Let's cross our fingers and hope this setup finally works nicely.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
{{< sigdl >}}
|
||||
Loading…
Add table
Add a link
Reference in a new issue