Software /
code /
prosody
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 |