🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

ネットワーク

ネットワークとは、複数のコンピューター間を接続する技術です。インターネットが最も主流なネットワークの形態で、TCP/IP・HTTP・DNSなどの様々なプロトコルや、ルータやサーバーなどの様々な機器の上に成り立っています。

Q&A

解決済

3回答

6403閲覧

処理に応じて同一NICに設定した複数のIPアドレスを使い分けたい

yoshinon48

総合スコア13

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

ネットワーク

ネットワークとは、複数のコンピューター間を接続する技術です。インターネットが最も主流なネットワークの形態で、TCP/IP・HTTP・DNSなどの様々なプロトコルや、ルータやサーバーなどの様々な機器の上に成り立っています。

0グッド

0クリップ

投稿2019/11/13 05:27

編集2019/11/17 13:24

Linux環境において、あるNICに複数のIPアドレスを設定しようとしております。

例)
eth0 :192.168.11.10
eth0:1:192.168.11.20

上記IPアドレスを付与したNICより通信可能なサーバに対して
ある処理の場合は「192.168.11.10」より、異なる処理の場合は「192.168.11.20」より
といった具合に、処理に応じて通信元のIPアドレスを使い分けたいのですが
可能でしょうか?

※経緯
通信先のサーバ管理者より、処理毎に異なるIPアドレスを使用して
通信して欲しい旨、要望をいただいているためとなります。
しかし、対象の通信先サーバへ通信可能なNICが現在一つしかないため
対応方法について検討しております。

大変お手数ですが、ご教示の程よろしくお願いいたします。

(2019/11/17追記)
ご返答が遅くなり申し訳ございません。
また質問内容について不明確な部分が多く申し訳ございません。

通信元/通信先のOSはRedHatEnterpriseLinux6となります。
通信元から通信先に、TCPプロトコルにてデータの問い合わせを行います。
(この問い合わせ内容については具体的にはお伝えできません。
大変申し訳ございません。)

上記問い合わせを行うデータについて、データ毎に通信元IPを
変更してほしいと通信先のシステムより指示がありました。
そこで、先の質問の通り同一のサーバの同一のNICに異なる二つの
IPアドレスを設定して、データ毎に異なるIPアドレスを使用して
問い合わせることが出来るかどうかを確認しております。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/11/13 07:15

環境やOS、質問者さんの側のNICを持つ機器の役割やプログラムや使用したいサービスなどにより、回答が全く違うものになると思います。 可能な限り具体的に書かないと、欲しい回答は頂けないと思いますよ。
guest

回答3

0

その「ある処理」と言うのが自分でプログラミングできる実行プログラムなのであれば、ソケットインターフェースのsetsockoptSO_BINDTODEVICEオプションを指定することで、接続する際のネットワークインターフェースを指定することができます。(実際に使う際は、root権限が必要なようです)

socket - Linux Programmer's Manual (7)

そうではなく、既に配置されたデーモンや各種プログラムに適用したいというのであれば、それらプログラムがそれ相応のオプションを用意していない限り、できないと思われます。

投稿2019/11/13 06:02

編集2019/11/19 02:46
dodox86

総合スコア9256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/11/17 13:40

追記された内容を見ると、回答者さんのおっしゃるように、クライアントソケットの明示的なbind指定が必要そうですね。 ただ、私の記憶ではbind()はクライアントソケットでも使えたと思います。 必要であればご自分(質問者さん)でご確認下さい。
退会済みユーザー

退会済みユーザー

2019/11/17 18:13

自分でもroutingが気になったので、virtualboxで少し確認してみました。 virtualboxでnatを一本hostonlyを一本の計2本を繋ぐと、default routerはnat側になります。 なのでhostonly側のIPを使ってクライアントソケットにbindして繋ぐコード実行してみました。 このときhostonly側でキャプチャしてみたところ、何もキャプチャできなかったのですが、nat側でキャプチャしたら、srcipがhostonly側のものが取得出来ました。 つまり、IPさえあればその経路を使わなくても接続を確立できそうだということです。 ※setsockoptは未使用&一般ユーザーで実行 #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <cstdio> #include <cstring> int main(int argc, char* argv[]) { int s; if ( ( s = socket(AF_INET, SOCK_STREAM, 0) ) < 0 ){ fprintf(stderr, "Socket create failure!!!\n"); return 1; } struct sockaddr_in server_addr; struct sockaddr_in client_addr; memset(&server_addr, 0, sizeof(server_addr)); memset(&client_addr, 0, sizeof(client_addr)); server_addr.sin_family = PF_INET; server_addr.sin_port = htons(80); inet_aton("10.0.2.2", &(server_addr.sin_addr)); client_addr.sin_family = PF_INET; client_addr.sin_port = htons(8888); inet_aton("192.168.56.4", &(client_addr.sin_addr)); if (bind(s, (struct sockaddr *)&client_addr, sizeof(client_addr)) != 0) { perror(argv[0]); fprintf(stderr, "Can not bind.\n"); return 1; } if ( connect(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0 ){ perror(argv[0]); fprintf(stderr, "Can not connect.\n"); return 1; } const char req[] = "GET / HTTP/1.1\r\nHost: 10.0.2.2\r\n\r\n"; if (send(s, req, sizeof(req) - 1, 0) < 0) { perror(argv[0]); fprintf(stderr, "Can not send.\n"); return 1; } shutdown(s, SHUT_WR); char dummy; recv(s, &dummy, sizeof(dummy),0); close(s); return 0; }
dodox86

2019/11/17 20:38

dameoさん、情報ありがとうございます。クライアント側でbind~connectする方法は知りませんでした。私にとっても勉強になりました。ここまでの情報量だったら、せっかくなので別回答でしてもらっていた方が良かったかもしれませんね。
退会済みユーザー

退会済みユーザー

2019/11/18 01:11

そうですね。別回答にしときます。もう少し丁寧に書かないと伝わらない気もするので。
guest

0

ベストアンサー

dodox86さんの回答のコメントという形で書いていたのですが、後から読んでみて、端折りすぎてる気がしたので、こちらで書かせて頂きます。ただし、(dodox86さんの意図はよく分かりませんが)コンセプトは同じだと思っています。

目的

同一IP、ポートのTCPのサーバに対して、クライアント側から状況に応じてIPを使い分けて通信したい

ネットワーク

冗長化されたネットワークならサーバ側や経路もIPが違うものだと思うが、そうではなく、同一IPなのにクライアント側だけ状況により異なるIPでTCPで通信する必要がある。そのような状況を再現するため、今回は確認用に以下のようなネットワークを構築した。

text

1(XXX.XXX.XXX.XXX/24):至インターネット 2サーバ(Windows 10 Home 64bit) 3(10.0.2.2/24):VirtualBox-NATアダプタ 4(192.168.56.1):VirtualBox-ホストオンリーアダプター 5|| 6(10.0.2.15/24): eth0 7(192.168.56.4): eth1 8クライアント(CentOS6 64bit)

クライアント側のネットワーク状況は以下のようになる。

text

1[user@centos6 ~]$ ip a 21: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 3 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 4 inet 127.0.0.1/8 scope host lo 5 inet6 ::1/128 scope host 6 valid_lft forever preferred_lft forever 72: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 8 link/ether MACアドレス brd ff:ff:ff:ff:ff:ff 9 inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0 10 inet6 IP6アドレス/64 scope link 11 valid_lft forever preferred_lft forever 123: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 13 link/ether MACアドレス brd ff:ff:ff:ff:ff:ff 14 inet 192.168.56.4/24 brd 192.168.56.255 scope global eth1 15 inet6 IP6アドレス/64 scope link 16 valid_lft forever preferred_lft forever 17[user@centos6 ~]$ ip r 1810.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 19192.168.56.0/24 dev eth1 proto kernel scope link src 192.168.56.4 20169.254.0.0/16 dev eth0 scope link metric 1002 21169.254.0.0/16 dev eth1 scope link metric 1003 22default via 10.0.2.2 dev eth0

着目すべき点は、defaultな経路としては、eth0が選ばれているということ。
つまり、ホストにアクセスするときはeth1を使うが、それ以外の通信は全てeth0を使用する経路選択となる。

確認

上記ネットワークで、eth0に繋がるサーバIPに、クライアント側からeth0のIPとeth1のIPを状況に応じて使い分けて通信できるかどうかを確認する。

サーバ側

python3のhttp.serverを起動する。httpサーバなら何でもいい。pythonがたまたま入ってたので使用。

text

1python -m http.server --cgi 80

※cgi-bin/はこの説明では使用しない

クライアント側

以下のC++プログラムを使用する(中身はC)(client.cpp)。

C++

1#include <sys/types.h> 2#include <sys/socket.h> 3#include <netinet/in.h> 4#include <arpa/inet.h> 5#include <unistd.h> 6#include <cstdio> 7#include <cstring> 8 9int main(int argc, char* argv[]) 10{ 11 int s; 12 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0){ 13 fprintf(stderr, "Socket create failure!!!\n"); 14 return 1; 15 } 16 17 struct sockaddr_in server_addr; 18 struct sockaddr_in client_addr; 19 memset(&server_addr, 0, sizeof(server_addr)); 20 memset(&client_addr, 0, sizeof(client_addr)); 21 server_addr.sin_family = PF_INET; 22 server_addr.sin_port = htons(80); 23 inet_aton("10.0.2.2", &(server_addr.sin_addr)); 24 client_addr.sin_family = PF_INET; 25 client_addr.sin_port = htons(0); 26 inet_aton("192.168.56.4", &(client_addr.sin_addr)); 27 28 if (bind(s, (struct sockaddr *)&client_addr, sizeof(client_addr)) != 0) { 29 perror(argv[0]); 30 fprintf(stderr, "Can not bind.\n"); 31 return 1; 32 } 33 34 if (connect(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0){ 35 perror(argv[0]); 36 fprintf(stderr, "Can not connect.\n"); 37 return 1; 38 } 39 const char req[] = "GET / HTTP/1.1\r\nHost: 10.0.2.2\r\n\r\n"; 40 if (send(s, req, sizeof(req) - 1, 0) < 0) { 41 perror(argv[0]); 42 fprintf(stderr, "Can not send.\n"); 43 return 1; 44 } 45 shutdown(s, SHUT_WR); 46 char dummy[65536]; 47 int len; 48 do { 49 len = recv(s, &dummy, sizeof(dummy) - 1,0); 50 dummy[len] = '\0'; 51 printf("%s", dummy); 52 } while (len > 0); 53 close(s); 54 55 return 0; 56}

肝は普通見かけないクライアントソケットへのbind。ここでアドレスを指定している。

以下でコンパイル/実行出来る。

text

1$ g++ -g client.cpp 2$ ./a.out

※-gはデバッグ用のオプション

そして、今回は通信するパケットをキャプチャするためにtcpdumpを使用。上記の実行に先立って別端末から起動しておく。

text

1sudo tcpdump -v -i eth0 port 80

eth1から出ていくと思っていたが、経路設定どおり、eth0から出ていくため、eth0でキャプチャしている。

結果

eth0のキャプチャ結果

text

1tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 211:02:44.645870 IP (tos 0x0, ttl 64, id 37642, offset 0, flags [DF], proto TCP (6), length 60) 3 192.168.56.4.39408 > 10.0.2.2.http: Flags [S], cksum 0xb6a7 (correct), seq 192253294, win 14600, options [mss 1460,sackOK,TS val 35331684 ecr 0,nop,wscale 6], length 0 411:02:44.646718 IP (tos 0x0, ttl 64, id 37915, offset 0, flags [none], proto TCP (6), length 44) 5 10.0.2.2.http > 192.168.56.4.39408: Flags [S.], cksum 0x87ca (correct), seq 41408001, ack 192253295, win 65535, options [mss 1460], length 0 611:02:44.646754 IP (tos 0x0, ttl 64, id 37643, offset 0, flags [DF], proto TCP (6), length 40) 7 192.168.56.4.39408 > 10.0.2.2.http: Flags [.], cksum 0x667f (correct), ack 1, win 14600, length 0 811:02:44.647050 IP (tos 0x0, ttl 64, id 37644, offset 0, flags [DF], proto TCP (6), length 74) 9 192.168.56.4.39408 > 10.0.2.2.http: Flags [P.], cksum 0x04eb (incorrect -> 0xc8e1), seq 1:35, ack 1, win 14600, length 34 1011:02:44.647176 IP (tos 0x0, ttl 64, id 37916, offset 0, flags [none], proto TCP (6), length 40) 11 10.0.2.2.http > 192.168.56.4.39408: Flags [.], cksum 0x9f65 (correct), ack 35, win 65535, length 0 1211:02:44.647206 IP (tos 0x0, ttl 64, id 37645, offset 0, flags [DF], proto TCP (6), length 40) 13 192.168.56.4.39408 > 10.0.2.2.http: Flags [F.], cksum 0x665c (correct), seq 35, ack 1, win 14600, length 0 1411:02:44.647344 IP (tos 0x0, ttl 64, id 37917, offset 0, flags [none], proto TCP (6), length 40) 15 10.0.2.2.http > 192.168.56.4.39408: Flags [.], cksum 0x9f64 (correct), ack 36, win 65535, length 0 1611:02:44.660887 IP (tos 0x0, ttl 64, id 37919, offset 0, flags [none], proto TCP (6), length 195) 17 10.0.2.2.http > 192.168.56.4.39408: Flags [P.], cksum 0x08d7 (correct), seq 1:156, ack 36, win 65535, length 155 1811:02:44.660909 IP (tos 0x0, ttl 64, id 37920, offset 0, flags [none], proto TCP (6), length 1460) 19 10.0.2.2.http > 192.168.56.4.39408: Flags [.], cksum 0x1b39 (correct), seq 156:1576, ack 36, win 65535, length 1420 2011:02:44.660961 IP (tos 0x0, ttl 64, id 37646, offset 0, flags [DF], proto TCP (6), length 40) 21 192.168.56.4.39408 > 10.0.2.2.http: Flags [.], cksum 0x6211 (correct), ack 156, win 15544, length 0 2211:02:44.661035 IP (tos 0x0, ttl 64, id 37647, offset 0, flags [DF], proto TCP (6), length 40) 23 192.168.56.4.39408 > 10.0.2.2.http: Flags [.], cksum 0x5121 (correct), ack 1576, win 18460, length 0 2411:02:44.661092 IP (tos 0x0, ttl 64, id 37921, offset 0, flags [none], proto TCP (6), length 1460) 25 10.0.2.2.http > 192.168.56.4.39408: Flags [.], cksum 0xd410 (correct), seq 1576:2996, ack 36, win 65535, length 1420 2611:02:44.661097 IP (tos 0x0, ttl 64, id 37922, offset 0, flags [none], proto TCP (6), length 1460) 27 10.0.2.2.http > 192.168.56.4.39408: Flags [.], cksum 0xfea2 (correct), seq 2996:4416, ack 36, win 65535, length 1420 2811:02:44.661098 IP (tos 0x0, ttl 64, id 37923, offset 0, flags [none], proto TCP (6), length 799) 29 10.0.2.2.http > 192.168.56.4.39408: Flags [FP.], cksum 0xc6f4 (correct), seq 4416:5175, ack 36, win 65535, length 759 3011:02:44.661123 IP (tos 0x0, ttl 64, id 37648, offset 0, flags [DF], proto TCP (6), length 40) 31 192.168.56.4.39408 > 10.0.2.2.http: Flags [.], cksum 0x407d (correct), ack 2996, win 21300, length 0 3211:02:44.661168 IP (tos 0x0, ttl 64, id 37649, offset 0, flags [DF], proto TCP (6), length 40) 33 192.168.56.4.39408 > 10.0.2.2.http: Flags [.], cksum 0x2fd9 (correct), ack 4416, win 24140, length 0 3411:02:44.661208 IP (tos 0x0, ttl 64, id 37650, offset 0, flags [DF], proto TCP (6), length 40) 35 192.168.56.4.39408 > 10.0.2.2.http: Flags [.], cksum 0x21c9 (correct), ack 5176, win 26980, length 0

一部チェックサムがincorrectになっているが、通信自体は出来ており、eth0を使用し、アドレスにはeth1のアドレスが使用されている。サーバ側でアドレスを取ろうとしたが、NATでIP偽装されており、127.0.0.1になっていたため、そちらは未確認。

投稿2019/11/18 02:07

編集2019/11/18 02:14
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2019/11/19 02:56 編集

> (dodox86さんの意図はよく分かりませんが)コンセプトは同じだと思っています。 setsockoptでSO_BINDTODEVICEを指定することに比べてスーパーユーザーの権限を持つ必要が無いので、プログラムを書く場合においてはより良い方法かもしれなく、有意義な情報と思ってのコメントでした。お手を煩わせてしまったようですみません。
guest

0

「ある処理」と「異なる処理」がなにかわかりません。
それぞれの処理がNIC指定で動作するならできるでしょうけど
普通に「なんとなく」では切り分けするのは難しいですね

投稿2019/11/13 05:44

yambejp

総合スコア116690

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問