File: appliance_config.lua

package info (click to toggle)
ntopng 5.2.1%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 121,832 kB
  • sloc: javascript: 143,431; cpp: 71,175; ansic: 11,108; sh: 4,687; makefile: 911; python: 587; sql: 512; pascal: 234; perl: 118; ruby: 52; exp: 4
file content (464 lines) | stat: -rw-r--r-- 13,640 bytes parent folder | download
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
--
-- (C) 2020 - ntop.org
--

local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/system_config/?.lua;" .. package.path
package.path = dirs.installdir .. "/pro/scripts/lua/modules/?.lua;" .. package.path
require "lua_utils" 
local system_config = require "system_config"
local json = require "dkjson"
local ipv4_utils = require "ipv4_utils"
local os_utils = require "os_utils"
local sys_utils = require "sys_utils"
local tz_utils = require "tz_utils"

-- ##############################################

-- Example 
-- package.path = dirs.installdir .. "/scripts/lua/modules/system_config/?.lua;" .. package.path
-- -- Editable
-- local appliance_config = require "appliance_config":create(true)
-- -- Readable
-- local appliance_config = require "appliance_config":create()

-- ##############################################

-- NOTE:
-- - The LAN interface in "passive" mode is the Management Interface
-- - WAN interfaces in "passive" mode are the Capture Interfaces

-- ##############################################

local appliance_config = {}

-- ##############################################

function appliance_config:create(editable)
   -- Instance of the base class
   local _system_config = system_config:create()

   -- Subclass using the base class instance
   self.key = "appliance"
   -- self is passed as argument so it will be set as base class metatable
   -- and this will actually make it possible to override functions
   local _appliance_config = _system_config:create(self)

   if editable then
      _appliance_config:editable()
   else
      _appliance_config:readable()
   end

   -- Return the instance
   return _appliance_config
end

-- ##############################################

-- Returns the supported modes
function appliance_config:getSupportedModes()
  local all_modes = {
    { name = "passive", label = i18n("passive") },
    { name = "bridging", label = i18n("bridge") },
  }

  return all_modes
end

-- ##############################################

function appliance_config:getOperatingMode()
  if not self.config.globals.operating_mode then
    return "passive"
  end

  return self.config.globals.operating_mode
end

-- ##############################################

function appliance_config:getPassiveInterfaceName()
  if self.config.globals.available_modes["passive"] then
    return self.config.globals.available_modes["passive"]["interfaces"]["lan"]
  end

  return nil
end

-- ##############################################

-- Get the physical LAN interfaces, based on the current operating mode
-- nf_config overrides this
function appliance_config:getPhysicalLanInterfaces()
  local mode = self:getOperatingMode()
  if not mode then return {} end

  if mode == "passive" then
    return { self.config.globals.available_modes[mode].interfaces.lan, }
  elseif mode == "bridging" then
    return self.config.globals.available_modes[mode].interfaces.lan
  end
end

-- Get the physical WAN interfaces, based on the current operating mode
-- nf_config and appliance_config overrides this
function appliance_config:getPhysicalWanInterfaces()
  local mode = self:getOperatingMode()
  if not mode then return {} end

  return self.config.globals.available_modes[mode].interfaces.wan
end


-- ##############################################

function appliance_config:getWirelessConfiguration()
  return self.config.wireless or {}
end

function appliance_config:setWirelessConfiguration(config)
  if config.enabled then
    if isEmptyString(config.ssid) then
      return false
    end

    if not isEmptyString(config.passphrase) then
      local len = string.len(config.passphrase)
      if len < 8 or len > 63 then
        return false
      end
    end
  end

  self.config.wireless = config

  return true
end

-- ##############################################

function appliance_config:_get_config_skeleton()
   local config = {
      ["defaults"] = {},
      ["disabled_wans"] = {},
      ["globals"] = {
         ["available_modes"] = {},
         ["lan_recovery_ip"] =  {
            ["ip"] =  "192.168.160.10",
            ["netmask"] =  "255.255.255.0",
            ["comment"] =  "Static LAN IP address used to reach the box set on the bridge interface"
         },
	 ["management_access"] = {
	    ["bind_to"] = "lan",
	 },
      },
      ["interfaces"] = {
         ["comment"]= "List of available network interfaces. Only those listed in globals.operating_mode are actually configured",
         ["configuration"] = {}
      },
      ["date_time"] = {
	 ["ntp_sync"] = {
	    ["enabled"] = true,
	 },
	 ["timezone"] = "Europe/Rome",
      },
      ["wireless"] = {
         ["enabled"] = false,
         ["ssid"] = "ntopng",
         ["passphrase"] = "",
      }
   }

   return config
end

-- ##############################################

function appliance_config:_guess_config()
   local config = self:_get_config_skeleton()
   local default_global_dns = self:_get_default_global_dns_preset()
   local wired_default = nil
   local devs = system_config.get_all_interfaces()
   local wired_devs  = {}
   local wifi_devs = system_config.get_wifi_interfaces()
   local ip_devs = system_config.get_ip_interfaces()
   local dhcp_ifaces = system_config.get_dhcp_interfaces() 
   local bridge_devs = system_config.get_bridge_interfaces()
   local wan_iface = system_config.get_default_gw_interface()

   -- set the timezone to the current system timezone
   if not isEmptyString(tz_utils.TimeZone()) then
      config["date_time"]["timezone"] = tz_utils.TimeZone()
   end

   if wan_iface and not devs[wan_iface] then
      wan_iface = nil -- safety check
   end

   local first_wired = nil
   local static_wired = nil

   -- NOTE: we use pairsByKeys to impose an order across multiple guesses
   for name, _ in pairsByKeys(devs) do
      local addr = ip_devs[name]

      -- Bridge
      if bridge_devs[name] then
         if addr then
            bridge_devs[name]["ip"] = addr
         end

      -- WiFi
      elseif wifi_devs[name] then
         if addr then
            wifi_devs[name]["ip"] = addr
         end

      -- Wired
      else
         if not system_config.is_virtual_interface(name) then
            wired_devs[name] = {}

            if first_wired == nil then
               first_wired = name
            end

            if name ~= wan_iface and dhcp_ifaces[name] == nil and static_wired == nil then
               static_wired = name
            end

            if addr then
               wired_devs[name]["ip"] = addr
            end
         end
      end
   end

   -- Set wired_default to the first interface, possibly not the wan or dhcp
   wired_default = static_wired or first_wired

   local operating_mode = nil

   -- ###################
   -- Passive

   local passive = {}

   local management = nil
   if wan_iface then
      management = wan_iface
   elseif table.len(wired_devs) > 1 then
      management = first_wired
   end
   if management ~= nil then
      passive["interfaces"] = {}
      passive["interfaces"]["lan"] = management
      passive["interfaces"]["wan"] = {}
      passive["interfaces"]["unused"] = {}
      passive["comment"] = "Passive monitoring appliance"

      for a, b in pairsByKeys(wired_devs) do
         if a ~= passive["interfaces"]["lan"] then
            -- table.insert(passive["interfaces"]["unused"], a)
            table.insert(passive["interfaces"]["wan"], a)
         end
      end

      config["globals"]["available_modes"]["passive"] = passive

      if operating_mode == nil then
         operating_mode = "passive"
      end
   end

   -- ###################
   -- Bridge interfaces

   local bridging = {}
   local bridging_defined = false
   local bridge_ifname = nil

   -- If we currently have a bridge interface, use its configuration
   if table.len(bridge_devs) > 0 then
      local used_ifaces = {}

      for a,b in pairsByKeys(bridge_devs) do
         if table.len(b.ports) > 1 then
            bridge_ifname = a
            bridging["name"] = a
            bridging["interfaces"] = { unused = {} }
            bridging["comment"] = "Transparent bridge"

            bridging["interfaces"]["lan"] = {}
            bridging["interfaces"]["wan"] = {}

            for n,c in pairsByKeys(b.ports) do
               if n == 1 then
                  table.insert(bridging["interfaces"]["lan"], c)
               else
                  table.insert(bridging["interfaces"]["wan"], c)
               end
               used_ifaces[c] = true
            end

            bridging_defined = true

            if operating_mode == nil then
               operating_mode = "bridging"
            end
            break
         end
      end

      if bridging_defined then
         -- add other interfaces to the unused ones
         for iface,_ in pairsByKeys(wired_devs) do
            if used_ifaces[iface] == nil then
               table.insert(bridging["interfaces"]["unused"], iface)
            end
         end
      end
   end

   -- If we do not have a bridge interface but have enough interfaces
   if (not bridging_defined) and (table.len(wired_devs) > 1) then
      local n = 0
      bridge_ifname = "br0"

      bridging["name"] = bridge_ifname
      bridging["interfaces"] = { unused = {} }
      bridging["comment"] = "Transparent bridge"

      for a,b in pairsByKeys(wired_devs) do
         if n == 0 then
            bridging["interfaces"]["lan"] = { a }
         elseif(n == 1) then
            bridging["interfaces"]["wan"] = { a }
         else
            table.insert(bridging["interfaces"]["unused"], a)
         end

         n = n + 1
      end

      bridging_defined = true
   end

   if not bridging_defined and ntop.isIoTBridge() then
      bridge_ifname = "br0"
      bridging["name"] = bridge_ifname
      bridging["interfaces"] = {
        lan = { "wlan0" },
        wan = { management },
        unused = {} 
      }
      bridging["comment"] = "Wireless bridge"
      bridging_defined = true
   end

   if bridging_defined then
      config["globals"]["available_modes"]["bridging"] = bridging
   end

   -- ###################

   if operating_mode ~= nil then
      config["globals"]["operating_mode"] = operating_mode
   end

   -- ###################
   -- Network configuration

   for a,b in pairs(wired_devs) do

      config["interfaces"]["configuration"][a] = {
         ["family"] = "wired",
         ["network"] = {
            ["primary_dns"] =  default_global_dns.primary_dns,
            ["secondary_dns"] =  default_global_dns.secondary_dns
         }
      }

      -- Note: we force static on the wired_default if not in bridging mode
      if dhcp_ifaces[a] and (a ~= wired_default or operating_mode == "bridging") then
         config["interfaces"]["configuration"][a]["network"]["mode"] = "dhcp"
         config["interfaces"]["configuration"][a]["network"]["ip"] = "192.168.10.1"
         config["interfaces"]["configuration"][a]["network"]["netmask"] = "255.255.255.0"
         config["interfaces"]["configuration"][a]["network"]["gateway"] = "0.0.0.0"
      else
         -- non DHCP interface / wired_default
         config["interfaces"]["configuration"][a]["network"]["mode"] = "static"

         local netmask

         if (ip_devs[a] == nil) then
            -- e.g. on the wired_default
            ip_devs[a] = "192.168.1.1"
            netmask = "255.255.255.0"
         else
            -- The device has an IP address
            local addresses = system_config.getAllInterfaceAddresses(a)
            for _, addr in pairs(addresses) do
               if addr.ip == ip_devs[a] then
                  netmask = addr.netmask
               end
            end

            if isEmptyString(netmask) then netmask = "255.255.255.0" end
         end

         local gateway = system_config._interface_get_default_gateway(a)
         config["interfaces"]["configuration"][a]["network"]["ip"] = ip_devs[a]
         config["interfaces"]["configuration"][a]["network"]["netmask"] = netmask

         if not isEmptyString(gateway) then
            config["interfaces"]["configuration"][a]["network"]["gateway"] = gateway
         end
      end
   end

   if wired_default ~= nil then
      -- Add the aliased interface to the configuration
      config["interfaces"]["configuration"][wired_default..":1"] = { 
        ["family"] = "wired",
        ["network"] = {}
      }
      config["interfaces"]["configuration"][wired_default..":1"]["network"]["mode"] = "static"
      config["interfaces"]["configuration"][wired_default..":1"]["network"]["ip"] = "192.168.10.1"
      config["interfaces"]["configuration"][wired_default..":1"]["network"]["netmask"] = "255.255.255.0"
   end

   if bridge_ifname ~= nil then
      -- Add the bridge interface to the configuration
      config["interfaces"]["configuration"][bridge_ifname] = {
         ["family"] = "bridge",
         ["network"] = {
            ["primary_dns"] =  default_global_dns.primary_dns,
            ["secondary_dns"] =  default_global_dns.secondary_dns
         }
      }
      config["interfaces"]["configuration"][bridge_ifname]["network"]["mode"] = "dhcp"
   end

   -- ###################
   -- Wireless configuration

   -- TODO detect actual wireless settings

   -- for a,b in pairs(wifi_devs) do
   --    config["interfaces"]["configuration"][a] = {
   --       ["family"] = "wireless",
   --       ["network"] = {}
   --    }
   -- end

   -- Make sure to apply the mode specific settings
   self:_apply_operating_mode_settings(config)

   return config
end

-- ##############################################

return appliance_config