init.lua 3.85 KB
Newer Older
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
1 2
--[[
Alpine Wall main module
3
Copyright (C) 2012-2016 Kaarle Ritvanen
4
See LICENSE file for license details
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
5 6 7
]]--


8
local M = {}
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
9

10 11 12 13
local class = require('awall.class')
local resolve = require('awall.dependency')
local IPSet = require('awall.ipset')
local IPTables = require('awall.iptables').IPTables
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
14

15
local optfrag = require('awall.optfrag')
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
16 17
local combinations = optfrag.combinations

18
M.PolicySet = require('awall.policy')
19

20
local util = require('awall.util')
21
local extend = util.extend
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
22

23

24 25 26
local posix = require('posix')
local chdir = posix.chdir

Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
27
local stringy = require('stringy')
28

Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
29

30
local events
31
local procorder
32
local achains
33

34
function M.loadmodules(path)
35
   events = {}
36
   achains = {}
37 38

   local function readmetadata(mod)
39 40 41
      local export = mod.export or {}
      for name, target in pairs(export) do events[name] = target end

42
      extend(achains, mod.achains)
43

44
      return util.keys(export)
45 46
   end

47
   readmetadata(require('awall.model'))
48

49 50
   local cdir = posix.getcwd()
   if path then assert(chdir(path)) end
51

52
   local modules = {}
53 54 55
   for _, modfile in ipairs(
      posix.dir((path or '/usr/share')..'/awall/modules')
   ) do
56
      if stringy.endswith(modfile, '.lua') then
57
	 table.insert(modules, 'awall.modules.'..modfile:sub(1, -5))
58
      end
59
   end
60
   table.sort(modules)
61 62

   local imported = {}
63
   for i, name in ipairs(modules) do
64
      extend(imported, readmetadata(require(name)))
65
   end
66

67
   assert(chdir(cdir))
68

69
   events['%modules'] = {before=imported}
70
   procorder = resolve(events)
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
71 72
end

73
function M.loadclass(path)
74
   assert(path:sub(1, 1) ~= '%')
75 76 77
   return events[path] and events[path].class
end

Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
78

79
M.Config = class()
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
80

81
function M.Config:init(policyconfig)
82

83
   self.objects = policyconfig:expand()
84
   self.iptables = IPTables()
85

86
   local actions = {}
87

Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
88
   local function insertrules(trules, obj)
89 90
      for i, trule in ipairs(trules) do
	 local t = self.iptables.config[trule.family][trule.table][trule.chain]
91 92 93 94 95 96 97 98
	 local opts = optfrag.command(trule)

	 if trule.target then
	    local acfrag = {
	       family=trule.family,
	       table=trule.table,
	       chain=trule.target
	    }
99 100 101
	    local key = optfrag.location(acfrag)
	    if not actions[key] then
	       actions[key] = true
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
102 103 104 105 106 107 108 109 110 111 112 113 114
	       if stringy.startswith(trule.target, 'custom:') then
		  local name = trule.target:sub(8, -1)
		  local rules = (self.objects.custom or {})[name]
		  if not rules then
		     obj:error('Invalid custom chain: '..name)
		  end
		  insertrules(
		     combinations(
			{{chain=trule.target}}, util.list(rules), {acfrag}
		     ),
		     rules
		  )
	       else insertrules(combinations(achains, {acfrag})) end
115
	    end
116
	 end
117

118
	 if trule.position == 'prepend' then
119
	    table.insert(t, 1, opts)
120
	 else
121
	    table.insert(t, opts)
122
	 end
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
123 124 125
      end
   end

126
   for i, path in ipairs(procorder) do
127
      if path:sub(1, 1) ~= '%' then
128 129 130
	 local objs = self.objects[path]
	 if objs then
	    for k, v in pairs(objs) do
131
	       objs[k] = events[path].class.morph(
132 133 134 135 136
		  v,
		  self,
		  path..' '..k..' ('..policyconfig.source[path][k]..')'
	       )
	    end
137 138 139
	 end
      end
   end
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
140

141
   for i, event in ipairs(procorder) do
142
      if event:sub(1, 1) == '%' then
143 144 145
	 local r = events[event].rules
	 if r then
	    if type(r) == 'function' then r = r(self.objects) end
146 147 148 149
	    if r then
	       assert(type(r) == 'table')
	       insertrules(r)
	    end
150 151 152
	 end
      elseif self.objects[event] then
	 for i, rule in ipairs(self.objects[event]) do
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
153
	    insertrules(rule:trules(), rule)
154
	 end
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
155 156
      end
   end
157

158
   self.ipset = IPSet(self.objects.ipset)
159
end
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
160

161
function M.Config:print()
162
   self.ipset:print()
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
163
   io.write('\n')
164 165 166
   self.iptables:print()
end

167
function M.Config:dump(dir)
168
   self.ipset:dump(dir and dir..'/ipset-' or '/etc/ipset.d/')
169
   self.iptables:dump(dir or '/etc/iptables')
170
end
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
171

172
function M.Config:test()
173 174
   self.ipset:create()
   self.iptables:test()
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
175
end
176

177
function M.Config:activate()
178 179 180
   self:test()
   self.iptables:activate()
end
181 182 183


return M