diff options
author | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2013-05-09 16:44:04 +0300 |
---|---|---|
committer | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2013-05-09 16:50:46 +0300 |
commit | 8fb5828d05ba436eff65eb0753ba1dfb1ad1b797 (patch) | |
tree | 3f7c7ecfb3ec864ed867dc2f01c484cd241f9959 | |
parent | bd7b76e3316959028fc7686357fc916f56a4d10b (diff) | |
download | acf2-8fb5828d05ba436eff65eb0753ba1dfb1ad1b797.tar.bz2 acf2-8fb5828d05ba436eff65eb0753ba1dfb1ad1b797.tar.xz |
basic network configuration module
-rw-r--r-- | acf/model/combination.lua | 47 | ||||
-rw-r--r-- | acf/model/field.lua | 61 | ||||
-rw-r--r-- | acf/model/init.lua | 94 | ||||
-rw-r--r-- | acf/model/net.lua | 88 | ||||
-rw-r--r-- | acf/modules/awall.lua | 37 | ||||
-rw-r--r-- | acf/modules/net.lua | 25 |
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') |