summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--acf/model/combination.lua47
-rw-r--r--acf/model/field.lua61
-rw-r--r--acf/model/init.lua94
-rw-r--r--acf/model/net.lua88
-rw-r--r--acf/modules/awall.lua37
-rw-r--r--acf/modules/net.lua25
6 files changed, 240 insertions, 112 deletions
diff --git a/acf/model/combination.lua b/acf/model/combination.lua
new file mode 100644
index 0000000..7228233
--- /dev/null
+++ b/acf/model/combination.lua
@@ -0,0 +1,47 @@
+--[[
+Copyright (c) 2012-2013 Kaarle Ritvanen
+See LICENSE file for license details
+--]]
+
+module(..., package.seeall)
+
+local err = require('acf.error')
+local raise = err.raise
+
+local fld = require('acf.model.field')
+local String = fld.String
+
+local to_field = require('acf.model.model').to_field
+
+local object = require('acf.object')
+local class = object.class
+local super = object.super
+
+
+require 'stringy'
+
+
+Range = class(String)
+
+function Range:init(params)
+ super(self, Range):init(params)
+ if not self.type then self.type = fld.Integer end
+end
+
+function Range:validate(context, value)
+ local comps = stringy.split(value, '-')
+ if #comps > 2 then raise(context.path, 'Invalid range') end
+ for _, v in ipairs(comps) do to_field(self.type):_validate(context, v) end
+end
+
+
+Union = class(String)
+
+function Union:validate(context, value)
+ super(self, Union):validate(context, value)
+ for _, tpe in ipairs(self.types) do
+ local field = to_field(tpe)
+ if err.call(field.validate, field, context, value) then return end
+ end
+ raise(context.path, self.error or 'Invalid value')
+end
diff --git a/acf/model/field.lua b/acf/model/field.lua
index ad26818..8927dfd 100644
--- a/acf/model/field.lua
+++ b/acf/model/field.lua
@@ -106,6 +106,67 @@ function Field:validate_saved(context)
end
+local Primitive = class(Field)
+
+function Primitive:validate(context, value)
+ local t = self.dtype
+ if type(value) ~= t then raise(context.path, 'Not a '..t) end
+end
+
+
+String = class(Primitive)
+
+function String:init(params)
+ super(self, String):init(params)
+ self.dtype = 'string'
+end
+
+function String:validate(context, value)
+ super(self, String):validate(context, value)
+ if self['max-length'] and string.len(value) > self['max-length'] then
+ raise(context.path, 'Maximum length exceeded')
+ end
+end
+
+function String:meta(context)
+ local res = super(self, String):meta(context)
+ res['max-length'] = self['max-length']
+ return res
+end
+
+
+Number = class(Primitive)
+
+function Number:init(params)
+ super(self, Number):init(params)
+ self.dtype = 'number'
+end
+
+function Number:_validate(context, value)
+ return super(self, Number):_validate(
+ context,
+ value and tonumber(value) or value
+ )
+end
+
+
+Integer = class(Number)
+
+function Integer:validate(context, value)
+ super(self, Integer):validate(context, value)
+ if math.floor(value) ~= value then raise(context.path, 'Not an integer') end
+end
+
+
+Boolean = class(Primitive)
+
+function Boolean:init(params)
+ super(self, Boolean):init(params)
+ self.dtype = 'boolean'
+ self.widget = self.dtype
+end
+
+
TreeNode = class(Field)
function TreeNode:load(context, create)
diff --git a/acf/model/init.lua b/acf/model/init.lua
index f325053..f1f127f 100644
--- a/acf/model/init.lua
+++ b/acf/model/init.lua
@@ -5,18 +5,28 @@ See LICENSE file for license details
module(..., package.seeall)
-error = require('acf.error')
-local raise = error.raise
-local relabel = error.relabel
+err = require('acf.error')
+local raise = err.raise
+local relabel = err.relabel
+
+local combination = require('acf.model.combination')
+Union = combination.Union
+Range = combination.Range
local fld = require('acf.model.field')
local Field = fld.Field
+Boolean = fld.Boolean
+Integer = fld.Integer
+Number = fld.Number
+String = fld.String
local model = require('acf.model.model')
Action = model.Action
new = model.new
local to_field = model.to_field
+net = require('acf.model.net')
+
node = require('acf.model.node')
permission = require('acf.model.permission')
register = require('acf.model.root').register
@@ -33,84 +43,6 @@ local map = require('acf.util').map
require 'stringy'
--- TODO object-specific actions
-
-
-local Primitive = class(Field)
-
-function Primitive:validate(context, value)
- local t = self.dtype
- if type(value) ~= t then raise(context.path, 'Not a '..t) end
-end
-
-
-String = class(Primitive)
-
-function String:init(params)
- super(self, String):init(params)
- self.dtype = 'string'
-end
-
-function String:validate(context, value)
- super(self, String):validate(context, value)
- if self['max-length'] and string.len(value) > self['max-length'] then
- raise(context.path, 'Maximum length exceeded')
- end
-end
-
-function String:meta(context)
- local res = super(self, String):meta(context)
- res['max-length'] = self['max-length']
- return res
-end
-
-
-Number = class(Primitive)
-
-function Number:init(params)
- super(self, Number):init(params)
- self.dtype = 'number'
-end
-
-function Number:_validate(context, value)
- return super(self, Number):_validate(
- context,
- value and tonumber(value) or value
- )
-end
-
-
-Integer = class(Number)
-
-function Integer:validate(context, value)
- super(self, Integer):validate(context, value)
- if math.floor(value) ~= value then raise(context.path, 'Not an integer') end
-end
-
-
-Boolean = class(Primitive)
-
-function Boolean:init(params)
- super(self, Boolean):init(params)
- self.dtype = 'boolean'
- self.widget = self.dtype
-end
-
-
-Range = class(String)
-
-function Range:init(params)
- super(self, Range):init(params)
- if not self.type then self.type = Integer end
-end
-
-function Range:validate(context, value)
- local comps = stringy.split(value, '-')
- if #comps > 2 then raise(context.path, 'Invalid range') end
- for _, v in ipairs(comps) do to_field(self.type):_validate(context, v) end
-end
-
-
Reference = class(Field)
function Reference:init(params)
diff --git a/acf/model/net.lua b/acf/model/net.lua
new file mode 100644
index 0000000..725c543
--- /dev/null
+++ b/acf/model/net.lua
@@ -0,0 +1,88 @@
+--[[
+Copyright (c) 2012-2013 Kaarle Ritvanen
+See LICENSE file for license details
+--]]
+
+module(..., package.seeall)
+
+local raise = require('acf.error').raise
+local Union = require('acf.model.combination').Union
+
+local fld = require('acf.model.field')
+local String = fld.String
+
+local object = require('acf.object')
+local class = object.class
+local super = object.super
+
+local update = require('acf.util').update
+
+
+require 'stringy'
+
+
+IPv4Address = class(String)
+
+function IPv4Address:validate(context, value)
+ super(self, IPv4Address):validate(context, value)
+ local function test(...)
+ if #arg ~= 4 then return true end
+ for _, octet in ipairs(arg) do
+ if tonumber(octet) > 255 then return true end
+ end
+ end
+ if test(string.match(value, '^(%d+)%.(%d+)%.(%d+)%.(%d+)$')) then
+ raise(context.path, 'Invalid IPv4 address')
+ end
+end
+
+
+IPv6Address = class(String)
+
+function IPv6Address:validate(context, value)
+ super(self, IPv6Address):validate(context, value)
+
+ local function invalid() raise(context.path, 'Invalid IPv6 address') end
+
+ if value == '' then invalid() end
+
+ local comps = stringy.split(value, ':')
+ if #comps < 3 then invalid() end
+
+ local function collapse(i, ofs)
+ if comps[i] > '' then return end
+ if comps[i + ofs] > '' then invalid() end
+ table.remove(comps, i)
+ end
+ collapse(1, 1)
+ collapse(#comps, -1)
+ if #comps > 8 then invalid() end
+
+ local short = false
+ for _, comp in ipairs(comps) do
+ if comp == '' then
+ if short then invalid() end
+ short = true
+ elseif not string.match(comp, '^%x%x?%x?%x?$') then invalid() end
+ end
+ if not short and #comps < 8 then invalid() end
+end
+
+
+IPAddress = class(Union)
+
+function IPAddress:init(params)
+ super(self, IPAddress):init(
+ update(
+ params, {types={IPv4Address, IPv6Address}, error='Invalid IP address'}
+ )
+ )
+end
+
+
+Port = class(fld.Integer)
+
+function Port:validate(context, value)
+ super(self, Port):validate(context, value)
+ if value < 0 or value > 65535 then raise(context.path, 'Invalid port') end
+end
diff --git a/acf/modules/awall.lua b/acf/modules/awall.lua
index bb9cedc..76f9943 100644
--- a/acf/modules/awall.lua
+++ b/acf/modules/awall.lua
@@ -6,37 +6,12 @@ See LICENSE file for license details
module(..., package.seeall)
local M = require('acf.model')
-
local object = require('acf.object')
-local class = object.class
-local super = object.super
-
-
-IPv4Addr = class(M.String)
-function IPv4Addr:validate(context, value)
- local function test(...)
- if #arg ~= 4 then return true end
- for _, octet in ipairs(arg) do
- if tonumber(octet) > 255 then return true end
- end
- end
- if test(string.match(value, '(%d+)%.(%d+)%.(%d+)%.(%d+)')) then
- M.error.raise(context.path, 'Invalid IP address')
- end
-end
-
-Port = class(M.Integer)
-function Port:validate(txn, path, value)
- super(self, Port):validate(txn, path, value)
- if value < 0 or value > 65535 then M.error.raise(path, 'Invalid port') end
-end
-PortRange = class(M.Range)
-function PortRange:init() super(self, PortRange):init{type=Port} end
-Direction = class(M.String)
+Direction = object.class(M.String)
function Direction:init()
- super(self, Direction):init{choice={'in', 'out'}}
+ object.super(self, Direction):init{choice={'in', 'out'}}
end
@@ -49,7 +24,7 @@ IPSet.family = M.String{required=true, choice={'inet', 'inet6'}}
Service = M.new()
Service.proto = M.String{required=true}
-Service.port = M.Collection{type=PortRange}
+Service.port = M.Collection{type=M.Range{type=M.net.Port}}
Service['icmp-type'] = M.String
-- TODO fw zone
@@ -93,12 +68,12 @@ Limit.log = M.Reference{scope='../../../log'}
FilterRule = M.new(PolicyRule)
FilterRule['conn-limit'] = Limit
FilterRule['flow-limit'] = Limit
-FilterRule.dnat = IPv4Addr
+FilterRule.dnat = M.net.IPv4Address
FilterRule['no-track'] = M.Boolean{default=false}
NATRule = M.new(Rule)
-NATRule['to-addr'] = M.Range{type=IPv4Addr}
-NATRule['to-port'] = PortRange
+NATRule['to-addr'] = M.Range{type=M.net.IPv4Address}
+NATRule['to-port'] = M.Range{type=M.net.Port}
MarkRule = M.new(Rule)
MarkRule.mark = M.Integer{required=true}
diff --git a/acf/modules/net.lua b/acf/modules/net.lua
new file mode 100644
index 0000000..447c876
--- /dev/null
+++ b/acf/modules/net.lua
@@ -0,0 +1,25 @@
+--[[
+Copyright (c) 2012-2013 Kaarle Ritvanen
+See LICENSE file for license details
+--]]
+
+module(..., package.seeall)
+
+local M = require('acf.model')
+
+local Host = M.new()
+Host.ipaddr = M.net.IPAddress
+Host.canonical = M.String
+Host.alias = M.Collection{type=M.String}
+
+local Resolv = M.new()
+Resolv.nameserver = M.Collection{type=M.net.IPAddress}
+Resolv['search-domain'] = M.Collection{type=M.String, addr='search/domain'}
+
+local Net = M.new()
+Net.hostname = M.String{addr='/augeas/etc/hostname/hostname'}
+Net.hosts = M.Collection{type=Host, addr='/augeas/etc/hosts'}
+Net.resolv = M.Model{model=Resolv, addr='/augeas/etc/resolv.conf'}
+
+M.register('net', Net)
+M.permission.defaults('/net')