%20%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%20IP%20%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%BE%E3%81%99.png)
ネットワーク通信に同じポート (34964) を使用するアプリケーションが 2 つあります。最初のアプリケーション (ソース コード) は私が制御しており、192.168.0.4:34964 を使用します。一方、他のアプリケーションはすべての IP アドレス (0.0.0.0:34964) を使用/「要求」しようとしますが、このアプリケーションは制御できません。各アプリケーションは単独で実行しても動作しますが、同時に実行しようとすると、次のエラーが発生します: アドレスのバインドに失敗しました。
質問
2 番目のアプリケーションがすべての IP アドレス (0.0.0.0) を使用/要求するのを防ぎ、代わりに 192.168.0.5 を使用する方法はありますか。起動する前に行うか、ネットワーク名前空間にカプセル化することで行うかのどちらかです。
何も試していないし、アイデアも尽きてしまいました...
より詳細なバージョン: 2 つの別々の Profinet ネットワークで通信するための 2 つのアプリケーション。最初のアプリケーションは Profinet デバイスとして機能し、Siemens Profinet コントローラーと通信します。このアプリケーションのソース コードにアクセスできます。2 番目のアプリケーションは、Profinet Siemens デバイスと通信する Profinet コントローラーとして機能する必要があります。現在、このために Codesys を使用しており、ソース コードを変更する権限がありません。
答え1
いくつかの選択肢があります。
LD_プリロード
LD_PRELOAD
ライブラリを使用してシステムコールをインターセプトし、bind()
特定のアドレスに強制的にバインドすることもできます。その一例は次のとおりです。これこれを次のようにコンパイルします。
gcc -nostartfiles -fpic -shared bind.c -o bind.so -ldl -D_GNU_SOURCE
次のように使用します:
BIND_ADDR=127.0.0.1 LD_PRELOAD=./bind.so /path/to/myprogram
Docker を使用したネットワーク名前空間
プログラムを独自のネットワーク名前空間内で実行することもできます。最も簡単これを行うには、アプリケーション用の Docker イメージを構築し、それを Docker で実行し、Docker のポート マッピング機能を使用して、選択したホスト IP でサービスを公開します。
ここにドラゴンがいる
上記の解決策のいずれかを強くお勧めします。ネットワーク名前空間について質問があったため、以下を記載します。
macvlan を使用したネットワーク名前空間
Docker を使わずに実行することも可能ですが、少し手間がかかります。まず、新しいネットワーク名前空間を作成します。
# ip netns add myns
次に、macvlan
ホスト インターフェイスの 1 つに関連付けられたインターフェイスを作成し、それを名前空間に配置します。
# ip link add myiface link eth0 type macvlan mode bridge
# ip link set myiface netns myns
ローカル ネットワーク上のアドレスを割り当てます。
# ip netns exec myns \
ip addr add 192.168.0.4/24 dev myiface
# ip netns exec myns \
ip link set myiface up
そして、名前空間内に適切なルーティング ルールを作成します ( を実際のゲートウェイ アドレスに置き換えます192.168.0.1
)。
# ip netns exec myns \
ip route add default via 192.168.0.1
次に、ネットワーク名前空間内でプログラムを実行します。
# ip netns exec myns \
/path/to/myprogram
これでプログラムが実行され、 にのみバインドされます。192.168.0.4
これは、それが名前空間内で表示される唯一のアドレスであるためです。ただし、mavclan
インターフェースの制限に注意してください。ネットワーク上の他のホストはサービスに接続できますが、サービスが実行されているホストからそのアドレスに接続することはできません (macvlan
ホスト上に別のインターフェースを作成し、192.168.0.4
そのインターフェースを介して への接続をルーティングしない限り)。
veth インターフェースを備えたネットワーク名前空間
macvlan
インターフェースを使用する代わりに、veth
インターフェース ペアを作成し、そのペアの一方の端をネットワーク名前空間内に置き、もう一方の端をホスト上に配置することができます。IP マスカレードを使用して、名前空間からローカル ネットワークにパケットを渡します。
ネットワーク名前空間を作成します。
# ip netns add myns
インターフェース ペアを作成します。
# ip link add myiface-in type veth peer name myiface-out
ペアの一方の端をネットワーク名前空間に割り当てます。
# ip link setns myiface-in myns
ペアの両端にアドレスを設定し、リンクを起動します。
# 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
ホスト上で IP マスカレードを設定します。これにより、着信パケットが192.168.0.4
名前空間にリダイレクトされます。
# 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
これにより、送信パケットが偽装されます。
# iptables -t nat -A POSTROUTING -s 192.168.99.2 -j MASQUERADE
ホストでIP転送が有効になっていること(sysctl -w net.ipv4.ip_forward=1
)と、iptablesFORWARD
チェーンが接続の転送を許可していることを確認する必要があります(iptables -A FORWARD -d 192.168.99.2 -j ACCEPT
ルールは順番に処理されるため、拒否ルールは前にこちらが優先されます。