Difference between revisions of "Use Cell Phone As LAN Gateway"

From Nearline Storage
Jump to navigation Jump to search
 
(17 intermediate revisions by the same user not shown)
Line 1: Line 1:
I'd like to use my cell phone's data connection to backup my cable modem.  In other words, when the cable goes out, I want to be able to switch my main house router over to using my cell phone as its WAN network provider.
+
I'd like to use my cell phone's 5G data connection as a backup for my cable modem.  In other words, when the cable goes out, I want to be able to switch my main house router over to using my cell phone as its WAN network provider.
  
Like most, my cell phone has both wifi hotspot and USB tethering capabilities.  My house router cannot make use of either of these.  My solution, then, is to use a Raspberry Pi computer as an intermediate, "stacked" router in between my cell phone and my house router.  The router's WAN port is connected to the Pi's ethernet port and the cell phone is tethered to one of the Pi's USB ports.
+
Like most, my cell phone has both wifi hotspot and USB tethering capabilities.  My house router cannot make use of either of these.  My solution, then, is to use an old laptop I had sitting on the shelf as an intermediate, "stacked" router in between my cell phone and my house router.  The router's WAN port is connected to the laptop's ethernet port and the cell phone is tethered to one of the laptop's USB ports.
  
No changes are required on the cell phone, other than turning off its wifi connection and turning on the USB tethering feature.  No changes are required on my router.  It will pick up its connection details from a DHCP server running on the Pi.  All that's required is to properly configure the Pi.
+
No changes are required on the cell phone, other than turning off its wifi connection and turning on the USB tethering feature.  No changes are required on my router.  It will pick up its connection details from a DHCP server running on the laptop.  All that's required is to properly configure the laptop.  I'm a long-time Fedora Linux user so ...
  
== Install Raspian ==
+
== Install Fedora ==
I installed the [https://www.raspberrypi.org/software/operating-systems/ "Lite"] version of the Raspian distribution.
+
 
 +
I used the [https://alt.fedoraproject.org network install ISO image] on a USB key to install a "minimal" Fedora server.  Be sure to create a general userid during the installation process.  Check the "Make this user administrator" box to give this user sudoer access.
  
 
== Set up sshd for remote access ==
 
== Set up sshd for remote access ==
  
Connect the Pi to the existing LAN and access it via ssh.
+
Connect to the existing LAN and install your public key in <code>~/.ssh/authorized keys</code> of the general userid you created during install.
 
 
Install your public key in <code>/home/pi/.ssh/authorized keys</code>
 
  
After confirming that access using your public key works, modify <code>/etc/ssh/sshd_config</code> to prohibit logins using passwords by uncommenting <code>PasswordAuthentication no</code>
+
After confirming that access using your public key works, modify <code>/etc/ssh/sshd_config</code> to prohibit remote logins using passwords by uncommenting <code>PasswordAuthentication no</code>
  
== Upgrade and install additional packages ==
+
== Install additional packages ==
 
<pre>
 
<pre>
sudo apt update
+
sudo dnf -y install net-tools dhcp-server dnsmasq
sudo apt update
 
sudo apt install isc-dhcp-server dnsmasq vim dnsutils
 
 
</pre>
 
</pre>
  
== Disable unnecessary network ports opened by avahi-daemon ==
+
== Configure the ethernet port with a static address ==
 +
 
 
<pre>
 
<pre>
sudo systemctl stop avahi-daemon
+
nmcli con mod enp0s25 ipv4.method manual
sudo systemctl disable avahi-daemon.socket
+
nmcli con mod enp0s25 ipv4.addresses 10.254.239.1
sudo systemctl disable avahi-daemon
+
nmcli con mod enp0s25 ipv4.routes 10.254.239.0/24 0.0.0.0
 +
nmcli con mod enp0s25 connection.zone trusted
 
</pre>
 
</pre>
  
== Configure the ethernet port with a static address ==
+
Putting this interface into firewalld's "trusted" zone allows all traffic to flow on all ports.
 
 
'''/etc/dhcpcd.conf'''
 
  
Leave the defaults in this file as is. Add a static address definition for the eth0 port:
+
If the interface is not brought up and configured during the boot process, put the following lines into <code>/etc/NetworkManager/conf.d/99-ignore-carrier.conf</code>:
 
<pre>
 
<pre>
interface eth0
+
[device]
static ip_address=10.254.239.1/24
+
match-device=interface-name:enp0s25
 +
ignore-carrier=1
 
</pre>
 
</pre>
  
== Configure and start the isc-dhcp-server ==
+
== Configure and start the dhcp-server ==
 
 
'''/etc/default/isc-dhcp-server'''
 
 
 
Set <code>INTERFACESv4="eth0"</code>
 
  
 
'''/etc/dhcp/dhcpd.conf'''
 
'''/etc/dhcp/dhcpd.conf'''
Line 59: Line 53:
 
</pre>
 
</pre>
  
Enable and start the isc-dhcp-server systemd service.
+
Enable and start the dhcpd systemd service.
  
== Prevent ssh access to the Pi from the internet ==
+
== Prevent ssh access to the laptop from the internet ==
  
 
Modify <code>/etc/ssh/sshd_config</code> and set <code>ListenAddress 10.254.239.1</code>
 
Modify <code>/etc/ssh/sshd_config</code> and set <code>ListenAddress 10.254.239.1</code>
Line 67: Line 61:
 
== Start the dnsmasq service ==
 
== Start the dnsmasq service ==
  
No configuration changes are required. Enable and start the dnsmasq systemd service.
+
In the <code>/etc/dnsmasq.conf</code> file, change:
 +
<pre>
 +
interface=lo
 +
</pre>
 +
to be
 +
<pre>
 +
interface=enp0s25
 +
</pre>
 +
 
 +
Enable and start the dnsmasq systemd service.
  
== Enable forwarding in the kernel ==
+
== Enable routing in the kernel ==
  
 
'''/etc/sysctl.d/97-dlk-router.conf'''
 
'''/etc/sysctl.d/97-dlk-router.conf'''
Line 75: Line 78:
 
net.ipv4.ip_forward=1
 
net.ipv4.ip_forward=1
 
</pre>
 
</pre>
 +
 
Then do <code>sudo sysctl -p</code>
 
Then do <code>sudo sysctl -p</code>
  
== Create firewall script ==
+
== Configure firewalld ==
 +
 
 +
I created a "router" zone in firewalld which will allow all traffic to flow like the "trusted" zone does and will do masquerading like the "external" zone does.  This will be set to be the default zone so that any adapters added to the laptop, like our cell phone's tether, will be put into this zone by NetworkManager.
  
'''/etc/network/if-pre-up.d/iptables'''
 
 
<pre>
 
<pre>
#!/bin/sh
+
firewall-cmd --new-zone=router --permanent
 
+
firewall-cmd --zone=router --set-description="Wide open zone with masqueradingUsed for externally facing router interfaces." --permanent
#  Set up rules for a router that tethers my cell phone
+
firewall-cmd --zone=router --set-target=ACCEPT --permanent
#  and acts as a replacement for the cable modem in my
+
firewall-cmd --zone=router --add-masquerade --permanent
#  network when the cable goes out.
+
firewall-cmd --zone=router --add-rich-rule="rule port port=22 protocol=tcp drop" --permanent
#
+
firewall-cmd --zone=router --add-rich-rule="rule port port=53 protocol=tcp drop" --permanent
#  There's wide open flow between the cell phone interface
+
firewall-cmd --zone=router --add-rich-rule="rule port port=53 protocol=udp drop" --permanent
#  and the ethernet interfaceWe're only concerned about
+
firewall-cmd --zone=router --add-rich-rule="rule port port=67 protocol=tcp drop" --permanent
#  blocking external access to services on the router itself.
+
firewall-cmd --zone=router --add-rich-rule="rule port port=67 protocol=udp drop" --permanent
 
+
firewall-cmd --zone=router --add-rich-rule="rule port port=323 protocol=udp drop" --permanent
#  usb0: the tethered cell phone
+
firewall-cmd --zone=router --add-rich-rule="rule port port=5353 protocol=udp drop" --permanent
IF=usb0
+
firewall-cmd --reload
 
+
firewall-cmd --set-default-zone=router
#  Set up masquerading in the nat table
 
/usr/sbin/iptables -t nat -F
 
/usr/sbin/iptables -t nat -P PREROUTING ACCEPT
 
/usr/sbin/iptables -t nat -P INPUT ACCEPT
 
/usr/sbin/iptables -t nat -P OUTPUT ACCEPT
 
/usr/sbin/iptables -t nat -P POSTROUTING ACCEPT
 
/usr/sbin/iptables -t nat -A POSTROUTING -o $IF -j MASQUERADE
 
 
 
#  Completely open access on all interfaces
 
/usr/sbin/iptables -F
 
/usr/sbin/iptables -P INPUT ACCEPT
 
/usr/sbin/iptables -P FORWARD ACCEPT
 
/usr/sbin/iptables -P OUTPUT ACCEPT
 
 
 
#  Block inbound ssh, dns, and dhcp traffic from the internet just
 
#  to be safe (the daemons should already be ignoring these ports)
 
/usr/sbin/iptables -A INPUT -i $IF -p tcp --dport 22 -j DROP
 
/usr/sbin/iptables -A INPUT -i $IF -p tcp --dport 53 -j DROP
 
/usr/sbin/iptables -A INPUT -i $IF -p udp --dport 53 -j DROP
 
/usr/sbin/iptables -A INPUT -i $IF -p udp --dport 67 -j DROP
 
/usr/sbin/iptables -A INPUT -i $IF -p udp --dport 68 -j DROP
 
 
</pre>
 
</pre>
 
Then do <code>chown 0:0 /etc/network/if-pre-up.d/iptables</code> and <code>chmod a+x /etc/network/if-pre-up.d/iptables</code>.  Run the script.
 
  
 
== Testing the router ==
 
== Testing the router ==
  
Power on the Pi.
+
Power on the laptop and connect a PC to the laptop's ethernet port.  The PC should obtain an address in the 10.254.239.0/24 subnet from DHCP on the laptop.  If the PC doesn't immediately get an address, it may be necessary to restart the dhcpd service on the laptop.
  
* The Pi can be run headless but a monitor and keyboard make it easier to monitor the Pi and fix any problems that occur.
+
Restart the dnsmasq service on the laptop.  It does not connect to the ethernet interface unless it is active when dnsmasq starts up.
  
Connect a PC to the Pi's ethernet port.  The PC should obtain an address in the 10.254.239.0/24 subnet from DHCP on the Pi.  Make sure that this is only active connection on the PC, i.e., turn off any wireless connections the PC may have, etc.
+
Turn off any other network connections the PC may have.
  
Connect the cell phone to a USB port on the Pi and turn off its wifi connection and turn on its tethering function.  You should be able to watch the Pi's log using <code>journalctl -f</code> and see the usb0 connection come up on the Pi.
+
Connect the cell phone to a USB port on the laptop and turn off its wifi connection and turn on its tethering function.  You should be able to watch the laptop's log using <code>journalctl -f</code> and see the new connection come up on the laptop.
  
 
The PC should now be able to use the internet as normal.
 
The PC should now be able to use the internet as normal.
  
Login to the Pi and check the ports it is exposing.  Disable services or adjust the firewall rules script as necessary.
+
Login to the laptop and check the ports it is exposing.  Disable services or adjust firewalld's rich rules as necessary.
 +
 
 
<pre>
 
<pre>
pi@raspberrypi:~ $ sudo netstat -tulpn
+
[root@router ~]# netstat -tulpn
 
Active Internet connections (only servers)
 
Active Internet connections (only servers)
 
Proto Recv-Q Send-Q Local Address          Foreign Address        State      PID/Program name     
 
Proto Recv-Q Send-Q Local Address          Foreign Address        State      PID/Program name     
tcp        0      0 0.0.0.0:53             0.0.0.0:*              LISTEN      478/dnsmasq         
+
tcp        0      0 0.0.0.0:5355            0.0.0.0:*              LISTEN      542/systemd-resolve
tcp        0      0 10.254.239.1:22         0.0.0.0:*              LISTEN      482/sshd          
+
tcp        0      0 127.0.0.1:53           0.0.0.0:*              LISTEN      574/dnsmasq         
tcp6      0      0 :::53                   :::*                    LISTEN      478/dnsmasq         
+
tcp        0      0 127.0.0.53:53          0.0.0.0:*              LISTEN      542/systemd-resolve
udp        0      0 0.0.0.0:53             0.0.0.0:*                          478/dnsmasq         
+
tcp        0      0 0.0.0.0:22             0.0.0.0:*              LISTEN      575/sshd: /usr/sbin
udp        0      0 0.0.0.0:67              0.0.0.0:*                          542/dhcpd           
+
tcp6      0      0 :::5355                :::*                    LISTEN      542/systemd-resolve
udp        0      0 0.0.0.0:68              0.0.0.0:*                          463/dhcpcd         
+
tcp6      0      0 ::1:53                 :::*                    LISTEN      574/dnsmasq         
udp6      0      0 :::53                   :::*                                478/dnsmasq
+
tcp6      0      0 :::22                  :::*                    LISTEN      575/sshd: /usr/sbin
 +
udp        0      0 0.0.0.0:5355            0.0.0.0:*                          542/systemd-resolve
 +
udp        0      0 127.0.0.1:53           0.0.0.0:*                          574/dnsmasq         
 +
udp        0      0 127.0.0.53:53          0.0.0.0:*                          542/systemd-resolve
 +
udp        0      0 0.0.0.0:67              0.0.0.0:*                          612/dhcpd           
 +
udp        0      0 127.0.0.1:323          0.0.0.0:*                          566/chronyd       
 +
udp6      0      0 :::5355                :::*                                542/systemd-resolve
 +
udp6      0      0 ::1:53                 :::*                                574/dnsmasq        
 +
udp6      0      0 ::1:323                :::*                                566/chronyd
 
</pre>
 
</pre>
  
Check the iptables configuration:
+
Check the firewalld configuration:
 +
 
 
<pre>
 
<pre>
pi@raspberrypi:~ $ sudo iptables -t nat -L -v -n
+
[root@router ~]# firewall-cmd --list-all-zones
Chain PREROUTING (policy ACCEPT 41552 packets, 3577K bytes)
+
FedoraServer
pkts bytes target     prot opt in    out    source               destination       
+
  target: default
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: cockpit dhcpv6-client ssh
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
 +
 
 +
FedoraWorkstation
 +
  target: default
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: dhcpv6-client samba-client ssh
 +
  ports: 1025-65535/udp 1025-65535/tcp
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
 +
 
 +
block
 +
  target: %%REJECT%%
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services:
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
 +
 
 +
dmz
 +
  target: default
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: ssh
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
 +
 
 +
drop
 +
  target: DROP
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services:
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
 +
 
 +
external
 +
  target: default
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: ssh
 +
  ports:
 +
  protocols:
 +
  masquerade: yes
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
 +
 
 +
home
 +
  target: default
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: dhcpv6-client mdns samba-client ssh
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
  
Chain INPUT (policy ACCEPT 5945 packets, 482K bytes)
+
internal
pkts bytes target     prot opt in    out    source               destination       
+
  target: default
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: dhcpv6-client mdns samba-client ssh
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
  
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
+
nm-shared
pkts bytes target    prot opt in    out    source               destination       
+
  target: ACCEPT
23677 2174K MASQUERADE  all  --  *      usb0    0.0.0.0/0            0.0.0.0/0         
+
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: dhcp dns ssh
 +
  ports:
 +
  protocols: icmp ipv6-icmp
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
 +
rule priority="32767" reject
  
Chain OUTPUT (policy ACCEPT 597 packets, 42913 bytes)
+
public
pkts bytes target     prot opt in    out    source               destination       
+
  target: default
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: dhcpv6-client mdns ssh
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
  
Chain POSTROUTINGING (0 references)
+
router (active)
pkts bytes target     prot opt in    out    source              destination
+
  target: ACCEPT
</pre>
+
  icmp-block-inversion: no
<pre>
+
  interfaces: enp14s0u2
pi@raspberrypi:~ $ sudo iptables -L -v -n
+
  sources:
Chain INPUT (policy ACCEPT 19754 packets, 1515K bytes)
+
  services:  
pkts bytes target    prot opt in    out    source              destination       
+
  ports:
    0    0 DROP      tcp  --  usb0   *      0.0.0.0/0            0.0.0.0/0            tcp dpt:22
+
  protocols:
    0    0 DROP      tcp  -- usb0   *      0.0.0.0/0            0.0.0.0/0            tcp dpt:53
+
   masquerade: yes
    0    0 DROP      udp  --  usb0   *      0.0.0.0/0            0.0.0.0/0            udp dpt:53
+
  forward-ports:
    0    0 DROP      udp --  usb0  *      0.0.0.0/0            0.0.0.0/0            udp dpt:67
+
  source-ports:
  145 50750 DROP      udp --  usb0  *      0.0.0.0/0            0.0.0.0/0            udp dpt:68
+
   icmp-blocks:  
 +
   rich rules:  
 +
rule port port="22" protocol="tcp" drop
 +
rule port port="53" protocol="tcp" drop
 +
rule port port="53" protocol="udp" drop
 +
rule port port="67" protocol="udp" drop
 +
rule port port="67" protocol="tcp" drop
 +
rule port port="323" protocol="udp" drop
 +
rule port port="5353" protocol="udp" drop
  
Chain FORWARD (policy ACCEPT 298K packets, 172M bytes)
+
trusted (active)
pkts bytes target     prot opt in    out    source               destination       
+
  target: ACCEPT
 +
  icmp-block-inversion: no
 +
  interfaces: enp0s25
 +
  sources:
 +
  services:
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
  
Chain OUTPUT (policy ACCEPT 20143 packets, 2172K bytes)
+
work
pkts bytes target     prot opt in    out    source               destination       
+
  target: default
 +
  icmp-block-inversion: no
 +
  interfaces:
 +
  sources:
 +
  services: dhcpv6-client mdns ssh
 +
  ports:
 +
  protocols:
 +
  masquerade: no
 +
  forward-ports:
 +
  source-ports:
 +
  icmp-blocks:
 +
  rich rules:
 
</pre>
 
</pre>
  
Line 185: Line 335:
 
When the cable modem dies, unplug it from the home router.
 
When the cable modem dies, unplug it from the home router.
  
Connect the home router to the Pi's ethernet port and power up the Pi.
+
Connect the home router to the laptop's ethernet port and power up the laptop.
 
 
* The Pi can be run headless but a monitor and keyboard make it easier to monitor the Pi and fix any problems that occur.
 
  
Connect the phone to the Pi's USB port and turn off its wifi connection and turn on its tethering feature.
+
Connect the phone to the laptop's USB port and turn off its wifi connection and turn on its tethering feature.
  
 
The devices on your LAN should now have network access as usual.
 
The devices on your LAN should now have network access as usual.
  
 
Know that the longer you run this way, the more astronomical will be the data charges on your cell phone bill.
 
Know that the longer you run this way, the more astronomical will be the data charges on your cell phone bill.

Latest revision as of 15:50, 11 March 2021

I'd like to use my cell phone's 5G data connection as a backup for my cable modem. In other words, when the cable goes out, I want to be able to switch my main house router over to using my cell phone as its WAN network provider.

Like most, my cell phone has both wifi hotspot and USB tethering capabilities. My house router cannot make use of either of these. My solution, then, is to use an old laptop I had sitting on the shelf as an intermediate, "stacked" router in between my cell phone and my house router. The router's WAN port is connected to the laptop's ethernet port and the cell phone is tethered to one of the laptop's USB ports.

No changes are required on the cell phone, other than turning off its wifi connection and turning on the USB tethering feature. No changes are required on my router. It will pick up its connection details from a DHCP server running on the laptop. All that's required is to properly configure the laptop. I'm a long-time Fedora Linux user so ...

Install Fedora

I used the network install ISO image on a USB key to install a "minimal" Fedora server. Be sure to create a general userid during the installation process. Check the "Make this user administrator" box to give this user sudoer access.

Set up sshd for remote access

Connect to the existing LAN and install your public key in ~/.ssh/authorized keys of the general userid you created during install.

After confirming that access using your public key works, modify /etc/ssh/sshd_config to prohibit remote logins using passwords by uncommenting PasswordAuthentication no

Install additional packages

sudo dnf -y install net-tools dhcp-server dnsmasq

Configure the ethernet port with a static address

nmcli con mod enp0s25 ipv4.method manual
nmcli con mod enp0s25 ipv4.addresses 10.254.239.1
nmcli con mod enp0s25 ipv4.routes 10.254.239.0/24 0.0.0.0
nmcli con mod enp0s25 connection.zone trusted

Putting this interface into firewalld's "trusted" zone allows all traffic to flow on all ports.

If the interface is not brought up and configured during the boot process, put the following lines into /etc/NetworkManager/conf.d/99-ignore-carrier.conf:

[device]
match-device=interface-name:enp0s25
ignore-carrier=1

Configure and start the dhcp-server

/etc/dhcp/dhcpd.conf

default-lease-time 600;
max-lease-time 7200;
ddns-update-style none;
authoritative;
subnet 10.254.239.0 netmask 255.255.255.0 {
  range 10.254.239.20 10.254.239.254;
  option broadcast-address 10.254.239.255;
  option routers 10.254.239.1;
}

Enable and start the dhcpd systemd service.

Prevent ssh access to the laptop from the internet

Modify /etc/ssh/sshd_config and set ListenAddress 10.254.239.1

Start the dnsmasq service

In the /etc/dnsmasq.conf file, change:

interface=lo

to be

interface=enp0s25

Enable and start the dnsmasq systemd service.

Enable routing in the kernel

/etc/sysctl.d/97-dlk-router.conf

net.ipv4.ip_forward=1

Then do sudo sysctl -p

Configure firewalld

I created a "router" zone in firewalld which will allow all traffic to flow like the "trusted" zone does and will do masquerading like the "external" zone does. This will be set to be the default zone so that any adapters added to the laptop, like our cell phone's tether, will be put into this zone by NetworkManager.

firewall-cmd --new-zone=router --permanent
firewall-cmd --zone=router --set-description="Wide open zone with masquerading.  Used for externally facing router interfaces." --permanent
firewall-cmd --zone=router --set-target=ACCEPT --permanent
firewall-cmd --zone=router --add-masquerade --permanent
firewall-cmd --zone=router --add-rich-rule="rule port port=22 protocol=tcp drop" --permanent
firewall-cmd --zone=router --add-rich-rule="rule port port=53 protocol=tcp drop" --permanent
firewall-cmd --zone=router --add-rich-rule="rule port port=53 protocol=udp drop" --permanent
firewall-cmd --zone=router --add-rich-rule="rule port port=67 protocol=tcp drop" --permanent
firewall-cmd --zone=router --add-rich-rule="rule port port=67 protocol=udp drop" --permanent
firewall-cmd --zone=router --add-rich-rule="rule port port=323 protocol=udp drop" --permanent
firewall-cmd --zone=router --add-rich-rule="rule port port=5353 protocol=udp drop" --permanent
firewall-cmd --reload
firewall-cmd --set-default-zone=router

Testing the router

Power on the laptop and connect a PC to the laptop's ethernet port. The PC should obtain an address in the 10.254.239.0/24 subnet from DHCP on the laptop. If the PC doesn't immediately get an address, it may be necessary to restart the dhcpd service on the laptop.

Restart the dnsmasq service on the laptop. It does not connect to the ethernet interface unless it is active when dnsmasq starts up.

Turn off any other network connections the PC may have.

Connect the cell phone to a USB port on the laptop and turn off its wifi connection and turn on its tethering function. You should be able to watch the laptop's log using journalctl -f and see the new connection come up on the laptop.

The PC should now be able to use the internet as normal.

Login to the laptop and check the ports it is exposing. Disable services or adjust firewalld's rich rules as necessary.

[root@router ~]# netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:5355            0.0.0.0:*               LISTEN      542/systemd-resolve 
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      574/dnsmasq         
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      542/systemd-resolve 
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      575/sshd: /usr/sbin 
tcp6       0      0 :::5355                 :::*                    LISTEN      542/systemd-resolve 
tcp6       0      0 ::1:53                  :::*                    LISTEN      574/dnsmasq         
tcp6       0      0 :::22                   :::*                    LISTEN      575/sshd: /usr/sbin 
udp        0      0 0.0.0.0:5355            0.0.0.0:*                           542/systemd-resolve 
udp        0      0 127.0.0.1:53            0.0.0.0:*                           574/dnsmasq         
udp        0      0 127.0.0.53:53           0.0.0.0:*                           542/systemd-resolve 
udp        0      0 0.0.0.0:67              0.0.0.0:*                           612/dhcpd           
udp        0      0 127.0.0.1:323           0.0.0.0:*                           566/chronyd         
udp6       0      0 :::5355                 :::*                                542/systemd-resolve 
udp6       0      0 ::1:53                  :::*                                574/dnsmasq         
udp6       0      0 ::1:323                 :::*                                566/chronyd

Check the firewalld configuration:

[root@router ~]# firewall-cmd --list-all-zones
FedoraServer
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: cockpit dhcpv6-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

FedoraWorkstation
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client samba-client ssh
  ports: 1025-65535/udp 1025-65535/tcp
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

block
  target: %%REJECT%%
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: 
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

dmz
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

drop
  target: DROP
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: 
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

external
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: ssh
  ports: 
  protocols: 
  masquerade: yes
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

home
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client mdns samba-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

internal
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client mdns samba-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

nm-shared
  target: ACCEPT
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcp dns ssh
  ports: 
  protocols: icmp ipv6-icmp
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
	rule priority="32767" reject

public
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client mdns ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

router (active)
  target: ACCEPT
  icmp-block-inversion: no
  interfaces: enp14s0u2
  sources: 
  services: 
  ports: 
  protocols: 
  masquerade: yes
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
	rule port port="22" protocol="tcp" drop
	rule port port="53" protocol="tcp" drop
	rule port port="53" protocol="udp" drop
	rule port port="67" protocol="udp" drop
	rule port port="67" protocol="tcp" drop
	rule port port="323" protocol="udp" drop
	rule port port="5353" protocol="udp" drop

trusted (active)
  target: ACCEPT
  icmp-block-inversion: no
  interfaces: enp0s25
  sources: 
  services: 
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

work
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client mdns ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:

Using the router

When the cable modem dies, unplug it from the home router.

Connect the home router to the laptop's ethernet port and power up the laptop.

Connect the phone to the laptop's USB port and turn off its wifi connection and turn on its tethering feature.

The devices on your LAN should now have network access as usual.

Know that the longer you run this way, the more astronomical will be the data charges on your cell phone bill.