7

署名されていないintとして格納されているIPアドレス(ipNumeric)を含むテーブルAと、サブネット(subnetNumeric)を含むテーブルBがあります。

INET_NTOA(ipNumeric) = 192.168.0.1
INET_NTOA(subnetNumeric) = 192.168.0.0

このIPがサブネットのメンバーであるかどうかを確認したいと思います。

サブネットはクラスA、B、Cです。

これはMySQLでオンザフライで妥当な時間内に実行できますか、それともサブネット範囲を事前に計算する必要がありますか?

4

4 に答える 4

14

確かに、それは実行可能です。サブネットマスクは、サブネットクラスで指定された数の最上位ビットを1に設定して計算するという考え方です。クラスCの場合、それは

SELECT -1 << 8;

次に、サブネットマスクと現在のIPアドレスをANDします。IPがサブネット内にある場合、結果はサブネットアドレス(標準のネットワーク関連のもの)と等しくなるはずです。したがって、最終的には次のようになります。

SELECT (-1 << 8) & INET_ATON("192.168.0.1") = INET_ATON("192.168.0.0");

更新:はい、ネットワーククラスまたはサブネットマスク(同等の情報)を知っている必要があります。X.Y.0.0この情報がない場合、サブネットが存在する場合をどのように処理できるかを検討してください。これですか、X.Y.0.0/16それともX.Y.0.0/83番目のオクテットがたまたま0になっている場所ですか?知る方法はありません。

サブネットマスクがわかっている場合は、クエリを次のように記述できます。

SELECT (-1 << (33 - INSTR(BIN(INET_ATON("255.255.255.0")), "0"))) &
       INET_ATON("192.168.0.1") = INET_ATON("192.168.0.0");
于 2012-04-03T22:00:31.400 に答える
1

まず、テストをサポートするテーブルを作成します。

CREATE TABLE a (ipNumeric INT UNSIGNED);
INSERT INTO a (ipNumeric) VALUES(INET_ATON("172.16.40.101"));
INSERT INTO a (ipNumeric) VALUES(INET_ATON("192.168.1.12"));
INSERT INTO a (ipNumeric) VALUES(INET_ATON("10.1.5.51"));
INSERT INTO a (ipNumeric) VALUES(INET_ATON("10.7.1.78"));      
CREATE TABLE b (subnetNumeric INT UNSIGNED);
INSERT INTO b (subnetNumeric) VALUES (INET_ATON("192.168.0.0"));
INSERT INTO b (subnetNumeric) VALUES (INET_ATON("10.1.0.0"));
INSERT INTO b (subnetNumeric) VALUES (INET_ATON("172.16.0.0"));

次に、アドレスとマスク=サブネットに基づいて、テーブル間で一致するものを選択して検索します。ここでは、クラスBサブネット(255.255.0.0)を想定しています。INET_ATON()関数を使用できるため、ビットシフトする必要はありません。

SELECT INET_NTOA(a.ipNumeric),INET_NTOA(b.subnetNumeric) FROM a,b 
       WHERE (a.ipNumeric & INET_ATON("255.255.0.0")) = b.subnetNumeric;

+------------------------+----------------------------+
| INET_NTOA(a.ipNumeric) | INET_NTOA(b.subnetNumeric) |
+------------------------+----------------------------+
| 192.168.1.12           | 192.168.0.0                |
| 10.1.5.51              | 10.1.0.0                   |
| 172.16.40.101          | 172.16.0.0                 |
+------------------------+----------------------------+
于 2012-04-03T22:36:28.000 に答える
1

これは私たちが使用するMySQL関数です。

DELIMITER $$
DROP FUNCTION IF EXISTS `ip_in_subnet_mask`$$
CREATE DEFINER=`root`@`%` FUNCTION `ip_in_subnet_mask`(ip VARCHAR(20), subnet VARCHAR(20), netmask VARCHAR(20)) RETURNS TINYINT(1)
    DETERMINISTIC
BEGIN
    RETURN (INET_ATON(ip) & INET_ATON(netmask)) = INET_ATON(subnet);
END$$
DELIMITER ;

例:t.ipが192.168.0.xの範囲にあるすべての行を検索します。ここで0 <= x <= 255

 SELECT *
 FROM t
 WHERE
    ip_in_subnet_mask(t.ip, "192.168.0.0", "255.255.255.0")
于 2015-04-27T09:45:15.203 に答える
0

アドレスが文字列として保存される場合の解決策があります。したがって、アルゴリズムのその部分を作成したい場合は、ここで私のソリューションを使用できます。

特にIPv6の場合は、少し注意が必要です。IPv6では、オプションで、1:0:0:0:0:0:0:1と同等の1:: 1のような圧縮セグメントを使用できます。これが、注意が必要な主な理由です。

IPAddress Javaライブラリは、指定されたサブネット内のアドレスを検索するためのmysqlSQLを生成します。リンクはこの問題をより詳細に説明しています。免責事項:私はプロジェクトマネージャーです。

基本的なアルゴリズムは、サブネットアドレスのネットワークセクションを取得し、次にそのセクションの各バリアントを取得し(たとえば、上記の2つの文字列は完全なアドレス1 :: 1のバリアントです)、セグメントセパレータの数をカウントしてから実行します。一致するアドレスのmysqlサブ文字列だけでなく、一致するアドレスの区切り文字の総数もカウントします。

サンプルコードは次のとおりです。

public static void main(String[] args) throws IPAddressStringException {
    System.out.println(getSearchSQL("columnX", "1.2.3.4/16"));
    System.out.println(getSearchSQL("columnX", "1:2:3:4:5:6:7:8/64"));
    System.out.println(getSearchSQL("columnX", "1::8/64"));
}

static String getSearchSQL(String expression, String ipAddressStr) throws IPAddressStringException {
    IPAddressString ipAddressString = new IPAddressString(ipAddressStr);
    IPAddress ipAddress = ipAddressString.toAddress();
    IPAddressSection networkPrefix = ipAddress.getNetworkSection(ipAddress.getNetworkPrefixLength(), false);
    StringBuilder sql = new StringBuilder("Select rows from table where ");
    networkPrefix.getStartsWithSQLClause(sql, expression);
    return sql.toString();
}

Ouptut:

Select rows from table where (substring_index(columnX,'.',2) = '1.2')
Select rows from table where (substring_index(columnX,':',4) = '1:2:3:4')
Select rows from table where ((substring_index(columnX,':',4) = '1:0:0:0') OR ((substring_index(columnX,':',2) = '1:') AND (LENGTH (columnX) - LENGTH(REPLACE(columnX, ':', '')) <= 5)))
于 2016-10-19T19:41:05.473 に答える