My VoIP provider recently added support for TLS/SRTP-based call encryption. Here's what I did to enable this feature on my Asterisk server.
First of all, I changed the registration line in /etc/asterisk/sip.conf
to
use the "tls" scheme:
[general]
register => tls://mydid:mypassword@servername.voip.ms
then I enabled incoming TCP connections:
tcpenable=yes
and TLS:
tlsenable=yes
tlscapath=/etc/ssl/certs/
Finally, I changed my provider entry in the same file to:
[voipms]
type=friend
host=servername.voip.ms
secret=mypassword
username=mydid
context=from-voipms
allow=ulaw
allow=g729
insecure=port,invite
transport=tls
encryption=yes
(Note the last two lines.)
The dialplan didn't change and so I still have the following in
/etc/asterisk/extensions.conf
:
[pstn-voipms]
exten => _1NXXNXXXXXX,1,Set(CALLERID(all)=Francois Marier <5551234567>)
exten => _1NXXNXXXXXX,n,Dial(SIP/voipms/${EXTEN})
exten => _1NXXNXXXXXX,n,Hangup()
exten => _NXXNXXXXXX,1,Set(CALLERID(all)=Francois Marier <5551234567>)
exten => _NXXNXXXXXX,n,Dial(SIP/voipms/1${EXTEN})
exten => _NXXNXXXXXX,n,Hangup()
exten => _011X.,1,Set(CALLERID(all)=Francois Marier <5551234567>)
exten => _011X.,n,Authenticate(1234) ; require password for international calls
exten => _011X.,n,Dial(SIP/voipms/${EXTEN})
exten => _011X.,n,Hangup(16)
Server certificate
After setting everything up, I saw the following error in my logs:
asterisk[8691]: ERROR[8691]: tcptls.c:966 in __ssl_setup: TLS/SSL error loading cert file. <asterisk.pem>
due to the fact that I didn't set tlscertfile
in
/etc/asterisk/sip.conf
and that it's using its default value of
asterisk.pem
, a non-existent file.
I initially thought that since my Asterisk server is only acting as a TLS client, and not a TLS server, there's probably no harm in not having a certificate. In practice however, my TLS connection was a little unreliable and it would regularly fail with the following TLS errors:
asterisk[534775]: ERROR[534879]: iostream.c:538 in ast_iostream_close: SSL_shutdown() failed: error:00000005:lib(0):func(0):DH lib, Underlying BIO error: Broken pipe
asterisk[534775]: ERROR[610289]: tcptls.c:553 in ast_tcptls_client_start: Unable to connect SIP socket to w.x.y.z:5061: Connection refused
asterisk[534775]: ERROR[610289]: tcptls.c:553 in ast_tcptls_client_start: Unable to connect SIP socket to w.x.y.z:5061: Connection reset by peer
I therefore decided to setup a Let's Encrypt certificate in Asterisk to eliminate the original error.
Firewall
This originally appeared not to be necessary, but I found that I ran into a number of intermittent connection errors such as:
asterisk[1280841]: ERROR[1537920]: tcptls.c:553 in ast_tcptls_client_start: Unable to connect SIP socket to w.x.y.z:5061: Connection reset by peer
and so I put the official firewall
recommendations in
/etc/network/iptables.up.rules
:
# SIP and RTP on TCP/UDP (servername.voip.ms)
-A INPUT -s w.x.y.z/32 -p tcp --dport 5061 -j ACCEPT
-A INPUT -s w.x.y.z/32 -p udp --sport 5004:5005 --dport 10001:20000 -j ACCEPT
where w.x.y.z
is the IP address of servername.voip.ms
as returned by
dig +short servername.voip.ms
.
Here is how I installed Debian 10 / buster on my GnuBee Personal Cloud 2, a free hardware device designed as a network file server / NAS.
Flashing the LibreCMC firmware with Debian support
Before we can install Debian, we need a firmware that includes all of the necessary tools.
On another machine, do the following:
- Download the latest
librecmc-ramips-mt7621-gb-pc1-squashfs-sysupgrade_*.bin
. - Mount a vfat-formatted USB stick.
- Copy the file onto it and rename it to
gnubee.bin
. - Unmount the USB stick
Then plug a network cable between your laptop and the black network port and plug the USB stick into the GnuBee before rebooting the GnuBee via ssh:
ssh 192.68.10.1
reboot
If you have a USB serial cable, you can use it to monitor the flashing process:
screen /dev/ttyUSB0 57600
otherwise keep an eye on the LEDs and wait until they are fully done
flashing.
When you want to exit
screen,
use Ctrl-a
then k
.
Getting ssh access to LibreCMC
Once the firmware has been updated, turn off the GnuBee manually using the power switch and turn it back on.
Now enable SSH access via the built-in LibreCMC firmware:
- Plug a network cable between your laptop and the black network port.
- Open web-based admin panel at http://192.168.10.1.
- Go to System | Administration.
- Set a root password.
- Disable ssh password auth and root password logins.
- Paste in your RSA ssh public key.
- Click Save & Apply.
- Go to Network | Firewall.
- Select "accept" for WAN Input.
- Click Save & Apply.
Finaly, go to Network | Interfaces and note the ipv4 address of the WAN port since that will be needed in the next step.
Installing Debian
The first step is to install Debian jessie on the GnuBee.
Connect the blue network port into your router/switch and ssh into the GnuBee using the IP address you noted earlier:
ssh root@192.168.1.xxx
and the root password you set in the previous section.
Then use fdisk /dev/sda
to create the following partition layout on the
first drive:
Device Start End Sectors Size Type
/dev/sda1 2048 8390655 8388608 4G Linux swap
/dev/sda2 8390656 234441614 226050959 107.8G Linux filesystem
Note that I used an 120GB solid-state drive as the system drive in order to minimize noise levels.
Then format the swap partition:
mkswap /dev/sda1
and download the latest version of the jessie installer:
wget --no-check-certificate https://raw.githubusercontent.com/gnubee-git/GnuBee_Docs/master/GB-PCx/scripts/jessie_3.10.14/debian-jessie-install
(Yes, the --no-check-certificate
is really unfortunate. Please leave a
comment if you find a way to work around it.)
The stock installer fails to bring up the correct networking configuration
on my network and so I have modified the
install script by changing
the eth0.1
blurb to:
auto eth0.1
iface eth0.1 inet static
address 192.168.10.1
netmask 255.255.255.0
Then you should be able to run the installer succesfully:
sh ./debian-jessie-install
and reboot:
reboot
Restore ssh access in Debian jessie
Once the GnuBee has finished booting, login using the serial console:
- username:
root
- password:
GnuBee
and change the root password using passwd
.
Look for the IPv4 address of eth0.2
in the output of the ip addr
command
and then ssh into the GnuBee from your desktop computer:
ssh root@192.168.1.xxx # type password set above
mkdir .ssh
vim .ssh/authorized_keys # paste your ed25519 ssh pubkey
Finish the jessie installation
With this in place, you should be able to ssh into the GnuBee using your public key:
ssh root@192.168.1.172
and then finish the jessie installation:
wget --no-check-certificate https://raw.githubusercontent.com/gnubee-git/gnubee-git.github.io/master/debian/debian-modules-install
bash ./debian-modules-install
reboot
After rebooting, I made a few tweaks to make the system more pleasant to use:
update-alternatives --config editor # choose vim.basic
dpkg-reconfigure locales # enable the locale that your desktop is using
Upgrade to stretch and then buster
To upgrade to stretch, put this in /etc/apt/sources.list
:
deb http://httpredir.debian.org/debian stretch main
deb http://httpredir.debian.org/debian stretch-updates main
deb http://security.debian.org/ stretch/updates main
Then upgrade the packages:
apt update
apt full-upgrade
apt autoremove
reboot
To upgrade to buster, put this in /etc/apt/sources.list
:
deb http://httpredir.debian.org/debian buster main
deb http://httpredir.debian.org/debian buster-updates main
deb http://security.debian.org/debian-security buster/updates main
and upgrade the packages:
apt update
apt full-upgrade
apt autoremove
reboot
At this point, my GnuBee is running the latest version of Debian stable, however there are two remaining issues to fix:
openssh-server doesn't work and I am forced to access the GnuBee via the serial interface.
The firmware is running an outdated version of the Linux kernel.
Both of these issues can be resolved by upgrading the firmware to a recent version of Linux.
Upgrading the firmware
In order to move to the firmware that Neil Brown has been working on for a while, I prepared a USB stick:
$ sudo fdisk -l /dev/sdc
Disk /dev/sdc: 3.77 GiB, 4027580416 bytes, 7866368 sectors
Disk model: USB Disk
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x6cb65e6c
Device Boot Start End Sectors Size Id Type
/dev/sdc1 2048 7866367 7864320 3.8G c W95 FAT32 (LBA)
$ sudo mkfs.vfat /dev/sdc1
using a dos
partition table and a W95 FAT32 (LBA)
partition.
Then I grabbed the latest gnubee-*-gbpc2.bin
file from
https://neil.brown.name/gnubee/ and copied it onto the USB stick with the
appropriate name:
cp gnubee-5.4.14-gbpc2.bin /media/usbdisk/GNUBEE.BIN
I plugged the stick into the GnuBee and rebooted it to upgrade the firmware, watching the process using the serial console.
Once booted, I had to delete /etc/udev/rules.d/70-persistent-net.rules
in
order to fix a long timeout while bringing up the network interfaces during
boot.
If you want to see the boot messages to ensure there are no errors, run
journalctl -b
.
Finally, I cleaned up a deprecated and no-longer-needed package:
apt purge ntpdate
and removed its invocation from /etc/rc.local
and /etc/cron.d/ntp
.
Fixing the serial console
The serial console, automatically started by systemd, seems to get corrupted every now and then. If you see garbled output (i.e. binary characters instead of text), then you are running into this problem.
The fix, suggested by Jernej
Jakob, is
to override the default systemd unit file by creating a
/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf
with the
following contents:
[Service]
ExecStart=
ExecStart=-/sbin/agetty -o '-p -- \\u' 57600 %I $TERM
Fixing the hardware clock between restarts
When the GnuBee boots, you may have noticed that the clock is wrong until
systemd-timesyncd
updates the time using
NTP. This leads to
messages like these:
Aug 23 02:46:15 hostname systemd-fsck[839]: GNUBEE-ROOT: Superblock last mount time is in the future.
Aug 23 02:46:15 hostname systemd-fsck[839]: #011(by less than a day, probably due to the hardware clock being incorrectly set)
...
Aug 23 02:46:41 hostname systemd[1]: systemd-fsckd.service: Succeeded.
Aug 23 13:04:30 hostname systemd-timesyncd[1309]: Synchronized to time server for the first time 162.159.200.1:123 (time.cloudflare.com).
and unnecessary executions of fsck
.
Often these hardware issues are due to a lack of a battery to keep the clock
alive while the unit is powered down. In order to work around this, I
installed the fake-hwclock
package and then edited
the /lib/systemd/system/fake-hwclock.service
file to change the following
line from:
Before=sysinit.target
to:
Before=sysinit.target systemd-fsck-root.service
so that the clock is restored before the filesystem check.
I also added the following to /etc/.gitignore
to make
etckeeper
happy:
/fake-hwclock.data
since fake-hwclock
unfortunately keeps its data file in
/etc/
.
Fixing network drops
I regularly see the GnuBee drop its network connections and nothing short of
a reboot will fix it in my experience. Not sure whether that's a
driver/kernel problem, but I decided to try to prevent it by scheduling
a daily reboot in /etc/cron.d/reboot-daily
:
30 18 * * * root /bin/grep --quiet finish= /proc/mdstat || /bin/systemctl reboot
The extra check is there to ensure that the machine doesn't reboot if it's busy re-synchronizing the RAID array.