Transparenter Tintenfisch mit SSL-Bump für Gentoo mit nft

Bild

Hintergrund


Kürzlich habe ich mich verpflichtet, die Firewall auf meinem PC mit bewährten iptables in brandneue nftables zu übersetzen. Für eine eingehendere Untersuchung von NF-Tabellen habe ich mir die Aufgabe gestellt: einen transparenten Proxyserver (Squid) mit verschlüsselter Verbindungsanalyse (HTTPS) zu konfigurieren, um den Internetzugang auf virtuelle Maschinen, Raspberry Pi-PCs sowie mein Smartphone (mit Android) zu verteilen 6. Version) über eine drahtlose Verbindung (mit der Hostapd-Anwendung).


.
, .
, ( , , . .). , , .
,


«Gentoo Linux» «OpenRC».

sys-kernel/gentoo-sources-5.3.1
USE=""
USE-
-net-proxy/squid-4.8
USE="caps ssl ssl-crtd"
dev-libs / openssl-1.1.1c-r1
USE = "asm test zlib"
Nft Appnet-firewall / nftables-0.9.2
USE = "doc gmp modern_kernel"
IP-Anwendungsys-apps / iproute2-5.2.0-r1
USE = "Caps minimal"
Protokollierungsdienstapp-admin / ulogd-2.0.7-r1
USE = "nfct nflog"

Kernel-Tuning


Bild
Gleiches aber Text
[*] Networking support --->
Networking options --->
[*] TCP/IP networking
[*] IP: advanced router
[*] IP: policy routing
[*] Network packet filtering framework (Netfilter) --->
[*] Advanced netfilter configuration
Core Netfilter Configuration --->
# ,
[*] Netfilter ingress support
# ,
<*> Netfilter LOG over NFNETLINK interface
<*> Netfilter connection tracking support
<*> Netfilter nf_tables support
<*> Netfilter nf_tables set infrastructure
# ,
[*] Netfilter nf_tables netdev tables support
<*> Netfilter nf_tables conntrack module
# ,
<*> Netfilter nf_tables counter module
# ,
<*> Netfilter nf_tables log module
<*> Netfilter nf_tables masquerade support
<*> Netfilter nf_tables nat module
<*> Netfilter nf_tables socket match support
<*> Netfilter nf_tables tproxy support
IP: Netfilter Configuration --->
[*] IPv4 nf_tables support
# ,
<*> Ethernet Bridge nf_tables support --->


Als Referenz zitiere ich einen Auszug aus /usr/src/linux/.config:

CONFIG_NET=y
CONFIG_INET=y
<b>CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y</b>
CONFIG_NETFILTER=y
CONFIG_NETFILTER_ADVANCED=y
CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_NETLINK=y
CONFIG_NETFILTER_NETLINK_LOG=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_TABLES=y
CONFIG_NF_TABLES_SET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_CT=y
CONFIG_NFT_COUNTER=y
CONFIG_NFT_LOG=y
CONFIG_NFT_MASQ=y
CONFIG_NFT_NAT=y
<b>CONFIG_NFT_SOCKET=y
CONFIG_NFT_TPROXY=y</b>
CONFIG_NF_TABLES_BRIDGE=y

Netzwerkkonfiguration


Wenn der net.lo-Dienst nicht zum Boot-Runlevel hinzugefügt wird, sollte er dort hinzugefügt werden:

rc-config add net.lo boot

Auf die gleiche Weise werden sie erstellt und so konfiguriert, dass sie für die Standardstufe des Netzdienstes ausgeführt werden. br0 (Brücke für virtuelle Maschinen und Smartphone), net. enp0s25 (kabelgebundene Schnittstelle) und net. wlp3s0 (drahtlose Schnittstelle), zum Beispiel:

ln -s net.lo /etc/init.d/net.br0
rc-config add net.br0 default

Die endgültige Konfigurationsdatei /etc/conf.d/net in unserem Beispiel sieht folgendermaßen aus (abzüglich der Einstellungen, die nicht mit unserer Aufgabe zusammenhängen):

Bild

Gleiches aber Text
# TProxy
routes_lo='local default dev lo table 3128'

# Qemu bridge
bridge_force_br0=''
mac_br0='XX:XX:XX:XX:XX:XX'
config_br0='192.168.120.1/24'

# Ethernet
config_enp0s25='dhcp'
modules_enp0s25='udhcpc'
dhcp_enp0s25='release nontp'
udhcpc_enp0s25='--retries 8 --timeout 10'
fallback_enp0s25='10.a.b.c/16'
fallback_routes_enp0s25='default via 10.a.0.1'

# Wi-Fi
if [[ -f /var/lib/misc/hostapd ]]; then
  modules_wlp3s0="!ifconfig !iwconfig !wpa_supplicant"
  config_wlp3s0='null'
else
  config_wlp3s0='dhcp'
  modules_wlp3s0='udhcpc'
  wpa_supplicant_wlp3s0='-Dnl80211'
fi

postup() {
  if [ "${IFACE}" == lo ]; then
    ip rule add fwmark 3128 lookup 3128
  fi
  return 0
}


Die hervorgehobenen Zeilen fügen eine neue Routing-Tabelle hinzu, in diesem Beispiel unter der Nummer 3128, und das Gate ist die Standardeinstellung dafür (die Loopback-Schnittstelle). Die Regel lautet, nach welchen Paketen eine Firewall mit der Label-Nummer 3128 gekennzeichnet ist (in beiden Fällen Dezimalzahlen). nach diesem Zeitplan serviert.

Fügen Sie der folgenden Zeile zu /etc/sysctl.conf hinzu (oder ändern Sie vorhandene), um zu verhindern, dass geroutete Pakete aufgrund nicht übereinstimmender Adressen auf Netzwerkebene verworfen werden (transparentes Proxying hält Pakete intakt!):

Bild

Wenn Sie diese Einstellungen vor dem Neustart anwenden müssen, dann sollten Sie sie zusätzlich für beide Netzwerkschnittstellen mit Internetzugang einstellen:

sysctl net.ipv4.conf.enp0s25.rp_filter=0
sysctl net.ipv4.conf.wlp3s0.rp_filter=0

Proxy-Einstellungen


Da der normale (nicht transparente) Port des Proxyservers auf die Bridge-Adresse ( 192.168.120.1 ) festgelegt ist, fügen Sie die folgende Zeile zu /etc/rc.conf hinzu:

rc_squid_need="net.br0"

Die folgenden Proxy-Einstellungen werden in diesem Artikel nicht berücksichtigt:

  • Überprüfung der Identität von Benutzern an einem regulären (nicht transparenten) Port;
  • ICAP zur Integration in ein Gerät zur Verhinderung von Datenlecks (z. B. InfoWatch Traffic Monitor);
  • Generieren von Verschlüsselungsschlüsseln und Erstellen eines Zertifikats.

Die Konfigurationsdatei /etc/squid/squid.conf sieht am Ende so aus (nur für den Fall, ich gebe es komplett):

Bild

Bild

Gleiches aber Text
	#    
1	acl virtual_machines src 192.168.120.0/24
2	acl SSL_ports port 443
	#      HTTPS 
3	acl SSL_ports port 1012        #  badssl.com
	#      HTTPS 
4	acl SSL_ports port 33443       # getcourse.ru  artlinerschool.ru
5	acl Safe_ports port 21         # ftp
6	acl Safe_ports port 80         # http
7	acl Safe_ports port 443        # https
	#     
8	acl Safe_ports port 1012       #  badssl.com
9	acl Safe_ports port 1025-65535 #  
10	acl CONNECT method CONNECT 
11	http_access deny !Safe_ports
12	http_access deny CONNECT !SSL_ports
13	http_access allow localhost manager
14	http_access deny manager
15	http_access allow localhost
	#      -
16	http_access allow virtual_machines
17	http_access deny all
	#   () .   ,       (,   - FTP)
18	http_port 192.168.120.1:3128 ssl-bump options=ALL:NO_SSLv3:NO_TLSv1 cert=/etc/squid/squid.pem
	#      .     «loopback»,         3128,  ,         
19	http_port 127.0.0.1:3129 tproxy
	#      .     «loopback»,         3128,  ,         
20	https_port 127.0.0.1:3130 tproxy ssl-bump options=ALL:NO_SSLv3:NO_TLSv1 cert=/etc/squid/squid.pem
	# -    ,   -
21	always_direct allow all
	#    ,   
22	acl BrokenButTrustedServers dstdomain "/etc/squid/selfsigned.txt"
	#      ,   
23	sslproxy_cert_error allow BrokenButTrustedServers
24	sslproxy_cert_error deny all
	#       TLS
25	tls_outgoing_options min-version=1.2
	#    
26	acl blocked ssl::server_name "/etc/squid/blocked_domains.txt"
	#   ,    -   (          SSL)
27	acl fragile dstdomain "/etc/squid/fragile_domains.txt"
28	acl step1 at_step SslBump1
29	ssl_bump peek step1
	#     
30	ssl_bump terminate blocked
	#       ,    -  
31	ssl_bump splice fragile
	#     ,  
32	ssl_bump bump all
	#    
33	sslcrtd_program /usr/libexec/squid/security_file_certgen -s /var/lib/squid/ssl -M 4MB
34	cache_dir rock /var/cache/squid-r 512 max-size=32768
35	cache_dir aufs /var/cache/squid 512 64 1024 min-size=32768
36	coredump_dir /var/tmp/squid
37	refresh_pattern    ^ftp:          1440 20% 10080
38	refresh_pattern -i (/cgi-bin/|\?) 0    0%  0
39	refresh_pattern    .              0    20% 4320
40	memory_replacement_policy heap GDSF
41	cache_replacement_policy LFUDA
42	maximum_object_size 32 MB
43	logfile_rotate 3
44	debug_options ALL,1,rotate=3
45	cache_mem 512 MB
46	visible_hostname host.shadow.amn
47	udp_incoming_address 127.0.0.1
48	pinger_enable off


Firewall-Setup


Richten Sie die Dienste nftables und ulogd auf der Standardebene "Standard" ein (letzteres wird für die Paketbenachrichtigung benötigt):

rc-config add nftables default
rc-config add ulogd default

Fügen Sie /etc/rc.conf die folgende Zeile hinzu, da die Firewall-Einstellungen eine Brücke enthalten:

rc_nftables_need="net.br0"

Damit die Benachrichtigung in /etc/sysctl.conf funktioniert, müssen Sie die folgende Zeile hinzufügen:

net.netfilter.nf_log.2 = nfnetlink_log

Damit sich die Konfigurationsdatei im Ordner / etc / nftables befindet, nehmen wir in /etc/conf.d/nftables die folgende Änderung vor:

NFTABLES_SAVE="/etc/nftables/rules-save"

Nehmen Sie eine weitere Änderung an /etc/conf.d/nftables vor, um zu verhindern, dass temporäre Änderungen in der Konfigurationsdatei gespeichert werden:

SAVE_ON_STOP="no"

Ich werde die der Firewall zugewiesenen Aufgaben beschreiben:

  1. Die Standardregeln in allen Ketten der IP-Filtertabelle sollten Pakete entfernen (auch in der Ausgabekette!). Ähnliches gilt für Netdev-Filtertabellen.
  2. Der Austausch jeglicher Art, mit Ausnahme von IPv4 und dem damit verbundenen Dienstaustausch (z. B. ARP), wird so schnell wie möglich unterdrückt (weder IPv4 noch IPSec werden verwendet).
  3. IPv4-Multicast-Pakete werden ebenfalls so früh wie möglich entfernt.
  4. Zum Schutz eines Android-Smartphones (bei Verbindung mit der Bridge mithilfe der Hostapd-Anwendung) sollte der Broadcast-Austausch von virtuellen Maschinen, die unter Microsoft Windows ausgeführt werden, nicht an eine drahtlose Schnittstelle übertragen werden.
  5. Sie können unsere Wi-Fi-Geräte nur mit bekannten MAC-Adressen verwenden.

Die Konfigurationsdatei / etc / nftables / rules-save am Ende sieht folgendermaßen aus (abzüglich der meisten Erklärungen):

Bild

Bild

Bild

Bild

Bild

Bild

Gleiches aber Text
1	#!/sbin/nft -f
	#  ,     
2	define icmp_types = { destination-unreachable, time-exceeded, parameter-problem, echo-request, echo-reply }
3	define host = 192.168.120.1
4	define br = br0
5	define my_br_mac = XX:XX:XX:XX:XX:XX
6	define eth = enp0s25
7	define my_eth_mac = YY:YY:YY:YY:YY:YY
8	define wifi = wlp3s0
9	define my_wifi_mac = WW:WW:WW:WW:WW:WW
10	define my_phone = TT:TT:TT:TT:TT:TT
11	define virtual_machines = 192.168.120.0/24
12	define privileged_vm = { 192.168.120.22, 192.168.120.129 }
13	define dhcp_client = 192.168.120.224/27
14	define transmission_port = 51413
15	define no_track = { microsoft-ds, ms-wbt-server }
16	define vm_ssh = 192.168.120.70
17	define infowatch_pc = { 10.a.0.0/16, 10.h.0.0/16 }
18	define infowatch_my = 10.a.b.c
19	define squid_normal = 3128
20	define squid_transp = 3129
21	define squid_trassl = 3130
22	define sslvpn.infowatch.com = 46.148.194.86
23	define files.infowatch.ru = 178.16.25.15
24	define iwprint.infowatch.ru = 10.d.e.f
25	define s163.getcourses.ru = 95.213.153.163
26	define tls-v1-2.badssl.com = 104.154.89.105
27	flush ruleset
28	table ip raw {
29	  chain prerouting {
30	    type filter hook prerouting priority -300;
	    #      ,          
31	    meta l4proto { tcp, udp } th dport $transmission_port notrack
32	    tcp sport $no_track ip saddr != $iwprint.infowatch.ru notrack
33	    ip saddr { $sslvpn.infowatch.com, $files.infowatch.ru } tcp sport https notrack
34	  }
35	}
36	table ip filter {
37	  chain input {
38	    type filter hook input priority 0; policy drop;
	    #         ,        «loopback»
39	    iif lo accept
	    #   ICMP       ,       ICMP
40	    icmp type $icmp_types accept
	    #   
41	    ct state invalid counter drop
	    #   ,     (SACK)  TCP.        ,       
42	    tcp flags syn tcp option maxseg size < 999 counter drop
	    #   Bittorrent,         31
43	    iif $eth meta l4proto { tcp, udp } th dport $transmission_port accept
	    #  ,  ,       ,      
44	    tcp flags & (syn | ack) == syn ct state untracked log prefix "Untracked:" group 2 counter counter drop
	    #    ,        32
45	    tcp sport $no_track accept
	    #    ,        33
46	    ip saddr { $sslvpn.infowatch.com, $files.infowatch.ru } tcp sport https accept
	    #     ,   3128 ( )
47	    iif $br ip saddr $virtual_machines mark set 3128 counter accept
	    #       ,      ()  -
48	    iif $br ip daddr $host ip saddr $virtual_machines tcp dport { domain, http, microsoft-ds, nfs, $squid_normal } accept
	    #     
49	    ct state { established, related } accept
	    #       ,   
50	    iif $br udp dport { domain, bootps, tftp, 4011 } counter accept
	    #    ,        ,   (.  38)
51	    counter comment "  "
52	  }
53	  chain output {
54	    type filter hook output priority 100; policy drop;
	    #         ,        «loopback»
55	    oif lo accept
	    #   ICMP       ,       ICMP
56	    icmp type $icmp_types counter accept
	    #          (   48  50)
57	    oif { $eth, $wifi } udp dport . udp sport { bootps . bootpc } counter accept
58	    oif $br ip saddr $host ip daddr { $dhcp_client, 255.255.255.255 } udp sport . udp dport { bootps . bootpc } counter accept
59	    oif $br ip saddr $host ip daddr $virtual_machines udp sport { domain, tftp } counter accept
60	    oif $br ip saddr $host ip daddr $virtual_machines tcp sport { domain, http, microsoft-ds } accept
	    #  -           .      HTTPS   ,            
61	    oif $br ip daddr $virtual_machines tcp sport { http, https, 1012 } counter accept
	    #      ,     ,    1024
62	    meta l4proto { tcp, udp } th sport >= 1025 accept
	    #    ,        ,   (.  54)
63	    counter comment "  "
64	  }
65	  chain forward {
66	    type filter hook forward priority 0; policy drop;
	    #        (MTU)
67	    tcp flags syn tcp option maxseg size set rt mtu counter
	    #         
68	    iif $br ip daddr != $host meta l4proto { tcp, udp } th dport domain drop
	    #      ( -)      ,     ,  ,   .    ,      ( 80  443)     -,    divert         forward (  66  81).  ,   96      ,      80  443
69	    iif $br ip saddr { $privileged_vm, $dhcp_client } accept
70	    oif $br ip daddr { $privileged_vm, $dhcp_client } accept
	    #    ,        ,   (.  66)
71	    counter comment "  "
72	  }
	  #    «   • »     HTTPS  ,   443
73	  set nonstandard_https {
74	    type ipv4_addr . inet_service;
75	    elements = {
76	      $s163.getcourses.ru . 33443, #   artlinerschool.ru
77	      $tls-v1-2.badssl.com . 1012, #   badssl.com
78	  }
79	}
80	  chain divert {
81	    type filter hook prerouting priority -150; policy accept;
	    #   3128 (. .)   TCP,   ,    (  -)
82	    meta l4proto tcp socket transparent 1 mark set 3128 accept
	    #   3128 (. .)   TCP   ,   80.      -
83	    ip daddr != { 127.0.0.1, $host } tcp dport http tproxy to 127.0.0.1:$squid_transp mark set 3128 counter accept
	    #   3128 (. .)   TCP   ,   443.      -
84	    ip daddr != { 127.0.0.1, $host } tcp dport https tproxy to 127.0.0.1:$squid_trassl mark set 3128 counter accept
	    #    3128 (. .)   TCP        nonstandard_https (.  76  77  ).      -
85	    ip daddr . tcp dport @nonstandard_https tproxy to 127.0.0.1:$squid_trassl mark set 3128 counter accept
86	  }
87	}
88	table ip nat {
89	  chain prerouting {
90	    type nat hook prerouting priority 0; policy accept;
	    #               SSH
91	    iif $eth ip daddr $infowatch_my ip saddr $infowatch_pc tcp dport ssh counter dnat $vm_ssh
92	  }
93	  chain postrouting {
94	    type nat hook postrouting priority 100; policy accept;
	    #      ,   -,         .  -     UID  GID 
95	    oif { $eth, $wifi } ip saddr $virtual_machines skuid . skgid { squid . squid } counter masquerade
	    #      ,     ,  ,     , (   69  70).     ,    ,       HTTPS .           nonstandard_https (.  76  77  ).
96	    oif { $eth, $wifi } ip saddr { $privileged_vm, $dhcp_client } tcp dport != { http, https } log prefix "NAT:" group 2 counter masquerade
97	  }
98	}
	
99	table bridge filter {
  #   №5:     Wi-Fi   
100	  chain input {
    type filter hook input priority -200; policy accept;
    iif $wifi ether saddr != $my_phone counter drop
  }
  #   №4:    ,    IPv4,      
  chain forward {
101	    type filter hook forward priority -200; policy accept;
102	    oif $wifi ether type arp accept
103	    oif $wifi ip protocol { icmp, tcp, udp } ip daddr != 192.168.120.255 accept
104	    oif $wifi drop
105	  }
  #   №5:   Wi-Fi     
106	  chain output {
    type filter hook input priority 200; policy accept;
    oif $wifi ether daddr != $my_phone counter drop
  }
}
	#   №2:     ,    IPv4
107	table netdev filter {
108	  chain enp0s25 {
109	    type filter hook ingress device enp0s25 priority 0; policy drop;
110	    ether type arp accept
111	    ether daddr $my_eth_mac ip protocol { icmp, tcp, udp, gre } accept
112	  }
113	  chain wlp3s0 {
114	    type filter hook ingress device wlp3s0 priority 0; policy drop;
	    #  ARP  EAPOL  ,        
115	    ether type { arp, 0x888e } accept
	    #       ,         ,   
116	    ether daddr { $my_br_mac, $my_wifi_mac, ff:ff:ff:ff:ff:ff } ip protocol { icmp, tcp, udp, gre } accept
117	  }
118	}


Anpassung der Verbraucher


Auf dem PC selbst


Für gründlichere Tests eines transparenten Proxyservers habe ich beschlossen, ihn für alle Anwendungen (mit einigen Ausnahmen, dazu später mehr) auf dem PC selbst zu verwenden.

Fügen Sie das Proxy-Server-Zertifikat zum freigegebenen Speicher hinzu:

mkdir -p /usr/local/share/ca-certificates
cp /etc/squid/squid.pem /usr/local/share/ca-certificates/squid.crt

Aktualisieren Sie das Repository:

update-ca-certificates

Anwendungen - Firefox- und Chromium-Webbrowser verwenden keinen gemeinsamen Zertifikatspeicher. Daher sollte dieser dem entsprechenden Speicher dieser Anwendungen hinzugefügt werden.

Erstellen Sie die Konfigurationsdatei /etc/env.d/38proxy mit den folgenden Zeilen:

http_proxy=http://192.168.120.1:3128
https_proxy=http://192.168.120.1:3128
ftp_proxy=http://192.168.120.1:3128

Umgebungsvariablen aktualisieren:

env-update

Nach erneuter Eingabe werden die Einstellungen auf alle Anwendungen angewendet.

Über Ausnahmen:

  1. Für den Fall, dass wir den Chromium-Webbrowser verlassen, wird er ohne Proxyserver immer direkt mit dem Netzwerk verbunden. Dazu ändern wir die Konfigurationsdatei / etc / chromium / default auf folgende Weise:

    CHROMIUM_FLAGS="--enable-seccomp-sandbox —no-proxy-server"
  2. Bei Vorhandensein der Umgebungsvariablen https_proxy versucht die xfreerdp-Anwendung, eine Verbindung über einen Proxyserver herzustellen. Fügen Sie der Shell-Konfigurationsdatei daher die folgende Zeile hinzu:

    alias xfreerdp='https_proxy= xfreerdp'
  3. Die youtube-dl-Anwendung kann das Zertifikat möglicherweise nicht überprüfen, wahrscheinlich aufgrund der Art des Python-Zertifikatspeichers. Eine dauerhafte Lösung wurde noch nicht gefunden. Fügen Sie der Shell-Konfigurationsdatei die folgende Zeile hinzu:

    alias youtube-dl='youtube-dl --no-check-certificate'

Auf virtuellen Maschinen von Red Hat Enterprise Linux OS 6 und 7


Aktivieren Sie auf der virtuellen Maschine PEM-Zertifikate:

update-ca-trust force-enable

Wir schreiben das Proxyserver-Zertifikat vom PC auf die virtuelle Maschine neu:

scp squid.crt root@192.168.120.66:/etc/pki/ca-trust/source/anchors/

Auf der virtuellen Maschine aktualisieren wir das Zertifikat:

update-ca-trust extract

Auf virtuellen Maschinen mit Microsoft Windows-Betriebssystemen verschiedener Editionen


Das Zertifikat wird in den allgemeinen Zertifikatspeicher des Computers (nicht des Benutzers!) Im Abschnitt "Vertrauenswürdige Wurzeln ..." hochgeladen. Der Firefox-Webbrowser verwendet keinen gemeinsamen Zertifikatspeicher. Daher sollte das Zertifikat dem entsprechenden Speicher dieser Anwendung hinzugefügt werden.

Auf einem Raspberry Pi PC mit Raspbian OS


Das Anwendungs-Upgrade war ohne Installation eines Zertifikats erfolgreich.

Auf Smartphones mit Android OS


Das Zertifikat wird auf das Gerät vorinstalliert und dann mithilfe der Zertifikatverwaltungsanwendung installiert. Danach wird der Benutzer aufgefordert, die Sicherheit beim Betreten des Geräts (falls noch nicht geschehen) mithilfe eines Grafikschlüssels oder eines Kennworts zu erhöhen.

Fazit


Die neue Linux-Firewall (nft) ist ein großartiges Beispiel für freie Software, die gut zu Squid passt, dem De-facto-Standard eines kostenlosen Proxyservers.

Primäre Quellen


1. http://wiki.squid-cache.org/Features/Tproxy4
2. /usr/src/linux/Documentation/networking/tproxy.txt
3. http://wiki.nftables.org
4. nft (8)
5. https://www.bounca.org/tutorials/install_root_certificate.html

Autor: Shamil SaitovNikodim_Tychoblin

All Articles