Comparison

util/ip.lua @ 13431:4698f1e36e02

util.ip: Remove ip.bits and related code, switch to more efficient strbitop 100,000 iterations of match() on my laptop from 3.5s -> 0.5s.
author Matthew Wild <mwild1@gmail.com>
date Fri, 23 Feb 2024 12:14:51 +0000
parent 12975:d10957394a3c
comparison
equal deleted inserted replaced
13430:1a5e3cf037f6 13431:4698f1e36e02
4 -- This project is MIT/X11 licensed. Please see the 4 -- This project is MIT/X11 licensed. Please see the
5 -- COPYING file in the source package for more information. 5 -- COPYING file in the source package for more information.
6 -- 6 --
7 7
8 local net = require "prosody.util.net"; 8 local net = require "prosody.util.net";
9 local hex = require "prosody.util.hex"; 9 local strbit = require "prosody.util.strbitop";
10 10
11 local ip_methods = {}; 11 local ip_methods = {};
12 12
13 local ip_mt = { 13 local ip_mt = {
14 __index = function (ip, key) 14 __index = function (ip, key)
25 -- Lua 5.3+ calls this if both operands are tables, even if metatables differ 25 -- Lua 5.3+ calls this if both operands are tables, even if metatables differ
26 return false; 26 return false;
27 end 27 end
28 return ipA.packed == ipB.packed; 28 return ipA.packed == ipB.packed;
29 end 29 end
30
31 local hex2bits = {
32 ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011",
33 ["4"] = "0100", ["5"] = "0101", ["6"] = "0110", ["7"] = "0111",
34 ["8"] = "1000", ["9"] = "1001", ["A"] = "1010", ["B"] = "1011",
35 ["C"] = "1100", ["D"] = "1101", ["E"] = "1110", ["F"] = "1111",
36 };
37 30
38 local function new_ip(ipStr, proto) 31 local function new_ip(ipStr, proto)
39 local zone; 32 local zone;
40 if (not proto or proto == "IPv6") and ipStr:find('%', 1, true) then 33 if (not proto or proto == "IPv6") and ipStr:find('%', 1, true) then
41 ipStr, zone = ipStr:match("^(.-)%%(.*)"); 34 ipStr, zone = ipStr:match("^(.-)%%(.*)");
64 57
65 function ip_methods:normal() 58 function ip_methods:normal()
66 return net.ntop(self.packed); 59 return net.ntop(self.packed);
67 end 60 end
68 61
69 function ip_methods.bits(ip) 62 -- Returns the longest packed representation, i.e. IPv4 will be mapped
70 return hex.encode(ip.packed):upper():gsub(".", hex2bits); 63 function ip_methods.packed_full(ip)
71 end
72
73 function ip_methods.bits_full(ip)
74 if ip.proto == "IPv4" then 64 if ip.proto == "IPv4" then
75 ip = ip.toV4mapped; 65 ip = ip.toV4mapped;
76 end 66 end
77 return ip.bits; 67 return ip.packed;
78 end 68 end
79 69
80 local match; 70 local match;
81 71
82 local function commonPrefixLength(ipA, ipB) 72 local function commonPrefixLength(ipA, ipB)
83 ipA, ipB = ipA.bits_full, ipB.bits_full; 73 return strbit.common_prefix_bits(ipA.packed_full, ipB.packed_full);
84 for i = 1, 128 do
85 if ipA:sub(i,i) ~= ipB:sub(i,i) then
86 return i-1;
87 end
88 end
89 return 128;
90 end 74 end
91 75
92 -- Instantiate once 76 -- Instantiate once
93 local loopback = new_ip("::1"); 77 local loopback = new_ip("::1");
94 local loopback4 = new_ip("127.0.0.0"); 78 local loopback4 = new_ip("127.0.0.0");
236 elseif ipB.proto == "IPv4" then 220 elseif ipB.proto == "IPv4" then
237 ipB = ipB.toV4mapped; 221 ipB = ipB.toV4mapped;
238 bits = bits + (128 - 32); 222 bits = bits + (128 - 32);
239 end 223 end
240 end 224 end
241 return ipA.bits:sub(1, bits) == ipB.bits:sub(1, bits); 225 return strbit.common_prefix_bits(ipA.packed, ipB.packed) >= bits;
242 end 226 end
243 227
244 local function is_ip(obj) 228 local function is_ip(obj)
245 return getmetatable(obj) == ip_mt; 229 return getmetatable(obj) == ip_mt;
246 end 230 end