summaryrefslogtreecommitdiffstats
path: root/acf/modules/awall.lua
blob: 8d2563816920c618c276f57fdf038663b79d52b5 (plain)
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)