aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.rst24
-rw-r--r--lua/inet/core.lua121
-rw-r--r--lua/inet/init.lua2
3 files changed, 102 insertions, 45 deletions
diff --git a/README.rst b/README.rst
index 207b1d9..b227b1a 100644
--- a/README.rst
+++ b/README.rst
@@ -76,6 +76,7 @@ API Description
``inet.is_set(foo)`` is ``set`` table?
``inet.set()`` get new empty ``set`` instance.
``inet.mixed_networks`` IPv6 mixed notation ``set``
+``inet.lpeg`` LPeg_ patterns
``inet.version`` API version (currently ``1``)
======================= =====================================================
@@ -188,6 +189,29 @@ There is a multitude of different ways to create ``inet*`` instances.
inet('192.0.2.0', 33) -- returns nil, 'invalid mask'
inet('2001:db8::', 129) -- returns nil, 'invalid mask'
+Usable in LPeg patterns
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Internally ``inet`` uses LPeg_ to parse IP adresses, but the
+LPeg patterns are also available for embedding into your
+own LPeg patterns.
+
+::
+
+ local lpeg = require 'lpeg'
+ local P = lpeg.P
+ local http_host_v6 = P('[') * inet.lpeg.ipv6 * P(']')
+ local http_host = http_host_v6 + inet.lpeg.ipv4
+ local my_http_uri = P('https://') * http_host * P('/') * -1
+
+ my_http_uri:match('https://192.0.2.0/') -- returns inet('192.0.2.0')
+ my_http_uri:match('https://[2001:db8::1]/') -- returns inet('2001:db8::1')
+
+ inet.lpeg.ipv6:match('2001:db8::/64') -- returns inet('2001:db8::/64')
+ inet.lpeg.ipv4:match('192.0.2.0/24') -- returns inet('192.0.2.0/24')
+ inet.lpeg.ip:match('2001:db8::/64') -- returns inet('2001:db8::/64')
+ inet.lpeg.ip:match('192.0.2.0/24') -- returns inet('192.0.2.0/24')
+
Mangling
--------
diff --git a/lua/inet/core.lua b/lua/inet/core.lua
index 2b36543..a12a036 100644
--- a/lua/inet/core.lua
+++ b/lua/inet/core.lua
@@ -79,13 +79,42 @@ function inet:full_family()
return format('ipv%d', self:family())
end
+local function build_bip(o1, o2, o3, o4)
+ return lshift(o1, 24) + lshift(o2, 16) + lshift(o3, 8) + o4
+end
+
+local function make_inet4(bip, mask)
+ return setmetatable({
+ bip = bip,
+ mask = mask or 32,
+ }, inet4)
+end
+
+local function make_inet6(pcs, mask)
+ local r = setmetatable({
+ pcs = pcs,
+ mask = mask or 128,
+ }, inet6)
+
+ -- ensure that the result is balanced
+ if not r:is_balanced() then
+ r:balance()
+ return nil, tostring(r)..' unbalanced'
+ end
+
+ return r
+end
+
+local ipv4_peg
local ipv4_parser
+local ipv6_peg
local ipv6_parser
do
local lpeg = require 'lpeg'
local C, Ct = lpeg.C, lpeg.Ct
local S, R = lpeg.S, lpeg.R
local B, Cc = lpeg.B, lpeg.Cc
+ local Cmt = lpeg.Cmt
local digit = R('09')
@@ -105,7 +134,13 @@ do
local mask12 = R('12') * digit
local mask3 = S('3') * R('02')
local netmask = S('/') * C(mask12 + mask3 + digit)
- ipv4_parser = ipv4addr * (netmask + Cc()) * -1
+ local ipv4_base = ipv4addr * (netmask + Cc()) /
+ function (o1, o2, o3, o4, mask)
+ local bip = build_bip(o1, o2, o3, o4)
+ return bip, tonumber(mask)
+ end
+ ipv4_parser = ipv4_base * -1
+ ipv4_peg = ipv4_base / make_inet4
end
do
@@ -124,20 +159,43 @@ do
local partial = (piece * (colpi^-6))^-1 * colcol * ((picol^-6)*(ipv4embed+piece))^-1
local netmask = S('/') * C((digit^-3)) / tonumber
local pieces = full + partial
- ipv6_parser = Ct(pieces) * ((netmask + Cc())^-1) * -1
- end
-end
+ local function check_pcs(_, _, pcs, mask)
+ if #pcs > 8 then return false end
+ if mask ~= nil and mask > 128 then return false end
+ return true, pcs, mask
+ end
-local function build_bip(o1, o2, o3, o4)
- return lshift(o1, 24) + lshift(o2, 16) + lshift(o3, 8) + o4
+ local function expand_pieces(pcs)
+ local zero_pieces = 8 - #pcs
+ for i=1,#pcs do
+ if pcs[i] == '::' then
+ pcs[i] = 0
+ for j=#pcs,i,-1 do
+ pcs[j+zero_pieces] = pcs[j]
+ end
+ for j=1,zero_pieces do
+ pcs[i+j] = 0
+ end
+ end
+ end
+ assert(#pcs == 8, 'incorrect number of pieces')
+ return pcs
+ end
+
+ local ipv6_base = Cmt(Ct(pieces) * ((netmask + Cc())^-1), check_pcs) /
+ function (pcs, mask)
+ expand_pieces(pcs)
+ return pcs, mask
+ end
+ ipv6_parser = ipv6_base * -1
+ ipv6_peg = ipv6_base / make_inet6
+ end
end
local function inet4_from_string(ipstr)
- local o1, o2, o3, o4, mask = ipv4_parser:match(ipstr)
- if not o1 then return nil, 'parse error' end
-
- local bip = build_bip(o1, o2, o3, o4)
- return bip, tonumber(mask)
+ local bip, mask = ipv4_parser:match(ipstr)
+ if not bip then return nil, 'parse error' end
+ return bip, mask
end
local function inet4_from_number(bip)
@@ -166,23 +224,6 @@ local inet4_constructors = {
local function inet6_from_string(ipstr)
local pcs, netmask = ipv6_parser:match(ipstr)
if not pcs then return nil, 'parse error' end
- if #pcs > 8 then return nil, 'too many pieces' end
- local zero_pieces = 8 - #pcs
- for i=1,#pcs do
- if pcs[i] == '::' then
- pcs[i] = 0
- for j=#pcs,i,-1 do
- pcs[j+zero_pieces] = pcs[j]
- end
- for j=1,zero_pieces do
- pcs[i+j] = 0
- end
- end
- end
- if #pcs > 8 then return nil, 'too many pieces' end
- if netmask ~= nil and netmask > 128 then
- return nil, 'invalid netmask'
- end
return pcs, netmask
end
@@ -239,28 +280,13 @@ end
local function new_inet4(ip, mask)
local bip, outmask = generic_new(inet4_constructors, 32, ip, mask)
if not bip then return nil, outmask end
- return setmetatable({
- bip = bip,
- mask = outmask,
- }, inet4)
+ return make_inet4(bip, outmask)
end
local function new_inet6(ip, mask)
local pcs, outmask = generic_new(inet6_constructors, 128, ip, mask)
if not pcs then return nil, outmask end
-
- local r = setmetatable({
- pcs = pcs,
- mask = outmask,
- }, inet6)
-
- -- ensure that the result is balanced
- if not r:is_balanced() then
- r:balance()
- return nil, tostring(r)..' unbalanced'
- end
-
- return r
+ return make_inet6(pcs, outmask)
end
local function new_inet(ip, mask)
@@ -877,5 +903,10 @@ M.is_inet4 = is_inet4
M.is_inet6 = is_inet6
M.is_inet = is_inet
M.new_inet = new_inet
+M.lpeg = {
+ ipv4 = ipv4_peg,
+ ipv6 = ipv6_peg,
+ ip = ipv4_peg + ipv6_peg,
+}
return M
diff --git a/lua/inet/init.lua b/lua/inet/init.lua
index 56c0eed..229fbd8 100644
--- a/lua/inet/init.lua
+++ b/lua/inet/init.lua
@@ -22,6 +22,8 @@ M.is4 = core.is_inet4
M.is6 = core.is_inet6
M.is = core.is_inet
+M.lpeg = core.lpeg
+
M.is_set = set.is_set
M.set = set.new