.png)
Tenho dois aplicativos que usam a mesma porta para comunicação em rede (34964). Eu tenho controle sobre (código-fonte) o primeiro aplicativo e ele usa 192.168.0.4:34964. Enquanto o outro aplicativo tenta usar/"reivindicar" todos os endereços IP (0.0.0.0:34964), mas sobre este não tenho controle. Cada aplicativo funciona sozinho, porém quando tento fazê-los rodar ao mesmo tempo recebo um erro: Failed to bind address.
Pergunta
Existe alguma maneira de evitar que o segundo aplicativo use/reivindica todos os endereços IP (0.0.0.0) e, em vez disso, use 192.168.0.5. Antes de iniciá-lo ou encapsulando-o em um namespace de rede?
Não tentei nada e estou sem ideias...
Versão mais detalhada: Duas aplicações para comunicação em duas redes Profinet separadas. A primeira aplicação atua como um dispositivo Profinet e se comunica com um controlador Siemens Profinet, tenho acesso ao código fonte desta aplicação. A segunda aplicação deve funcionar como um Controlador Profinet que se comunica com um dispositivo Profinet Siemens, atualmente estou usando o Codesys para isso e não tenho acesso para alterar o código fonte.
Responder1
Você tem poucas opções.
LD_PRELOAD
Você poderia usar uma LD_PRELOAD
biblioteca para interceptar a bind()
chamada do sistema para forçar a ligação a um endereço específico. Um exemplo disso éesse, que você compila assim:
gcc -nostartfiles -fpic -shared bind.c -o bind.so -ldl -D_GNU_SOURCE
E use assim:
BIND_ADDR=127.0.0.1 LD_PRELOAD=./bind.so /path/to/myprogram
Namespaces de rede com Docker
Você também pode optar por executar seu programa dentro de seu próprio namespace de rede. Omais fácilA maneira de fazer isso seria construir uma imagem Docker para seu aplicativo e, em seguida, executá-la no Docker e usar os recursos de mapeamento de porta do Docker para expor o serviço no IP do host de sua escolha.
Aqui há dragões
Eu recomendaria fortemente uma das soluções acima. Incluo apenas o seguinte porque você perguntou sobre namespaces de rede.
Namespaces de rede com macvlan
Se você quiser fazer isso sem o Docker é possível, mas com um pouco mais de trabalho. Primeiro, crie um novo namespace de rede:
# ip netns add myns
Em seguida, crie uma macvlan
interface associada a uma de suas interfaces de host e coloque-a no namespace:
# ip link add myiface link eth0 type macvlan mode bridge
# ip link set myiface netns myns
E atribua um endereço na sua rede local:
# ip netns exec myns \
ip addr add 192.168.0.4/24 dev myiface
# ip netns exec myns \
ip link set myiface up
E crie regras de roteamento apropriadas dentro do namespace (substituindo seu endereço de gateway real 192.168.0.1
):
# ip netns exec myns \
ip route add default via 192.168.0.1
Agora, execute seu programa dentro do namespace da rede:
# ip netns exec myns \
/path/to/myprogram
Agora seu programa está em execução e será vinculado apenas a 192.168.0.4
, porque esse é o único endereço visível dentro do namespace. Mas! Esteja ciente da limitação das mavclan
interfaces: embora outros hosts na sua rede possam se conectar ao serviço, você não poderá se conectar a esse endereço a partir do host no qual ele está sendo executado (a menos que você crie outra macvlan
interface no host e rotear conexões por 192.168.0.4
meio dessa interface).
Namespaces de rede com interfaces veth
Em vez de usar macvlan
interfaces, você pode criar um veth
par de interfaces, com uma extremidade do par dentro de um namespace de rede e a outra em seu host. Você usará o mascaramento de IP para passar pacotes do namespace para sua rede local.
Crie o namespace da rede:
# ip netns add myns
Crie um par de interfaces:
# ip link add myiface-in type veth peer name myiface-out
Atribua uma extremidade do par ao namespace da sua rede:
# ip link setns myiface-in myns
Configure um endereço em cada extremidade do par e abra os links:
# ip addr add 192.168.99.1/24 dev myiface-out
# ip link set myiface-out up
# ip netns exec myns ip addr add 192.168.99.2/24 dev myiface-in
# ip netns exec myns ip link set myiface-in up
Configure o mascaramento de IP em seu host. Isso redirecionará os pacotes recebidos 192.168.0.4
para o seu namespace:
# iptables -t nat -A PREROUTING -d 192.168.0.4 -p tcp --dport 34964 -j DNAT --to-destination 192.168.99.2
# iptables -t nat -A OUTPUT -d 192.168.0.4 -p tcp --dport 34964 -j DNAT --to-destination 192.168.99.2
E isso mascarará os pacotes de saída:
# iptables -t nat -A POSTROUTING -s 192.168.99.2 -j MASQUERADE
Você precisará garantir que o encaminhamento de IP esteja habilitado em seu host ( sysctl -w net.ipv4.ip_forward=1
) e que sua FORWARD
cadeia iptables permita o encaminhamento da conexão ( iptables -A FORWARD -d 192.168.99.2 -j ACCEPT
, tendo em mente que as regras são processadas em sequência, portanto, uma regra de rejeiçãoanteseste terá precedência).