A firewall is software that closes ports to prevent either hacking (from the outside) or telemetry (from the inside). Servers traditionally receive the brunt of outside attempts, while clients (phones, notebooks, work stations) may have untrusted apps installed. We look at Linux servers and clients, and briefly at Windows clients.
Two network protocols are typically used today (on the transport layer):
The majority of connections are tcp
because they
are more stable, delivering information if something goes wrong;
however all this comes with a performance cost.
Gaming and other quickness-oriented applications use
udp
and do not care if one packet or the other gets lost,
as long as everything is fast. Some
services
may use both, typically udp
for quickness with a
tcp
fall-back.
Every connection has a source (client) and destination (server).
When a client initiates a connection to a server
protocol:ip:port
, it also has to tell the server
where to send the reply, as in client protocol:ip:port
.
Server ports are typically in the range 0..1024
(well-known ports)
while client ports are typically in the range
49152..65535
(ephemeral ports).
Servers may, after an initial tcp connection, switch to an
ephemeral port for the remainder of the communication.
From my personal experience, any tcp port above 10000
and any udp port above 1024
seems to be treated
as ephemeral.
On a Linux server, typical incoming ports are
22
(ssh, tcp+udp),
443
(https, tcp),
and sometimes
67
(dhcp server, udp),
993
(imaps, tcp)
or
995
(pop3s, tcp),
and
989-990
(ftps, tcp).
Typical outgoing ports include all of the
above and additionally
20-21
(ftp, tcp),
53
(dns, udp+tcp),
68
(dhcp client, udp),
80
(http, tcp),
123
(ntp, udp),
465
(smtps, tcp)
and 8245
(dyndns, tcp).
We first look at the console to see which services are transmitting data:
netstat -a --tcp --udp iptraf-ng
... and then go the old-fashioned
iptables
way:
# this host (input): iptables -A INPUT -p icmp -j ACCEPT iptables -A INPUT -p tcp --dport ssh -j ACCEPT iptables -A INPUT -p tcp --dport https -j ACCEPT iptables -A INPUT -p tcp --dport imaps -j ACCEPT iptables -A INPUT -p udp --dport 1024:65535 -j ACCEPT iptables -A INPUT -p tcp --dport 10000:65535 -j ACCEPT iptables -A INPUT -p tcp ! --syn -j ACCEPT # this host (output): iptables -A OUTPUT -p icmp -j ACCEPT iptables -A OUTPUT -p tcp --dport ssh -j ACCEPT iptables -A OUTPUT -p tcp --dport https -j ACCEPT iptables -A OUTPUT -p tcp --dport http -j ACCEPT iptables -A OUTPUT -p tcp --dport ftp -j ACCEPT iptables -A OUTPUT -p tcp --dport ftp-data -j ACCEPT iptables -A OUTPUT -p udp --dport ntp -j ACCEPT iptables -A OUTPUT -p tcp --dport domain -j ACCEPT iptables -A OUTPUT -p udp --dport domain -j ACCEPT iptables -A OUTPUT -p tcp --dport pop3 -j ACCEPT iptables -A OUTPUT -p tcp --dport smtps -j ACCEPT iptables -A OUTPUT -p udp --dport 1024:65535 -j ACCEPT iptables -A OUTPUT -p tcp --dport 10000:65535 -j ACCEPT iptables -A OUTPUT -p tcp ! --syn -j ACCEPT # restrict access conservatively: iptables -P FORWARD DROP iptables -P INPUT DROP iptables -P OUTPUT DROP
One optional thing is to allow any follow-up
tcp packets,
i.e. everything after the initial
SYN
(last line per section); this makes the tcp 10000:65535
(one line above) superfluous.
And ping
uses a non-tcp/udp protocol called
icmp,
which we also allow.
On a client, typical outgoing ports are
20-21
(ftp, tcp),
22
(ssh, udp+tcp),
53
(dns, udp+tcp),
68
(dhcp client, udp),
80
(http, tcp),
123
(ntp, udp),
443
(https, tcp),
993
(imaps, tcp) or 995
(pops, tcp),
989-990
(ftps, tcp).
Typical incoming ports are
22
(ssh, udp+tcp).
Traditionally, Linux clients have not used firewalls because when all apps are open source, any unwanted behaviour would most probably be found by someone on the Internet and would then become widely known. However with binary-only apps (e.g. gog galaxy or steam) becoming more popular, we must assume malicious behaviour too.
We use the more comfortable
ufw
[docs]
[blog1]
which has a
GUI
called
gufw
[docs];
it uses iptables
[chains]
under the hood.
Rules are host-wide and saved in /etc/ufw/
,
with /etc/default/ufw
also pertinent.
apt-get install ufw gufw nano -w /etc/default/ufw IPV6=yes # because we will switch output default to DROP nano -w /etc/ufw/before.rules -A ufw-before-output -p icmp --icmp-type destination-unreachable -j ACCEPT -A ufw-before-output -p icmp --icmp-type source-quench -j ACCEPT -A ufw-before-output -p icmp --icmp-type time-exceeded -j ACCEPT -A ufw-before-output -p icmp --icmp-type parameter-problem -j ACCEPT -A ufw-before-output -p icmp --icmp-type echo-request -j ACCEPT # output equivalents (dhcp, dns) for input defaults -A ufw-before-output -p udp --sport 68 --dport 67 -j ACCEPT -A ufw-before-output -p udp --dport domain -j ACCEPT -A ufw-before-output -p tcp --dport domain -j ACCEPT ufw reload clear && tail -f /var/log/ufw.log
With gufw
you can start a Windows-like click-fest
and save the results in a profile, saved in
/etc/gufw/
e.g. as Home.profile
,
from which you can extract the ufw
commands.
We do it manually here:
sudo su # you must be root ufw enable # back: ufw disable clear && ufw status verbose ufw default deny incoming ufw default deny outgoing ping heise.de # with the before.rules above, should still work ufw allow out ssh ssh other.local ufw allow out 9001 tor-browser ufw allow out imaps ufw allow out smtps thunderbird ufw allow out ntp timedatectl status systemctl restart systemd-timesyncd systemctl status systemd-timesyncd.service ufw allow out 6881:6999/tcp # torrent for new Linux distros ufw allow out 6881:6999/udp ufw allow in 6881:6999/tcp ufw allow in 6881:6999/udp
By default, out
dns and https are enabled,
as well as in
ssh.
A level below ufw
command configurability,
in
(but not out
) dns and dhcp
are visible in iptables -L INPUT
; and
"all except SYN
" is visible in
iptables -L ufw-before-input
as well as
iptables -L ufw-before-output
.
The rest has been configured above.
Apps may still use http(s) for telemetry, so a
per-app application approach is needed;
profiles are in /etc/ufw/applications.d/
and saved in
Windows
ini file format.
The command structure is described deep within
man ufw
.
However we are in for a disappointment [forum1] [forum2]: This is all only for inbound traffic; as far as I could test there is no such thing for outbound. Proof:
ufw app list # which (app) profiles exist nano -w /etc/ufw/applications.d/firefox [Firefox] title=Firefox browser description=Internet browser with plugins ports=80/tcp ufw app update firefox ufw app info Firefox ufw allow from any app Firefox to any iptables -L ufw-user-output && iptables -L ufw-user-input
... we see that out
is unchanged, while
in
has a useless sapp_Firefox entry.
One thing left for us is using iptables
with
owner/group setting
[blog1].
Here we use it to allow port access that no other application has.
addgroup accesshttp adduser myuser accesshttp iptables -I OUTPUT 1 -m owner --gid-owner accesshttp -p tcp --dport 80 -j ACCEPT sg accesshttp -c 'firefox' iptables -D OUTPUT 1 # because cannot be maintained by gufw nano -w /etc/ufw/before.rules -A ufw-before-output -m owner --gid-owner accesshttp -p tcp --dport 80 -j ACCEPT ufw reload iptables -L ufw-before-output sg accesshttp -c 'firefox'
... essentially using the group accesshttp
as
enabling profile. While starting the app is somewhat cumbersome,
we can now start the same app with and without port access.
So this is our restrictive-by-default method to
allow per app.
The opposite approach is to make iptables
more
permissive and restrict per app.
You can either use the same approach as above, or do it like
Android
with
SELinux
[blog1]
and configure port access per app (the simpler
AppArmor
is not per-port). Good luck.
Windows apps are usually binary-only and thus must be
considered potentially malicious.
In general, Windows clients follow the same pattern as Linux clients,
adding the odd 445
(Active Directory,
SMB),
593
(Exchange
rpc)
or 691
(Exchange routing).
One difference is that Windows generally filters per app ("personal firewall"). On Windows 10, you can configure the built-in firewall by the usual click-fest. Once upon a time on Windows XP, I used Tiny Personal Firewall and let it ask me per connection attempt, making the more trustworthy ones permanent. So at least for output per-app, Windows does it better.
I hope you enjoyed our little journey into typical firewall usage. Have a nice day!
EOF (Apr:2021)