我有一个表A,其中IP地址(ipNumeric)存储为无符号整数,表B包含子网(subnetNumeric):
INET_NTOA(ipNumeric) = 192.168.0.1
INET_NTOA(subnetNumeric) = 192.168.0.0
我想检查一下这个IP是否是子网的成员。
子网是A,B和C类。
这可以在MySQL中的合理时间内进行,还是子网范围可以预先计算?
答案 0 :(得分:11)
当然,这是可行的。我们的想法是,我们通过将最高有效位设置为1来计算子网掩码,这与子网类规定的数量一样多。对于C类,那将是
SELECT -1 << 8;
然后,用你拥有的IP地址和子网掩码;如果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/8
第三个八位字节刚刚发生是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");
答案 1 :(得分:0)
首先创建表以支持测试。
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"));
现在根据地址&amp ;;选择查找表格之间的匹配项。 mask =子网。这里我们假设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 |
+------------------------+----------------------------+
答案 2 :(得分:0)
这是我们使用的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 ;
e.g。查找t.ip在192.168.0.x范围内的所有行,其中0&lt; = x&lt; = 255
SELECT *
FROM t
WHERE
ip_in_subnet_mask(t.ip, "192.168.0.0", "255.255.255.0")
答案 3 :(得分:0)
我有一个地址存储为字符串的解决方案。因此,如果您希望制作算法的那一部分,可以在此处使用我的解决方案。
这有点棘手,特别是对于IPv6。在IPv6中,可以选择压缩段,例如1 :: 1,相当于1:0:0:0:0:0:0:1,这是它很棘手的主要原因。
The IPAddress Java library将生成mysql SQL以搜索给定子网中的地址。该链接更详细地描述了该问题。免责声明:我是项目经理。
基本算法是获取子网地址的网络部分,然后获取该部分的每个变体(例如,上面的两个字符串是完整地址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)))