-
Notifications
You must be signed in to change notification settings - Fork 1
/
pm_netifd_firewall.lua
138 lines (112 loc) · 4.06 KB
/
pm_netifd_firewall.lua
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
#!/usr/bin/env lua
-- -*-lua-*-
--
-- $Id: pm_netifd_firewall.lua $
--
-- Author: Markus Stenberg <markus [email protected]>
--
-- Copyright (c) 2013 cisco Systems, Inc.
--
-- Created: Mon Oct 7 12:12:07 2013 mstenber
-- Last modified: Fri Oct 11 05:17:07 2013 mstenber
-- Edit time: 67 min
--
-- This code is responsible for adapting the firewall status of the
-- system to that what we consider currently valid.
-- We _only_ handle 'hnet' proto interfaces.
-- 'Algorithm'
-- - initally set all interfaces to lan
-- - listen to network interface dump changes
-- - for everything with ipv6-prefix, set associated hnet interface to wan
-- - commit changes to uci if any detected
require 'pm_handler'
module(..., package.seeall)
RELOAD_FIREWALL_COMMAND='/etc/init.d/firewall enabled && fw3 -q reload'
local _parent = pm_handler.pm_handler_with_ni
pm_netifd_firewall = _parent:new_subclass{class='pm_netifd_firewall'}
function pm_netifd_firewall:init()
_parent.init(self)
-- we keep two lists in sync with the system: all _our_ interfaces
-- in lan and wan state (and additionally, we get system's current
-- ones when doing changes so that we don't remove anything that
-- has been set there by non-hnet case)
self.set_lan_state = {}
self.set_wan_state = {}
end
function pm_netifd_firewall:get_state()
local ni = self.ni
local wan_state = mst.set:new()
-- external-only -> we already get what we want
ni:iterate_interfaces(function (ifo)
local device = ifo.l3_device or ifo.device
local hnet_ifname = ni:device2hnet_interface(device)
if hnet_ifname
then
wan_state:insert(hnet_ifname)
end
end, true)
local lan_state = mst.set:new()
ni:iterate_interfaces(function (ifo)
local ifname = ifo.interface
self:a(ifname, 'no ifname?!?', ifo)
lan_state:insert(ifname)
end, false, true)
local lan_list = lan_state:keys()
table.sort(lan_list)
local wan_list = wan_state:keys()
table.sort(wan_list)
return lan_list, wan_list
end
function pm_netifd_firewall:set_uci_firewall(c, zonename, include, exclude)
local found
self:d('set_uci_firewall', zonename, include, exclude)
c:foreach('firewall', 'zone', function (s)
self:d(' considering', s)
if s.name == zonename
then
local nw = s.network or {}
-- seems like owrt provides these lists as strings..
if type(nw) == 'string'
then
nw = mst.string_split(nw, ' ')
end
local ns = mst.array_to_set(nw)
local is = mst.array_to_set(include)
local es = mst.array_to_set(exclude)
self:d(' doing set up', ns, is, es)
ns = ns:union(is):difference(es)
found = true
local nl = ns:keys()
table.sort(nl)
self:d(' got', nl)
c:set('firewall', s['.name'], 'network', nl:join(' '))
return false
end
end)
return found
end
function pm_netifd_firewall:run()
local ls, ws = self:get_state()
-- nop if we already have what we wanted
if mst.repr_equal(ls, self.set_lan_state) and mst.repr_equal(ws, self.set_wan_state)
then
return
end
self.set_lan_state = ls
self.set_wan_state = ws
local c = self:get_uci_cursor()
if not c
then
return
end
local c1 = self:set_uci_firewall(c, 'lan', ls, ws)
local c2 = self:set_uci_firewall(c, 'wan', ws, ls)
if c1 or c2
then
self:d('committing changes')
c:commit('firewall')
-- restart firewall - hardcoding command here isn't elegant but
-- oh well
self.shell(RELOAD_FIREWALL_COMMAND)
end
end