0

4 つのゲートウェイ ノードを備えた 25 (まもなく 100+ になる) ノード (OpenWRT) アドホック L2 メッシュ ネットワーク (batman-adv) があります。各ノードには、5 GHz および 2.4 GHz のワイヤレス インターフェイスがあります。2.4 はクライアント アクセス用で、メッシュは 5 GHz インターフェイスで動作します。

すべてのノードはほぼ同一です (ソフトウェア)。GW のメッシュへのブロードキャスト インターネット (イーサネット) アクセスと、いくつかのノードには、DHCP、SQL、および http サービスをメッシュに提供する単一のサーバーに接続された LAN ポート (イーサネット) があります。設計上、インターネットまたは DCHP / SQL / HTTP サーバーへのアクセスを物理的に提供するノードに関する制限はありません (つまり、コロケーションは設計オプションではありません)。

現在、ワイヤレス クライアントは GW の WAN ポートに制限なくアクセスできます。プロジェクトの次のフェーズは、LAN サーバーでホストされているアカウント情報 (つまり、データベース内のアカウント情報) に基づいて WAN インターフェースへのアクセスを制限することです。

私がやりたいことは、GWノードのiptablesをリモートで操作して、サーバーからの情報に基づいてインターネットアクセスを制御することですが、iptablesコマンドをGWに取得するための最良の方法がわかりません。私が最初に考えたのは、SSH 経由でバッチ コマンドを実行するか、SSH クライアントにコマンドをストリーム配信することでした。独自の単純な TCP/IP サーバーを作成することもできます。RPC モデルも存在する可能性があります。

上記の推奨方法、または考慮すべき長所と短所はありますか。ありがとうございました。

編集: iptables は同時呼び出しでブロックされますか、それともユーザーが使用をシリアル化する必要がありますか?

4

2 に答える 2

1

すべてのゲートウェイで同じポリシーが適用されると思います。おそらく、ポリシーを一元的に維持しています。その場合、集中型サーバーで「iptables-restore」形式のポリシーを作成し、GW ごとに 1 つのコマンドを実行するだけです。このコマンドは、おそらくセキュア チャネル経由で実行する必要があります。私はscp + sshを使用します。

これは、テーブル全体を新しいテーブルに置き換えることを除いて、提案したものとまったく同じです。一度に 1 つのルールを追加すると、ポリシーに矛盾が生じたり、穴が開いたりする可能性があります。また、損失の多い環境では、すべての GW の同期を維持するのが難しい場合があります。したがって、iptables-restore にストレスがかかります。

于 2013-09-27T06:23:44.570 に答える
0

最終的に、OpenWRT で php-ssh2、php-mysqli、および iptables と ipset の組み合わせ (パッケージ ipset、iptables-mod-ipset、kmod-ipt-ipset) を使用することにしました。

完全なインターネット アクセスを許可する IP アドレスを含む ipset を作成しました。

ipset create ip_whitelist hash:ip

OpenWRT では、ソース IP が ip_whitelist にない場合、すべてのトラフィック http トラフィックをインターネット サーバーにリダイレクトするように iptables をセットアップしました。

iptables --table nat --new prerouting_mychain
iptables --table nat --insert PREROUTING -j prerouting_mychain
iptables --table nat --append prerouting_mychain --match set --match-set ip_whitelist src -j RETURN
iptables --table nat --append prerouting_mychain --dport 80 -j DNAT --to-destination <internal http server>

これで、ipset にない IP のリダイレクトが処理されますが、他の不正なトラフィックをブロックする必要があります。これは、FORWARD チェーンのフィルター テーブルで行われます。

iptables --table filter --new forward_mychain
iptables --table filter --insert FORWARD -j forward_mychain
iptables --table filter --insert forward_mychain -j DROP (this ends up being the last rule)
iptables --table filter --insert forward_mychain --match set --match-set ip_whitelist src -j ACCEPT

私の場合、ブラウザがルックアップでフリーズしないように、常に DNS を許可したいと考えています。

iptables --table filter --insert forward_mychain -p udp --dport 53 -j ACCEPT
iptables --table filter --insert forward_mychain -p udp --sport 53 -j ACCEPT

これで、FORWARD チェーンがセットアップされ、ipset 内の IP からのトラフィックと DNS トラフィックのみが許可されます。

承認された IP が ipset に追加されます。

ipset add ip_whitelist 10.10.10.10

そして次のように削除します:

ipset del ip_whitelist 10.10.10.10

私の場合、エントリに有効期限を設定して、データベース チェックのために内部サイトに強制的にリダイレクトさせます。

ipset add ip_whitelist 10.10.10.10 timeout 3600(秒)

このタイムアウトは、最初に ipset を作成するときにデフォルトとして設定することもできます。

あとは、リダイレクトされた http トラフィック用の php ページを作成し、データベースにクエリを実行して、ゲートウェイ ルーターに ipset コマンドを送信するだけです。

最初の私の単純なデータベース:

CREATE DATABASE Testdb; 
CREATE TABLE `Clients` (   
`IP` varchar(15) DEFAULT NULL,   
`Created` datetime DEFAULT NULL,   
`Expiry` datetime DEFAULT NULL,   
`LastAccess` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,   UNIQUE KEY `ipidx` (`IP`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

そして、redirect.php:

<!DOCTYPE html >
<html>
   <head>
       <title></title>
   </head>
   <body>
       <?php
       $ClientIPAddr = filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP);
       $sqlQuery = "";
       if (($ClientIPAddr === FALSE) || ($ClientIPAddr === NULL)) {
           echo "Failed to obtain client IP [" . $_SERVER["REMOTE_ADDR"] . "]";
           exit;
       }

データベースのクエリ/挿入:

       $mysqli = new mysqli("<database ip>", "dbuser", "dbpass", "Testdb");
       if ($mysqli->connect_errno) {
           echo "Failed to connect to MySQL: " . $mysqli->connect_error;
           exit;
       } else {
           echo "Connected (" . $mysqli->server_info . ")<br />";
       }
       echo "Now for a query on " . $ClientIPAddr . ":<br />";
       // Check to see if IP is in database and has not expired
       $sqlQuery = "SELECT IP, TIMEDIFF(Expiry, now()) from Clients where IP=\"" . $ClientIPAddr . "\";";
       if (($result = $mysqli->query($sqlQuery)) === FALSE) {
           echo "Query Error (" . $mysqli->error . ") on (" . $sqlQuery . ")<br />";
           exit;
       } else {
           echo "<h2>Query Result(" . $result->num_rows . "):</h2>";
           echo "<table>";
           while (($row = $result->fetch_array(MYSQLI_NUM)) !== NULL) {
               echo "<tr>";
               foreach ($row as $value) {
                   echo "<td>" . $value . "</td>";
               }
               echo "</tr>";
           }
           echo "</table>";
           echo "<h1>Welcome to my Test Page</h1>";
           if ($result->num_rows === 0) {
               echo "<p>New(" . $result->num_rows . "): " . $ClientIPAddr . "</p>";
               echo "<p>You now have full Internet access.</p>";
           } else {
               echo "<p>Returning(" . $result->num_rows . "): " . $ClientIPAddr . "</p>";
               echo "<p>Your Internet access has been extended.</p>";
           }
           $result->free();
           $sqlQuery = "INSERT INTO Clients (IP, Created, Expiry) VALUES (\"" . $ClientIPAddr . "\", now(),
               timestampadd(hour, 24, now())) ON DUPLICATE KEY UPDATE Expiry=timestampadd(hour, 24, now());";
           if (($result = $mysqli->query($sqlQuery)) === FALSE) {
               echo "Query Error (" . $mysqli->error . ") on (" . $sqlQuery . ")<br />";
               exit;
           } else {

IP を ipset に追加して、インターネット アクセスを承認します。

               // **************** UPDATE IPSET *****************
               //ssh2_connect, ssh2_fingerprint, ssh2_auth_pubkey_file, ssh2_auth_password, ssh2_exec
               if (($sshConnect = ssh2_connect("<GW IP>")) === FALSE) {
                   $err = error_get_last();
                   echo $err["message"];
                   exit;
               }
               if (ssh2_auth_pubkey_file($sshConnect, "root", "/usr/share/nginx/rsa.pub", "/usr/share/nginx/rsa") === FALSE) {
                   $err = error_get_last();
                   echo $err["message"];
                   exit;
               }
               if (($stream = ssh2_exec($sshConnect, "ipset add ip_whitelist " . $ClientIPAddr)) === FALSE) {
                   $err = error_get_last();
                   echo $err["message"];
                   exit;
               }
               $stderr_stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
               if ((stream_set_blocking($stream, true) === FALSE) ||
                       (stream_set_blocking($stderr_stream, true) === FALSE)) {
                   $err = error_get_last();
                   echo $err["message"];
                   exit;
               }
               if (($resultStr = stream_get_contents($stream)) === FALSE) {
                   $err = error_get_last();
                   echo $err["message"];
                   exit;
               }
               if ($resultStr === "") { // Likely an error
                   if (($resultStr = stream_get_contents($stderr_stream)) === FALSE) {
                       $err = error_get_last();
                       echo $err["message"];
                       exit;
                   }
               }
               echo "<pre>" . $resultStr . "</pre>";
           }
       }
       $mysqli->close();
       ?>
   </body>
</html>

ご覧のとおり、これは非常に粗いです。ただし、必要なすべての機能にヒットします。これが他の誰かに役立つことを願っています。

于 2013-10-26T04:11:33.763 に答える