Esta é uma reimplementação Go do mmproxy, criada para melhorar a estabilidade do tempo de execução do mmproxy, ao mesmo tempo que fornece desempenho potencialmente maior em termos de conexão e taxa de transferência de pacotes.
go-mmproxy
é um aplicativo independente que desembrulha o protocolo PROXY do HAProxy (também adotado por outros projetos como NGINX) para que a conexão de rede com o servidor final venha do endereço IP e número da porta do cliente - em vez do servidor proxy. Como eles compartilham mecanismos básicos, a postagem do blog da Cloudflare sobre mmproxy serve como um excelente artigo sobre como go-mmproxy
funciona nos bastidores.
go install github.com/path-network/go-mmproxy@latest
Você precisará de pelo menos go 1.21
para construir o binário go-mmproxy
. Consulte os primeiros passos do Go se o seu gerenciador de pacotes não tiver uma versão nova o suficiente do golang.
go-mmproxy
deve ser executado:
CAP_NET_ADMIN
para poder definir a opção de soquete IP_TRANSPARENT
. Roteie todo o tráfego originado de loopback de volta para loopback:
ip rule add from 127.0.0.1/8 iif lo table 123
ip route add local 0.0.0.0/0 dev lo table 123
ip -6 rule add from ::1/128 iif lo table 123
ip -6 route add local ::/0 dev lo table 123
Se a opção --mark
for fornecida para go-mmproxy
, todos os pacotes roteados para a interface de loopback terão a marca definida. Isso pode ser usado para configurar regras de roteamento mais avançadas com iptables, por exemplo, quando você precisa que o tráfego do loopback seja roteado para fora da máquina.
Como o UDP não tem conexão, se um soquete estiver vinculado a 0.0.0.0
a pilha do kernel procurará uma interface para enviar uma resposta ao endereço de origem falsificado - em vez de apenas usar a interface da qual recebeu o pacote original. A interface encontrada provavelmente não será a interface de loopback, o que evitará as regras especificadas acima. A maneira mais simples de corrigir isso é vincular os ouvintes do servidor final a 127.0.0.1
(ou ::1
). Geralmente, isso também é recomendado para evitar o recebimento de conexões sem proxy.
Usage of ./go-mmproxy:
-4 string
Address to which IPv4 traffic will be forwarded to (default "127.0.0.1:443")
-6 string
Address to which IPv6 traffic will be forwarded to (default "[::1]:443")
-allowed-subnets string
Path to a file that contains allowed subnets of the proxy servers
-close-after int
Number of seconds after which UDP socket will be cleaned up (default 60)
-l string
Address the proxy listens on (default "0.0.0.0:8443")
-listeners int
Number of listener sockets that will be opened for the listen address (Linux 3.9+) (default 1)
-mark int
The mark that will be set on outbound packets
-p string
Protocol that will be proxied: tcp, udp (default "tcp")
-v int
0 - no logging of individual connections
1 - log errors occurring in individual connections
2 - log all state changes of individual connections
Exemplo de invocação:
sudo ./go-mmproxy -l 0.0.0.0:25577 -4 127.0.0.1:25578 -6 [::1]:25578 --allowed-subnets ./path-prefixes.txt
O benchmark foi executado no Dell XPS 9570 com CPU Intel Core i9-8950HK a 2,90 GHz (12 núcleos lógicos). O serviço upstream para o qual o proxy enviou tráfego foi simulado pelo servidor bpf-echo. O tráfego foi gerado por tcpkali v1.1.1.
O seguinte comando foi usado para geração de carga em todos os casos (50 conexões, tempo de execução de 10s, envio de cabeçalho PROXYv1 para cada conexão, uso PINGrn
como mensagem TCP):
tcpkali -c 50 -T 10s -e1 'PROXY TCP4 127.0.0.1 127.0.0.1 {connection.uid} 25578rn' -m 'PINGrn' 127.0.0.1:1122
⇅ Mbps | ↓Mbps | ↑ Mbps | ↓ pacote/s | ↑ pacotes/s | |
---|---|---|---|---|---|
cloudflare/mmproxy | 1524.454 | 756.385 | 768.069 | 70365,9 | 65921,9 |
go-mmproxy GOMAXPROCS=1 | 7418.312 | 2858.794 | 4559.518 | 262062,7 | 391334.6 |
go-mmproxy | 45483.233 | 16142.348 | 29340.885 | 1477889,6 | 2518271.5 |
sem procuração | 52640.116 | 22561.129 | 30078.987 | 2065805.4 | 2581621.3 |