iptables.lua 3.85 KB
Newer Older
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
1 2
--[[
Iptables file dumper for Alpine Wall
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 9
local class = require('awall.class')
local raise = require('awall.uerror').raise
10 11

local util = require('awall.util')
12
local printmsg = util.printmsg
13
local sortedkeys = util.sortedkeys
14

15

16
local mkdir = require('posix').mkdir
17
local lpc = require('lpc')
18 19


20 21
local M = {}

22 23 24 25 26 27
local families = {inet={cmd='iptables',
			file='rules-save',
			procfile='/proc/net/ip_tables_names'},
		  inet6={cmd='ip6tables',
			 file='rules6-save',
			 procfile='/proc/net/ip6_tables_names'}}
28

29 30 31 32 33 34 35
M.builtin = {
   filter={'FORWARD', 'INPUT', 'OUTPUT'},
   mangle={'FORWARD', 'INPUT', 'OUTPUT', 'POSTROUTING', 'PREROUTING'},
   nat={'INPUT', 'OUTPUT', 'POSTROUTING', 'PREROUTING'},
   raw={'OUTPUT', 'PREROUTING'},
   security={'FORWARD', 'INPUT', 'OUTPUT'}
}
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
36

37 38
local backupdir = '/var/run/awall'

39

40
local BaseIPTables = class()
41

42
function BaseIPTables:print()
43
   for _, family in sortedkeys(families) do
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
44 45
      self:dumpfile(family, io.output())
      io.write('\n')
46 47 48
   end
end

49 50
function BaseIPTables:dump(dir)
   for family, tbls in pairs(families) do
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
51
      local file = io.open(dir..'/'..families[family].file, 'w')
52 53 54 55 56
      self:dumpfile(family, file)
      file:close()
   end
end

57 58 59
function BaseIPTables:restore(test)
   local disabled = true

60
   for family, params in pairs(families) do
61 62 63 64
      local file = io.open(params.procfile)
      if file then
	 io.close(file)

Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
65 66 67
	 local pid, stdin, stdout = lpc.run(
	    params.cmd..'-restore', table.unpack{test and '-t' or nil}
	 )
68 69 70 71 72 73 74
	 stdout:close()
	 self:dumpfile(family, stdin)
	 stdin:close()
	 assert(lpc.wait(pid) == 0)

	 disabled = false

75
      elseif test then printmsg('Warning: '..family..' rules not tested') end
76
   end
77

78
   if disabled then raise('Firewall not enabled in kernel') end
79 80
end

81
function BaseIPTables:activate()
82
   M.flush()
83 84
   self:restore(false)
end
85

86
function BaseIPTables:test() self:restore(true) end
87 88


89
M.IPTables = class(BaseIPTables)
90

91
function M.IPTables:init()
92 93
   self.config = {}
   setmetatable(self.config,
94 95 96 97 98 99
		{__index=function(t, k)
			    t[k] = {}
			    setmetatable(t[k], getmetatable(t))
			    return t[k]
			 end})
end
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
100

101
function M.IPTables:dumpfile(family, iptfile)
102
   iptfile:write('# '..families[family].file..' generated by awall\n')
103 104
   local tables = self.config[family]
   for i, tbl in sortedkeys(tables) do
105
      iptfile:write('*'..tbl..'\n')
106 107
      local chains = tables[tbl]
      for i, chain in sortedkeys(chains) do
108
	 local policy = '-'
109
	 if util.contains(M.builtin[tbl], chain) then
110 111 112
	    policy = tbl == 'filter' and 'DROP' or 'ACCEPT'
	 end
	 iptfile:write(':'..chain..' '..policy..' [0:0]\n')
113
      end
114 115
      for i, chain in sortedkeys(chains) do
	 for i, rule in ipairs(chains[chain]) do
116
	    iptfile:write('-A '..chain..' '..rule..'\n')
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
117 118
	 end
      end
119 120 121 122
      iptfile:write('COMMIT\n')
   end
end

123 124 125 126 127 128 129 130 131

local Current = class(BaseIPTables)

function Current:dumpfile(family, iptfile)
   local pid, stdin, stdout = lpc.run(families[family].cmd..'-save')
   stdin:close()
   for line in stdout:lines() do iptfile:write(line..'\n') end
   stdout:close()
   assert(lpc.wait(pid) == 0)
132 133 134
end


135
local Backup = class(BaseIPTables)
136

137 138 139
function Backup:dumpfile(family, iptfile)
   for line in io.lines(backupdir..'/'..families[family].file) do
      iptfile:write(line..'\n')
140 141
   end
end
142

143

144 145
function M.backup()
   mkdir(backupdir)
146
   Current():dump(backupdir)
147 148
end

149
function M.revert() Backup():activate() end
150

151 152
function M.flush()
   local empty = M.IPTables()
153 154 155 156
   for family, params in pairs(families) do
      local success, lines = pcall(io.lines, params.procfile)
      if success then
	 for tbl in lines do
157 158 159 160
	    if M.builtin[tbl] then
	       for i, chain in ipairs(M.builtin[tbl]) do
		  empty.config[family][tbl][chain] = {}
	       end
161
	    else printmsg('Warning: not flushing unknown table: '..tbl) end
162 163 164 165 166
	 end
      end
   end
   empty:restore(false)
end
167 168

return M