Building a Software-Defined Network with Raspberry Pis and a Zodiac FX switch

Charlie L
Cyber Reboot
Published in
8 min readDec 11, 2017

--

Portable Software-Defined Network

In our last post we walked through the recent improvements to both FAUCET and Poseidon to enable them to work with each other. This blog post is a run through of the setup of getting Poseidon and FAUCET working and talking to each other using Raspberry Pis (RPis) and a Zodiac FX switch.

Here’s the list of materials we’ll be using:

  • 1 RaspberryPi 3 (serves as Controller1)
  • 2 RaspberryPi 2s (Client1, Client2)
  • 1 Northbound Network Zodiac FX (https://northboundnetworks.com/collections/zodiac-fx)
  • 1 Battery pack
  • 1 Laptop running OS X or Linux (Server1)
  • 4 USB A to Micro B cables
  • Handful of USB Ethernet dongles
  • Handful of Ethernet cables

First let’s configure the switch so that FAUCET can connect to it once FAUCET is set up. On the Zodiac you’ll want to do a firmware upgrade if you haven’t already, to make sure you’re running at least version 0.82. Once that’s been upgraded, you can pop into the console of the switch on the machine you plugged the USB cable into by looking for the new device in /dev. On OS X it shows up as /dev/tty.usbmodem1421 for me. Now that you know the device, you can run:

screen /dev/tty.usbmodem1421 9600

You should see something like this:

Zodiac FX Console

From here, just set the configuration to match the following (use the help command to set the IP Addresses and ports):

Zodiac_FX# config
Zodiac_FX(config)# show config
— — — — — — — — —— — — — — — — -Configuration
Name: Zodiac_FX
MAC Address: 70:B3:D5:6C:D3:2E
IP Address: 192.168.1.99
Netmask: 255.255.255.0
Gateway: 192.168.1.1
OpenFlow Controller: 192.168.1.10
OpenFlow Port: 6653
Openflow Status: Enabled
Failstate: Secure
Force OpenFlow version: Disabled
EtherType Filtering: Disabled
— — — —— — — — — — — — — — — — -Zodiac_FX(config)# save
Zodiac_FX(config)# restart

Now that the switch is ready to go, boot up your RPi 3 (we’ll refer to this as Controller1). It needs Raspbian loaded up with Docker CE and Compose installed on it. Now you want to pull down the FAUCET repository since this RPi will be your controller.

git clone https://github.com/faucetsdn/faucet

FAUCET requires two YAML files to be configured. The first is /etc/ryu/faucet/faucet.yaml, which you’ll need to create and populate with a simple configuration of the network switch topology and rules that should be applied. Here’s an example that we’ll use for our setup; note the dp_id needs to match the MAC address of the switch (printed on the bottom of the switch) you’re connecting to:

dps:
zodiac-fx-1:
dp_id: 0x70b3d56cd32e
hardware: ZodiacFX
proactive_learn: true
interfaces:
1:
native_vlan: demo
2:
native_vlan: demo
3:
native_vlan: mirror
vlans:
demo:
vid: 300
mirror:
vid: 101
max_hosts: 0

This configuration basically says that ports 1 and 2 are on the VLAN and are allowed to talk to each other, and port 3 is on a different VLAN since we’re going to use that as a mirror port for Poseidon. Port 4 is not specified since on the Zodiac FX, port 4 is a dedicated controller only port. Now that we have that set, we also need to populate /etc/ryu/faucet/gauge.yaml. We’ll use these settings to start:

faucet_configs:
- ‘/etc/ryu/faucet/faucet.yaml’
watchers:
port_status_poller:
type: ‘port_state’
dps: [‘zodiac-fx-1’]
db: ‘influx’
port_stats_poller:
type: ‘port_stats’
dps: [‘zodiac-fx-1’]
interval: 10
db: ‘prometheus’
flow_table_poller:
type: ‘flow_table’
interval: 60
dps: [‘zodiac-fx-1’]
db: ‘influx’
dbs:
ft_file:
type: ‘text’
compress: True
file: ‘flow_table.yaml.gz’
prometheus:
type: ‘prometheus’
prometheus_addr: ‘0.0.0.0’
prometheus_port: 9303
influx:
type: ‘influx’
influx_db: ‘faucet’
influx_host: ‘influxdb’
influx_port: 8086
influx_user: ‘faucet’
influx_pwd: ‘faucet’
influx_timeout: 10

At this point, FAUCET is ready to run, so first let’s wire everything and set our interfaces up. Controller1 will need to have 2 network interfaces, one to talk to the switch, and a second one to talk to the laptop (we’ll refer to it as Server1) which will be running Poseidon. To get our second network interface, we’ll use a USB dongle. The one that will be plugged into the switch (Port 4) needs to match the OpenFlow Controller IP Address we set on the Zodiac, 192.168.1.10; the other can be whatever we like. In this setup we’re going to use a crossover cable to Server1 so they can communicate without needing another switch in between them. So we end up with something like this in /etc/network/interfaces on Controller1 that will be running FAUCET:

auto eth0
iface eth0 inet static
address 172.16.1.109
gateway 172.16.1.1
auto eth1
iface eth1 inet static
address 192.168.1.10
netmask 255.255.255.0

Since we want to be able to reach FAUCET running on Controller1 from Server1 that will be running Poseidon, we’re going to want to make sure that SSH is enabled on Controller1.

The first time FAUCET runs it needs to pull down Docker images from the Docker Hub, so you’ll need internet connectivity the first time. This is where having the wireless LAN that comes on the RPi becomes very useful.

Let’s start up FAUCET on Controller1 and make sure it can talk to the switch (one could add this to /etc/rc.local to have this run on boot):

cd /home/pi/faucet && FAUCET_CONFIG_STAT_RELOAD=1 docker-compose -f docker-compose-pi.yaml up --build -d

If everything is working we’ll see FAUCET connected to the switch in the controller’s log file /var/log/ryu/faucet/faucet.log like so:

Nov 27 22:30:51 faucet INFO will automatically reload new config on changes
Nov 27 22:30:51 faucet INFO Add new datapath DPID 123917682135854 (0x70b3d56cd32e)
Nov 27 22:30:51 faucet INFO DPID 123917682135854 (0x70b3d56cd32e) connected
Nov 27 22:30:51 faucet.valve INFO DPID 123917682135854 (0x70b3d56cd32e) Cold start configuring DP
Nov 27 22:30:51 faucet.valve INFO DPID 123917682135854 (0x70b3d56cd32e) Configuring VLAN demo vid:300 ports:Port 1,Port 2
Nov 27 22:30:51 faucet.valve INFO DPID 123917682135854 (0x70b3d56cd32e) Configuring VLAN mirror vid:101 ports:Port 3

Ok great, now we have Controller1 up and running and talking to the switch. Now we can setup Server1, which can run either Linux or OS X. For this example we’ll be using Ubuntu 16.04. We’re going to need two network interfaces on Server1 as well, and since my laptop doesn’t have any ethernet ports, we’re going to use two USB dongles, and again the wireless LAN for internet. Server1 will also need Docker CE installed. The first USB dongle, we’ll call eth1, should be plugged into the crossover cable that goes to Controller1, the second USB dongle, we’ll call eth2, should be plugged into Port 3 on the switch (this will be our mirror port). The interface settings in /etc/network/interfaces should look something like this:

auto eth1
iface eth0 inet static
address 172.16.1.110
gateway 172.16.1.1
allow-hotplug eth2
iface eth2 inet manual
pre-up ifconfig $IFACE up
post-down ifconfig $IFACE down

At this point, you should be able to connect to Controller1 from Server1 using ssh credentials:

ssh pi@172.16.1.109

If that is successful, then your SSH configuration is correct and your crossover cable and network interfaces are good.

Adding Poseidon into the mix

At this point, we can now proceed and get Poseidon up and running on Server1. We’ll first want to pull down the repository from GitHub, set a couple of configuration options for our setup, and then start Vent which will orchestrate all of the things Poseidon needs.

git clone https://github.com/cyberreboot/poseidon
cd poseidon
export controller_uri=172.16.1.109
export controller_user=pi
export controller_pass=myPassword
export controller_type=faucet
export collector_nic=eth2
export controller_mirror_ports=’{“zodiac-fx-1”:3}’
export max_concurrent_reinvestigations=1
./helpers/run

We note a couple of things about the environment variables that are being exported. By default, Poseidon is set to connect to BCF, which makes its connection through REST calls to the BCF API. That means it only requires three variables to be assigned:

  1. the URI of the controller to connect to,
  2. a username,
  3. and a password to login with.

Since we’re connecting to a FAUCET controller in this setup, we need to specify a hostname or IP Address for the URI that Poseidon will SSH to using the username and password (keys are supported with passphrases, but for this example we’re just going to use simple passwords). Additionally we need to tell Poseidon that controller type is no longer BCF, but instead FAUCET. Next, we specify what the network interface on Server1 is that traffic will be mirrored to, so that Vent can capture that data and send it on to be classified and analyzed for behavior. Additionally, for FAUCET, we provide which ports on which switches connected to the controller are mirror ports. In this case, the name of the switch is zodiac-fx-1, which we specified in the faucet.yaml file above, and the port we’re mirroring to is 3. Lastly, for FAUCET we set the max number of concurrent re-investigations to 1 because mirroring with FAUCET currently is at the port level only for combined inbound and outbound traffic.

Now we have Poseidon up and running and taking to the FAUCET controller which is connected to our switch. With the two remaining free ports on the switch we can hook up our two remaining RPis (Client1 and Client2) and put them on the same netmask. With the controller up, they should be able to freely communicate because they’re on the same VLAN and no ACLs are set. Once they start communicating on the switch, the controller will learn that there are new devices, and Poseidon will grab that information from the controller and start mirroring traffic of unknown devices. That mirrored traffic will then be sent on to the classifier and run through behavioral analysis to see if the device type that was detected is behaving abnormally or not (our machine learning models for this are still a work in progress). At this point a message is then sent back to Poseidon with the results and confidences, and Poseidon can make a decision about what to do upstream to the controller and subsequently switch such as shutdown, degrade, monitor, etc.

Thanks to some risers, I was able to stack everything and take it out the of initial cardboard box (pictured below) and turn it into a small portable unit that ended up taking much less space, and it is easier to interact with the ports on the RPis.

While there is still a lot more work to be done, so far early results have been promising as we move forward supporting both BCF and FAUCET as viable SDN controllers that Poseidon can connect to.

Initial prototype

Some additional photos of the final setup:

Cyber Reboot, an IQT lab, challenges the traditional approach to cybersecurity with the goal of rebalancing the equation to increase the cost and complexity for our adversaries while reducing cost and complexity for our defenders.

Learn more at http://www.cyberreboot.org/ and follow us on Twitter: @_cyberreboot

--

--