In my previous blog I explained that I wanted to build a network monitoring device. I described the hardware I will be using. In this blog I’ll talk about setting everything up and installing the software and configuring it.
Assembly
The assembly is straightforward. On the Waveshare board it’s clearly marked where you need to install the CM4. Align it correctly and gently push untill it snaps in to place.
Connect the USB-C slave port to your computer and power on the device.
Raspberry Pi OS
The first step is to install an OS on the Raspberry Pi CM4. Download the Raspberry Pi Imager from here:
https://www.raspberrypi.com/software/
The GUI is self explaining. I tried both Raspberry Pi OS and Ubuntu Pi OS. Where the Raspberry Pi OS was running smoothly, the Ubuntu Pi OS was very unresponsive from time to time. Needless to say I stuck with Raspberry Pi OS and based on that this blog is created.
Update Pi OS
After flashing the Raspberry it’s time to connect it to your router. Connect the eth1 port to your router. Find the IP address that the CM4 got from your DHCP server and SSH into the CM4. The Waveshare comes with dual HDMI. You can connect the Waveshare to a monitor and continue the setup directly on the CM4.
The first thing you want to do is block SSH on eth0:
iptables -A INPUT -i eth0 -p tcp --dport 22 -j DROP
With that done it’s time to update the CM4.
sudo apt update && sudo apt upgrade
Configure the networkcards. If you are using a monitor on your CM4, use the top right corner where you’ll find the network configuration icon. Otherwise use nmtui from the cli. The setting I used:
eth0 – dynamic IP
eth1 – static IP (192.168.1.254 in my case)
Optional: USB drive for logging
I don’t want to hammer the eMMC chip with logs and will be using an USB drive for logging purposes.
Mine showed up as /dev/sda, you can see yours with:
df -Th
First unmount the partitions:
sudo umount /dev/sda1 sudo umount /dev/sda2
Create a new partition table and single partition:
sudo fdisk /dev/sda # Press 'd' to delete existing partitions (repeat for all partitions) # Press 'n' for new partition # Press 'p' for primary partition # Press Enter for default first sector # Press Enter for default last sector # Press 'w' to write changes
Format the partition with ext4:
sudo mkfs.ext4 /dev/sda1
Create a mount point and mount the drive:
sudo mkdir -p /mnt/ntopng sudo mount /dev/sda1 /mnt/ntopng sudo mkdir -p /mnt/ntopng/logs sudo mkdir -p /mnt/ntopng/flows sudo mkdir -p /mnt/ntopng/rrd sudo chown -R ntopng:ntop /mnt/ntopng/*
Add to /etc/fstab for permanent mounting:
echo "/dev/sda1 /mnt/ntopng ext4 defaults,noatime 0 2" | sudo tee -a /etc/fstab
Install ntopng
I want to monitor the bandwidth per IP and for that I will be using ntopng. Here are the steps how to install it.
# Add ntop repository
wget https://packages.ntop.org/RaspberryPI/apt-ntop.deb sudo dpkg -i apt-ntop.deb
# Update package information
sudo apt update
# Install ntopng and nprobe
sudo apt install ntopng nprobe
You will need to edit the configuration of ntopng. Here is my configuration:
cat /etc/ntopng/ntopng.conf # Specify where to store the PID file for process management -G=/var/run/ntopng.pid # Set the data directory for storing persistent data on the USB drive --data-dir=/mnt/ntopng # Configure flow storage: use disk storage, keep data for 7 days, max 2GB -F="disk;days=7;max=2048" # Bind ntopng to CPU core #2 for better performance --cpu-affinity=2 # Limit maximum number of active flows to 50,000 to control memory usage --max-num-flows=50000 # Limit maximum number of tracked hosts to 10,000 --max-num-hosts=10000 # Remove idle hosts after 1 hour (3600 seconds) --host-max-idle=3600 # Export flow data every 30 seconds --dump-flows=30 # Export host data every 300 seconds (5 minutes) --dump-hosts=300 # Store log files on the USB drive --log-dir=/mnt/ntopng/logs # Monitoring interfaces (eth0,eth1 commented out) #-i=eth0,eth1 # Currently monitoring only eth0 interface -i=eth0 # Set web interface port to 3000 -w=3000 # Set URL prefix for the web interface --http-prefix="/ntop" # Use local Redis instance for data caching --redis-host=localhost # Enable DNS resolution (mode 1: resolve all numeric IPs) --dns-mode=1 # Enable detailed flow collection for better traffic analysis --enable-flow-collection # Listen on port 2055 for NetFlow data from network devices --collector-port=2055 # Listen on port 6343 for sFlow data from network devices --collector-port=6343
Optionally: if you used a USB for logging set the correct permissions:
sudo chown ntopng:ntop /mnt/ntopng sudo chmod 755 /mnt/ntopng
Let’s test the configuration and start ntopng
sudo systemctl enable ntopng sudo systemctl restart ntopng
You should be able to logon to ntopng on:
http://<CM4 IP>:3000 (in my case http://192.168.1.254:3000)
If not check the status:
sudo systemctl status ntopng
OS configuration
By default IP forwarding is disabled. You need to enable it with this command:
# Enable IP forwarding immediately
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
# Make the change permanent (survives reboots)
sudo echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf sudo sysctl -p
Optional: disable IPv6:
sudo echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf sudo echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf sudo echo "net.ipv6.conf.eth0.disable_ipv6 = 1" >> /etc/sysctl.conf
Now traffic from eth0 will be forwarded to eth1 and vice versa.
Iptables configuration
Now that the OS will forward packets, we need to enable that in IPtables.
# Clear existing rules sudo iptables -F sudo iptables -t nat -F # Set default policies sudo iptables -P INPUT DROP sudo iptables -P FORWARD ACCEPT sudo iptables -P OUTPUT ACCEPT # Allow local traffic sudo iptables -A INPUT -i lo -j ACCEPT # Allow established connections sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # Allow internal network traffic sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT # Block and log ntopng web interface access from WAN sudo iptables -A INPUT -p tcp --dport 3000 -m limit --limit 5/min -j LOG --log-prefix "ntopng DROP: " sudo iptables -A INPUT -p tcp --dport 3000 -j DROP # Block and log SSH access from WAN sudo iptables -A INPUT -p tcp --dport 22 -m limit --limit 5/min -j LOG --log-prefix "SSH DROP: " sudo iptables -A INPUT -p tcp --dport 22 -j DROP # Allow DNS forwarding sudo iptables -A FORWARD -p udp --dport 53 -j ACCEPT sudo iptables -A FORWARD -p udp --sport 53 -j ACCEPT # Allow LAN to WAN traffic sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT # Allow related WAN to LAN traffic sudo iptables -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT # Enable NAT sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Save configuration:
sudo apt install iptables-persistent sudo iptables-save > /etc/iptables/rules.v4
That’s it! You should have a working network monitoring tool now!
Fail2ban
As this device is directly behind my modem it will get hammered by hackers, you want to secure it as best as possible. I use fail2ban to block IPs trying to hack the CM4.
Install fail2ban:
sudo apt install fail2ban
First, create a custom jail configuration (don’t modify the default one):
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit the local configuration:
sudo vi /etc/fail2ban/jail.local
Add this:
[DEFAULT] bantime = 1h findtime = 10m maxretry = 3 banaction = iptables-multiport [sshd] enabled = true port = ssh filter = custom-ssh logpath = /mnt/ntopng/logs/iptables/ssh.log maxretry = 3 findtime = 600 bantime = 3600
Since we’re using iptables to log SSH drop attempts, we need to create a custom filter:
sudo vi /etc/fail2ban/filter.d/custom-ssh.local
Add this:
[INCLUDES] before = common.conf [Definition] _daemon = (?:kernel|raspberrypi kernel) failregex = ^.* %(_daemon)s: \[\d+\.\d+\] SSH DROP:.* SRC=<HOST>.*DPT=22 ^.* %(_daemon)s: SSH DROP:.* SRC=<HOST>.*DPT=22 ignoreregex =
Set up logging directory for iptables:
sudo mkdir -p /mnt/ntopng/logs/iptables sudo chown syslog:adm /mnt/ntopng/logs/iptables
Configure rsyslog to send iptables logs to this location:
sudo vi /etc/rsyslog.d/10-iptables.conf
Add this:
# Create template for iptables logging
template(name="IptablesFormat" type="string" string="%TIMESTAMP:::date-rfc3339% %msg%\n")
# Log iptables messages
if $msg contains "SSH DROP" then {
action(type="omfile"
file="/mnt/ntopng/logs/iptables/ssh.log"
template="IptablesFormat"
fileOwner="syslog"
fileGroup="adm"
fileCreateMode="0640"
dirCreateMode="0750")
stop
}
if $msg contains "ntopng DROP" then {
action(type="omfile"
file="/mnt/ntopng/logs/iptables/ntopng.log"
template="IptablesFormat"
fileOwner="syslog"
fileGroup="adm"
fileCreateMode="0640"
dirCreateMode="0750")
stop
}
Restart and enable services:
sudo systemctl restart rsyslog sudo systemctl enable fail2ban sudo systemctl restart fail2ban
Verify fail2ban is working:
sudo fail2ban-client status sshd
This setup will automatically ban IPs that attempt to access SSH or the ntopng interface from the internet. The typical ban time is one hour, but you can adjust this based on your security preferences.
Final setup
With all the software installed it’s time to put the CM4 to work. My setup is like this:
Internet -> CM4 eth0
CM4 eth1 -> Router
That way the CM4 is inline and will see all the traffic coming in and going out of my network. This setup gives the best privacy to my family members. That’s because the CM4 sees my router as a client. Everything behind the router is not visible due to NAT.
Performance
I did a simple iperf3 test on the CM4 from my PC to the Waveshare interfaces.
eth1: [ ID] Interval Transfer Bitrate [ 5] 0.00-1.02 sec 86.5 MBytes 715 Mbits/sec [ 5] 1.02-2.00 sec 76.1 MBytes 647 Mbits/sec [ 5] 2.00-3.00 sec 93.5 MBytes 782 Mbits/sec [ 5] 3.00-4.01 sec 109 MBytes 909 Mbits/sec [ 5] 4.01-5.01 sec 109 MBytes 914 Mbits/sec [ 5] 5.01-6.01 sec 108 MBytes 907 Mbits/sec [ 5] 6.01-7.02 sec 92.5 MBytes 774 Mbits/sec [ 5] 7.02-8.00 sec 102 MBytes 868 Mbits/sec [ 5] 8.00-9.00 sec 110 MBytes 917 Mbits/sec [ 5] 9.00-10.00 sec 109 MBytes 915 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate [ 5] 0.00-10.00 sec 996 MBytes 835 Mbits/sec receiver eth0: [ ID] Interval Transfer Bitrate [ 5] 0.00-1.01 sec 112 MBytes 930 Mbits/sec [ 5] 1.01-2.02 sec 110 MBytes 925 Mbits/sec [ 5] 2.02-3.02 sec 109 MBytes 912 Mbits/sec [ 5] 3.02-4.02 sec 111 MBytes 928 Mbits/sec [ 5] 4.02-5.00 sec 106 MBytes 905 Mbits/sec [ 5] 5.00-6.00 sec 112 MBytes 934 Mbits/sec [ 5] 6.00-7.01 sec 112 MBytes 933 Mbits/sec [ 5] 7.01-8.01 sec 110 MBytes 925 Mbits/sec [ 5] 8.01-9.01 sec 112 MBytes 934 Mbits/sec [ 5] 9.01-10.00 sec 107 MBytes 904 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate [ 5] 0.00-10.00 sec 1.07 GBytes 923 Mbits/sec receiver
I’m happy with that I see.
Conclusion
It was a bit tricky setting everything up. I had a hard time with the network part. I “forgot” to change my routers wan interface to the IP of the CM4 eth1 interface.
I’m also shocked by the amount of traffic:
Total Traffic 10.9 GB [15,132,481 Pkts]
And the system isn’t even online for half a day:
11:47:00 up 1 day, 6 min, 6 users, load average: 1.42, 1.17, 1.18
Note that the CM4 handles the load well, currently the load average is just above 1. But for extremely high-traffic networks (gigabit+), you might want to consider adjusting the sampling rate or monitoring parameters.
Thanks for reading!