06 May 2020 - tsp
Last update 29 May 2022
19 mins
Since a friend required this - this is a short write-up on how to use your RaspberryPi (with FreeBSD) with an UMTS/LTE modem to provide internet connectivity to your local network. Note that I still do not believe that it’s a good idea to use mobile networks as any way of internet connectivity (to be fair I don’t see them as being internet connections in most cases at all). But there might be reasons to do this - for example if you’re really running a mobile node (If you’re running a system at a fixed location you should really use a fixed landline - no matter what medium - instead of a radio based system).
First off. This is of course an do-it-yourself solution and there are plenty of buy-able ready to use devices out there. The main advantage of doing such things for by oneself is the flexibility one gains. One can run arbitrary software on the RaspberryPi (as long as it compiles on the OS that’s going to be used), one can do fancy network configurations, etc. And one can keep it up to date by oneself.
I’m going to use FreeBSD as the operating system even on the RaspberryPi. I’m choosing this over Linux mainly because of personal preference - I like the long term consistency, the development approach and the adherence to Unix specifications when implementing base commands. And I like the simplicity of FreeBSD compared with other platforms - even on the RaspberryPi where the boot process is done using U-Boot.
Note: Links provided are Amazon affiliate links. Qualified purchases will lead to some profit for the author of this page (it doesn’t change the price for you).
First one has to install the operating system. One can download the
latest FreeBSD release. One can locate the release on the
FreeBSD download page. Be sure to
use either RPI-B
, RPI2
or RPI3
depending on the hardware
you’re using.
First simply download the image. It comes as an .xz
archive that has
to be uncompressed first. On FreeBSD you can do this with
unxz IMAGE.xz
for the 12.1 Release one could for example simply do
fetch https://download.freebsd.org/ftp/releases/arm64/aarch64/ISO-IMAGES/12.1/FreeBSD-12.1-RELEASE-arm64-aarch64-RPI3.img.xz
unxz FreeBSD-12.1-RELEASE-arm64-aarch64-RPI3.img.xz
On Windows one might use use a tool like 7-Zip. On
Mac OS X one also has the unxz
command (or xz -d IMAGE.xz
) command
available.
After that one has to flash the image onto the SD card. On most Unices this
is done using dd
. This might require root privileges since raw disk
access (i.e. use sudo
) is required because dd destroys potential file system
data on the SD card. Be sure to write to the correct disk. On Unices you can look
into dmesg
output, insert the SD card and immediately look at dmesg
again. You’ll see the device name of the newly attached device (for example adaN
or similar). Now one can use dd
to write the image to the disk:
dd if=IMAGE.img of=/dev/adaN
for the previously mentioned image that would be
dd if=FreeBSD-12.1-RELEASE-arm64-aarch64-RPI3.img of=/dev/adaN
On Windows a tool like Win32DiskImager might be used to write onto the specific SD card. Be sure to select the right one again!
On any OS - beware that if you write onto the wrong disk there is no way of recovering your data!
Now you can insert the SD card into your RasberryPi and do the remaining configuration either with a local monitor and keyboard or via a (trusted) network. If you initially boot your RaspberryPi using FreeBSD as operating system it will use DHCP to get an IP address if this is supported on your network and start sshd to allow access using either
raspberry
and password raspberry
freebsd
and password freebsd
The default root
password (who is not allowed to login via SSH) is
normally set to root
If you do setup via network please set all passwords to non default values
using the passwd
command first (this is also a good idea when setting
up without a network connection). Once for the user you log in with:
$ passwd
And once for root
after you’ve elevated into the root
account:
$ su
$ passwd
$ exit
The most simple way of setting date and time is using the network time protocol. This step is required as soon as some data is downloaded from the network and signatures or an revision control system is used. If your system has been attached to an ethernet based network configured via DHCP you can directly use:
ntpdate pool.ntp.org
If note one can set the current date and time using date
(note that
the raspberry will loose this information on every reboot since it doesn’t
contain a RTC. It’s possible of attaching one but as long as you’re using
it as internet gateway one can also use ntpdate
automatically on
boot and then it’s a good idea to track the current time using ntpd
anyways)
To use the NTP daemon one has to edit /etc/ntpd.conf
. A typical
minimal configuration would look like the following:
tos minclock 3 maxclock 6
server 0.at.pool.ntp.org
server 1.at.pool.ntp.org
server 2.at.pool.ntp.org
server 3.at.pool.ntp.org
restrict default limited kod nomodify notrap noquery nopeer
restrict source limited kod nomodify notrap noquery
restrict 127.0.0.1
restrict ::1
leapfile "/var/db/ntpd.leap-seconds.list"
After that one can launch ntpd using
/etc/rc.d/ntpd onestart
One can also make that change permanent by adding to /etc/rc.conf
:
ntpd_enable="YES"
Note that ntpd
only adjusts the time if the offset is small enough (i.e.
it only compensates clock drift). To run ntpdate
on bootup after
networks have been configured one can also add
ntpdate_enable="YES"
to ones rc.conf
. This should be done on RaspberryPi without an external
realtime-clock since ntpd
won’t adjust the initial time due to too large
time differences. Note that this requires one to have an network connection
up and running already.
If one wants to set the date and time during normal operation using ntpdate
one has to stop a running ntpd
:
/etc/rc.d/ntpd stop
ntpdate
/etc/rc.d/ntpd start
Also note that that ntpd
is loading a kernel module to deploy a
mandatory access control module that allows ntpd to set the date and time
without running with root privileges at any time.
Now it’s a good idea to connect yourself to a network. How you do this depends
on your current networking situation. If you have a wired network with internet
connectivity available it might be convenient to use the existing internet
connection to perform the setup steps. If you’ve connected your PaspberryPi
to your network during bootup and your network performs auto configuration
it should already be configured using DHCP
(IPv4, DNS servers)
and SLAAC
(IPv6). If not we should first setup the required LTE connection.
In already connected cases you can of course do this later so that you don’t
have to mess around with default routes to perform setup via your faster
landline.
Some USB modems like the one I’m using are announcing themselves as USB
CD devices to allow “easy” installation of drivers on some operating systems
and are required to be reinitialized so that they can be used as a modem
permanently. This can be done using the usb_modeswitch
utility. To install
that utility one has to have some kind of network connection before doing
the UMTS/LTE setup. Then one can install the tool using
$ su
$ pkg install sysutils/usb_modeswitch
After installation and attachment of the modem one
can use usb_modeswitch
to permanently force the device into
modem mode instead of virtual CD-ROM mode - there is also the possibility
of doing this on every attachment by adding usb_modeswitch into devd or devfs
rules but I won’t cover this here.
To switch the device into modem mode for Huawei modems temporarily one can use
$ usb_modeswitch -v 12d1 -p 1c0b -M '55534243123456780000000000000011062000000100000000000000000000'
Note that the product and vendor ID might be different. One can list all attached
usb devices using usbconfig
Instead of using some cryptic command one can also look into /usr/local/share/usb_modeswitch/
using ls -l
- if there is a matching vendor and product ID for one’s own
USB modem one can simply use
$ usb_modeswitch -v 12d1 -p 1c0b -c /usr/local/share/usb_modeswitch/12d1:1c0b
to permanently disable virtual CD mode.
On my systems I’m currently using a short rc.init
script - i.e. a file
in /usr/local/etc/rc.d/usbmodeswitch
that performs the modeswitch on
every boot:
#!/bin/sh
# PROVIDE: usbmodeswitch
# REQUIRE: FILESYSTEMS
# BEFORE: ppp
# usb modeswitch script for Huawei modem
# with sysutils/usb_modeswitch
. /etc/rc.subr
name="usbmodeswitch"
start_cmd="usbmodeswitch_start"
stop_cmd=":"
rcvar="usbmodeswitch_enable"
usbmodeswitch_start()
{
/usr/local/sbin/usb_modeswitch -v 0x12d1 -p 0x1f01 -V 0x12d1 -P 0x14dc -M "55534243123456780000000000000011063000000100010000000000000000"
/bin/sleep 10
}
load_rc_config $name
run_rc_command "$@"
This is enabled by the following /etc/rc.conf
entry:
usbmodeswitch_eable="YES"
To setup the LTE connection one has to configure pppd
. This daemon
is capable of connecting to various PPP
services (not through
PPTP for DSL Modems, this can be done using mpd5
as described
in one of my previous articles).
Note that you have to do most modifications with root privileges so first
elevate yourself to root
:
$ su
First one has to determine which device one is going to use. All devices
that are used to communicate with modems (any many more) will be listed in the
device filesystem at /dev/
. To list the currently available files
one can use
ls /dev/
Since we know that our device will be emulating an UART device
via USB we can look only at cuaU
devices.
ls /dev/cuaU*
Most of the USB 3G/4G/5G modems expose multiple serial interfaces for different
functionality so one might have to do some experimentation. In my case it’s
the /dev/cuaU0.0
device that is going to be used (and my modem also
exposes the interfaces cuaU0.1
and cuaU0.2
for short message system
and voice communications). Normally these files should already belong to
the uucp
user and dialer
group with read and write permissions
for user and group.
The configuration of pppd
happens primarily via /etc/ppp/ppp.conf
.
It’s segmented into various profiles. To edit the file one can use one
of the many editors available (vi
for more advanced users, ee
might be a better choice for beginners).
Then you can simply use the editor to edit PPP configuration:
$ ee /etc/ppp/ppp.conf
On most setups I’m currently using a default configuration like the following:
default:
set log Phase Chat Connect LCP IPCP CCP command Warning Error Alert tun
ident user-ppp VERSION
Without going into to much default this configures the steps taken during buildup of a PPP session and describes which optional features are supported and should be used. Now there is a single profile for every network provider that one’s going to use. For example I’ve configured one for Drei in Austria using the following settings:
drei:
disable ipv6cp
disable mppe lqr deflate deflate24 acfcomp vjcomp pred1 protocomp
set device /dev/cuaU0.0
# set speed 921600
set speed 115200
set timeout 300
nat enable yes
set dial "ABORT BUSY ABORT \"NO\\sCARRIER\" ABORT \"ERROR\" TIMEOUT 10 \
\"\" \
AT OK-AT-OK \
AT+CFUN=1 OK-AT-OK \
AT+CMEE=2 OK-AT-OK \
AT+CSQ OK \
AT+CGDCONT=1,\\\"ip\\\",\\\"drei.at\\\" OK \
ATD*99***1# CONNECT"
enable dns
resolv writable
set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.255 0.0.0.0
add default HISADDR
This configuration is rather complex:
/dev/cuaU0.0
with a baud rate of 921600.pppd
can do this
directly for us. If one needs more fancy configuration like port forwards, etc.
one should of course continue to use natd
and set this property to no.CGDCONT
). The domain
specifies sets the APN
that is used by your network provider. At the
end ATD
starts the dialing processdns
and update the /etc/resolv.conf
file so
local application use the DNS server supplied by the provider and
are capable of resolving domain names.After this configuration has been saved one can edit /etc/rc.conf
and
add appropriate lines:
ppp_profile="drei"
ppp_nat="YES"
ppp_mode="auto"
If one wants to run pppd
as root:
ppp_user="root"
After saving rc.conf
and leaving the editor one can test the PPP
connection using
$ /etc/rc.d/ppp onestart
If one can connect to the outside world (for example trying to ping www.google.com
)
and everything works one can make the startup of pppd
permanent and
launch it on boot by adding the following to /etc/rc.conf
ppp_enable="YES"
Now the internet connection is working.
If the gateway box will also be the DHCP server one need to configure the ethernet
interface with a static address. This is again done in /etc/rc.conf
.
To set a static IP address of 10.5.0.1
with an 24 bit netmask (255.255.255.0
)
one might include:
ifconfig_ue0="inet 10.5.0.1 netmask 255.255.255.0"
If one also has an static IPv6 address one should add this (of course with the correct IPv6 prefix specified):
ipv6_ifconfig_ue0="FFFF:FFFF:FFFF:FFFF::1 prefixlen 64"
If one wants to use the RaspberryPi also as DHCP server (i.e. the server
that distributed IP addresses and configures DNS servers) to the local network
one should run isc-dhcpd
. This is provided in the net/dhcpd
package
and can be installed using
$ su
$ pkg install net/dhcpd
The configuration is rather simple and happens in /usr/local/etc/dhcpd.conf
The main options I’m normally setting is:
option domain-name
should supply the local domain name (if any). This has
to be a domain name you’re controlling. You should never ever be tempted
to use a suffix like .local
or a domain that you’re not controlling
since that might lead to major problems later on (.local
is for example
used by mDNS)option domain-name-servers
points to one or more DNS servers. One might
specify public DNS servers here if one doesn’t run a local DNS cache or one
might specify the RaspberryPi’s own address - then all clients will
use the RaspberryPi as DNS resolver.default-lease-time
and max-lease-time
specify the duration
in seconds that an IP address is by default delegated to a client and
of course the maximum time it can be renewed without being re-assigned.authoritative
(if one doesn’t know
what this means this should be the case …)For example the configuration might look like the following:
option domain-name "example.com";
option domain-name-servers 10.5.0.1;
default-lease-time 1440;
max-lease-time 10080;
ddns-update-style none;
authoritative;
log-facility local7;
subnet 10.5.0.1 netmask 255.255.255.0 {
range 10.5.0.100 10.5.0.200;
option routers 10.5.0.1;
option subnet-mask 255.255.255.0;
option ntp-servers 86.59.113.124;
option time-offset 2;
option broadcast-address 10.5.0.255;
}
As one can see the sample configuration not only configures the range from
which DHCP addresses are assigned but also the default gateway (routers
)
as well as an ntp-server
and an time-offset
(i.e. Timezone).
There are of course many more options one might set - depending on ones own
network (automatic configuration for SMTP servers, domain names, etc.).
One can also add static host declarations for hosts that always should get the same address assigned (for example when they’re providing servers). It’s a nice idea to do this using DHCP too so one only has one central configuration store:
host hostwithsamplename {
hardware ethernet AA:BB:CC:DD:EE:FF:00;
fixed-address 10.5.0.201;
}
Note that the fixed-address
has not to be included in the DHCP range
specified above! The hardware-ethernet
address is the MAC address of
the device that should be assigned that static address. If one’s also
running an own DNS zone (might be interesting too) one can also use symbolic
names instead of IP addresses for the host configuration - and of course also
for NTP servers, etc.
Then one can add automatic launch of dhcpd to /etc/rc.conf
:
dhcpd_enable="YES"
dhcpd_flags="-q"
dhcpd_conf="/usr/local/etc/dhcpd.conf"
dhcpd_ifaces="ue0"
dhcpd_withumask="022"
dhcpd_chuser_enable="YES"
dhcpd_withuser="dhcpd"
dhcpd_withgroup="dhcpd"
dhcpd_chroot_enable="YES"
dhcpd_devfs_enable="YES"
dhcd_rootdir="/var/db/dhcpd"
See for example
If I get some more time I’ll also add either here or (more likely) as separate posts:
ipfw
firewallThis article is tagged:
Dipl.-Ing. Thomas Spielauer, Wien (webcomplains389t48957@tspi.at)
This webpage is also available via TOR at http://rh6v563nt2dnxd5h2vhhqkudmyvjaevgiv77c62xflas52d5omtkxuid.onion/