Skip to content

Netfilter

Netfilter proporciona diferents “hooks” (punt d’anclatge) en el flux de processament que et permet registrar funcions per aplicar als paquets de xarxa en aquell punt concret de processament.

Netfilter permet filtrar en múltiples nivells de xarxa:

4 TransportPortTCPUDP
3 NetworkAddressIPv4IPv6ARPICMP
2 Data LinkVLANEthernetPPP

nftables forma part del projecte netfilter i és la utilitat que et permet interactuar amb nefilter mitjançant l’eina nft.

Crea *dues màquines server a {% link “/cloud/isard/” %}.

Ha de tenir les interficies “Default”, “Wireguard VPN” i “provençana1”.

Configura la interficie “provençana1” amb la IP 10.0.0.X/24 on X és el teu número de PC, amb increments de +50.

Per exemple 10.0.0.10 i 10.0.0.60.

Terminal window
$ sudo ip addr add dev enp3s0 10.0.0.x/24
$ sudo ip link set dev enp3s0 up

Modifica el nom del host:

Terminal window
$ sudo hostnamectl set-hostname box-1

Surt i torna a entrar a la màquina.

Una taula a nftables és un espai de noms que conté una col·lecció de chains, sets, maps, flowtables, i stateful objects.

Cada taula ha de tenir assignat una única family d’adreces que defineix els tipus de paquets que processa aquesta taula.

Quan crees una taula pots escollir entre aquestes famílies d’adreces:

ipLa taula filtra paquets IPv4.
ip6La taula filtra paquets IPv6.
inetLa taula filtra paquets IPv4 i IPv6, i pots utilitzar una única regla pels dos tipus de paquets en el que tenen en comú, per exemple el port.
arpLa taula filtra paquets ARP a nivell 2, abans que el kernel faci qualsevol gestió a nivell 3.
bridgeUn pont conecta dos segments Ethernet i els paquets es reenvien en funció de l’adreça Ethernet. Com que el reenviament es fa a la capa 2, aquest encaminament és transparent als protocols de capa superior com pot ser el protocol IP.
netdevLa taula s’enllaça directament a una única interficie de xarxa enlloc de un protocol.
ingressFa el mateix que netdev, però més fàcil de configurar (des del kernel 5.10).

No hi ha taules predeterminades per a nftables.

Per tant, l’ordre list tables no torna cap resultat si no has definit cap taula.

Terminal window
$ sudo nft list tables

A {% link “/linux/ufw/” %} vas veure que per defecte UFW està deshabilitat.

Crea un firewall amb UFW:

Terminal window
$ sudo ufw allow 22
$ sudo ufw enable

Pots verificar que s’han creat dues taules amb el nom filter:

Terminal window
$ sudo nft list tables
table ip filter
table ip6 filter

Encara que les dos taules tenen el mateix nom pertanyen a famílies diferents: ip i ip6.

En la taula filter està la regla que permet connexions entrants (dport) al port 22:

Terminal window
$ sudo nft list table filter | grep "dport 22"
tcp dport 22 counter packets 0 bytes 0 accept
udp dport 22 counter packets 0 bytes 0 accept

Deshabilita el firewall

Terminal window
$ sudo ufw disable

Eliminar les taules filter:

Terminal window
$ sudo nft delete table filter
$ sudo nft list tables
table ip6 filter

Com que per defecte la família és ip si no indiques altre cosa, només s’ha borrat la taula ip filter,

Borra la taula ip6 filter:

Terminal window
$ sudo nft delete table ip6 filter
$ sudo nft list tables

Quan crees una taula li pots posar qualsevol nom, però per defecte és costum que el nom sigui filter com fa UFW.

Crea el fitxer test.nft:

#!/usr/sbin/nft -f
table ip filter {
}

Executa el fitxer:

Terminal window
$ chmod u+x ./test.nft
$ sudo ./test.nft

Tal com hem vist abans, un cop s’ha afegit la taula l’ordre list tables retorna el nom de la taula:

Terminal window
$ sudo nft list tables
table ip filter

Pots mostrar la informació d’una taula concreta:

Terminal window
$ sudo nft list table filter
table ip filter {
}

Com has vist a {% link “/linux/ufw/” %}, un firewall és un conjunt de regles que es processen per decidir que és fa amb un paquet.

Però les regles no s’afegeixen directament a les taules sinó a les cadenes.

Una cadena s’enllaça a un dels hooks que proporciona netfilter per tal de poder filtrar els paquets de xarxes en punts diferents del seu processament.

Els “hooks” que pots utilitzar al configurar una cadena base, i que et permeten manipular els paquets en un punt concret, són aquests:

ingressEl paquet acaba se ser processat per la controladora de la NIC
preroutingEl paquet no ha estat acceptat pel “flowtable” i està pendent de ser encaminat (a una altre host) o no.
inputEl paquet es processarà al mateix host i està pendent de ser processat pel procés corresponent.
forwardEl paquet no es processarà al host
outputEl paquet s’ha originat per un procés del host.
postroutingEl paquet està a punt de sortir del host.

Però no tots els paquets passen per tots aquests hooks: no és el mateix processar un paquet ARP que un paquet IP.

Un paquet ARP només passa pels “hooks” input i output (a més de l’ingress), no hi ha “routing”.

{% panel %}

flowchart LR
    S(("ARP")) --> I[input] --> H@{shape: fr-rect, label: "Process"} --> O[ouput]--> E(("ARP"))
    style S fill:#ffaa50
    style E fill:#ffaa50

{% endpanel %}

En canvi, un paquet IP passa per tots els “hooks”:

{% panel %}

flowchart LR
    S(("IP")) --> Pre[Prerouting] --> R{Routing} -- no --> I[Input] --> Process@{shape: fr-rect, label: "Process"} --> O[ouput] --> Post
    R -- yes --> F[Forward] --> Post[Postrouting] --> E(("IP"))
    style S fill:#ffaa50
    style E fill:#ffaa50

{% endpanel %}

Una cadena base s’ha d’enllaçar a alguna d’aquestes fases (o “hooks”).

Afegeix una cadena input a la taula filter:

#!/usr/sbin/nft -f
table ip filter {
chain input {
type filter hook input priority 0
}
}

$ sudo ./test.nft

Verifica que la taula s’ha configurat com tu vols:

Terminal window
sudo nft list table filter
table ip filter {
chain input {
type filter hook input priority filter; policy accept;
}
}

Has creat un cadena “input” que s’enllaça al hook input.

{% panel %}

flowchart LR
    S(("IP")) --> Pre[Prerouting] --> R{Routing} -- no --> I[Input] --> Process@{shape: fr-rect, label: "Process"} --> O[ouput] --> Post
    R -- yes --> F[Forward] --> Post[Postrouting] --> E(("IP"))
    style I fill:#f44
    style S fill:#ffaa50
    style E fill:#ffaa50

{% endpanel %}

Per tant, veuràs tots els paquets IPv4 que no s’encaminen a una altre adreça.

Totes les cadenes “base” tenen una política per defecte que es pot especificar al crear la cadena.

Aquesta és la política que s’aplicarà a un paquet si no hi ha cap regla en la cadena que decideixi que fer amb un paquet.

Si no dius res, per defecte la cadena es crea amb policy accept.

Només pots escollir entre dues polítiques predeterminades:

Només pots escollir entre dues polítiques predeterminades:

acceptEl paquet seguirà el seu camí.
dropEl paquet serà eliminat.

Pots canviar la política per defecte d’una cadena:

#!/usr/sbin/nft -f
table ip filter {
chain input {
type filter hook input priority 0; policy drop;
}
}

Actualitza nftables:

Terminal window
$ sudo ./test.nft

A partir d’ara nftables no permet cap paquet d’entrada i perds la connexió a la màquina virtual.

Per sort, aquesta configuració només funciona mentre la màquina està funcionat.

Apaga la màquina, arranca de nou i connecta’t.

Verifica que no hi ha cap taula:

Terminal window
$ sudo nft list tables

També pots registrar la cadena de sortida:

#!/usr/sbin/nft -f
table ip filter {
chain input {
type filter hook input priority 0
}
chain output {
type filter hook output priority 0
}
}

Output chain s’enganxa al hook output i veurà els paquets de sortida un cop s’han processat:

{% panel %}

flowchart LR
    S(("IP")) --> Pre[Prerouting] --> R{Routing} -- yes --> I[Input] --> Process@{shape: fr-rect, label: "Process"} --> O[ouput] --> Post
    R -- no --> F[Forward] --> Post[Postrouting] --> E(("IP"))
    style I fill:#f44
    style O fill:#f44
    style S fill:#ffaa50
    style E fill:#ffaa50

{% endpanel %}

A diferència dels “hooks” anteriors, un ingress hook és específic d’un dispositiu de xarxa.

Has de crear una taula de la familia netdev:

#!/usr/sbin/nft -f
table ip filter {
chain input {
type filter hook input priority 0
}
chain output {
type filter hook output priority 0
}
}
table netdev filter {
chain enp2s0 {
type filter hook ingress device "enp2s0" priority 0
}
}

$ sudo nft list chains

Com que la cadena és específica d’un dispositiu de xarxa, és obligatori especificar el dispositiu on s’enganxarà la cadena.

Totes les cadenes que hem creat són de tipus filter:

Terminal window
$ sudo nft list chain filter input
table ip filter {
chain input {
type filter hook input priority filter; policy accept;
}
}

Aquest tipus es fa servir per filtrar paquets de les families arp, bridge, ip, ip6 o inet.

L’altre tipus és route que es fa servir per redirigir els paquets en base a un camp de la capçalera IP o si es modifica la marca del paquet.

El tipus route només es pot fer servir amb les famílies ip, ip6 o inet

Si defineixes més d’una cadena pel mateix “hook” el valor priority indica quina s’utilitzarà primer.

Quan més petit sigui el número, la cadena s’executarà abans.

Afegeix una cadena input-ssh que anirà abans que la cadena input:

#!/usr/sbin/nft -f
table ip filter {
# ...
chain input-ssh {
type filter hook input priority -1
}
}
# ...

Les regles prenen mesures sobre els paquets de xarxa (p. ex. acceptant-los o deixant-los caure) en funció de si coincideixen amb els criteris especificats.

Cada regla consta de zero o més expressions seguides d’una o més declaracions:

Expressions: Cada expressió prova si un paquet coincideix amb un camp de càrrega útil específic o metadades de paquet/flux. Les expressions múltiples s’avaluen linealment d’esquerra a dreta: si la primera expressió coincideix, llavors s’avalua la següent expressió i així successivament.

Si arribem a l’expressió final, aleshores el paquet coincideix amb totes les expressions de la regla i s’executen les declaracions de la regla.

Declaracions Cada declaració fa una acció, com ara establir la marca netfilter, comptar el paquet, registrar el paquet o emetre un veredicte com acceptar o deixar el paquet o saltar a una altra cadena.

Igual que amb les expressions, diverses declaracions s’avaluen linealment d’esquerra a dreta: una sola regla pot fer diverses accions utilitzant diverses sentències.

Tingues en compte que una declaració de veredicte per la seva naturalesa posa fi a la regla.

Afegeix una regla a la cadena output:

Terminal window
chain output {
type filter hook output priority 0
ip daddr 8.8.8.8 counter
}
  • ip daddr 8.8.8.8 és una expressió que ha de fet match: paquets IP que tenen com adreça destí 8.8.8.8 (daddr = destination address)

  • counter és una declaració: va contant el número de bytes que han activat la regla.

Quan enumeres les regles d’una cadena pots utilitzar modificadors per traduir adreces IP a noms DNS, protocols TCP, etc.

Terminal window
$ sudo nft -N list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr dns.google counter packets 0 bytes 0
}
}

Afegir un comptador és una tècnica molt útil per verificar si una regla funciona:

Fes un ping a 8.8.8.8 i verifica que la regla s’ha activat:

Terminal window
$ ping -c 1 8.8.8.8 > /dev/null
$ sudo nft list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr 8.8.8.8 counter packets 1 bytes 84
}
}

Un comptador compta tant el nombre total de paquets com el total de bytes que ha vist des de l’últim restabliment.

Fes un ping a dns.google i verifica que la regla s’ha activat:

Terminal window
$ ping -c 1 dns.google > /dev/null
$ sudo nft list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr 8.8.8.8 counter packets 2 bytes 168
}
}

Fes un ping a 1.1.1.1 i verifica que la regla no s’ha activat:

Terminal window
$ ping -c 1 1.1.1.1 > /dev/null
$ sudo nft list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr 8.8.8.8 counter packets 2 bytes 168
}
}

Afageix la regla repetida:

Terminal window
chain output {
type filter hook output priority 0
ip daddr 8.8.8.8 counter
ip daddr 8.8.8.8 counter
}

Si torne a fer un ping a google pots veure que s’han activat les dos regles:

Terminal window
$ ping -c 1 dns.google > /dev/null
$ sudo nft list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr 8.8.8.8 counter packets 4 bytes 336
ip daddr 8.8.8.8 counter packets 1 bytes 84

Les regles es processen de dalt a baix.

Elimina el comptador de la primera regla i torna a fer un ping:

Terminal window
$ nano test.nft
$ sudo ./test.nft
$ ping -c 1 dns.google > /dev/null
$ sudo nft list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr 8.8.8.8 counter packets 5 bytes 420
ip daddr 8.8.8.8 counter packets 2 bytes 168
ip daddr 8.8.8.8
ip daddr 8.8.8.8 counter packets 1 bytes 84

El que has fet és afegir dos regles noves!

El que fa el fitxer és afegir regles, etc.

Modifica el fitxer:

#!/usr/sbin/nft -f
flush ruleset
table ip filter {
chain output {
type filter hook output priority 0
ip daddr 8.8.8.8 counter
ip daddr 8.8.8.8 drop
ip daddr 8.8.8.8 counter
}
}

Pots verur que el primer que fem és eliminar-ho tot amb flush ruleset 🙂!

Però les regles no estan només per contar paquets, sinó per acceptar o rebutjar paquets amb drop.

Si fas de nou un ping l’última regla no es processa i el comptador no s’activa.

Terminal window
$ ping -c 1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
--- 8.8.8.8 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
isard@box-1:~$ sudo nft list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr 8.8.8.8 counter packets 2 bytes 168
ip daddr 8.8.8.8 drop
ip daddr 8.8.8.8 counter packets 0 bytes 0
}
}

Com que les regles es processen de dalt a baix, la segona regla elimina el paquet: el paquet ja no és processa més en la cadena de regles i no serà acceptat per continuar el seu camí i ser enviat a 8.8.8.8.

A continuació modifica l’script afegint comentaris i variables:

#!/usr/sbin/nft -f
flush ruleset
# Google Public DNs
define dns_google = { 8.8.8.8, 8.8.4.4}
table ip filter {
chain output {
type filter hook output priority 0
ip daddr $dns_google counter
counter
}
}

Pots veure que els comentaris han desaparegut i enlloc de les variables hi ha els valors definits a les variables:

Terminal window
$ sudo nft list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr { 8.8.4.4, 8.8.8.8 } counter packets 0 bytes 0
counter packets 766 bytes 68036
}
}

Fes un ping a 8.8.8.8 i un altre a 8.8.4.4, i verifica que la regla ip daddr { … } funciona:

Terminal window
$ ping -c 1 8.8.8.8 > /dev/null
$ sudo nft list chain filter output
table ip filter {
chain output {
type filter hook output priority filter; policy accept;
ip daddr { 8.8.4.4, 8.8.8.8 } counter packets 1 bytes 84
counter packets 1660 bytes 151800
}
}
...

Mira quina és la IP origen de la connexió ssh:

Terminal window
$ sudo tcpdump -i any port 22
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
22:07:59.385459 enp2s0 Out IP box-1.ssh > 10.0.29.109.50414: Flags [P.], seq 4286926479:4286926555, ack 1031133820, win 436, options [nop,nop,TS val 665503130 ecr 2743213119], length 76
...

En el meu cas la IP és 10.0.29.109.

Modifica l’script per tal de que només permeti connexions ssh desde la màquina WSL:

#!/usr/sbin/nft -f
flush ruleset
define wsl = 10.0.29.109
table ip filter {
chain input {
type filter hook input priority 0
tcp dport 22 ip saddr != $wsl drop
}
}

La regla ssh funciona, sinó ara mateix hauries perdut la connexió.

Pots veure que la regla té:

  • 2 expressions: tcp dport 22 i ip saddr != 10.0.29.109
  • 1 declaració: drop

Verifica que desde la màquina box-2 ja no et pots conectar per ssh.

Terminal window
box-2$ ssh isard@10.0.0.50
ssh: connect to host 10.0.0.50 port 22: Connection timed out

nftables és un servei del sistema que es controla a través de systemd.

El servei executa l’script /etc/nftables.conf.

Reemplaça el fitexer nftables.conf:

Terminal window
sudo cp test.nft /etc/nftables.conf

Arrenca el firewall amb systemctl:

Terminal window
sudo systemctl enable --now nftables
Created symlink /etc/systemd/system/sysinit.target.wants/nftables.service /usr/lib/systemd/system/nftables.service.

A partir d’ara sempre que arrenquis la màquina el firewall estarà actiu amb aquesta configuració.

Per aquest motiu les proves sempre les has de fer amb el fitxer test.nft.

1.- Modifica el firewall perquè per defecte només accepti connexions d’entrada ssh:

{% sol %}

#!/usr/sbin/nft -f
flush ruleset
define wsl = 10.0.29.109
table ip filter {
chain input {
type filter hook input priority 0; policy drop
iifname "lo" accept
tcp dport 22 ip saddr == $wsl accept
}
}

Has d’afegir la regla iifname "lo" accept perquè alguns serveis bàsics del sistema operatiu funcionen amb la interfície “loopback”, com per exemple, la resolució de noms. {% endsol %}

2.- Arrenca un servidor nginx i verifica que ni la màquina wsl ni box-2 poden accedir al servidor.

Terminal window
$ curl 10.0.0.50
curl: (28) Failed to connect to 10.0.0.50 port 80 after 134542 ms: Couldn't connect to server

3.- Configura nftables perquè també accepti connexions entrants tcp al port 80:

{% sol %}

Terminal window
table ip filter {
chain input {
type filter hook input priority 0; policy drop
iifname "lo" accept
tcp dport 22 ip saddr == $wsl accept
tcp dport 80 accept
}
}

{% endsol %}

4.- Verifica que encara que acceptes els paquets destinats al port 80, no et pots connectar als servidors http d’altres màquines:

Terminal window
$ curl google.es
curl: (6) Could not resolve host: google.es

Quan tenim un problema amb la configuració de nftables a més d’utilitzar un contador (“counter”) per veure que una regla s’ha activat podem fer un “tracing”.

Afegeix al final de la cadena l’expressió: meta nftrace set 1

Terminal window
table ip filter {
chain input {
type filter hook input priority 0; policy drop
iifname "lo" accept
tcp dport 22 ip saddr == $wsl accept
tcp dport 80 accept
meta nftrace set 1
}
}

Torna a carregar nftables i comença a monitoritzar l’entrada de paquets: nft monitor trace.

Terminal window
$ sudo nft monitor trace

Pots veure que la regla no s’activa (els paquest ssh sòn acceptats abans que li toqui el torn a aquesta regla).

Peró si executes curl https://10.0.0.50, llavors el paquet si que arriba a l’última regla:

Terminal window
$ sudo nft monitor trace
trace id 925a4f61 ip filter input packet: iif "enp3s0" ether saddr 52:54:00:6b:76:33 ether daddr 52:54:00:15:2f:a1 ip saddr 10.0.0.100 ip daddr 10.0.0.50 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 13968 ip length 60 tcp sport 49464 tcp dport 443 tcp flags == syn tcp window 64240
trace id 925a4f61 ip filter input rule meta nftrace set 1 (verdict continue)
trace id 925a4f61 ip filter input policy drop
...

Ara podem provar perquè no funciona curl google.es.

Obre una altre terminal:

Terminal window
box-1$ curl google.es
curl: (6) Could not resolve host: google.es

Pots veure que el firewall no accepta el paquet de tornada de saddr 8.8.8.8:

Terminal window
$ sudo nft monitor trace
trace id 2f05a9dc ip filter input packet: iif "enp1s0" ether saddr 52:54:00:47:b3:69 ether daddr 52:54:00:0c:0b:8a ip saddr 8.8.8.8 ip daddr 192.168.122.123 ip dscp cs0 ip ecn not-ect ip ttl 111 ip id 12106 ip length 71 udp sport 53 udp dport 42566 udp length 51 @th,64,96 0xabae81800001000100000000
trace id 2f05a9dc ip filter input rule meta nftrace set 1 (verdict continue)
trace id 2f05a9dc ip filter input policy drop
...

Fins ara estem aplicant regles sense estat: només tenim en compte el paquet que estem filtrant.

Però hi ha molts paquets que estan relacionats perquè pertanyen a una mateixa connexió.

Recordes que al principi al explicar el hooks hem parlat de la “flowtable”?

Netfilter té un sistema de seguiment de connexions que permet rastrejar quins paquets pertanyen a la mateixa connexió.

Pots afegir aquesta regla a la cadena input: ct state established,related accept

Terminal window
table ip filter {
chain input {
type filter hook input priority 0; policy drop
iifname "lo" accept
ct state established,related accept
tcp dport 22 ip saddr == $wsl accept
tcp dport 80 accept
meta nftrace set 1
}
}

Aquesta regla diu que:

  • ct - És una expressió de tipus “connection tracking”
  • state - Fem un tracking de l’estat de la connexió
  • established, related — Són els estats de conntrack que volem fer “match”

Ara ja funciona:

Terminal window
$ curl -s google.es | head -1
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">

Contiua llegint aquest document

En aquesta secció veurem diferents expressions per fet “match” en els paquets que s’estan filtrant.

Un meta-selector et permet fer match respecte informació que el host local té sobre el paquet (com ara com o quan es va rebre) i que no necessàriament està en el mateix paquet.

També en alguns casos pots incorporat metainformació tal com s’explica a Setting packet metainformation.

Nosaltres només veurem uns quants selectors, però en aquest enllaç tens tota la informació al respecte: Matching packet metainformation.

Pots fer un match per uid o gid de l’usuari que ha creat el socket mitjançant les keywords skuid i skgid.

A continuació:

  • Crea un nou usuari alice.
  • Configura el firewall perquè no permeti a l’usuari alice realitzar connexions de sortida:
Terminal window
table ip filter {
chain output {
type filter hook output priority 0
meta skuid alice drop
}
}

Verifica que el firewall funciona:

Terminal window
$ ping -c 1 google.es | head -1
PING google.es (142.250.186.35) 56(84) bytes of data.
$ su -c "ping -c 1 google.es" alice
Password:
ping: google.es: Temporary failure in name resolution

Modifica el firewall perquè faci servir el uid de l’usuari enlloc del seu nom, i verifica que funciona.

També pots fer match per time, day o hour.

D’aquesta manera pots controlar l’accés a determinats serveis en hores determinades o generar un log d’accéss en hores o dies no habituals.

A continuació tenim una regla que no permet cap connexió de sortida entre les 00:00 i les 06:00:

Terminal window
table ip filter {
chain output {
type filter hook output priority 0
meta hour 00:00-06:00 drop
}
}

Modifica l’hora del sistema perquè s’activi la regla:

Terminal window
$ sudo timedatectl set-ntp no
$ sudo timedatectl set-time '05:59:00'

La informació completa està a Matching packet headers.

La informació de nivell 2 només està disponible en el camí d’entrada (ingress, prerouting, input)

Modifica el fitxer index.html del servidor nginx perquè respongui amb “Hello from box-1”.

Verifica que box-2 té accés al servidor:

Terminal window
box-2$ curl box-1
Hello from box-1

Mira quina és l’adreça MAC de box-2:

Terminal window
$ cat /sys/class/net/enp3s0/address
52:54:00:6b:76:33

Modifica el firewall perquè no permeti connexions de box-2 mitjançant un filtre MAC:

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
ether saddr 52:54:00:6b:76:33 drop
}
}

Verifica que la regla funciona:

Terminal window
box-2$ curl box-1
curl: (28) Failed to connect to 10.0.0.50 port 80 after 133377 ms: Couldn't connect to server

També pots fer un match segons l’adreça IPv4 origen i destí:

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
ip saddr 10.0.0.100 drop
}
}

Verifica que box-2 no és pot conectar ni per HTTP ni per ping.

Terminal window

Modifica la IP de box-2 per evitar el firewall:

Enlloc d’eliminar els paquets entrants de la màquina box-1 pots eliminar els de sortida a la màquina box-1 mitjançant una cadena output.

Modifica el firewall i verifica que box-2 tampoc és pot conectar ni per HTTP ni per ping.

Si vols pots eliminar totes les sol·licituds d’eco ICMP (conegudes popularment com a pings):

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
icmp type echo-request drop
}
}

Verifica que funciona:

Terminal window
$ ping 10.10.0.50
PING 10.10.0.50 (10.10.0.50) 56(84) bytes of data.
^C

Pots utilitzar nft describe per trobar les paraules clau de tipus icmp disponibles.

Per filtrar en un protocol de capa 4 com TCP, pots fer-ho amb aquesta regla:

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
ip protocol tcp drop
}
}

Verifica que la màquina client pot fer ping, però no curl.

Terminal window
wsl$ ping box-1
PING box-1 (10.2.39.218) 56(84) bytes of data.
64 bytes from box-1 (10.2.39.218): icmp_seq=1 ttl=62 time=36.5 ms
...

Torna a arrencar la màquina box-1 per poder conectar-te amb ssh.

Pots crear un regla per eliminar tots el paquets TCP en un rang de ports:

Terminal window
table ip filter {
chain output {
type filter hook output priority 0
tcp dport 100-1024 drop
}
}

Amb aquesta regla server no pot establir una connexió HTTPS:

Terminal window
$ curl https://www.google.com
^C

També pot utilitzar el conjunt anònim l4proto i un expressió th (transport header) per fer match a la vegada de paquets TCP i UDP dirigits al port 53 (DNS ) - el protocol fa servir els dos ports.

Terminal window
table ip filter {
chain output {
type filter hook output priority 0
meta l4proto { tcp, udp } th dport 53 drop
}
}

Pots veure que funciona, encara que el que està bloquejant és el local resolver cache:

Terminal window
$ nslookup google.com
;; communications error to 127.0.0.53#53: timed out
...

La informació completa està a: Matching connection tracking stateful metainformation

Les expressions conntrack (ct) permeten configurar tallafocs amb estat de tal manera que es poden identificar tots els paquets que pertanyen a una mateixa connexió.

Modifica el firewall per fer un tracking de les connexions:

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
ct state established, related accept
}
}

Pots veure el tracking de la connexió ssh:

Terminal window
$ sudo apt install -y conntrack
$ sudo conntrack -L -o id,extended
ipv4 2 tcp 6 299 ESTABLISHED src=10.0.29.109 dst=10.2.39.218 sport=50454 dport=22 src=10.2.39.218 dst=10.0.29.109 sport=22 dport=50454 [ASSURED] mark=0 use=1 id=1189582752
ipv4 2 udp 17 29 src=127.0.0.1 dst=127.0.0.53 sport=59490 dport=53 src=127.0.0.53 dst=127.0.0.1 sport=53 dport=59490 mark=0 use=1 id=3172624988
ipv4 2 tcp 6 75 TIME_WAIT src=192.168.122.122 dst=141.30.62.22 sport=38194 dport=80 src=141.30.62.22 dst=192.168.122.122 sport=80 dport=38194 [ASSURED] mark=0 use=1 id=3291912715
conntrack v1.4.8 (conntrack-tools): 3 flow entries have been shown.

Pots limitar el trànsit per paquets o bytes mitjançant limit.

L’exemple següent mostra una regla que només permet com a màxim 1 paquet per segon de sol·licituts HTTP – és un exemple! :

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
ct state established, related accept
tcp dport 80 limit rate over 1/second counter drop
}
}

Modifica la pàgina del servidor de box-1:

Terminal window
$ echo "Server box-1" | sudo tee /var/www/html/index.html

Pots verificar que el firewall limita el número de paquets que s’admeten per segon protegint al servidor nginx de que el saturin amb peticions HTTP:

Terminal window
box-2$ TIMEFORMAT=%R
box-2$ $ time curl box-1
Server box-1
0.097
box-2$ time curl box-1
Server box-1
1.087
box-2$ time curl box-1
Server box-1
7.298

També pots limitar pel número de bytes per tal de limitar l’ample de banda del servidor.

Baixa el llibre “War and Peace”:

Terminal window
box-1$ sudo curl https://www.gutenberg.org/files/2600/2600-0.txt -o /var/www/html/war-and-peace.txt

Modifica el firewall:

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
ct state established, related accept
tcp dport 80 limit rate over 100bytes/second counter drop
}
}

Verifica que el firewall limita la velocitat de baixada de fitxers:

Terminal window
$ time curl -o /dev/null box-1/war-and-peace.txt

A continuació veurem algunes sentències que actuen sobre els paquets que han fet “match” en una regla.

Enlloc d’eliminar un paquet el pots rebutjar:

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
tcp dport 80 reject
}
}

Pots verificar que el servidor informa al client que rebutja la connexió amb un paquet “port unreachable”:

No funciona amb wireguard

Terminal window
$ curl box-1
curl: (7) Failed to connect to box-1 port 80 after 44 ms: Couldn't connect to server

Si vols pots canviar el motiu pel qual no s’accepta la connexió:

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
tcp dport 80 reject with icmp type host-unreachable
}
}

Pots tenir un registre dels paquets que s’han processat mitjançant l’acció log.

Aquesta és la regla més senzilla que pots utilitzar:

Si fas una petició HTTP desde el client pots veure que el paquet queda registrat al syslog:

Terminal window
$ sudo cat /var/log/kern.log | grep 10.0.0.100 | tail -1
2024-12-18T18:26:07.659843+00:00 box-1 kernel: IN=enp3s0 OUT= MAC=52:54:00:15:2f:a1:52:54:00:6b:76:33:08:00 SRC=10.0.0.100 DST=10.0.0.50 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=18982 DF PROTO=TCP SPT=42798 DPT=80 WINDOW=501 RES=0x00 ACK URGP=0

A continuació tens una regla típica de match, log i accept de trànsit ssh entrant per deixar registrades totes les conexions ssh que s’han fet al servidor:

Terminal window
table ip filter {
chain input {
type filter hook input priority 0
tcp dport 22 ct state new log prefix "New SSH connection: "
}
}

El prefix indica el string inicial que s’utilitza com a prefix per al missatge que es registra.

Si mires el registre pots veure que la teva connexió ssh ha quedat registrada (SRC=10.0.29.109):

Terminal window
$ sudo cat /var/log/kern.log | grep "New SSH"
2024-12-18T18:29:15.165023+00:00 box-1 kernel: New SSH connection: IN=enp2s0 OUT= MAC=52:54:00:50:12:3f:9a:4b:2c:ac:1f:67:08:00 SRC=10.0.29.109 DST=10.2.39.218 LEN=88 TOS=0x10 PREC=0x00 TTL=63 ID=27645 DF PROTO=TCP SPT=44160 DPT=22 WINDOW=15002 RES=0x00 ACK PSH URGP=0

Continua llegint aquest document


El contingut d'aquest lloc web té llicència CC BY-NC-ND 4.0.

©2022-2025 xtec.dev