Comparison

util/ip.lua @ 8435:47195f035d2f

util.ip: Instantiate various addresses used for comparisons once
author Kim Alvefur <zash@zash.se>
date Fri, 01 Dec 2017 02:23:57 +0100
parent 8434:ec8f37baffaa
child 8436:ab9ddfb03d4d
comparison
equal deleted inserted replaced
8434:ec8f37baffaa 8435:47195f035d2f
65 ip = ip.toV4mapped; 65 ip = ip.toV4mapped;
66 end 66 end
67 return ip.bits; 67 return ip.bits;
68 end 68 end
69 69
70 local match;
71
70 local function commonPrefixLength(ipA, ipB) 72 local function commonPrefixLength(ipA, ipB)
71 ipA, ipB = ipA.bits_full, ipB.bits_full; 73 ipA, ipB = ipA.bits_full, ipB.bits_full;
72 for i = 1, 128 do 74 for i = 1, 128 do
73 if ipA:sub(i,i) ~= ipB:sub(i,i) then 75 if ipA:sub(i,i) ~= ipB:sub(i,i) then
74 return i-1; 76 return i-1;
75 end 77 end
76 end 78 end
77 return 128; 79 return 128;
78 end 80 end
79 81
82 -- Instantiate once
83 local loopback = new_ip("::1");
84 local loopback4 = new_ip("127.0.0.0");
85 local sixtofour = new_ip("2002::");
86 local teredo = new_ip("2001::");
87 local linklocal = new_ip("fe80::");
88 local linklocal4 = new_ip("169.254.0.0");
89 local uniquelocal = new_ip("fc00::");
90 local sitelocal = new_ip("fec0::");
91 local sixbone = new_ip("3ffe::");
92 local defaultunicast = new_ip("::");
93 local multicast = new_ip("ff00::");
94 local ipv6mapped = new_ip("::ffff:0:0");
95
80 local function v4scope(ip) 96 local function v4scope(ip)
81 local fields = {}; 97 if match(ip, loopback4, 8) then
82 ip:gsub("([^.]*).?", function (c) fields[#fields + 1] = tonumber(c) end); 98 return 0x2;
83 -- Loopback: 99 elseif match(ip, linklocal4) then
84 if fields[1] == 127 then 100 return 0x2;
85 return 0x2; 101 else -- Global unicast
86 -- Link-local unicast:
87 elseif fields[1] == 169 and fields[2] == 254 then
88 return 0x2;
89 -- Global unicast:
90 else
91 return 0xE; 102 return 0xE;
92 end 103 end
93 end 104 end
94 105
95 local function v6scope(ip) 106 local function v6scope(ip)
96 -- Loopback: 107 if ip == loopback then
97 if ip:match("^[0:]*1$") then 108 return 0x2;
98 return 0x2; 109 elseif match(ip, linklocal, 10) then
99 -- Link-local unicast: 110 return 0x2;
100 elseif ip:match("^[Ff][Ee][89ABab]") then 111 elseif match(ip, sitelocal, 10) then
101 return 0x2;
102 -- Site-local unicast:
103 elseif ip:match("^[Ff][Ee][CcDdEeFf]") then
104 return 0x5; 112 return 0x5;
105 -- Multicast: 113 elseif match(ip, multicast, 10) then
106 elseif ip:match("^[Ff][Ff]") then 114 return ip.packed:byte(2) % 0x10;
107 return tonumber("0x"..ip:sub(4,4)); 115 else -- Global unicast
108 -- Global unicast:
109 else
110 return 0xE; 116 return 0xE;
111 end 117 end
112 end 118 end
113 119
114 local function label(ip) 120 local function label(ip)
115 if commonPrefixLength(ip, new_ip("::1", "IPv6")) == 128 then 121 if ip == loopback then
116 return 0; 122 return 0;
117 elseif commonPrefixLength(ip, new_ip("2002::", "IPv6")) >= 16 then 123 elseif match(ip, sixtofour, 16) then
118 return 2; 124 return 2;
119 elseif commonPrefixLength(ip, new_ip("2001::", "IPv6")) >= 32 then 125 elseif match(ip, teredo, 32) then
120 return 5; 126 return 5;
121 elseif commonPrefixLength(ip, new_ip("fc00::", "IPv6")) >= 7 then 127 elseif match(ip, uniquelocal, 7) then
122 return 13; 128 return 13;
123 elseif commonPrefixLength(ip, new_ip("fec0::", "IPv6")) >= 10 then 129 elseif match(ip, sitelocal, 10) then
124 return 11; 130 return 11;
125 elseif commonPrefixLength(ip, new_ip("3ffe::", "IPv6")) >= 16 then 131 elseif match(ip, sixbone, 16) then
126 return 12; 132 return 12;
127 elseif commonPrefixLength(ip, new_ip("::", "IPv6")) >= 96 then 133 elseif match(ip, defaultunicast, 96) then
128 return 3; 134 return 3;
129 elseif commonPrefixLength(ip, new_ip("::ffff:0:0", "IPv6")) >= 96 then 135 elseif match(ip, ipv6mapped, 96) then
130 return 4; 136 return 4;
131 else 137 else
132 return 1; 138 return 1;
133 end 139 end
134 end 140 end
135 141
136 local function precedence(ip) 142 local function precedence(ip)
137 if commonPrefixLength(ip, new_ip("::1", "IPv6")) == 128 then 143 if ip == loopback then
138 return 50; 144 return 50;
139 elseif commonPrefixLength(ip, new_ip("2002::", "IPv6")) >= 16 then 145 elseif match(ip, sixtofour, 16) then
140 return 30; 146 return 30;
141 elseif commonPrefixLength(ip, new_ip("2001::", "IPv6")) >= 32 then 147 elseif match(ip, teredo, 32) then
142 return 5; 148 return 5;
143 elseif commonPrefixLength(ip, new_ip("fc00::", "IPv6")) >= 7 then 149 elseif match(ip, uniquelocal, 7) then
144 return 3; 150 return 3;
145 elseif commonPrefixLength(ip, new_ip("fec0::", "IPv6")) >= 10 then 151 elseif match(ip, sitelocal, 10) then
146 return 1; 152 return 1;
147 elseif commonPrefixLength(ip, new_ip("3ffe::", "IPv6")) >= 16 then 153 elseif match(ip, sixbone, 16) then
148 return 1; 154 return 1;
149 elseif commonPrefixLength(ip, new_ip("::", "IPv6")) >= 96 then 155 elseif match(ip, defaultunicast, 96) then
150 return 1; 156 return 1;
151 elseif commonPrefixLength(ip, new_ip("::ffff:0:0", "IPv6")) >= 96 then 157 elseif match(ip, ipv6mapped, 96) then
152 return 35; 158 return 35;
153 else 159 else
154 return 40; 160 return 40;
155 end 161 end
156 end 162 end
184 end 190 end
185 191
186 function ip_methods:scope() 192 function ip_methods:scope()
187 local value; 193 local value;
188 if self.proto == "IPv4" then 194 if self.proto == "IPv4" then
189 value = v4scope(self.addr); 195 value = v4scope(self);
190 else 196 else
191 value = v6scope(self.addr); 197 value = v6scope(self);
192 end 198 end
193 self.scope = value; 199 self.scope = value;
194 return value; 200 return value;
195 end 201 end
202
203 local rfc1918_8 = new_ip("10.0.0.0");
204 local rfc1918_12 = new_ip("172.16.0.0");
205 local rfc1918_16 = new_ip("192.168.0.0");
196 206
197 function ip_methods:private() 207 function ip_methods:private()
198 local private = self.scope ~= 0xE; 208 local private = self.scope ~= 0xE;
199 if not private and self.proto == "IPv4" then 209 if not private and self.proto == "IPv4" then
200 local ip = self.addr; 210 private = match(self, rfc1918_8, 8) or match(self, rfc1918_12, 12) or match(self, rfc1918_16);
201 local fields = {};
202 ip:gsub("([^.]*).?", function (c) fields[#fields + 1] = tonumber(c) end);
203 if fields[1] == 127 or fields[1] == 10 or (fields[1] == 192 and fields[2] == 168)
204 or (fields[1] == 172 and (fields[2] >= 16 or fields[2] <= 32)) then
205 private = true;
206 end
207 end 211 end
208 self.private = private; 212 self.private = private;
209 return private; 213 return private;
210 end 214 end
211 215
217 cidr = cidr:sub(1, ip_len-1); 221 cidr = cidr:sub(1, ip_len-1);
218 end 222 end
219 return new_ip(cidr), bits; 223 return new_ip(cidr), bits;
220 end 224 end
221 225
222 local function match(ipA, ipB, bits) 226 function match(ipA, ipB, bits)
223 local common_bits = commonPrefixLength(ipA, ipB); 227 local common_bits = commonPrefixLength(ipA, ipB);
224 if bits and ipB.proto == "IPv4" then 228 if bits and ipB.proto == "IPv4" then
225 common_bits = common_bits - 96; -- v6 mapped addresses always share these bits 229 common_bits = common_bits - 96; -- v6 mapped addresses always share these bits
226 end 230 end
227 return common_bits >= (bits or 128); 231 return common_bits >= (bits or 128);