2013-07-24 18:49:07 +02:00
local utils = require ( ' util.utils ' )
local log = require ( ' util.logger ' )
local settings = require ( ' util.settings ' )
local wifi = require ( ' network.wlanconfig ' )
local uci = require ( ' uci ' ) . cursor ( )
2013-04-08 01:20:45 +02:00
local M = { }
local reconf = { }
local wifi
local reloadSilent
2013-07-24 18:49:07 +02:00
M.WWW_CAPTIVE_PATH = ' /usr/share/lua/wifibox/www '
M.WWW_CAPTIVE_INDICATOR = ' /www/.wifibox-inplace '
M.WWW_RENAME_NAME = ' /www-regular '
2013-04-08 01:20:45 +02:00
2013-04-18 11:30:48 +02:00
2013-04-09 14:37:31 +02:00
local function reloadBit ( dlist , itemname )
2013-07-24 18:49:07 +02:00
if dlist [ itemname ] == nil then dlist [ itemname ] = ' ' end
if dlist [ itemname ] == ' ' then dlist [ itemname ] = ' r '
elseif dlist [ itemname ] == ' c ' then dlist [ itemname ] = ' b '
2013-04-09 14:37:31 +02:00
end
end
local function commitBit ( dlist , itemname )
2013-07-24 18:49:07 +02:00
if dlist [ itemname ] == nil then dlist [ itemname ] = ' ' end
if dlist [ itemname ] == ' ' then dlist [ itemname ] = ' c '
elseif dlist [ itemname ] == ' r ' then dlist [ itemname ] = ' b '
2013-04-09 14:37:31 +02:00
end
end
2013-07-24 18:49:07 +02:00
local function bothBits ( dlist , itemname ) dlist [ itemname ] = ' b ' end
2013-04-09 14:37:31 +02:00
2013-04-18 11:30:48 +02:00
2013-04-08 01:20:45 +02:00
function M . init ( wifiInstance , reloadSilent )
wifi = wifiInstance
silent = reloadSilent or false
2013-09-04 19:23:51 +02:00
2013-04-08 01:20:45 +02:00
return true
end
--- Switch configuration between AP and station modes
-- @param components a table with components as keys with operations as values (add or remove)
-- Valid components (each with add and rm operation) are: apnet, staticaddr, dhcppool, wwwredir, dnsredir, wwwcaptive, natreflect.
-- and additionally: wifiiface/add, network/reload
function M . switchConfiguration ( components )
local dirtyList = { } -- laundry list, add config/script name as key with value c (commit), r (reload) or b (both)
2013-09-02 15:01:16 +02:00
2013-04-08 01:20:45 +02:00
for k , v in pairs ( components ) do
2013-07-24 18:49:07 +02:00
local fname = k .. ' _ ' .. v
if type ( reconf [ fname ] ) == ' function ' then
log : debug ( " reconfiguring component ' " .. k .. " ' ( " .. v .. " ) " )
2013-04-08 01:20:45 +02:00
reconf [ fname ] ( dirtyList )
else
2013-07-24 18:49:07 +02:00
log : warn ( " unknown component or action ' " .. fname .. " ' skipped " )
2013-04-08 01:20:45 +02:00
end
end
2013-09-02 15:01:16 +02:00
2013-04-08 01:20:45 +02:00
-- first run all commits, then perform reloads
for k , v in pairs ( dirtyList ) do
2013-07-24 18:49:07 +02:00
if v == ' c ' or v == ' b ' then M.commitComponent ( k ) end
2013-04-08 01:20:45 +02:00
end
for k , v in pairs ( dirtyList ) do
2013-07-24 18:49:07 +02:00
if v == ' r ' or v == ' b ' then M.reloadComponent ( k , silent ) end
2013-04-08 01:20:45 +02:00
end
end
function M . commitComponent ( c )
2013-07-24 18:49:07 +02:00
log : info ( " committing component ' " .. c .. " ' " )
2013-04-08 01:20:45 +02:00
uci : commit ( c )
end
function M . reloadComponent ( c , silent )
2013-07-24 18:49:07 +02:00
log : info ( " reloading component ' " .. c .. " ' " )
if silent ~= nil and silent then os.execute ( ' /etc/init.d/ ' .. c .. ' reload &> /dev/null ' )
else os.execute ( ' /etc/init.d/ ' .. c .. ' reload ' ) end
2013-04-08 01:20:45 +02:00
end
function M . uciTableSet ( config , section , options )
for k , v in pairs ( options ) do uci : set ( config , section , k , v ) end
end
--[[ Issue '/etc/init.d/network reload' command ]]
2013-07-24 18:49:07 +02:00
function reconf . network_reload ( dirtyList ) reloadBit ( dirtyList , ' network ' ) end
2013-04-09 14:37:31 +02:00
--[[ Issue '/etc/init.d/wireless reload' command ]]
2013-07-24 18:49:07 +02:00
function reconf . wireless_reload ( dirtyList ) reloadBit ( dirtyList , ' wireless ' ) end
2013-04-08 01:20:45 +02:00
2013-08-20 21:53:36 +02:00
--[[ Issue '/etc/init.d/dnsmasq reload' command ]]
function reconf . dhcp_reload ( dirtyList ) reloadBit ( dirtyList , ' dnsmasq ' ) end
2013-04-08 01:20:45 +02:00
--[[ Add wlan interface declaration to /etc/config/network ]]
function reconf . wifiiface_add ( dirtyList )
2013-07-24 18:49:07 +02:00
uci : set ( ' network ' , wifi.NET , ' interface ' )
commitBit ( dirtyList , ' network ' )
2013-04-08 01:20:45 +02:00
end
2013-04-18 11:30:48 +02:00
2013-04-08 01:20:45 +02:00
--[[ Add/remove access point network ]]
function reconf . apnet_add_noreload ( dirtyList ) reconf.apnet_add ( dirtyList , true ) end
function reconf . apnet_add ( dirtyList , noReload )
2013-07-27 00:25:43 +02:00
local ourSsid = wifi.getSubstitutedSsid ( settings.get ( ' network.ap.ssid ' ) )
2013-04-08 01:20:45 +02:00
local sname = nil
2013-07-24 18:49:07 +02:00
uci : foreach ( ' wireless ' , ' wifi-iface ' , function ( s )
if s.ssid == ourSsid then sname = s [ ' .name ' ] ; return false end
2013-04-08 01:20:45 +02:00
end )
2013-07-24 18:49:07 +02:00
if sname == nil then sname = uci : add ( ' wireless ' , ' wifi-iface ' ) end
2013-09-02 15:01:16 +02:00
2013-07-24 18:49:07 +02:00
M.uciTableSet ( ' wireless ' , sname , {
2013-04-08 01:20:45 +02:00
network = wifi.NET ,
2013-07-17 22:55:27 +02:00
ssid = ourSsid ,
2013-07-24 18:49:07 +02:00
encryption = ' none ' ,
device = ' radio0 ' ,
mode = ' ap ' ,
2013-04-08 01:20:45 +02:00
} )
2013-09-02 15:01:16 +02:00
2013-07-24 18:49:07 +02:00
commitBit ( dirtyList , ' wireless ' )
if noReload == nil or noReload == false then reloadBit ( dirtyList , ' network ' ) end
2013-04-08 01:20:45 +02:00
end
function reconf . apnet_rm ( dirtyList )
local sname = nil
2013-07-24 18:49:07 +02:00
uci : foreach ( ' wireless ' , ' wifi-iface ' , function ( s )
2013-07-27 00:25:43 +02:00
if s.ssid == wifi.getSubstitutedSsid ( settings.get ( ' network.ap.ssid ' ) ) then sname = s [ ' .name ' ] ; return false end
2013-04-08 01:20:45 +02:00
end )
2013-07-24 18:49:07 +02:00
if sname == nil then return log : info ( " AP network configuration does not exist, nothing to remove " ) end
uci : delete ( ' wireless ' , sname )
reloadBit ( dirtyList , ' network ' ) ; commitBit ( dirtyList , ' wireless ' )
2013-04-08 01:20:45 +02:00
end
2013-04-18 11:30:48 +02:00
2013-04-08 01:20:45 +02:00
--[[ Switch between wireless static IP and DHCP ]]
function reconf . staticaddr_add ( dirtyList )
2013-07-24 18:49:07 +02:00
uci : set ( ' network ' , wifi.NET , ' interface ' )
2013-05-02 16:29:29 +02:00
--TODO: remove ifname on wlan interface?
2013-06-17 20:23:00 +02:00
--NOTE: 'type = "bridge"' should -not- be added as this prevents defining a separate dhcp pool (http://wiki.openwrt.org/doc/recipes/routedap)
2013-07-24 18:49:07 +02:00
M.uciTableSet ( ' network ' , wifi.NET , {
proto = ' static ' ,
2013-07-27 00:25:43 +02:00
ipaddr = settings.get ( ' network.ap.address ' ) ,
netmask = settings.get ( ' network.ap.netmask ' )
2013-04-09 14:37:31 +02:00
} )
2013-07-24 18:49:07 +02:00
bothBits ( dirtyList , ' network ' )
2013-04-08 01:20:45 +02:00
end
--TODO: replace repeated deletes by M.uciTableDelete
function reconf . staticaddr_rm ( dirtyList )
2013-07-24 18:49:07 +02:00
uci : set ( ' network ' , wifi.NET , ' interface ' )
uci : set ( ' network ' , wifi.NET , ' proto ' , ' dhcp ' )
uci : delete ( ' network ' , wifi.NET , ' ipaddr ' )
uci : delete ( ' network ' , wifi.NET , ' netmask ' )
--uci:delete('network', wifi.NET, 'type') --do not remove since it is not added anymore
bothBits ( dirtyList , ' network ' )
2013-04-08 01:20:45 +02:00
end
2013-04-18 11:30:48 +02:00
2013-04-08 01:20:45 +02:00
--[[ Add/remove DHCP pool for wireless net ]]
2013-08-20 21:53:36 +02:00
function reconf . dhcppool_add_noreload ( dirtyList ) reconf.dhcppool_add ( dirtyList , true ) end
function reconf . dhcppool_add ( dirtyList , noReload )
2013-08-16 21:44:54 +02:00
uci : set ( ' dhcp ' , wifi.NET , ' dhcp ' ) --create section
2013-07-29 12:18:39 +02:00
M.uciTableSet ( ' dhcp ' , wifi.NET , {
2013-04-09 14:37:31 +02:00
interface = wifi.NET ,
2013-07-24 18:49:07 +02:00
start = ' 100 ' ,
limit = ' 150 ' ,
leasetime = ' 12h ' ,
2013-04-09 14:37:31 +02:00
} )
2013-08-20 21:53:36 +02:00
commitBit ( dirtyList , ' dhcp ' ) ;
if noReload == nil or noReload == false then reloadBit ( dirtyList , ' dnsmasq ' ) end
2013-04-08 01:20:45 +02:00
end
function reconf . dhcppool_rm ( dirtyList )
2013-07-24 18:49:07 +02:00
uci : delete ( ' dhcp ' , wifi.NET )
commitBit ( dirtyList , ' dhcp ' ) ; reloadBit ( dirtyList , ' dnsmasq ' )
2013-04-08 01:20:45 +02:00
end
2013-04-18 11:30:48 +02:00
2013-04-08 01:20:45 +02:00
--[[ Add/remove webserver 404 redirection and denial of dirlisting ]]
function reconf . wwwredir_add ( dirtyList )
2013-08-26 16:15:45 +02:00
uci : set ( ' uhttpd ' , ' main ' , ' error_page ' , ' /redirect.html ' )
2013-07-24 18:49:07 +02:00
uci : set ( ' uhttpd ' , ' main ' , ' no_dirlist ' , ' 1 ' )
bothBits ( dirtyList , ' uhttpd ' )
2013-04-08 01:20:45 +02:00
end
function reconf . wwwredir_rm ( dirtyList )
2013-07-24 18:49:07 +02:00
uci : delete ( ' uhttpd ' , ' main ' , ' error_page ' )
uci : delete ( ' uhttpd ' , ' main ' , ' no_dirlist ' )
bothBits ( dirtyList , ' uhttpd ' )
2013-04-08 01:20:45 +02:00
end
2013-04-18 11:30:48 +02:00
2013-04-08 01:20:45 +02:00
--[[ Add/remove redirecton of all DNS requests to self ]]
function reconf . dnsredir_add ( dirtyList )
2013-07-27 00:25:43 +02:00
local redirText = ' /#/ ' .. settings.get ( ' network.ap.address ' )
2013-07-24 18:49:07 +02:00
local sname = utils.getUciSectionName ( ' dhcp ' , ' dnsmasq ' )
if sname == nil then return log : error ( " dhcp config does not contain a dnsmasq section " ) end
if uci : get ( ' dhcp ' , sname , ' address ' ) ~= nil then return log : debug ( " DNS address redirection already in place, not re-adding " , false ) end
2013-09-02 15:01:16 +02:00
2013-07-24 18:49:07 +02:00
uci : set ( ' dhcp ' , sname , ' address ' , { redirText } )
commitBit ( dirtyList , ' dhcp ' ) ; reloadBit ( dirtyList , ' dnsmasq ' )
2013-04-08 01:20:45 +02:00
end
function reconf . dnsredir_rm ( dirtyList )
2013-07-24 18:49:07 +02:00
local sname = utils.getUciSectionName ( ' dhcp ' , ' dnsmasq ' )
if sname == nil then return log : error ( " dhcp config does not contain a dnsmasq section " ) end
2013-09-02 15:01:16 +02:00
2013-07-24 18:49:07 +02:00
uci : delete ( ' dhcp ' , sname , ' address ' )
commitBit ( dirtyList , ' dhcp ' ) ; reloadBit ( dirtyList , ' dnsmasq ' )
2013-04-08 01:20:45 +02:00
end
2013-04-18 11:30:48 +02:00
2013-04-08 01:20:45 +02:00
--TODO: handle os.rename() return values (nil+msg on error)
function reconf . wwwcaptive_add ( dirtyList )
2013-07-24 18:49:07 +02:00
if utils.exists ( M.WWW_CAPTIVE_INDICATOR ) then
return log : debug ( " WWW captive directory already in place, not redoing " , false )
2013-04-08 01:20:45 +02:00
end
2013-07-24 18:49:07 +02:00
local rv , reason = os.rename ( ' /www ' , M.WWW_RENAME_NAME )
2013-06-17 20:23:00 +02:00
if rv == true then
2013-07-24 18:49:07 +02:00
utils.symlink ( M.WWW_CAPTIVE_PATH , ' /www ' )
2013-04-18 11:30:48 +02:00
return true
else
2013-07-24 18:49:07 +02:00
return log : error ( " Could not rename /www to " .. M.WWW_RENAME_NAME .. " ( " .. reason .. " ) " )
2013-04-18 11:30:48 +02:00
end
2013-04-08 01:20:45 +02:00
end
function reconf . wwwcaptive_rm ( dirtyList )
2013-07-24 18:49:07 +02:00
if not utils.exists ( M.WWW_CAPTIVE_INDICATOR ) then return log : debug ( " WWW captive directory not in place, not undoing " , false ) end
os.remove ( ' /www ' )
if os.rename ( M.WWW_RENAME_NAME , ' /www ' ) ~= true then
return log : error ( " Could not rename " .. M.WWW_RENAME_NAME .. " to /www " )
2013-04-18 11:30:48 +02:00
end
return true
2013-04-08 01:20:45 +02:00
end
2013-04-18 11:30:48 +02:00
2013-04-08 01:20:45 +02:00
--[[ Setup/remove NAT reflection to redirect all IPs ]]
function reconf . natreflect_add ( dirtyList )
2013-07-24 18:49:07 +02:00
uci : set ( ' firewall ' , ' portalreflect ' , ' redirect ' ) ;
M.uciTableSet ( ' firewall ' , ' portalreflect ' , {
src = ' lan ' ,
proto = ' tcp ' ,
src_dport = ' 80 ' ,
dest_port = ' 80 ' ,
2013-07-27 00:25:43 +02:00
dest_ip = settings.get ( ' network.ap.address ' ) ,
2013-07-24 18:49:07 +02:00
target = ' DNAT '
2013-04-08 01:20:45 +02:00
} )
2013-07-24 18:49:07 +02:00
bothBits ( dirtyList , ' firewall ' )
2013-04-08 01:20:45 +02:00
end
function reconf . natreflect_rm ( dirtyList )
2013-07-24 18:49:07 +02:00
uci : delete ( ' firewall ' , ' portalreflect ' )
bothBits ( dirtyList , ' firewall ' )
2013-04-08 01:20:45 +02:00
end
2013-08-22 17:15:44 +02:00
--- Sets up access point mode.
-- Note: this function might belong in the wlanconfig module but that would introduce
-- a circular dependency, easiest solution is to place the function here.
-- @tparam string ssid The SSID to use for the access point.
-- @return True on success or nil+msg on error.
function M . setupAccessPoint ( ssid )
M.switchConfiguration { apnet = " add_noreload " }
wifi.activateConfig ( ssid )
-- NOTE: dnsmasq must be reloaded after network or it will be unable to serve IP addresses
M.switchConfiguration { wifiiface = " add " , network = " reload " , staticaddr = " add " , dhcppool = " add_noreload " , wwwredir = " add " , dnsredir = " add " }
M.switchConfiguration { dhcp = " reload " }
2013-09-02 15:01:16 +02:00
2013-08-22 17:15:44 +02:00
return true
end
--- Associates wlan device as client with the given SSID.
-- Note: this function might belong in the wlanconfig module but that would introduce
-- a circular dependency, easiest solution is to place the function here.
-- @tparam string ssid The SSID to associate with.
-- @tparam string passphrase The passphrase (if any) to use, may be left out if a UCI configuration exists.
-- @tparam boolean recreate If true, a new UCI configuration based on scan data will always be created, otherwise an attempt will be made to use an existing configuration.
-- @return True on success or nil+msg on error.
function M . associateSsid ( ssid , passphrase , recreate )
2013-10-04 16:29:53 +02:00
log : info ( " netconfig:associateSsid: " .. ( ssid or " <nil> " ) .. " , " .. ( passphrase or " <nil> " ) .. " , " .. ( recreate or " <nil> " ) )
2013-08-22 17:15:44 +02:00
-- see if previously configured network for given ssid exists
local cfg = nil
for _ , net in ipairs ( wifi.getConfigs ( ) ) do
if net.mode ~= " ap " and net.ssid == ssid then
cfg = net
break
end
end
2013-10-04 16:29:53 +02:00
2013-08-22 17:15:44 +02:00
-- if not, or if newly created configuration is requested, create a new configuration
if cfg == nil or recreate ~= nil then
local scanResult = wifi.getScanInfo ( ssid )
if scanResult ~= nil then
wifi.createConfigFromScanInfo ( scanResult , passphrase )
else
--check for error
return nil , " no wireless network with requested SSID is available "
end
end
2013-09-02 15:01:16 +02:00
2013-08-22 17:15:44 +02:00
-- try to associate with the network
wifi.activateConfig ( ssid )
--M.switchConfiguration{ wifiiface="add", apnet="rm", staticaddr="rm", dhcppool="rm", wwwredir="rm", dnsredir="rm", wwwcaptive="rm", wireless="reload" }
2013-09-04 19:23:51 +02:00
--M.switchConfiguration{ wifiiface="add", apnet="rm", staticaddr="rm", dhcppool="rm", wwwredir="rm", dnsredir="rm", wireless="reload" }
2013-10-04 16:29:53 +02:00
M.switchConfiguration { wifiiface = " add " , staticaddr = " rm " , dhcppool = " rm " , wwwredir = " rm " , dnsredir = " rm " , wireless = " reload " }
2013-09-02 15:01:16 +02:00
2013-08-22 17:15:44 +02:00
-- check if we are actually associated
2013-10-04 16:29:53 +02:00
local status = wifi.getDeviceState ( )
2013-08-22 17:15:44 +02:00
if not status.ssid or status.ssid ~= ssid then
return nil , " could not associate with network (incorrect passphrase?) "
end
2013-09-02 15:01:16 +02:00
2013-08-22 17:15:44 +02:00
return true
end
2013-04-08 01:20:45 +02:00
return M