The Internet of Things (IoT) is very handy. I enjoy being able to adjust the lights in my living room just by talking to Siri. Or having lights turn on and off at set times of the day.
But as we all know, IoT devices don’t just talk to us. In order to work, they need to communicate with all kinds of servers. And so I wanted to know what my devices are saying, and to whom.
You would expect a lot of it to be simple telemetry that is required to enable a device’s functionality. But there’s also scope for snooping.
Luckily, we have the technology to monitor what these devices are doing. And this is the first in a sporadic series of posts into which I delve into my network traffic to see what’s going on.
The situation
Most of our home automation is controlled via Apple Home. I’ve dabbled with using a Home Assistant server, but didn’t get all that far due to device incompatibilities.
We have a number of smart bulbs/lamps, plus some smart adapter sockets and some smart switches, most of which also control lights. The devices are mainly manufactured by Meross and Lifx. We also have three iRobot devices (two Roombas and a Braava – it’s a big house, okay).
A subnet of your own
The first task was to herd all the IoT devices into a specific corner of my home network. I use the 10.0.0.0/16 network for nearly all my hosts, but I do group devices by type.
Having failed to hack into my lightbulbs to set static IP addresses (I didn’t try very hard), the obvious step was to use my main router/firewall device to dish out predictable IPs via its DHCP server. I have a Netgate device running pfSense, but you can do this on most routers (using that term loosely).
I first took a look at the status section to see which DHCP leases had been handed out. I then created static assignments for the devices, assigning addresses in the 10.0.120.0/24 subnet.
I did the same for the iRobot machines, putting them in the 10.0.125.0/24 section and, later, I added our Kindles to the 10.0.122.0/24 region.
Sniffing the net
I decided to use two approaches to monitoring traffic on the network. The first was to use a command line utility in Linux to get an idea of what kinds of packets are flowing. The second was to write a utility (in Go) that more closely focuses on the devices and packets of interest.
But you have to see the packets to do this. With modern Ethernet switches and wireless traffic, it’s no trivial matter to use one machine to sniff the packets intended for another. It’s not like the old days of dumb hubs.
Fortunately, all the traffic goes through one choke point. This is where the router connects to the main switch. Basically, everything that goes out to or in from the Internet goes through that one switch connection. And the Netgear switch I’m using is a managed device that allows port mirroring.
Port 16 on the switch is the one that connects to the router. Port 15 is configured to mirror port 16, so it sees all the same traffic. And port 15 is connected to one of my Linux servers (which has a second Ethernet port for normal network operations). That server is called Pushkin and is running Ubuntu Server.
How to snoop
So, easy. I SSH into Pushkin and run tcpdump on the Ethernet port (enp3s0) connected to switch port 15. Here’s the script I used to capture 500 packets for the IoT devices:
#!/usr/bin/env zsh CAPDIR=/mnt/nas/sync/captures TIMESTAMP=$(date +"%Y%m%d%H%M%S") FILENAME=iot-capture_${TIMESTAMP}_tcpdump.pcap echo "Capturing to ${CAPDIR}/${FILENAME}" sudo tcpdump -i enp3s0 -c 500 -w ${CAPDIR}/${FILENAME} net 10.0.120.0/24 echo "IoT capture completed" exit 0
This worked a treat to get some initial impressions, although I later refined the script, swapping out tcpdump for tshark (just because).
#!/usr/bin/env zsh DURATION=60 TIMESTAMP=$(date +"%Y%m%d%H%M%S") SAVEDIR=/mnt/nas/sync/captures NET="10.0.0.0/16" NAME="home" CAST=" and not broadcast and not multicast" usage() { echo "usage:" echo " capture [[-d duration] [-net <CIDR>] [-iot/-roomba]]" echo " -b include broadcast & multicast" echo " -d <dur> duration in secs (default 1 minute)" echo " -net <CIDR> network - eg, 10.0.30.0/24" } while [ "$1" != "" ]; do case $1 in -b ) CAST="" ;; -d | --dur ) shift DURATION="$1" ;; -iot ) NET="10.0.120.0/24" NAME="iot" ;; -mobile ) NET="10.0.122.0/24" NAME="mobile" ;; -roomba ) NET="10.0.125.0/24" NAME="roomba" ;; -net ) shift NET="net $1" NAME="net" ;; * ) usage exit 1 esac shift done echo "Capturing traffic" echo "Use 'killall tshark' to quit capturing" exec tshark -q -a duration:$DURATION -i enp3s0 -f "net ${NET}${CAST}" -F pcapng -w ${SAVEDIR}/${NAME}_${TIMESTAMP}.pcap & exit 0
By default, this snoops for 60 seconds on the 10.0.0.0/16 network and excludes broadcast and multicast packets. The -d switch is used to change the duration. The -b switch includes broadcast and multicast. And the -iot, -roomba and -mobile switches (only one at a time, please) select specific subnets. Alternatively, the -net switch can be used to specify another subnet.
Obviously, these scripts are specifically tailored to my network and situation, but they give you an idea of how I went about this.
Checking the results
Both utilities – tcpdump and tshark – save the files in pcap format (or, to be more precise, pcapng). This isn’t a plain text format. So I opened the files in Wireshark to see what I’d snarfed up in the net.
For the most part it was what you might expect. An hour-long snoop on the main IoT network (10.0.120.0/24) turned up surprisingly little.
There was almost no traffic from the Lifx products that went outside the local network.
The Meross devices were different, and a bit odd. At regular intervals, a device would send a DNS request for the domain mqtt.meross.com or mqtt-alter.meross.com. Having received a response with the appropriate IP (the domains are hosted on AWS), the device would then send a SYN packet to the server – but with no response. Further SYN retransmission packets would be sent before the device gave up. I tried pinging the domains, also with no response. So, maybe, at one time Meross was running some kind of MQTT broker on the Internet but has stopped? Why would it have done either of those things?
There were also occasional check-ins with an NTP server (an Amazon one, as it happens).

An IoT device sending a DNS query followed by a SYN packet that appears not to be acknowledged, judging by the SYN retransmissions. Click for a larger image.
Other than that, there was little to see.
The one-hour capture of the IoT network yielded just over 2,000 packets – outgoing and incoming – between 14 devices. That averages out at just under 2.5 packets per minute per device.
Chatty Roombas
The Roombas were different (I haven’t yet tried the Braava). These machines opened a connection to a remote server on port 443 and then sent regular keepalive packets – one every 45-60 seconds.
I have a theory about this. The iRobot app allows you to control your domestic robots from afar. You might be at work and suddenly get the urge to vacuum the living room. For this to work, iRobot’s servers need to be able to connect to your robot. But, typically, the Roomba is connected to your local network behind a firewall that will, by default, reject any connections initiated from the outside. So the robot opens a connection between itself and iRobot’s server and keeps it alive in case of incoming instructions.
Like I said, that’s the theory. Let me know in a comment if you have better ideas.
I’m not entirely happy about having a permanent hole opened up in my firewall. And surely this must be a considerable burden on iRboot’s servers, with all these open connections.
There were also sporadic bits of application data being sent, but these were TLS 1.2 encoded and so unreadable. There wasn’t much of it. The servers being contacted were also hosted by AWS.
The Roomba tests were carried out with the robots idle and docked. I haven’t yet tried capturing packets when they are operating. And I still need to go through the packets I have got with a more critical eye.
Busy Kindles
I then turned by attention to my Kindle (an Oasis), running a five-minute capture. During that time, I woke up the Kindle, opened a book from the library, closed it and opened another one and read a few pages. Then I let it sit, switched on but doing nothing. So not a lot of activity on my part. I didn’t use the browser or visit the store.
The capture turned up 387 packets. That’s an average of just over 77 packets per minute for one device!
I still need to delve into these some more. I can see lots of encryption-related packets. And there is regular application data being sent – but, of course, it’s encrypted, so I’ve no idea what is in those packets.
That’s pretty much as far as I’ve got. I plan to analyse the packets a bit more, and to do further captures with the devices being a tad busier.
As I mentioned, I also wrote a small Go program, based on the gopacket library, to log packets in a simpler, text-based form, but more on that in a future post.