Lula transparente com SSL-Bump para Gentoo com nft

imagem

fundo


Recentemente, comprometi-me a traduzir o firewall no meu PC com iptables testadas pelo tempo para os novos nftables. Para um estudo mais aprofundado das tabelas nf, eu me propus a tarefa: configurar um servidor proxy transparente (Squid) com análise de conexão criptografada (HTTPS) para distribuir o acesso à Internet em máquinas virtuais, PCs Raspberry Pi e no meu smartphone (executando o Android 6ª versão) em uma conexão sem fio (usando o aplicativo 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"
Aplicação ipsys-apps / iproute2-5.2.0-r1
USE = "caps minimal"
Serviço de Logapp-admin / ulogd-2.0.7-r1
USE = "nfct nflog"

Ajuste do kernel


imagem
Mesma coisa, mas 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 --->


Para referência, cito um trecho 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

Configuração de rede


Se o serviço net.lo não for adicionado ao nível de execução da inicialização, ele deverá ser adicionado lá:

rc-config add net.lo boot

Da mesma maneira, eles são criados e configurados para serem executados no nível padrão do serviço de rede. br0 (ponte para máquinas virtuais e smartphone), net. enp0s25 (interface com fio) e net. wlp3s0 (interface sem fio), por exemplo:

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

O arquivo de configuração final /etc/conf.d/net em nosso exemplo se parece com isso (menos as configurações não relacionadas à nossa tarefa):

imagem

Mesma coisa, mas 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
}


As linhas destacadas adicionam uma nova tabela de roteamento, neste exemplo sob o número 3128, e o gate é o padrão para ela (a interface de loopback), e a regra é de acordo com quais pacotes marcados com um firewall com o número de etiqueta 3128 (números decimais nos dois casos) atendido por esse cronograma.

Para impedir que pacotes roteados sejam descartados devido à incompatibilidade de endereços no nível da rede (a proxy transparente mantém os pacotes intactos!), Adicione as seguintes linhas ao /etc/sysctl.conf (ou altere as existentes):

imagem

Se você precisar aplicar essas configurações antes de reiniciar, você deve configurá-los adicionalmente para as duas interfaces de rede com acesso à Internet:

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

Configurações de proxy


Como a porta normal (não transparente) do servidor proxy será fixada no endereço da ponte ( 192.168.120.1 ), adicione a seguinte linha ao /etc/rc.conf:

rc_squid_need="net.br0"

As seguintes configurações de proxy não serão consideradas neste artigo:

  • Verificação da identidade dos usuários em uma porta regular (não transparente);
  • ICAP para integrar com um dispositivo de prevenção de vazamento de dados (por exemplo, InfoWatch Traffic Monitor);
  • Gerando chaves de criptografia e criando um certificado.

O arquivo de configuração /etc/squid/squid.conf no final se parece com o seguinte (apenas no caso, eu dou-o completamente):

imagem

imagem

Mesma coisa, mas 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


Configuração de firewall


Configure os serviços nftables e ulogd no nível de execução "padrão" (este último é necessário para a notificação do pacote):

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

Como haverá uma ponte nas configurações do firewall, adicione a seguinte linha ao /etc/rc.conf:

rc_nftables_need="net.br0"

Para que a notificação funcione no /etc/sysctl.conf, você deve adicionar a seguinte linha:

net.netfilter.nf_log.2 = nfnetlink_log

Para que o arquivo de configuração esteja na pasta / etc / nftables, fazemos as seguintes alterações no /etc/conf.d/nftables:

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

Para impedir que alterações temporárias sejam salvas no arquivo de configuração, faça outra alteração no /etc/conf.d/nftables:

SAVE_ON_STOP="no"

Vou descrever as tarefas atribuídas ao firewall:

  1. As regras padrão em todas as cadeias da tabela de filtros IP devem remover pacotes (mesmo na cadeia de saída!). Da mesma forma para tabelas de filtro netdev;
  2. A troca de qualquer tipo, exceto o IPv4 e a troca de serviços relacionados (por exemplo, ARP), é suprimida o mais rápido possível (nem o IPv4 nem o IPSec são usados);
  3. Pacotes multicast IPv4 também são removidos o mais cedo possível;
  4. Para proteger um smartphone Android (quando conectado à ponte usando o aplicativo hostapd), a troca de broadcast realizada por máquinas virtuais em execução no Microsoft Windows não deve ser transmitida para uma interface sem fio.
  5. Você só pode usar nossos dispositivos Wi-Fi com endereços MAC conhecidos.

O arquivo de configuração / etc / nftables / rules-save no final se parece com isso (menos a maioria das explicações):

imagem

imagem

imagem

imagem

imagem

imagem

Mesma coisa, mas 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	}


Personalização do consumidor


No próprio PC


Para testes mais detalhados de um servidor proxy transparente, decidi usá-lo para todos os aplicativos (com algumas exceções, mais sobre isso mais tarde) no próprio PC.

Adicione o certificado do servidor proxy ao armazenamento compartilhado:

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

Atualize o repositório:

update-ca-certificates

Aplicativos - os navegadores Firefox e Chromium não usam um armazenamento de certificados comum, portanto, ele deve ser adicionado ao armazenamento correspondente desses aplicativos.

Crie o arquivo de configuração /etc/env.d/38proxy com as seguintes linhas:

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

Atualize variáveis ​​de ambiente:

env-update

Após reinserir, as configurações serão aplicadas a todos os aplicativos.

Sobre exceções:

  1. Para deixar o navegador da Web Chromium, ele sempre se conectará à rede diretamente, sem um servidor proxy, para isso, alteraremos o arquivo de configuração / etc / chromium / default da seguinte maneira:

    CHROMIUM_FLAGS="--enable-seccomp-sandbox —no-proxy-server"
  2. Na presença da variável de ambiente https_proxy, o aplicativo xfreerdp tenta se conectar através de um servidor proxy, portanto, adicione a seguinte linha ao arquivo de configuração do shell:

    alias xfreerdp='https_proxy= xfreerdp'
  3. O aplicativo youtube-dl não pode verificar o certificado, provavelmente devido à natureza do armazenamento de certificados Python. Uma solução permanente ainda não foi encontrada, portanto, adicione a seguinte linha ao arquivo de configuração do shell:

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

Nas máquinas virtuais do Red Hat Enterprise Linux OS 6 e 7


Na máquina virtual, ative os certificados PEM:

update-ca-trust force-enable

Reescrevemos o certificado do servidor proxy do PC para a máquina virtual:

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

Na máquina virtual, atualizamos o certificado:

update-ca-trust extract

Em máquinas virtuais com sistemas operacionais Microsoft Windows de diferentes edições


O certificado é carregado no armazenamento geral de certificados da máquina (não no usuário!) Na seção "Raízes confiáveis ​​...". O navegador da web Firefox não usa um repositório de certificados comum, portanto, o certificado deve ser adicionado ao repositório correspondente desse aplicativo.

Em um PC Raspberry Pi com sistema operacional Raspbian


A atualização do aplicativo foi bem-sucedida sem a instalação de um certificado.

Em smartphones com sistema operacional Android


O certificado é pré-carregado no dispositivo e instalado usando o aplicativo de gerenciamento de certificados. Depois disso, o usuário será solicitado a aumentar a segurança de entrar no dispositivo (se ainda não o tiver feito) com a ajuda de uma chave gráfica ou senha.

Conclusão


O novo firewall Linux (nft) é um ótimo exemplo de software livre que combina bem com o Squid, o padrão de fato de um servidor proxy gratuito.

Fontes primárias


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