Home Articles

远程操作iptables(OpenWRT)

Asked
Viewed 876 times
0

我有一个25(即将成为100)节点(OpenWRT)adhoc L2网状网络(batman-adv),有4个网关节点 . 每个节点都有一个5ghz和一个2.4ghz的无线接口 . 2.4用于客户端访问,网格在5ghz接口上运行 .

所有节点几乎相同(软件) . GW对网状网和一对节点的广播互联网(以太网)访问具有连接到单个服务器的LAN端口(以太网),为网状网提供DHCP,SQL和http服务 . 通过设计,对于哪些节点物理地提供对因特网或DCHP / SQL / HTTP服务器的访问没有限制(即,共址不是设计选项) .

目前,无线客户端可以无限制地访问GW的WAN端口 . 该项目的下一阶段是根据LAN服务器上托管的帐户信息(即数据库中的帐户信息)限制对WAN接口的访问 .

我想做的是远程操作GW节点的iptables来控制基于来自服务器的信息的Internet访问,但我不确定什么是获取GWs命令的最佳方法 . 我的第一个想法是通过SSH或流命令向SSH客户端执行批处理命令 . 我也可以编写自己的简单TCP / IP服务器 . 可能还有一个RPC模型 .

是否有上面给出的推荐方法或我应该考虑的优点和缺点 . 谢谢 .

编辑:iptables阻止并发呼叫或用户是否有必要序列化使用?

2 Answers

  • 1

    最后我决定使用php-ssh2,php-mysqli以及OpenWRT下的iptables和ipset的组合(包ipset,iptables-mod-ipset和kmod-ipt-ipset) .

    我创建了一个ipset来包含允许完全上网的ip地址:

    ipset create ip_whitelist hash:ip
    

    在OpenWRT上,如果源IP不在ip_whitelist中,我设置iptables将任何流量http流量重定向到我的Internet服务器:

    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和DNS流量中的IP的流量 .

    已授权的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 . ")
    "; } echo "Now for a query on " . $ClientIPAddr . ":
    "; // 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 . ")
    "; 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 . ")
    "; exit; } else {

    添加IP到ipset以授权Internet访问:

    // **************** 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>
    

    如你所见,这是非常粗糙的 . 但它确实击中了我需要的所有功能 . 我希望这对其他人有用 .

  • 0

    我猜你在所有网关上都有相同的策略 . 您可能集中维护该策略 . 在这种情况下,我只会在某个集中式服务器中以“iptables-restore”格式构建策略,并在每个GW上执行一个命令 . 您可能希望通过安全通道执行此命令 . 我只想使用scp ssh .

    除了用新表替换整个表之外,这与您的建议完全相似 . 一次添加一个规则可能会在策略中引入一些不一致,并可能引入漏洞 . 此外,在有损环境中保持所有GW同步可能会非常棘手 . 因此对iptables-restore的压力很大 .

Related