Conexão de backup de internet para processos específicos
Eu gostaria de adicionar uma conexão de Internet de backup secundária ao meu servidor Linux. Pretendo usar um modem USB LTE para essa finalidade.
Como essa conexão de celular será medida, quero limitar a quantidade de dados que podem ser consumidos ao mínimo necessário.
Tenho um aplicativo de servidor personalizado no qual posso fazer alterações. Ele tem algumas tarefas em que a conectividade ininterrupta é crítica e outras tarefas em que o tempo de inatividade não importa.
Estou imaginando algo assim:
- O servidor precisa fazer uma solicitação de API HTTP externa. A primeira tentativa é feita pela rota padrão do sistema (ou seja, eth0, a conexão primária com a Internet).
- Se a solicitação falhar ou atingir o tempo limite, tente novamente a solicitação pela interface LTE.
Somente o tráfego que meu processo do servidor deseja enviar explicitamente por LTE deve ser enviado por LTE. Nenhum outro tráfego de qualquer parte do sistema deve passar por LTE.
- Especificamente, usarei a localAddressopção de soquete do nó para especificar que a solicitação deve ser feita por LTE.
- Como posso garantir que outro tráfego não seja roteado pela interface LTE (mesmo se a eth0 estiver inativa)?
- E quanto à resolução DNS?
Respostas
Acabei conseguindo isso configurando uma tabela de rota alternativa e uma regra de política de roteamento para o endereço de origem da interface de backup.
O modem LTE USB que tenho se apresenta como um dispositivo NDIS, então ele simplesmente aparece como eth1
um IP 192.168.0.190 e faz o roteamento NAT internamente. Eu configurei eth1
com um IP estático e as rotas configuradas manualmente.
A configuração padrão usa DHCP, portanto, desative a interface e certifique-se de que todas as rotas adicionadas automaticamente sejam excluídas.
Adicione uma configuração de IP estático para a interface e ative-a.
Adicione entradas a uma tabela de roteamento alternativa (eu escolhi
1
) para a sub-rede e o gateway padrão.# ip route add 192.168.0.0/24 dev eth1 src 192.168.1.190 table 1 # ip route add default via 192.168.0.1 table 1
Defina regras de política de roteamento para que os aplicativos que usam explicitamente 192.168.1.190 como seu endereço de origem usem a tabela de roteamento 1 em vez do padrão.
# ip rule add from 192.168.0.190/32 table 1 # ip rule add to 192.168.0.190/32 table 1
Neste ponto, você deve ser capaz de testar sua conectividade.
$ curl https://wtfismyip.com/text 1.2.3.4 # primary ISP external IP $ curl --interface 192.168.0.190 https://wtfismyip.com/text
5.6.7.8 # backup LTE external IP
Se tudo estiver certo, torne a configuração permanente. Eu adicionei a /etc/network/interfaces
:
iface eth1 inet static
address 192.168.0.190
netmask 255.255.255.0
post-up ip route add 192.168.0.0/24 dev eth1 src 192.168.0.190 table 1
post-up ip route add default via 192.168.0.1 table 1
post-up ip rule add from 192.168.0.190/32 table 1
post-up ip rule add to 192.168.0.190/32 table 1
Agora, apenas os aplicativos que se ligam explicitamente a 192.168.0.190 ao fazer conexões de saída serão roteados pela conexão de backup. Todo o outro tráfego é roteado eth0
(ou o que quer que esteja configurado na main
tabela de roteamento [padrão]).
É possível que você tenha algo que enumere todos os IPs disponíveis e tente enviar tráfego deles, o que pode resultar em tráfego inesperado na conexão de backup, mas isso é improvável. Eu não observei esse tipo de tráfego.
Observe que isso não aborda a resolução de DNS. Em uma situação em que a conexão principal está offline, você pode ter sorte e obter uma consulta do cache, mas não é bom confiar nisso. Eu também não configuraria o resolvedor de todo o sistema para enviar solicitações pela interface LTE. Em vez disso, seu aplicativo pode lidar manualmente com a resolução DNS ao fazer solicitações de backup.
Com o node, é fácil fazer solicitações HTTP (ou qualquer conexão TCP) de um endereço de origem específico. Basta especificar a localAddressopção , por exemplo:
https.get('https://wtfismyip.com/text', { localAddress: '192.168.0.190' }, …);
Resolver a pesquisa de DNS é um pouco mais complicado. Também lookup
está disponível uma opção que permite substituir o processo de resolução DNS padrão. Você pode usar um personalizado dns.Resolverpara fazer pesquisas. Infelizmente, o nó não tinha uma maneira de especificar o endereço de origem para pesquisas DNS, então eu o adicionei . Com isso no lugar, você pode juntar as peças:
const resolver = new dns.Resolver();
resolver.setServers(['8.8.8.8']);
resolver.setLocalAddress('192.168.0.190'); // requires node > v15.0.0
https.get('https://wtfismyip.com/text', {
localAddress: '192.168.0.190',
lookup: function(hostname, opts, cb) {
resolver.resolve(hostname, function(err, records) {
if (err) cb(err);
else if (!records[0]) cb(new Error('Missing DNS record'));
else cb(null, records[0], 4);
});
}
}, function(res) { … });