Calamar transparente con SSL-Bump para Gentoo con nft

imagen

Antecedentes


Recientemente, me comprometí a traducir el firewall en mi PC con iptables probadas con el tiempo a las nuevas nftables. Para un estudio más profundo de las tablas nf, me puse la tarea: configurar un servidor proxy transparente (Squid) con análisis de conexión encriptado (HTTPS) para distribuir el acceso a Internet a máquinas virtuales, PC Raspberry Pi, así como a mi teléfono inteligente (con Android 6to lanzamiento) a través de una conexión inalámbrica (usando la aplicación 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 = "prueba asm zlib"
Aplicación Nftnet-firewall / nftables-0.9.2
USE = "doc gmp modern_kernel"
Aplicación ipsys-apps / iproute2-5.2.0-r1
USE = "caps mínimo"
Servicio de registroapp-admin / ulogd-2.0.7-r1
USE = "nfct nflog"

Kernel Tuning


imagen
Lo mismo pero texto
[*] 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 --->


Como referencia, cito un extracto 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

Configuración de la red


Si el servicio net.lo no se agrega al nivel de ejecución de arranque, se debe agregar allí:

rc-config add net.lo boot

Del mismo modo, se crean y configuran para ejecutarse para el nivel predeterminado del servicio de red. br0 (puente para máquinas virtuales y teléfonos inteligentes), neto. enp0s25 (interfaz cableada) y net. wlp3s0 (interfaz inalámbrica), por ejemplo:

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

El archivo de configuración final /etc/conf.d/net en nuestro ejemplo tiene este aspecto (menos la configuración no relacionada con nuestra tarea):

imagen

Lo mismo pero texto
# 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
}


Las líneas resaltadas agregan una nueva tabla de enrutamiento, en este ejemplo con el número 3128, y la puerta es la predeterminada (la interfaz de bucle invertido), y la regla es según qué paquetes marcados con un firewall con el número de etiqueta 3128 (números decimales en ambos casos) servido por este horario.

Para evitar que los paquetes enrutados se descarten debido a que las direcciones de nivel de red no coinciden (¡el proxy transparente mantiene los paquetes intactos!), Agregue las siguientes líneas a /etc/sysctl.conf (o cambie las existentes):

imagen

si necesita aplicar estas configuraciones antes de reiniciar, entonces también debe configurarlos para ambas interfaces de red con acceso a Internet:

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

Configuración de proxy


Dado que el puerto normal (opaco) del servidor proxy se fijará a la dirección del puente ( 192.168.120.1 ), agregue la siguiente línea a /etc/rc.conf:

rc_squid_need="net.br0"

La siguiente configuración de proxy no se considerará en este artículo:

  • Verificación de la identidad de los usuarios en un puerto regular (no transparente);
  • ICAP para integrarse con un dispositivo de prevención de fuga de datos (por ejemplo, InfoWatch Traffic Monitor);
  • Generando claves de cifrado y creando un certificado.

El archivo de configuración /etc/squid/squid.conf al final se ve así (por si acaso, lo doy por completo):

imagen

imagen

Lo mismo pero texto
	#    
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


Configuración de cortafuegos


Configure los servicios nftables y ulogd en el nivel de ejecución "predeterminado" (este último es necesario para la notificación del paquete):

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

Como habrá un puente en la configuración del firewall, agregue la siguiente línea a /etc/rc.conf:

rc_nftables_need="net.br0"

Para que la notificación funcione en /etc/sysctl.conf, debe agregar la siguiente línea:

net.netfilter.nf_log.2 = nfnetlink_log

Para que el archivo de configuración esté en la carpeta / etc / nftables, hacemos el siguiente cambio en /etc/conf.d/nftables:

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

Para evitar que se guarden cambios temporales en el archivo de configuración, realice otro cambio en /etc/conf.d/nftables:

SAVE_ON_STOP="no"

Describiré las tareas asignadas al firewall:

  1. Las reglas predeterminadas en todas las cadenas de la tabla de filtro ip deberían eliminar paquetes (¡incluso en la cadena de salida!). De manera similar para las tablas de filtro netdev;
  2. El intercambio de cualquier tipo, excepto IPv4 y el intercambio de servicios relacionados (por ejemplo, ARP), se suprime lo antes posible (no se utilizan IPv4 ni IPSec);
  3. Los paquetes de multidifusión IPv4 también se eliminan lo antes posible;
  4. Para proteger el teléfono inteligente Android (cuando está conectado al puente usando la aplicación hostapd), el intercambio de transmisión realizado por máquinas virtuales que se ejecutan bajo el sistema operativo Microsoft Windows no debe transmitirse a la interfaz inalámbrica.
  5. Solo puede usar nuestros dispositivos Wi-Fi con direcciones MAC conocidas.

El archivo de configuración / etc / nftables / rules-save al final se ve así (menos la mayoría de las explicaciones):

imagen

imagen

imagen

imagen

imagen

imagen

Lo mismo pero texto
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	}


Personalización del consumidor


En la PC misma


Para realizar pruebas más exhaustivas de un servidor proxy transparente, decidí usarlo para todas las aplicaciones (con algunas excepciones, más sobre eso más adelante) en la PC.

Agregue el certificado del servidor proxy a la tienda compartida:

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

Actualice el repositorio:

update-ca-certificates

Aplicaciones: los navegadores web Firefox y Chromium no utilizan un almacén de certificados común, por lo que deben agregarse al almacén correspondiente de estas aplicaciones.

Cree el archivo de configuración /etc/env.d/38proxy con las siguientes líneas:

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

Actualizar variables de entorno:

env-update

Después de volver a ingresar, la configuración se aplicará a todas las aplicaciones.

Sobre excepciones:

  1. Por si acaso, dejemos el navegador web Chromium, siempre se conectará a la red directamente, sin un servidor proxy, para esto cambiaremos el archivo de configuración / etc / chromium / default de esta manera:

    CHROMIUM_FLAGS="--enable-seccomp-sandbox —no-proxy-server"
  2. En presencia de la variable de entorno https_proxy, la aplicación xfreerdp intenta conectarse a través de un servidor proxy, por lo tanto, agregue la siguiente línea al archivo de configuración del shell:

    alias xfreerdp='https_proxy= xfreerdp'
  3. La aplicación youtube-dl no puede verificar el certificado, probablemente debido a la naturaleza del almacén de certificados de Python. Aún no se ha encontrado una solución permanente, por lo tanto, agregue la siguiente línea al archivo de configuración del shell:

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

En máquinas virtuales Red Hat Enterprise Linux OS 6 y 7


En la máquina virtual, habilite los certificados PEM:

update-ca-trust force-enable

Reescribimos el certificado del servidor proxy desde la PC a la máquina virtual:

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

En la máquina virtual actualizamos el certificado:

update-ca-trust extract

En máquinas virtuales con sistemas operativos Microsoft Windows de diferentes ediciones


El certificado se carga en el almacén de certificados general de la máquina (¡no el usuario!) En la sección "Raíces de confianza ...". El navegador web Firefox no utiliza un almacén de certificados común, por lo que el certificado debe agregarse al almacén correspondiente de esta aplicación.

En una PC Raspberry Pi con sistema operativo Raspbian


La actualización de la aplicación fue exitosa sin instalar un certificado.

En teléfonos inteligentes con sistema operativo Android


El certificado se carga previamente en el dispositivo y luego se instala mediante la aplicación de administración de certificados. Después de eso, se le pedirá al usuario que mejore la seguridad de ingresar al dispositivo (si aún no lo ha hecho) usando una clave gráfica o contraseña.

Conclusión


El nuevo firewall de Linux (nft) es un gran ejemplo de software libre que combina bien con Squid, el estándar de facto de un servidor proxy gratuito.

Fuentes primarias


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