Squid transparent avec SSL-Bump pour Gentoo avec nft

image

Contexte


Récemment, j'ai entrepris de traduire le pare-feu sur mon PC avec des iptables éprouvés par le temps pour les tout nouveaux nftables. Pour une étude plus approfondie des tables nf, je me suis fixé la tâche: configurer un serveur proxy transparent (Squid) avec analyse de connexion cryptée (HTTPS) pour distribuer l'accès Internet aux machines virtuelles, aux PC Raspberry Pi, ainsi qu'à mon smartphone (fonctionnant sous Android 6ème version) via une connexion sans fil (à l'aide de l'application hostapd).


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


«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"
Application IPsys-apps / iproute2-5.2.0-r1
USE = "caps minimal"
Service de journalisationapp-admin / ulogd-2.0.7-r1
USE = "nfct nflog"

Réglage du noyau


image
Même chose que du texte
[*] 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 --->


Pour référence, je cite un extrait de /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

Configuration du réseau


Si le service net.lo n'est pas ajouté au niveau d'exécution de démarrage, il doit y être ajouté:

rc-config add net.lo boot

De la même manière, ils sont créés et configurés pour s'exécuter pour le niveau par défaut du service net. br0 (pont pour machines virtuelles et smartphone), net. enp0s25 (interface filaire) et net. wlp3s0 (interface sans fil), par exemple:

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

Le fichier de configuration final /etc/conf.d/net dans notre exemple ressemble à ceci (moins les paramètres non liés à notre tâche):

image

Même chose que du texte
# 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
}


Les lignes en surbrillance ajoutent une nouvelle table de routage, dans cet exemple sous le numéro 3128, et la porte est la valeur par défaut (l'interface de bouclage), et la règle est selon quels paquets marqués d'un pare-feu avec le numéro d'étiquette 3128 (nombres décimaux dans les deux cas) servi par ce calendrier.

Afin d'éviter que les paquets routés ne soient rejetés en raison d'une incompatibilité des adresses de niveau réseau (le proxy transparent conserve les paquets intacts!), Ajoutez les lignes suivantes à /etc/sysctl.conf (ou modifiez celles existantes):

image

si vous devez appliquer ces paramètres avant de redémarrer, vous devez également les définir pour les deux interfaces réseau avec accès Internet:

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

Paramètres du proxy


Étant donné que le port normal (opaque) du serveur proxy sera fixé à l'adresse du pont ( 192.168.120.1 ), ajoutez la ligne suivante à /etc/rc.conf:

rc_squid_need="net.br0"

Les paramètres de proxy suivants ne seront pas pris en compte dans cet article:

  • Vérification de l'identité des utilisateurs sur un port régulier (non transparent);
  • ICAP à intégrer à un dispositif de prévention des fuites de données (par exemple InfoWatch Traffic Monitor);
  • Génération de clés de chiffrement et création d'un certificat.

Le fichier de configuration /etc/squid/squid.conf à la fin ressemble à ceci (juste au cas où, je le donne complètement):

image

image

Même chose que du texte
	#    
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


Configuration du pare-feu


Configurez les services nftables et ulogd au niveau d'exécution "par défaut" (ce dernier est nécessaire pour la notification du package):

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

Puisqu'il y aura un pont dans les paramètres du pare-feu, ajoutez la ligne suivante à /etc/rc.conf:

rc_nftables_need="net.br0"

Pour que la notification fonctionne dans /etc/sysctl.conf, vous devez ajouter la ligne suivante:

net.netfilter.nf_log.2 = nfnetlink_log

Pour que le fichier de configuration se trouve dans le dossier / etc / nftables, nous apportons la modification suivante dans /etc/conf.d/nftables:

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

Pour empêcher l'enregistrement des modifications temporaires dans le fichier de configuration, apportez une autre modification à /etc/conf.d/nftables:

SAVE_ON_STOP="no"

Je décrirai les tâches assignées au pare-feu:

  1. Les règles par défaut dans toutes les chaînes de la table de filtrage ip doivent supprimer les paquets (même dans la chaîne de sortie!). De même pour les tables de filtres netdev;
  2. L'échange de tout type, à l'exception d'IPv4 et des échanges de services associés (par exemple, ARP), est supprimé dès que possible (ni IPv4 ni IPSec ne sont utilisés);
  3. Les paquets de multidiffusion IPv4 sont également supprimés le plus tôt possible;
  4. Pour protéger le smartphone Android (lorsqu'il est connecté au pont à l'aide de l'application hostapd), l'échange de diffusion effectué par des machines virtuelles fonctionnant sous le système d'exploitation Microsoft Windows ne doit pas être transmis à l'interface sans fil.
  5. Vous ne pouvez utiliser nos appareils Wi-Fi qu'avec des adresses MAC connues.

Le fichier de configuration / etc / nftables / rules-save à la fin ressemble à ceci (moins la plupart des explications):

image

image

image

image

image

image

Même chose que du texte
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	}


Personnalisation du consommateur


Sur le PC lui-même


Pour des tests plus approfondis d'un serveur proxy transparent, j'ai décidé de l'utiliser pour toutes les applications (à quelques exceptions près, plus loin) sur le PC lui-même.

Ajoutez le certificat du serveur proxy au magasin partagé:

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

Mettez à jour le référentiel:

update-ca-certificates

Applications - Les navigateurs Web Firefox et Chromium n'utilisent pas de magasin de certificats commun, il convient donc de l'ajouter au magasin correspondant de ces applications.

Créez le fichier de configuration /etc/env.d/38proxy avec les lignes suivantes:

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

Mettre à jour les variables d'environnement:

env-update

Après avoir ressaisi, les paramètres seront appliqués à toutes les applications.

À propos des exceptions:

  1. Juste au cas où, quittons le navigateur Web Chromium, il se connectera toujours directement au réseau, sans serveur proxy, pour cela nous changerons le fichier de configuration / etc / chromium / default de cette façon:

    CHROMIUM_FLAGS="--enable-seccomp-sandbox —no-proxy-server"
  2. En présence de la variable d'environnement https_proxy, l'application xfreerdp essaie de se connecter via un serveur proxy, ajoutez donc la ligne suivante au fichier de configuration du shell:

    alias xfreerdp='https_proxy= xfreerdp'
  3. L'application youtube-dl ne peut pas vérifier le certificat, probablement en raison de la nature du magasin de certificats Python. Une solution permanente n'a pas encore été trouvée, alors ajoutez la ligne suivante au fichier de configuration du shell:

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

Sur les machines virtuelles Red Hat Enterprise Linux OS 6 et 7


Sur la machine virtuelle, activez les certificats PEM:

update-ca-trust force-enable

Nous réécrivons le certificat du serveur proxy du PC vers la machine virtuelle:

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

Sur la machine virtuelle, nous mettons à jour le certificat:

update-ca-trust extract

Sur les machines virtuelles avec des systèmes d'exploitation Microsoft Windows de différentes éditions


Le certificat est téléchargé dans le magasin de certificats général de la machine (pas l'utilisateur!) Dans la section "Racines de confiance ...". Le navigateur Web Firefox n'utilise pas de magasin de certificats commun, le certificat doit donc être ajouté au magasin correspondant de cette application.

Sur un PC Raspberry Pi avec Raspbian OS


La mise à niveau de l'application a réussi sans installer de certificat.

Sur les smartphones avec Android OS


Le certificat est préchargé sur l'appareil, puis installé à l'aide de l'application de gestion des certificats. Après cela, l'utilisateur sera invité à améliorer la sécurité de la saisie de l'appareil (si ce n'est pas déjà fait) à l'aide d'une clé graphique ou d'un mot de passe.

Conclusion


Le nouveau pare-feu Linux (nft) est un excellent exemple de logiciel gratuit qui va bien avec Squid, la norme de facto d'un serveur proxy gratuit.

Sources primaires


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

Auteur: Shamil SaitovNikodim_Tychoblin

All Articles