2台のNICを持つLinuxシステムがありますが、そのうちの1台(eth0
)がデフォルトゲートウェイです。もう一方(eth1
)はデフォルトゲートウェイではありません。どちらもインターネット接続を持つネットワーク接続を持っているので、リンク状態がアップしています。非ゲートウェイインターフェイスでインターネット接続を検出する方法
eth1
を定期的にチェックして、インターネットトラフィックがルーティングされるかどうかを確認します。私がeth1
をチェックしている間、私はインターネットトラフィックのルーティングを中断しないでeth0
にしておく必要があります。 eth1
で接続できたら、私のデフォルトゲートウェイを切り替える(これは安い接続なので)。
ソケットを開き、ソケットをeth1
にバインドしてポートに接続して接続を確認しようとしています。私は例として8.8.8.8:443
を使用しました。
bool canConnect(const string interface)
{
bool result = false;
sockaddr_in host;
timeval timeout;
int sock = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (sock == -1)
return result;
struct ifreq ifr;
::strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ);
int res = setsockopt(_sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
if (res < 0)
{
::close(sock);
return result;
}
int reuse = 1;
if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0)
{
::close(sock);
return result;
}
::inet_pton(AF_INET, "8.8.8.8", host.sin_addr);
host.sin_family = AF_INET;
host.sin_port = htons(443);
if (::connect(sock, (struct sockaddr *)&host , sizeof(host)) < 0)
{
int error = errno;
if (error != EINPROGRESS) // socket is non-blocking
{
::close(sock);
return result;
}
}
fd_set writeSet;
fd_set readSet;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_SET(sock, &readSet);
FD_SET(sock, &writeSet);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int res = ::select(sock + 1, &readSet, &writeSet, NULL, &timeout);
if (res < 0)
{
::close(sock);
return result;
}
else if (res == 0)
{
// function always exits here
::close(sock);
return result;
}
else if (FD_ISSET(sock, &writeSet) || FD_ISSET(sock, &readSet))
{
int val;
socklen_t len = sizeof(val);
::getsockopt(sock, SOL_SOCKET, SO_ERROR, &val, &len);
if (val == 0)
result = true;
}
::close(sock);
return result;
}
コードを実行すると、select()
は常にタイムアウトします。私はいくつかのコードをしないのですか、私はこの仕事をするために、カーネルオプションが必要なのです(私は一時的にeth1
にデフォルトゲートウェイを切り替えることで、これを証明している。
eth1
は、インターネット接続を持っているにもかかわらず、8.8.8.8:443
への接続を行うために管理することはありません?。。connect()
が成功した場合は
私は
Thanks @ remy-lebeau私はあなたのコメントをチェックしました - 私はほとんどが私のサンプルコードをコピーするときに誤植だと思う。 私はselectでチェックインを取り除き、選択範囲をconnect <0ブロック内に移動しました。 私はすでにポート443が開いていることを確認しているので8.8.8.8を使用していました。eth1をデフォルトゲートウェイとして追加するとコードが機能します。最終的には、私がコントロールしているWebサーバーを使用します。 問題は、eth1をデフォルトゲートウェイにする前に接続性をチェックして、切り替え時に動作することがわかっています。 – linusoft