1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
--[[
Copyright (c) 2012 Kaarle Ritvanen
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(txn, path, 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
error('Invalid IP address: '..value)
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 error('Invalid port: '..value) end
end
Range = class(M.String)
function Range:validate(txn, path, value)
local comps = stringy.split(value, '-')
if #comps > 2 then error('Invalid range: '..value) end
for _, v in ipairs(comps) do
local num = tonumber(v)
if not num then error('Invalid range: ' ..value) end
M.to_field(self.type):validate(txn, path, num)
end
end
PortRange = class(Range)
function PortRange:init() super(self, PortRange):init{type=Port} end
Direction = class(M.String)
function Direction:init()
super(self, Direction):init{choice={'in', 'out'}}
end
-- TODO reference types?
IPSet = M.new()
-- TODO choices
IPSet.type = M.String{required=true}
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['icmp-type'] = M.String
-- TODO fw zone
Zone = M.new()
Zone.iface = M.PrimitiveList{type=M.String}
Zone.addr = M.PrimitiveList{type=M.String}
Zone['route-back'] = M.Boolean{default=false}
LogClass = M.new()
LogClass.mode = M.String{default='log', choice={'log', 'nflog', 'ulog'}}
LogClass.limit = M.Integer
LogClass.prefix = M.String
IPSetReference = M.new()
IPSetReference.name = M.Reference{scope='../../ipset', required=true}
IPSetReference.args = M.Collection{type=Direction, required=true}
Rule = M.new()
Rule['in'] = M.Collection{type=M.Reference{scope='../../zone'}}
Rule.out = M.Collection{type=M.Reference{scope='../../zone'}}
Rule.src = M.Collection{type=M.String}
Rule.dest = M.Collection{type=M.String}
Rule.ipset = IPSetReference
Rule.ipsec = Direction
Rule.service = M.Collection{type=M.Reference{scope='../../service'}}
Rule.action = M.String{choice={'accept'}}
-- TODO no service field
PolicyRule = M.new(Rule)
PolicyRule.log = M.Reference{scope='../log'}
PolicyRule.action = M.String{required=true,
choice={'accept', 'drop', 'reject', 'tarpit'}}
Limit = M.new()
Limit.count = M.Integer
Limit.interval = M.Integer
Limit.log = M.Reference{scope='../../log'}
FilterRule = M.new(PolicyRule)
FilterRule['conn-limit'] = Limit
FilterRule['flow-limit'] = Limit
FilterRule.dnat = IPv4Addr
FilterRule['no-track'] = M.Boolean{default=false}
NATRule = M.new(Rule)
NATRule['to-addr'] = Range{type=IPv4Addr}
NATRule['to-port'] = PortRange
MarkRule = M.new(Rule)
MarkRule.mark = M.Integer{required=true}
ClampMSSRule = M.new(Rule)
ClampMSSRule.mss = M.Integer
AWall = M.new()
-- TODO differentiate lists?
AWall.service = M.Collection{type=M.Collection{type=Service}}
AWall.zone = M.Collection{type=Zone}
AWall.log = M.Collection{type=LogClass}
AWall.policy = M.Collection{type=PolicyRule}
AWall.filter = M.Collection{type=FilterRule}
AWall.dnat = M.Collection{type=NATRule}
AWall.snat = M.Collection{type=NATRule}
AWall.mark = M.Collection{type=MarkRule}
AWall['route-track'] = M.Collection{type=MarkRule}
AWall['clamp-mss'] = M.Collection{type=ClampMSSRule}
AWall['no-track'] = M.Collection{type=Rule}
AWall.ipset = M.Collection{type=IPSet}
M.register('awall',
'/json'..require('lfs').currentdir()..'/config/awall.json',
AWall)
|