-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ffh-check-connection: initial commit
This commit adds a new package which can be used for scheduled connectivity checks.
- Loading branch information
Showing
8 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
Copyright (c) 2021, Freifunk Hannover <info@hannover.freifunk.net> | ||
Copyright (c) 2013-2021, Project Gluon | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, | ||
this list of conditions and the following disclaimer. | ||
2. Redistributions in binary form must reproduce the above copyright notice, | ||
this list of conditions and the following disclaimer in the documentation | ||
and/or other materials provided with the distribution. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
include $(TOPDIR)/rules.mk | ||
|
||
PKG_NAME:=ffh-check-connection | ||
PKG_VERSION:=1 | ||
PKG_RELEASE:=1 | ||
|
||
include $(TOPDIR)/../package/gluon.mk | ||
|
||
define Package/$(PKG_NAME) | ||
TITLE:=Helper script to do ping checks with configurable IPv6 targets | ||
DEPENDS:=+gluon-core +libgluonutil +gluon-site +luaposix +luabitop +micrond @GLUON_MULTIDOMAIN | ||
endef | ||
|
||
define Package/$(PKG_NAME)/description | ||
Script to check when there is connectivity to configurable targets | ||
possible using ICMP IPv6 pings. This script will be executed every | ||
minute by ``micrond``. If e.g. the connection state changes it | ||
executes corresponding commands in a configurable manner. | ||
endef | ||
|
||
$(eval $(call BuildPackageGluon,$(PKG_NAME))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
ffh-check-connection | ||
==================== | ||
|
||
This package adds a script that checks if at least one connection to IPv6 hosts | ||
defined as *target groups* is working using the ping command. | ||
The script is called once every minute by ``micrond``. | ||
For example one can define a group of *local* targets to check if a connection | ||
to hosts in the mesh network is possible (e.g. time or update servers) and | ||
*global* targets for checking if a connection to the global internet is possible. | ||
Currently only IPv6 addresses are supported. | ||
This packages is e.g. being used by *ffh-wifi-offline-ssid*. | ||
|
||
domain.conf | ||
----------- | ||
|
||
Target groups can be pre-defined in the domain config. | ||
|
||
:: | ||
|
||
ffh_check_connection = { | ||
targets = { | ||
targets_local = { | ||
'fe80::dead:c0de:1', | ||
'fe80::bad:c0de:1', | ||
'fe80::dead:c0de:2', | ||
'fe80::bad:c0de:2', | ||
}, | ||
targets_global = { | ||
'2620:0:ccc::2', -- OpenDNS | ||
'2001:4860:4860::8888', -- Google DNS | ||
'2600::1', -- Sprint DNS | ||
'2620:0:ccd::2', -- OpenDNS | ||
'2001:4860:4860::8844', -- Google DNS | ||
'2600::2', -- Sprint DNS | ||
}, | ||
}, | ||
}, | ||
|
||
|
||
Defining target groups in the domain.conf will overwrite existing ones with the same | ||
name when performing a *sysupgrade* or by triggering *gluon-reconfigure*. | ||
|
||
Configuration via UCI | ||
--------------------- | ||
|
||
Packages can use ffh-check-connection to be triggered after connection checks. | ||
For this they can define the following *script* attributes: | ||
|
||
script : an entry for defining the ping target | ||
enabled : | ||
- a boolean defining whether the script will be considered | ||
interval : | ||
- the interval to execute the trigger script (in minutes - defaults to 1) | ||
command : | ||
- the command to execute | ||
groups : | ||
- the array of target groups on which the ping test will be performed on | ||
onchange : | ||
- if set true the command is only being executed on a state change or always otherwise | ||
trigger : | ||
- on which the command is being executed (``offline``, ``online`` or unset for both) | ||
|
||
|
||
*target* groups can be defined with the following attributes: | ||
|
||
target : an entry for defining the IPv6 address to ping | ||
hosts : | ||
- array containing the IPv6 addresses to perform the ping test on | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
local function check_target(t) | ||
need_string_array_match(t, '^[%x:]+$', false) | ||
end | ||
|
||
need_table(in_domain({'ffh_check_connection', 'targets'}), check_target, false) |
Empty file.
1 change: 1 addition & 0 deletions
1
ffh-check-connection/files/usr/lib/micron.d/ffh-check-connection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* * * * * /usr/sbin/ffh-check-connection |
13 changes: 13 additions & 0 deletions
13
ffh-check-connection/luasrc/lib/gluon/upgrade/500-ffh-check-connection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#!/usr/bin/lua | ||
|
||
local uci = require('simple-uci').cursor() | ||
local site = require 'gluon.site' | ||
|
||
for group, hosts in pairs(site.ffh_check_connection.targets()) do | ||
uci:delete('ffh-check-connection', 'target', group) | ||
uci:section('ffh-check-connection', 'target', group, { | ||
hosts = hosts | ||
}) | ||
end | ||
|
||
uci:save('ffh-check-connection') |
176 changes: 176 additions & 0 deletions
176
ffh-check-connection/luasrc/usr/sbin/ffh-check-connection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
#!/usr/bin/lua | ||
|
||
local bit = require('bit') | ||
local fcntl = require('posix.fcntl') | ||
local unistd = require 'posix.unistd' | ||
local util = require 'gluon.util' | ||
local uci = require('simple-uci').cursor() | ||
|
||
-- Minimal uptime (in minutes) before the checks start | ||
local min_uptime = 5 | ||
|
||
local offline_file_prefix = '/tmp/ffh-offline-' | ||
local firstrun_file = '/tmp/ffh-check-connection-firstrun' | ||
local lastrun_file = '/tmp/ffh-check-connection-lastrun' | ||
local lockfile = '/var/lock/ffh-check-connection.lock' | ||
|
||
local function readnumber(file) | ||
return tonumber(util.readfile(file)) | ||
end | ||
|
||
local function writenumber(file, num) | ||
io.open(file, "w"):write(tostring(math.floor(num))) | ||
end | ||
|
||
local function shuffle(tbl) | ||
new_tbl = {} | ||
for i, ele in ipairs(tbl) do | ||
table.insert(new_tbl, math.random(1, #new_tbl+1), ele) | ||
end | ||
|
||
return new_tbl | ||
end | ||
|
||
local function ping_hosts(hosts) | ||
for _, host in ipairs(hosts) do | ||
if 0 == os.execute("ping -c 1 -w 10 " .. host) then | ||
return true | ||
end | ||
end | ||
|
||
return false | ||
end | ||
|
||
local function check_connection(group, old_state, hosts) | ||
local offline_file = offline_file_prefix .. group | ||
local targets = shuffle(hosts) | ||
|
||
if ping_hosts(targets) then | ||
if not old_state then | ||
util.log(group .. 'connectivity available again') | ||
os.remove(offline_file) | ||
end | ||
|
||
return true | ||
end | ||
|
||
if old_state then | ||
util.log(group .. ' connectivity lost') | ||
writenumber(offline_file, (util.get_uptime() / 60)) | ||
end | ||
|
||
return false | ||
end | ||
|
||
local lockfd, err = fcntl.open(lockfile, bit.bor(fcntl.O_WRONLY, fcntl.O_CREAT), 384) -- mode 0600 | ||
|
||
if not lockfd then | ||
util.log(err, true) | ||
os.exit(1) | ||
end | ||
|
||
local ok, _ = fcntl.fcntl(lockfd, fcntl.F_SETLK, { | ||
l_start = 0, | ||
l_len = 0, | ||
l_type = fcntl.F_WRLCK, | ||
l_whence = unistd.SEEK_SET, | ||
}) | ||
|
||
if not ok then | ||
io.stderr:write(string.format( | ||
"Unable to lock file %s. Make sure there is no other instance running.\n", | ||
lockfile | ||
)) | ||
os.exit(1) | ||
end | ||
|
||
local uptime = math.floor(util.get_uptime() / 60) | ||
|
||
if uptime < min_uptime then | ||
os.exit(0) | ||
end | ||
|
||
math.randomseed(uptime) | ||
|
||
local firstrun = uptime | ||
local lastrun = uptime | ||
if unistd.access(firstrun_file) and unistd.access(lastrun_file) then | ||
firstrun = readnumber(firstrun_file) | ||
lastrun = readnumber(lastrun_file) | ||
else | ||
writenumber(firstrun_file, uptime) | ||
end | ||
|
||
local runtime = lastrun - firstrun | ||
|
||
local scripts = {} | ||
uci:foreach('ffh-check-connection', 'script', function(script) | ||
if not script['enabled'] then return end | ||
|
||
if not runtime or uptime - lastrun >= (tonumber(script['interval']) or 1) then | ||
table.insert(scripts, script) | ||
end | ||
end) | ||
|
||
local groups = {} | ||
uci:foreach('ffh-check-connection', 'target', function(group) | ||
-- do not perform connection checks for groups which are not in use | ||
for _, script in ipairs(scripts) do | ||
if util.contains(script['groups'], group['.name']) then | ||
groups[group['.name']] = group['hosts'] | ||
break | ||
end | ||
end | ||
end) | ||
|
||
local old_states = {} | ||
for group, _ in pairs(groups) do | ||
if unistd.access(offline_file_prefix .. group) then | ||
old_states[group] = false | ||
else | ||
old_states[group] = true | ||
end | ||
end | ||
|
||
local states = {} | ||
for group, hosts in pairs(groups) do | ||
states[group] = check_connection(group, old_states[group], hosts) | ||
end | ||
|
||
for _, script in ipairs(scripts) do | ||
local state_changed = false | ||
local state_offline = false | ||
local state_online = false | ||
|
||
for _, group in ipairs(script['groups']) do | ||
if nil ~= states[group] then | ||
if states[group] ~= old_states[group] then | ||
state_changed = true | ||
end | ||
|
||
if states[group] then | ||
state_online = true | ||
else | ||
state_offline = true | ||
end | ||
end | ||
end | ||
|
||
if not runtime or state_changed or not script['onchange'] then | ||
local do_run = not script['trigger'] | ||
|
||
if script['trigger'] == 'online' and state_online then | ||
do_run = true | ||
end | ||
|
||
if script['trigger'] == 'offline' and state_offline then | ||
do_run = true | ||
end | ||
|
||
if do_run then | ||
util.exec(script['command']) | ||
end | ||
end | ||
end | ||
|
||
writenumber(lastrun_file, (util.get_uptime() / 60)) |