OpenVPN, sobre o qual você sabia tão pouco

OpenVPN, quanto nesta palavra. Um servidor VPN de código aberto gratuito, com várias plataformas, configurável de maneira flexível e flexível, que na verdade é o padrão padrão para organizar o acesso a redes corporativas internas. A maioria dos administradores o usa com configurações padrão ou com configurações típicas amplamente descritas em diferentes HOW-TOs. Mas o OpenVPN é tão simples quanto parece à primeira vista? Neste artigo, consideraremos os mecanismos internos do OpenVPN, ocultos aos olhos, que alteram drasticamente a ideia de suas capacidades.


O servidor OpenVPN é distribuído na forma de código-fonte ou pacotes compilados prontos para instalar para vários sistemas operacionais. O OpenSSL é usado como uma biblioteca que fornece criptografia.


A maioria das configurações para conectar clientes ao servidor, bem como entre servidores, envolve o uso de várias chaves privadas ou privadas / públicas para garantir a segurança do tráfego interno. Para redes corporativas no modo MultiPoint-para-SinglePoint, geralmente é usada uma autoridade de certificação PKI, fácil de construir usando easy-rsa ou XCA . Para comunicação entre servidores ponto a ponto, uma configuração de chave compartilhada é usada principalmente. Lembre-se dos mecanismos e recursos básicos e conhecidos.


Principais mecanismos e capacidades


  • Autenticação de certificado


    Uma enorme quantidade de documentação foi escrita sobre isso. O ponto é simples. Está sendo criada uma autoridade de certificação que emite certificados de usuário. Com a ajuda de uma autoridade de certificação, é fornecido controle para conectar usuários ao servidor OpenVPN. Quando o certificado expira ou é revogado, o acesso do usuário é bloqueado. As chaves privadas com uma senha definida nelas, emitida em conjunto com o certificado, fornecem segurança contra conexões não autorizadas a recursos internos.


  • Chaves ponto a ponto privadas


    Do ponto de vista de conectar apenas um usuário / servidor aos recursos da empresa, um esquema com chaves privadas é usado. Uma chave é gerada em um dos hosts, que é compartilhado entre o servidor e o cliente.



Em todos os casos de conexão para segurança do handshake "handshake" entre o cliente e o servidor, o protocolo Diffie-Hellmann é usado.


  • Autenticação de usuário externo


    Para simplificar o controle sobre as conexões do usuário, em vez de um esquema com sua própria PKI, você pode usar um esquema com autenticação de usuário externo por login / senha . Esse esquema é conveniente para autenticar usuários por, digamos, um login / senha de domínio. Para conectar-se ao servidor, o certificado do servidor e a chave de assinatura do pacote HARDENING OPENVPN SECURITY são adicionados ao arquivo de configuração do cliente.
    exemplo de configuração do cliente


    dev tun proto udp #  IP  OpenVPN remote 172.16.111.166 # Port  port 1200 client resolv-retry infinite tls-client key-direction 1 auth SHA1 cipher BF-CBC #comp-lzo persist-key persist-tun # auth-user-pass c:/temp/pass.txt # # just create a file with name pass.txt # and put to it two lines # ------------- #username #password # ------------- #auth-user-pass verb 3 <ca> -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIJAOt3kFH7PxA0MA0GCSqGSIb3DQEBCwUAMIGjMQswCQYD .... -----END CERTIFICATE----- </ca> <tls-auth> -----BEGIN OpenVPN Static key V1----- 83ddd29fa82212f3059d85a41490134c .... a4f2c7df3a22364a49093bca102dedeb -----END OpenVPN Static key V1----- </tls-auth> 

    Parte da configuração do servidor para autenticação do cliente via arquivo
    Usando métodos de autenticação alternativos


     verify-client-cert none #client-cert-not-required username-as-common-name tls-server tls-auth /usr/local/etc/openvpn/ssl/tlsauth.key key-direction 0 tls-timeout 120 auth SHA1 cipher BF-CBC auth-user-pass-verify /usr/local/etc/openvpn/auth/auth-static-file.pl via-file 

    Esse esquema é conveniente, mas muito inseguro.


  • PAM


    Para aumentar a segurança, você pode usar plug-ins que fornecem verificação de login / senha em sistemas externos. O método mais comum é o PAM do sistema (Módulos de autenticação conectáveis).
    Adicione a linha ao arquivo de configuração OpenVPN


     plugin /usr/share/openvpn/plugin/lib/openvpn-auth-pam.so login 

  • Encaminhamento


    Porque A principal tarefa do servidor é fornecer aos usuários / servidores remotos acesso a recursos internos; o servidor permite determinar o roteamento estático dos clientes para o servidor e do servidor para os clientes. Do ponto de vista do acesso do cliente aos recursos internos, o servidor que usa DHCP e as diretivas "rota" ou "rota de envio" permitem transferir rotas de rede internas para o cliente. Para notificar o próprio servidor sobre redes remotas no lado do cliente, é usado "dir de configuração do cliente" (ccd), um mecanismo que permite usar a diretiva "iroute" para descrever a lista de redes internas do cliente que devem estar na tabela de roteamento do servidor para trafegar o tráfego para elas.



Nesse recurso "comum", amplamente utilizado, termina a personalização local e final para cada caso específico.


Recursos adicionais do OpenVPN


Considere os recursos adicionais do OpenVPN, dos quais alguém já deve ter ouvido falar, mas, na realidade, não viu ou usou.


  • Segurança de rede / filtragem de pacotes


    Porque O OpenVPN direciona o tráfego, possui dois modos de operação regulares mutuamente exclusivos. O primeiro modo é o roteamento dentro do servidor OpenVPN, o segundo modo é o roteamento nuclear entre interfaces. No primeiro caso, o OpenVPN é responsável por alternar e filtrar pacotes entre clientes / redes; no segundo caso, qualquer filtro de pacote do sistema suportado no host (pf, iptables, etc).
    Poucas pessoas sabem que o OpenVPN possui um filtro de pacotes interno que permite permitir ou isolar conexões entre usuários e redes.
    Sim sim Você leu certo. O OpenVPN possui seu próprio filtro de pacotes embutido. A capacidade de filtrar o tráfego foi implementada em 2010 .
    O filtro de pacotes OpenVPN é controlado pela interface de gerenciamento ou por plug-ins conectados ao OpenVPN.
    As regras de tráfego são gerenciadas através de um arquivo. O formato do arquivo é simples.


     [CLIENTS DROP|ACCEPT] {+|-}common_name1 {+|-}common_name2 . . . [SUBNETS DROP|ACCEPT] {+|-}subnet1 {+|-}subnet2 . . . [END] 

    As diretivas de bloco (ACCEPT / DENY) definem a ação padrão para todos os clientes não especificados dentro do bloco.
    Por exemplo, arquivo para o usuário user2


     [CLIENTS DROP] +user1 [SUBNETS DROP] [END] 

    bloqueará o tráfego para todos os usuários e redes, mas permitirá o tráfego para o cliente1. Se o usuário1 não descrever explicitamente a permissão para transferir tráfego para o usuário2, o tráfego seguirá apenas em uma direção user2-> user1.



Ou outro exemplo.
Desative tudo, exceto o acesso entre usuários e o servidor DNS localizado na rede local e o circuito de teste na rede 192.168.0.0/24


 [CLIENTS DROP] +user1 +user2 [SUBNETS DROP] +10.150.0.1 +10.150.1.1 +192.168.0.0/24 [END] 

O mecanismo de filtragem é ativado por meio do arquivo de configuração ou ao conectar o plug-in que "define" o sinalizador "OPENVPN_PLUGIN_ENABLE_PF".
Discutiremos essa oportunidade mais tarde.
O segundo modo de filtragem de tráfego é o filtro de pacotes embutido no sistema. Para ativá-lo, a configuração não deve ter uma diretiva "cliente para cliente". Do ponto de vista da automação da ativação / desativação das regras necessárias ao conectar / desconectar clientes, é mais conveniente usar inserções separadas na lista de regras, implementadas por meio de CHAINS in Iptables (Linux) ou em Anchors in PF (FreeBSD). A ativação / desativação de regras geralmente é feita por meio das diretivas de conexão / desconexão do cliente no arquivo de configuração do servidor, que chamam os scripts correspondentes quando o usuário se conecta / desconecta.


  • Autenticação avançada de PAM


    A autenticação estendida do PAM significa alterar a lógica do login do usuário e da verificação de senha. Isso é obtido instalando os plug-ins apropriados para o OpenVPN, que fornecem leitura e verificação de dados em fontes externas, ou conectando bibliotecas ao sistema que permitem que qualquer lógica seja script. Uma dessas bibliotecas é o pam_python , que ajuda a criar scripts para qualquer lógica de verificação de login / senha por meio de scripts Python.
    Se for usada, a sequência de verificação do usuário será alterada da seguinte maneira.


     plugin openvpn-plugin-auth-pam.so pam_python login USERNAME password PASSWORD domain mydomain.com 

    Como o “under the hood” do PAM são os algoritmos de diálogo do sistema com o usuário ou as bibliotecas externas, esses diálogos podem ser controlados. Por exemplo, conecte tokens OTP ao sistema . A biblioteca LinOTP é tomada simplesmente como exemplo, porque Perdi minha própria biblioteca auto-escrita durante os testes em algum lugar ¯ \ (ツ) / ¯
    Além disso, os exemplos são facilmente pesquisados ​​pela palavra "pam_python".
    O principal problema ao trabalhar com módulos PAM externos é a incapacidade de obter o ambiente de sessão do OpenVPN dentro do Python chamado ou qualquer outro script chamado através do pam do sistema. I.e. o script fornece apenas as funções para verificar o login / senha atribuídos a ele.


  • Autenticação Adiada


    O servidor OpenVPN suporta a chamada autenticação "atrasada". A autenticação "atrasada" é usada nos casos em que o serviço de autenticação não pode atender à solicitação de verificação de login / senha em tempo real.


  • Plugins OpenVPN


    Este é um universo paralelo separado, sobre o qual pode ser conhecido, mas, devido a alguma confusão, eles não conseguem ou têm medo de usar. De fato, escrever um plug-in funcional para o OpenVPN requer programação em C com tudo o que isso implica. Exemplos de plugins simples estão incluídos na árvore de código-fonte do OpenVPN ou , por exemplo, existe um plug - in para demonstrar as chamadas de método do OpenVPN .



Vamos tentar descobrir como os plugins funcionam no OpenVPN.
Funções e parâmetros usados ​​para trabalhar com plugins são descritos em um arquivo separado
A principal tarefa do plug-in, quando é inicializada pelo servidor OpenVPN, é transferir a lista de funções suportadas pelo plug-in e, ao chamar qualquer uma das funções, retornar o código de resposta correto, que ficará claro para o servidor.


 #define OPENVPN_PLUGIN_FUNC_SUCCESS 0 #define OPENVPN_PLUGIN_FUNC_ERROR 1 #define OPENVPN_PLUGIN_FUNC_DEFERRED 2 

Vamos nos aprofundar mais em cada grupo. Vamos considerar a lógica do trabalho com base na autenticação de senha do usuário.
Quando o servidor inicia, após a leitura do arquivo de configuração, o servidor chama as funções OPENVPN_PLUGIN_UP e OPENVPN_PLUGIN_ROUTE_UP. No ambiente variável das funções chamadas, os principais parâmetros do servidor em execução são transferidos.


 OPENVPN_PLUGIN_UP { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "daemon_log_redirect":"1", "daemon":"1", "route_net_gateway":"172.16.100.1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"0", "local_port_1":"1200", "route_network_1":"10.150.0.0" } 

 OPENVPN_PLUGIN_ROUTE_UP { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "daemon_log_redirect":"1", "daemon":"1", "route_net_gateway":"172.16.100.1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"2", "local_port_1":"1200", "route_network_1":"10.150.0.0" } 

Essas funções podem ser usadas para alertas na inicialização do servidor ou alterações na configuração.
Ao conectar um cliente, o OpenVPN solicita a capacidade de ativar um filtro de pacotes interno.


 OPENVPN_PLUGIN_ENABLE_PF { "route_netmask_1":"255.255.0.0", "daemon_start_time":"1545994898", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "local_1":"172.16.100.139", "script_context":"init", "config":"/usr/local/etc/openvpn/server150.conf", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "verb":"2", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "daemon":"1", "daemon_log_redirect":"1", "dev_type":"tun", "route_gateway_1":"10.150.0.2", "remote_port_1":"1200", "dev":"tun150", "pluginid":"11", "local_port_1":"1200", "route_network_1":"10.150.0.0" } 

Como você pode ver no dump, a variável pf_file apareceu. Este arquivo deve conter as regras do filtro de pacotes interno para a sessão atual que está sendo processada.
Em seguida, o nome de usuário e a senha do usuário são verificados na função OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY


 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "IV_NCP":"2", "IV_COMP_STUB":"1", "daemon_start_time":"1545994898", "IV_LZ4":"1", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_a3d0650a43b88ca1b5f305ce2c8f682.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"2", "IV_PLAT":"win", "daemon_pid":"626", "password":"12312312312312", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"5", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

Este é o único local em que a senha no ambiente variável está presente de forma clara.
O resultado desta função deve ser três respostas possíveis.


 #define OPENVPN_PLUGIN_FUNC_SUCCESS 0 #define OPENVPN_PLUGIN_FUNC_ERROR 1 #define OPENVPN_PLUGIN_FUNC_DEFERRED 2 

Se o servidor receber uma resposta OPENVPN_PLUGIN_FUNC_DEFERRED, o mecanismo de autenticação "atrasada" entra em operação. Como vemos, a variável "auth_control_file" apareceu no ambiente da variável, o conteúdo dessa variável contém o nome do arquivo no qual uma resposta do sistema de autenticação será esperada. A resposta é o símbolo 0 (para permitir acesso), 1 (para negar acesso) colocado no arquivo especificado. O parâmetro do servidor "janela manual" determina o tempo limite em segundos, durante os quais o servidor aguardará uma resposta. Enquanto aguarda, o tráfego de outros clientes não é interrompido.


Como trabalhamos com autenticação de senha, a função de verificação de certificado OPENVPN_PLUGIN_TLS_VERIFY não é chamada. Em vez disso, OPENVPN_PLUGIN_TLS_FINAL é chamado imediatamente, confirmando o estabelecimento da sessão.


 OPENVPN_PLUGIN_TLS_FINAL { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "IV_NCP":"2", "IV_COMP_STUB":"1", "daemon_start_time":"1545994898", "IV_LZ4":"1", "redirect_gateway":"0", "ifconfig_remote":"10.150.0.2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "link_mtu":"1622", "pf_file":"/tmp/openvpn_pf_b7a18ca8fac838679ca87ada6b8a356.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_a3d0650a43b88ca1b5f305ce2c8f682.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"2", "IV_PLAT":"win", "daemon_pid":"626", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"10", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

Em seguida, é chamada a chamada OPENVPN_PLUGIN_IPCHANGE, que é chamada antes de alterar o endereço IP do cliente.


 OPENVPN_PLUGIN_IPCHANGE { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "redirect_gateway":"0", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "ifconfig_remote":"10.150.0.2", "IV_NCP":"2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_321bb12075dc0e1b5440d227220bac5d.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "dev":"tun150", "pluginid":"3", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

A função OPENVPN_PLUGIN_CLIENT_CONNECT_V2 é chamada quando o endereço IP é definido pelo servidor DHCP interno.


 OPENVPN_PLUGIN_CLIENT_CONNECT_V2 { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "dev":"tun150", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "time_ascii":"Sat Jan 12 18:54:48 2019", "ifconfig_remote":"10.150.0.2", "IV_NCP":"2", "untrusted_port":"1200", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_321bb12075dc0e1b5440d227220bac5d.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "time_unix":"1547319288", "redirect_gateway":"0", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "remote_port_1":"1200", "ifconfig_pool_local_ip":"10.150.0.5", "pluginid":"9", "ifconfig_pool_remote_ip":"10.150.0.6", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

Em um ambiente variável, as variáveis ​​aparecem contendo os parâmetros do túnel "ifconfig_pool_local_ip" e "ifconfig_pool_remote_ip".


A função OPENVPN_PLUGIN_LEARN_ADDRESS é chamada quando o servidor OpenVPN aprende a conexão de endereços IP e as rotas para eles. Depois de sair dessa função, o procedimento para aplicar as configurações do filtro de pacotes do arquivo é ativado. A variável de ambiente OPENVPN_PLUGIN_LEARN_ADDRESS nesse caso corresponde à fase OPENVPN_PLUGIN_CLIENT_CONNECT_V2.


 fa56bf61-.../172.16.111.168:1200 ----- pf_check_reload : struct pf_context ----- fa56bf61-.../172.16.111.168:1200 enabled=1 fa56bf61-.../172.16.111.168:1200 filename='/tmp/openvpn_pf_343330698e4acdea34c8a8c7fb87d861.tmp' fa56bf61-.../172.16.111.168:1200 file_last_mod=1547319124 fa56bf61-.../172.16.111.168:1200 n_check_reload=1 fa56bf61-.../172.16.111.168:1200 reload=[1,15,1547319125] fa56bf61-.../172.16.111.168:1200 ----- struct pf_set ----- fa56bf61-.../172.16.111.168:1200 kill=0 fa56bf61-.../172.16.111.168:1200 ----- struct pf_subnet_set ----- fa56bf61-.../172.16.111.168:1200 default_allow=ACCEPT fa56bf61-.../172.16.111.168:1200 ----- struct pf_cn_set ----- fa56bf61-.../172.16.111.168:1200 default_allow=DROP fa56bf61-.../172.16.111.168:1200 12345678-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 fa56bf61-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 ---------- fa56bf61-.../172.16.111.168:1200 fa56bf61-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 12345678-90da-11e8-bf33-005056a12a82-1234567 ACCEPT fa56bf61-.../172.16.111.168:1200 -------------------- 

Quando um cliente é desconectado, a função OPENVPN_PLUGIN_CLIENT_DISCONNECT é chamada.


 OPENVPN_PLUGIN_CLIENT_DISCONNECT { "route_netmask_1":"255.255.0.0", "route_gateway_1":"10.150.0.2", "trusted_ip":"172.16.111.168", "link_mtu":"1622", "IV_COMP_STUB":"1", "daemon_start_time":"1547319280", "IV_LZ4":"1", "dev":"tun150", "common_name":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "time_ascii":"Sat Jan 12 18:54:48 2019", "bytes_received":"30893", "IV_NCP":"2", "untrusted_port":"1200", "ifconfig_remote":"10.150.0.2", "IV_LZ4v2":"1", "local_1":"172.16.100.139", "script_context":"init", "untrusted_ip":"172.16.111.168", "config":"/usr/local/etc/openvpn/server150.conf", "username":"fa56bf61-90da-11e8-bf33-005056a12a82-1234568", "trusted_port":"1200", "pf_file":"/tmp/openvpn_pf_4fcad505693b33f97c4fe105df8681cb.tmp", "ifconfig_local":"10.150.0.1", "tun_mtu":"1500", "auth_control_file":"/tmp/openvpn_acf_4bdddbada2885cde42cd3cb1b85d77e5.tmp", "daemon":"1", "IV_COMP_STUBv2":"1", "verb":"3", "IV_PLAT":"win", "daemon_pid":"52435", "time_unix":"1547319288", "redirect_gateway":"0", "route_vpn_gateway":"10.150.0.2", "proto_1":"udp", "route_net_gateway":"172.16.100.1", "IV_PROTO":"2", "daemon_log_redirect":"1", "time_duration":"3781", "dev_type":"tun", "IV_VER":"2.4.3", "IV_LZO":"1", "bytes_sent":"22684", "remote_port_1":"1200", "ifconfig_pool_local_ip":"10.150.0.5", "pluginid":"7", "ifconfig_pool_remote_ip":"10.150.0.6", "local_port_1":"1200", "IV_TCPNL":"1", "route_network_1":"10.150.0.0" } 

Em um ambiente variável, a duração da conexão e o tráfego do usuário são adicionados.


Como você pode ver, devido à abundância de dados em diferentes chamadas, escrever e depurar um plug-in na linguagem de programação C (C ++) será uma tarefa bastante demorada.
Para expandir a funcionalidade, decidiu-se fazer um "milagre" primeiro para o projeto interno e depois publicá-lo :)
Após uma longa leitura dos códigos fonte do OpenVPN e vários exemplos de plugins altamente especializados, foi criado um projeto que usa o Python como a linguagem de programação para a lógica de processamento da sessão. O código é um plug-in na linguagem C que se conecta ao OpenVPN, que envia todas as solicitações ao plug-in, envia o módulo para Python através da referência c-api .


OpenVPN plugin proxy python


Por que o módulo Python?


A referência c-api do Python, trabalhando diretamente com arquivos python, não funciona corretamente com o carregamento de bibliotecas python.


Como isso funciona?


Quando o plugin é inicializado no OpenVPN, ele retorna uma lista mascarada de todas as funções que ele pode servir. Quando a próxima fase da conexão ou evento interno ocorrer, o OpenVPN chama as funções correspondentes do plug-in. O plug-in converte a variável de ambiente e os parâmetros passados ​​para a função em uma estrutura, inicializa o python e passa a estrutura para o procedimento correspondente do módulo python. O procedimento retorna uma das três respostas ao plug-in (0 - Sucesso, 1 - Erro, 2 - Adiado). A resposta é transformada e retornada pelo OpenVPN.


Observe que todas as chamadas do módulo são "sem estado", o que significa que os procedimentos não se lembram e não sabem o que aconteceu anteriormente em outras chamadas. Você pode focar apenas no ambiente variável passado para o plug-in do OpenVPN.


Dentro do módulo python, você pode implementar qualquer lógica conectando as bibliotecas e os recursos necessários. Se você não tiver certeza da velocidade das verificações, use as confirmações "pendentes".


Usando o agrupamento de usuários conectados ao serviço, através do pf_file, você pode ajustar bastante a interação da rede entre usuários e outros recursos. Por sua vez, conectando o plug-in para monitoramento, sempre será possível gerenciar sessões do cliente por meio da interface de gerenciamento OpenVPN.


Durante o teste do projeto, um mecanismo de geração de senha foi desenvolvido, semelhante aos tokens jwt, mas com um tamanho menor.


O ponto é simples. O token contém o identificador do cliente e a data de validade do acesso. Para assinar o token, é utilizado o HMAC_SHA1 com uma chave privada. Após a assinatura do token, o conteúdo do texto é corrompido pela assinatura e convertido em base64. Assim, a "vedação" do token é obtida. Um token selado é usado como senha do usuário. Se ocorrer uma alteração não autorizada de um bloco de dados, xor interrompe, se xor interrompe, a verificação de assinatura é interrompida. Sem uma chave privada, a assinatura não pode ser alterada.


Se você não deseja controlar manualmente o horário da senha, gere esse token e verifique a validade dentro do plug-in sem chamar serviços externos. Esse esquema é muito conveniente para a geração de senha da sessão por um determinado período. Ao mesmo tempo, você pode transferir o conteúdo do token para um sistema de controle externo e ele se configurará para desconectar o usuário após a expiração do token.


Espero que as informações neste artigo tenham sido úteis para você.
Obrigado por reservar um tempo para lê-lo.
Se você tiver alguma dúvida, tentarei responder o que puder.


© Aborche 2019
Aborche

Source: https://habr.com/ru/post/pt435802/


All Articles