util.ip: Parse IP address using inet_pton
authorKim Alvefur <zash@zash.se>
Fri, 01 Dec 2017 04:39:12 +0100
changeset 8433 a58d560aa8d5
parent 8432 b3562a1b1caa
child 8434 a5a03d40a20c
util.ip: Parse IP address using inet_pton
util/ip.lua
--- a/util/ip.lua	Fri Dec 01 01:55:40 2017 +0100
+++ b/util/ip.lua	Fri Dec 01 04:39:12 2017 +0100
@@ -5,6 +5,8 @@
 -- COPYING file in the source package for more information.
 --
 
+local net = require "util.net";
+
 local ip_methods = {};
 
 local ip_mt = {
@@ -23,32 +25,30 @@
 };
 
 local function new_ip(ipStr, proto)
-	if not proto then
-		local sep = ipStr:match("^%x+(.)");
-		if sep == ":" or (not(sep) and ipStr:sub(1,1) == ":") then
-			proto = "IPv6"
-		elseif sep == "." then
-			proto = "IPv4"
+	local zone;
+	if (not proto or proto == "IPv6") and ipStr:find('%', 1, true) then
+		ipStr, zone = ipStr:match("^(.-)%%(.*)");
+	end
+
+	local packed, err = net.pton(ipStr);
+	if not packed then return packed, err end
+	if proto == "IPv6" and #packed ~= 16 then
+		return nil, "invalid-ipv6";
+	elseif proto == "IPv4" and #packed ~= 4 then
+		return nil, "invalid-ipv4";
+	elseif not proto then
+		if #packed == 16 then
+			proto = "IPv6";
+		elseif #packed == 4 then
+			proto = "IPv4";
+		else
+			return nil, "unknown protocol";
 		end
-		if not proto then
-			return nil, "invalid address";
-		end
-	elseif proto ~= "IPv4" and proto ~= "IPv6" then
+	elseif proto ~= "IPv6" and proto ~= "IPv4" then
 		return nil, "invalid protocol";
 	end
-	local zone;
-	if proto == "IPv6" and ipStr:find('%', 1, true) then
-		ipStr, zone = ipStr:match("^(.-)%%(.*)");
-	end
-	if proto == "IPv6" and ipStr:find('.', 1, true) then
-		local changed;
-		ipStr, changed = ipStr:gsub(":(%d+)%.(%d+)%.(%d+)%.(%d+)$", function(a,b,c,d)
-			return (":%04X:%04X"):format(a*256+b,c*256+d);
-		end);
-		if changed ~= 1 then return nil, "invalid-address"; end
-	end
 
-	return setmetatable({ addr = ipStr, proto = proto, zone = zone }, ip_mt);
+	return setmetatable({ addr = ipStr, packed = packed, proto = proto, zone = zone }, ip_mt);
 end
 
 local function toBits(ip)