As of today, I give away my book for free

IPv6-Workshop is the name of my book and the accompanying seminar series. It was first published in 2013 and was a category bestseller at Amazon Germany in 2014. Since June 2017, I give the ebook away for free and charge as little as Amazon allows me to for the printed version. My motivation is to help more people understand IPv6 and to speed up migration to the future Internet protocol.

Download the book for free at the IPv6-Workshop project page πŸ‡©πŸ‡ͺ.

A weird security policy!

A couple of months ago I had an interesting conversation with someone responsible for information security within a computer network related to national security of a large European state (which shall remain unnamed). When we hit the topic of link-layer security, that someone said something like: “In our networks, we enforce a VLAN (Virtual LAN) ID distance of 10 for security reasons! That is, VLAN ID 1 is reserved, the next valid VLAN ID is 11 and then 21 and so forth.”

I was about to call bullshit πŸ’© on that but then I wasn’t so sure anymore. Unfortunately, I had no chance for a follow-up discussion, leaving me thinking since then. πŸ€” Today I’d like to share my thoughts on this weird policy.

What is a VLAN ID?

To understand the implications of the distance-of-10 security policy, we have to take a look at what a VLAN ID is and where it is stored. An IEEE 802.1Q VLAN ID is a 12-bit number used to partition a physical network into logical Ethernet networks. Multiple link-layer networks can share the same physical link and bridges (switches) without (if everything works well) interfering with each other. To achieve this, there is an extra field inserted between the source MAC address and the EtherType.

Part of this so-called 802.1q header is set to a fixed value or used for prioritization and congestion control. The last 12 bit, however, are what we call the VLAN ID.

What is the security problem?

As you may have noticed, unlike in other protocols (e.g. most VPN protocols), segmentation using VLAN ID is not achieved by segmentation but by annotation. Also, there is no (additional) encryption taking place. It is, therefore, necessary to have all active link-layer equipment understand the 802.1q standard and act according to it. In practice, we want to use a managed switch to properly control were frames of a particular VLAN ID are allowed to pass the device in ingress or egress mode. Unmanaged devices (“dumb switches”) usually ignore the 802.1q header and just forward everything as if there was no 802.1q header at all. Obviously, a dumb switch imposes a thread to a network that is segmented using VLAN ID, not matter how large the distance between the individual VLAN ID is. So we can ignore this threat for the following discussion.

The actual threats to a VLAN ID segmented network are:

  • VLAN hopping due to implementation errors
  • VLAN hopping due to bit errors

VLAN hopping means, that a frame destined for a particular VLAN ends up in another VLAN because an attacker was able to confuse the switch regarding the true VLAN ID. Here is some more information on the topic. It is even funnier in virtual environments. I attended this talk at DEFCON 24 and found it somewhat related. As far as I know, there is no VLAN hopping attack that can be mitigated or made less likely by choosing a VLAN ID distance of exactly 10. So I am going to ignore the whole implementation error discussion, too. This leaves us with bit errors as a possible technical cause for VLAN hopping.

On the organizational level, there may be additional reasons for having a particular distance between two VLAN ID. We will discuss a few of them.

Fat fingers

A simple reason for a fixed VLAN ID distance may be the mitigation of consequences of typos in such a high-security environment. Let’s say we are the admin in said network and we are in a hurry to configure VLAN ID 11 on a couple of switch ports. If there would be no distance between the VLAN ID, the next valid (and probably used) VLAN ID would be 12. It is easy to slip from the 1 key to the 2 key on a standard keyboard. Thanks to the distance, frames for VLAN ID 11 ending up in the empty VLAN ID 12 are likely to cause some disruption but that is still better than leaking information.

Makes sense? I don’t think so! Let’s say we are still in a hurry (admins are always super stressed, right?) and we have to configure VLAN ID 21. Again, a slippy keyboard and our fat fingers don’t get along and we accidentally mistype the 2 for the 1. Congratulations, we may now be serving traffic for VLAN ID 21 in VLAN ID 11, which is valid and in use.

The security policy did not help us much, this can’t be the reason for its existence.


Let’s assume this wasn’t a high-security environment but a regular company headed to stellar growth over the next couple of years. As the company grows, so does its IT infrastructure. Maybe said company wants to add a second production line using the same IP addressing scheme as with the first one. Link-layer segmentation comes in handy here. Avoiding duplicate address confusions by separating the production line robots while still allowing them to use the same physical network. I saw a similar setup in the automotive industry once and it made me wonder WTF they are doing there. πŸš—

Back to our odd security policy: Having reserved some space between VLAN ID of organizational entities allows these entities to grow into the reserved space. If the first production line uses VLAN ID 11, the second would use VLAN ID 12, the third VLAN ID 13 and so on. This might provide a small benefit because now network admins just have to remember that everything from VLAN ID 11 to VLAN ID 20 πŸ™ˆ is production, and everything from VLAN ID 21 to 30 belongs to e.g. finance. This may lessen confusion and helps with plausibility checks when configuring a VLAN ID on network hardware. However, the moment the reserved space between two VLAN ID is used it violates the security policy. πŸ€·β€β™‚οΈ

I still can’t figure out how this can be any useful in a high-security environment.

Bit errors

The issue I have with this theory is, that Ethernet frames have a Frame Check Sequence (FCS) at the end of every frame. The FCS uses a Cyclic Redundancy Check (CRC) performed over the frame, to detect (most) bit errors. There must be a special case of multiple bits being changed on the wire in such a way, that the result still matches the FCS, or, that the CFS itself is also compromised in a way that it validates the changed frame contents. In other words, this is very unlikely. We may be struck by lighting⚑️ with a higher probability.

But for the sake of the argument and for education reasons, let’s assume we have a network that is creating bit errors in the VLAN ID part of the 802.1q header and somehow also causing bit errors in the FCS accordingly. It’s stupid, but let’s go with it for a while.

Once a VLAN ID is modified, we want the corresponding frame to get discarded or maybe end up in Nirvana. We do not want the frame to hop into another logical segment. The question now is, how do we have to choose the set of valid VLAN ID so that they have the least chance of hopping? The answer is actually quite easy: We want the bit-level distance between every two VLAN ID from the set to be as high as possible. The higher the number of bits that would need to be changed in transit, the less likely a frame can hop into another valid segment. We call this distance between two bit sequences the Hamming Distance and we would optimize or set to contain only VLAN IDs with a high Hamming distance between each other. The limiting factor is the total number of VLAN IDs that are used. The more VLAN IDs are in the set, the smaller the distance between them.

Just for fun, I wanted to know the distance between every two consecutive VLAN IDs from our security policy. Because I am too lazy to do it by hand, I made a computer help me.

Here is the Golang code for reference:

package main

import (


func main() {
	var dist uint64
	var a uint64
	var b uint64

	for i := 1; (((i + 1) * 10) + 1) <= 4096; i++ {
		a = (uint64(i) * 10) + 1
		b = a + 10
		dist = popcount.Count64(a ^ b)
		fmt.Printf("a=%v b=%v distance=%v\n", a, b, dist)

Running the code gives us this:

$ go run distance.go
a=11 b=21 distance=4
a=21 b=31 distance=2
a=31 b=41 distance=4
a=4071 b=4081 distance=3
a=4081 b=4091 distance=2

Let’s see the histogram over the output using Hamming distances as bins:

Actually, not that bad. There are no two VLAN IDs that have a Hamming distance of 1. There are plenty of bit distances of 2, 3, 4 and there is even one 10.πŸ˜‰ Maybe this isn’t such a bad policy after all? Well, remember that we are still high up in the ivory tower of theoretical bit errors and we have lost contact to real life networking probably three or more paragraphs ago. Please also note, that we calculated the Hamming distances between every N and N+1 which has a runtime complexity of O(n). It may get even worse if we compare every N to every other N (which raises the runtime complexity to O(n^2)


From what I have come up with so far, this policy makes little to no sense. Besides, in a high-security environment, one might want to use physically segmentation anyway. That is, running multiple cables with only one logical segment on each cable.

If anyone likes to enlighten me on why this VLAN ID distance policy might make sense, please do so! It has been teasing my brain long enough… 😜

Year of the X Festival: IoT in less than a day!

Today I attended the Year of the X Innovation Festival and happened to sit in a workshop run by Iteratec titled IoT in less than a day. What I love about Year of the X festivals is, that there is a general you can touch this attitude to the workshops and demos. This workshop was no exception! The company sent a team of over five developers and designers. They brought all kind of sensors ranging from a motion detector to an ultra-sonic distance sensor. There were also plenty of actors, for example, a self-built matrix display and an Internet-connected blender (mixing smoothies in the company colors). πŸ˜‚

During the workshop, attendees were invited to throw some IoT ideas into an online collaboration tool challenging the team to build a few of those in less than a day. An IoT challenge? I re-arranged my agenda to make some room! A couple of minutes later I found myself in the back office were the friendly Iteratec guys helped me to get started.

The Idea

I have a DHT22 temperature and humidity sensor connected to a RaspberryPi in my lab at home. The data is pulled once a minute by Prometheus (a time series database) and occasionally visualized using Grafana (a graphing frontend for monitoring data).

A very different approach was shown in the workshop. All sensors published their data to a central message broker and actors (or other sensors) could subscribe to the messages. I wanted to learn that and decided to connect a DHT22 sensor to a message broker via a NodeMCU. A platform I had my struggles with before. 😩

The Approach

The NodeMCU Platform can conveniently be programmed using the standard Arduino IDE which makes it easy to get started. There are libraries for all the common tasks. In fact, the hardest part was to get the UART interface working with macOS. πŸ™ˆ After that, the plan was as follows:

  • Connect to the wifi
  • Connect to the message broker
  • Read DHT22 sensor
  • Publish sensor data to message broker
  • Wait a couple of seconds and go back to Read DHT22 sensor

With a little help here and there (snprintf() on Arduino ignores the %f pattern and ignores floats!) I got everything working in a couple of hours. It was really great that the workshop organizers had brought almost an entire lab in boxes. πŸ‘

As message broker I used, a free message broker that has a nice visualization. It was very helpful to see if and what messages were send from where to where. I can recommend this service!

The Result

Serial console output of the NodeMCU:

Message broker visualization:

The NodeMCU and connected DHT22 sensor.

The Code

#include <ESP8266WiFi.h>
#include <MQTTClient.h>
#include "DHT.h"

const char *wifi_ssid     = "wifi";
const char *wifi_password = "secret";

const char *mqtt_server   = "";
const char *mqtt_id       = "my_first_node";
const char *mqtt_user     = "login";
const char *mqtt_password = "secret";

const int  dht_pin        = D6;

WiFiClient net;
MQTTClient client;
DHT dht(dht_pin, DHT22);

void setup() {

  // wifi
  Serial.print("wifi: ssid=");
  Serial.print("wifi: password=");
  Serial.print("wifi: connecting");
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
  Serial.print("wifi: ip_addr=");
  Serial.println("wifi: done!");

  // message broker connection
  client.begin(mqtt_server, net);

void connect() {
  Serial.print("mqtt: server=");
  Serial.print("mqtt: id=");
  Serial.print("mqtt: user=");
  Serial.print("mqtt: password=");
  Serial.print("mqtt: connecting");
  while (!client.connect(mqtt_id, mqtt_user, mqtt_password)) {
  Serial.println("mqtt: done!");

void loop() {
  // vars
  float temperature = 0.0;
  float humidity = 0.0;
  String message;

  delay(10); // stability fix
  if(!client.connected()) {

  temperature = dht.readTemperature();
  humidity = dht.readHumidity();
  message  = "temperature=";
  message += String(temperature, 1);
  message += " ";
  message += "humidity=";
  message += String(humidity, 1);  Serial.print("message_out: ");
  client.publish("sensors", message);


void messageReceived(String topic, String payload, char * bytes, unsigned int length) {
  Serial.print("message_in: topic=");
  Serial.print(" payload='");