Limit SSH to IPv6 on FreeBSD

When I first set up my server, I got numerous daily attempts to login via SSH almost immediately. None of them were successful, because I use public key authentication, of course, but the log spam was annoying nonetheless. The problem is with only 232 addresses, scanning all possible IPv4 addresses for open ports is quite easy.

But, yet again, IPv6 to the rescue. It has 2128 possible addresses, so scanning all of them for open ports is doable but takes a significant amount of time. My server has a /64 subnet, so even if someone knows the prefix, there are still 264 addresses to scan. Both my home internet and my cell phone provider support IPv6 (as they should), so limiting SSH to a spare IPv6 address was the obvious solution.

This is not an approach for security, but merely to get rid of the annoying login attempts. The server still has to be secured. No one should believe that trying to “hide” the IP address does anything for security. If anyone really wants to find it, he will. But it helped to reduce the random failed login attempts, from a couple of hundreds on bad days, to not a single one in more than a year. So without all this noise in the logs, I can more easily see if anyone is actually trying to get into my server now.

The first step is to add another IPv6 address to the network interface, which can be used for SSH. Let’s assume the IPv6 prefix for the /64 subnet is 2001:10:20:30. All regular services might use 2001:10:20:30::1, so 2001:10:20:30::2222 could be reserved for SSH only. The additional address can be added in the /etc/rc.conf, assuming the network interface is em0:

ipv6_default_interface="em0"
ifconfig_em0_ipv6="inet6 2001:10:20:30::1/64"
ifconfig_em0_alias0_ipv6="inet6 2001:10:20:30::2222/64"

The networking can be restartet with:

# service netif restart

Alternatively, the server can also be rebooted. Now ifconfig should list the additional address:

# ifconfig em0
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=6c07bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,TSO4,TSO6,LRO,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
ether 96:00:00:aa:bb:cc
hwaddr 96:00:00:aa:bb:cc
inet6 2001:10:20:30::1 prefixlen 64 
inet6 fe80::9400:ff:feaa:bbcc%vtnet0 prefixlen 64 scopeid 0x1 
inet6 2001:10:20:30::2222 prefixlen 64 
inet 10.20.30.40 netmask 0xffffffff broadcast 10.20.30.40 
nd6 options=8021<PERFORMNUD,AUTO_LINKLOCAL,DEFAULTIF>
media: Ethernet 10Gbase-T <full-duplex>
status: active

You can also try to ping the new address and it should work fine. If the services on your server are not bound to specific IP addresses, but to any, now is the time to fix that. The other services should only use the 2001:10:20:30::1 address, and 2001:10:20:30::2222 is for SSH exclusively. sockstat is your friend.

With the new IPv6 address up and running, SSH can be configured to only listen to it and nothing else. This is done by having only a single ListenAddress parameter in /etc/ssh/sshd_config:

ListenAddress 2001:10:20:30::2222

Save the config file and be sure you can access your server directly or via a serial console, in case you made a mistake and lock yourself out. Then restart SSH to apply the changes:

# service ssh restart

You can check with sockstat if sshd is only listening to the new IPv6 address:

# sockstat -l | grep sshd
root sshd 34490 3 tcp6 2001:10:20:30::2222:22 *:*

If it is listening to anything else, check your sshd_config file.

The only way to access the server via SSH is by using the new dedicated IPv6 address:

$ ssh 2001:10:20:30::2222

This is inconvenient, so I recommend adding a new subdomain, like myssh.myserver.com, with a single AAAA record:

$ host myssh.myserver.com
myssh.myserver.com has IPv6 address 2001:10:20:30::2222

With these little changes the amount of random login attempts can be significantly reduced. However, it only works when all of your devices from which you manage the server support and use IPv6. But that should be the standard nowadays.

Using a Raspberry Pi as a serial console server for FreeBSD

My home server runs FreeBSD 11.0, and, of course, has full disk encryption. This requires a passphrase to be entered while booting, so I need a keyboard and monitor attached, and have to be in the same room for restarts and after power outages. This is not acceptable at all. There is no need for a display and keyboard otherwise, and I want to be able to enter the passphrase remotely, but without compromising security. Luckily, the server has a serial port and I have a spare Raspberry Pi. So I can connect the serial port to the Raspberry Pi, SSH into it and use the serial console of the server just like physical access. Hooray for stuff from the 1960s still being useful!

So first things first, I need to connect the Raspberry Pi to the serial console. Since it only has USB (aside from GPIO), a USB to serial port adapter is necessary. The Raspberry Pi runs FreeBSD 11.0, which has good out-of-the-box support for the Prolific PL2303 chipset, so I just ordered a cheap adapter based on it. It probably works with Linux as well, if you’re using Raspbian. You can use dmesg to check if it was detected correctly:

# dmesg | grep Prolific
ugen0.4: <Prolific Technology Inc.> at usbus0
uplcom0: <Prolific Technology Inc. USB-Serial Controller, class 0/0,
rev 2.00/3.00, addr 4> on usbus0

Don’t forget (like I did) that the USB to serial port adapter only provides you with a serial port. To connect it to the server’s serial port, you still need a null modem cable or adapter.

Now that we have the hardware, it’s time to set up the server to use the serial console. This is pretty straight-forward, just add the following to your /boot/loader.conf and reboot, as described in the FreeBSD handbook:

boot_multicons="YES"
boot_serial="YES"
console="comconsole,efi"

If you don’t use EFI yet, replace efi with vidconsole. This outputs all kernel messages also to the serial console and lets you type in the passphrase during the boot process. You can also only use comconsole, but then there won’t be much output on a real monitor in case you need one.

Additionally, you may like to see a login prompt after the boot process is done, in case the server’s network is down and SSH doesn’t work. A terminal on the serial port can be activated by adding the following line in /etc/ttys:

ttyu0   "/usr/libexec/getty std.9600" dialup  on secure

Now you should already be able to use the serial console via the Raspberry Pi, with a tool of your choice:

# tip ucom1
# screen /dev/cuaU0 9600
# cu -l /dev/cuaU0 -s 9600

If you don’t want to be root to access the console (you don’t), you can add your user to the group dialer:

# pw groupmod dialer -M solence

Now that all is up and running, be aware that the serial console works like a monitor. If you log in via serial console and only close serial connection, it’s just like turning off your monitor, you’re still logged in! So be aware to always log out before closing the serial connection.

 

Increasing the port speed

This setup is usable, but painfully slow, because the default port speed is still 9,600 baud. In case you don’t remember the ancient unit baud, it’s symbols per second. This equals bits/sec, so 9,600 baud convert to 1,200 bytes/sec. Considering that the standard terminal line has 80 characters, that’s only 15 lines/sec.

So increasing the serial port speed to the maximum of 115,200 baud would be a good idea. This equals 14,000 bytes/sec or 180 terminal lines/sec, which sounds much better. Some tweaking on the server’s side is required, however.

First, add the desired speed to /boot/loader.conf:

comconsole_speed="115200"

Then change the speed in the corresponding entry in /etc/ttys:

ttyu0   "/usr/libexec/getty std.115200" dialup  on secure

In theory, this is sufficient and only requires a reboot to work, but in my case I also had to configure the serial port device. Check with stty if the port has the correct speed on the server:

# stty -f /dev/ttyu0

If the speed is set to 115,200 baud, everything is fine. If it’s still 9,600 baud, it has to be adjusted like described in this great tutorial.

After that’s done, the serial console can be used with the increased speed on the Raspberry Pi:

$ screen /dev/cuaU0 115200
$ cu -l /dev/cuaU0 -s 115200

You can also add an alias in /etc/remote for easy use with tip on the Raspberry Pi:

server:dv=/dev/cuaU0:br#115200:pa=none:

Now you can just use:

$ tip server

If your Raspberry Pi is accessible remotely, directly or via VPN, power outages or remote maintenance are no problem anymore. But make sure you can still reach the Raspberry Pi when the server you connected it to is down, otherwise all this would be pointless. Also, now you don’t even need keyboard and monitor at all, because it’s way more convenient to use SSH and the serial console than getting up and moving over to the box 🙂