Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>lilik-openwrt-22.03
@ -1,107 +0,0 @@ | |||
# Copyright (C) 2018 Jianhui Zhao | |||
# | |||
# This is free software, licensed under the GNU General Public License v2. | |||
# See /LICENSE for more information. | |||
# | |||
include $(TOPDIR)/rules.mk | |||
PKG_NAME:=wifidog-ng | |||
PKG_VERSION:=2.0.2 | |||
PKG_RELEASE:=2 | |||
PKG_LICENSE:=LGPL-2.1 | |||
PKG_LICENSE_FILES:=LICENSE | |||
PKG_MAINTAINER:=Jianhui Zhao <zhaojh329@gmail.com> | |||
include $(INCLUDE_DIR)/kernel.mk | |||
include $(INCLUDE_DIR)/package.mk | |||
define Package/wifidog-ng/default | |||
SUBMENU:=Captive Portals | |||
SECTION:=net | |||
CATEGORY:=Network | |||
TITLE:=Next generation WifiDog implemented in Lua | |||
DEPENDS:=+kmod-wifidog-ng +libubox-lua +libuci-lua +libubus-lua \ | |||
+ipset +dnsmasq-full +luasocket | |||
endef | |||
define Package/wifidog-ng-nossl | |||
$(Package/wifidog-ng/default) | |||
TITLE += (NO SSL) | |||
DEPENDS += +libuhttpd-nossl | |||
VARIANT:=nossl | |||
CONFLICTS:=wifidog-ng-openssl wifidog-ng-wolfssl wifidog-ng-mbedtls | |||
endef | |||
define Package/wifidog-ng-openssl | |||
$(Package/wifidog-ng/default) | |||
TITLE += (openssl) | |||
DEPENDS += +libuhttpd-openssl | |||
VARIANT:=openssl | |||
CONFLICTS:=wifidog-ng-wolfssl wifidog-ng-mbedtls | |||
endef | |||
define Package/wifidog-ng-wolfssl | |||
$(Package/wifidog-ng/default) | |||
TITLE += (wolfssl) | |||
DEPENDS += +libuhttpd-wolfssl | |||
VARIANT:=wolfssl | |||
CONFLICTS:=wifidog-ng-mbedtls | |||
endef | |||
define Package/wifidog-ng-mbedtls | |||
$(Package/wifidog-ng/default) | |||
TITLE += (mbedtls) | |||
DEPENDS += +libuhttpd-mbedtls | |||
VARIANT:=mbedtls | |||
endef | |||
define Package/wifidog-ng/default/install | |||
$(INSTALL_DIR) $(1)/usr/bin $(1)/etc/init.d $(1)/etc/config \ | |||
$(1)/etc/wifidog-ng $(1)//etc/hotplug.d/dhcp $(1)/usr/lib/lua | |||
$(INSTALL_BIN) ./files//wifidog-ng.lua $(1)/usr/bin/wifidog-ng | |||
$(INSTALL_BIN) ./files/wifidog-ng.init $(1)/etc/init.d/wifidog-ng | |||
$(INSTALL_CONF) ./files/wifidog-ng.config $(1)/etc/config/wifidog-ng | |||
$(INSTALL_CONF) ./files/ssl.key $(1)/etc/wifidog-ng | |||
$(INSTALL_CONF) ./files/ssl.crt $(1)/etc/wifidog-ng | |||
$(INSTALL_DATA) ./files/wifidog-ng.hotplug $(1)/etc/hotplug.d/dhcp/00-wifidog-ng | |||
$(CP) ./files/wifidog-ng $(1)/usr/lib/lua | |||
endef | |||
define Package/wifidog-ng/default/conffiles | |||
/etc/config/wifidog-ng | |||
/etc/wifidog-ng | |||
endef | |||
Package/wifidog-ng-nossl/conffiles = $(Package/wifidog-ng/default/conffiles) | |||
Package/wifidog-ng-openssl/conffiles = $(Package/wifidog-ng/default/conffiles) | |||
Package/wifidog-ng-wolfssl/conffiles = $(Package/wifidog-ng/default/conffiles) | |||
Package/wifidog-ng-mbedtls/conffiles = $(Package/wifidog-ng/default/conffiles) | |||
Package/wifidog-ng-nossl/install = $(Package/wifidog-ng/default/install) | |||
Package/wifidog-ng-openssl/install = $(Package/wifidog-ng/default/install) | |||
Package/wifidog-ng-wolfssl/install = $(Package/wifidog-ng/default/install) | |||
Package/wifidog-ng-mbedtls/install = $(Package/wifidog-ng/default/install) | |||
define KernelPackage/wifidog-ng | |||
SUBMENU:=Other modules | |||
TITLE:=Kernel module for wifidog-ng | |||
DEPENDS:=+kmod-nf-nat +kmod-ipt-ipset | |||
FILES:=$(PKG_BUILD_DIR)/wifidog-ng.ko | |||
endef | |||
include $(INCLUDE_DIR)/kernel-defaults.mk | |||
define Build/Compile | |||
$(MAKE) $(KERNEL_MAKEOPTS) M="$(PKG_BUILD_DIR)" modules | |||
endef | |||
$(eval $(call BuildPackage,wifidog-ng-nossl)) | |||
$(eval $(call BuildPackage,wifidog-ng-mbedtls)) | |||
$(eval $(call BuildPackage,wifidog-ng-wolfssl)) | |||
$(eval $(call BuildPackage,wifidog-ng-openssl)) | |||
$(eval $(call KernelPackage,wifidog-ng)) |
@ -1,24 +0,0 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIID8TCCAtmgAwIBAgICCCUwDQYJKoZIhvcNAQELBQAwczELMAkGA1UEBhMCQ04x | |||
EDAOBgNVBAgMB1RpYW5qaW4xEDAOBgNVBAcMB1RpYW5qaW4xFTATBgNVBAoMDENI | |||
SU5BU1NMIEluYzEpMCcGA1UEAwwgQ0hJTkFTU0wgQ2VydGlmaWNhdGlvbiBBdXRo | |||
b3JpdHkwHhcNMTgwMzAzMTQyODQ2WhcNMTkwMzAzMTQyODQ2WjCBgzELMAkGA1UE | |||
BhMCQ04xEDAOBgNVBAgMB3NpY2h1YW4xEjAQBgNVBAoMCXpoYW9qaDMyOTETMBEG | |||
A1UECwwKd2lmaWRvZy1uZzEQMA4GA1UEAwwHd2lmaWRvZzEnMCUGCSqGSIb3DQEJ | |||
ARYYamlhbmh1aXpoYW8zMjlAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC | |||
AQ8AMIIBCgKCAQEAyD8gd3XIJvkYeySP2q0toYsfvhlA+lceUPiMi16U1nR3TD5U | |||
uTNGsvYBDMiR7vG0NKClFT73u/d8HBcYcTBgbhHfBkz4v9S5aMdUYQsUMQEITBdE | |||
hPEeXVqqj796Lu6iEkNUFrtam2h3t+kYODjbszk2woBtohaRWfNyOB/AJH6Stv4l | |||
jkPYwt9NHcKQSm9kjcGsAqQwkgVd4UfHX2G20gaTijimeHlJL2wv61uLBUvYux0E | |||
+98KIcEIYu3BVAfoO2Omg/o73cwH+sFTswEXPuXirwrOzmJ850WBLScLkSKSATrY | |||
1YdU6CRaJuP/POFfSqAhn/mPRNQFU5fAaDcfEwIDAQABo34wfDAJBgNVHRMEAjAA | |||
MC8GCWCGSAGG+EIBDQQiFiBDSElOQVNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 | |||
eTAdBgNVHQ4EFgQU9XS4dW6j1r1lEOIHWkoJx3zSqqgwHwYDVR0jBBgwFoAUXB8j | |||
+sjhITHC2Df2iPzSb8JUQzMwDQYJKoZIhvcNAQELBQADggEBAFsaq5qehwp0zMqY | |||
cb0IX5/f4ZnscX587SM/NhORODa0p/bT3EwG3grtljHhRW+s/4c4gPgilrzV0Fxn | |||
Y5FodLfFdbNVjhgeSrDCRmwIvKSe81LYOe+rbfTBF0g3YYWDwcwc8tFvcwWBxqWn | |||
4F+u9aIKgHU7HXQokqCxEOTFjrAHVJf1OqtRMTXlBBb6ypVdHn0glfSxOIC/Vp2T | |||
5UR7oVdD4E8ASqe7Q7MmTeY377CRagfd0WD9XK7o+cbKkLLW1QWc8ht1rHjGp+/2 | |||
gmkxEmpX2Xhpv1FX/b6sj1dTmOc2bXBzpvV6yonRMu5dYsOrdDwbH/T05X+hCFW9 | |||
G86ZLFY= | |||
-----END CERTIFICATE----- |
@ -1,28 +0,0 @@ | |||
-----BEGIN PRIVATE KEY----- | |||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIPyB3dcgm+Rh7 | |||
JI/arS2hix++GUD6Vx5Q+IyLXpTWdHdMPlS5M0ay9gEMyJHu8bQ0oKUVPve793wc | |||
FxhxMGBuEd8GTPi/1Llox1RhCxQxAQhMF0SE8R5dWqqPv3ou7qISQ1QWu1qbaHe3 | |||
6Rg4ONuzOTbCgG2iFpFZ83I4H8AkfpK2/iWOQ9jC300dwpBKb2SNwawCpDCSBV3h | |||
R8dfYbbSBpOKOKZ4eUkvbC/rW4sFS9i7HQT73wohwQhi7cFUB+g7Y6aD+jvdzAf6 | |||
wVOzARc+5eKvCs7OYnznRYEtJwuRIpIBOtjVh1ToJFom4/884V9KoCGf+Y9E1AVT | |||
l8BoNx8TAgMBAAECggEAK/JmvrDzt1HtxIDWrWhaXly5H7BNKWPbPGv/9EpSoeo3 | |||
kF0RnP+a4YXJ3zNZi7YyFWa4NDx4hCEhdMzAyX6TezSi3LAh23/lHRC5/P5AdSzD | |||
1Gc6225LerN+QUQFna0zlox+NOrzTK4VsCAQ963K0b+ZvAARj4QibDpYc+bL9XYK | |||
fVrZSnGJhNY3S6YjTF4oyMejKxk+HPhgCVEcZCHiC0RmXVqfETe6Cu0UtDPTTK5Q | |||
IXYYZ0HLsqaGWwGCWm/ji6HjNCG1dUhUp/yZR+7X45Utok3Rd3wo0kxZGJ7LHH4N | |||
541qcFbaT3rX39uPypuK5dSc5lb98FAOl79jL/wnUQKBgQDjEycf6VKZYf8d/MMV | |||
4+0YrFV7sdi0k4TC+lFmfJZVFHqcPn99q3cO2b9npgLDpQpwpcyBGMh6hWufVXXA | |||
ctrxg8vjKBHG8MT70Lulvi+G3Fldw7EHVVQGEHRqPaSzA035JyVanDs6lgoqjj9b | |||
BuMQidIeaj2t28pEhc0rYstW6wKBgQDhwRzoCirKrtJDWclDkjbzkGUfoAKMz2p2 | |||
mSAs2xCdrx8vtFzUXcCLsvlXa+hIEe4O5cUZg+WLPfXiV4gtF74PTkmYADXRTUBl | |||
dHzfjVWQINEYFsWOEP5eYB0VWiA52JUaCuHuHILt6CSy3h8xPtnq+/oEFTeqh/2C | |||
XoN+seKeeQKBgQDUE1c/HpLeXf/+6crp7u3JVWqhFADo5b3gvBi6NzHQVEgPFO/N | |||
Vw7i98sj6pA6WTHe83qEN7lFdMaHETHgg2SonAcYKJwxyTywUspuiampsrJkOBhm | |||
WPMYltWjQ99GsZdpU343miJXHTpxdFkHku8OyylK7r6cWeIXDUAJfUOb8QKBgFbk | |||
ZoTljOzwdxvXTkFE4QPEmzed9f1OxHKbo6fANdgLlJxe9rAC2d6rZ49/iCtdQ1zW | |||
kZOtkceTdLXG7TI2BkCL6IWp5w0Fh/jE6l99XeaYywJTmXyCC/Y1VlxmkSrSsykP | |||
8UAeF0MM7DswhZ8FywjILcYuiHuJ1ki8qi40t745AoGAT/5imiro59cHMbbGEQb+ | |||
42oBY7RxeHkk6+8WTJA6kqv8tuOK3gvDFm5cRJVCduVF/Jf+276IMoTMEb8kBGQA | |||
R3CRsYwLPrpdWu2q9Ho1KtH+azt/d+3uglT9g3fhvFieNIwkRgaNNJQC6wmddDeG | |||
MEYv4HO1LykipsDVsFadVCk= | |||
-----END PRIVATE KEY----- |
@ -1,20 +0,0 @@ | |||
config gateway | |||
option enabled 1 | |||
option interface 'lan' | |||
option port 2060 | |||
option dhcp_host_white 1 | |||
option ssl_port 8443 | |||
option checkinterval 30 | |||
option client_timeout 5 | |||
option temppass_time 30 | |||
config server | |||
option host 'authserver.com' | |||
option port 80 | |||
option ssl 0 | |||
option path '/wifidog/' | |||
option login_path 'login' | |||
option portal_path 'portal' | |||
option msg_path 'gw_message.php' | |||
option ping_path 'ping' | |||
option auth_path 'auth' |
@ -1,3 +0,0 @@ | |||
[ "$ACTION" = "add" -o "$ACTION" = "update" ] || exit 0 | |||
ubus list wifidog-ng > /dev/null 2>&1 || exit 0 | |||
ubus call wifidog-ng roam "{\"mac\":\"$MACADDR\", \"ip\":\"$IPADDR\"}" |
@ -1,135 +0,0 @@ | |||
#!/bin/sh /etc/rc.common | |||
USE_PROCD=1 | |||
START=95 | |||
BIN=/usr/bin/wifidog-ng | |||
global_dhcp_host_white=1 | |||
validate_gateway_section() { | |||
uci_load_validate wifidog-ng gateway "$1" "$2" \ | |||
'enabled:bool:0' \ | |||
'interface:uci("network", "@interface"):lan' \ | |||
'dhcp_host_white:bool:1' | |||
} | |||
start_wifidog() { | |||
[ "$2" = 0 ] || { | |||
echo "validation gateway failed" >&2 | |||
exit 1 | |||
} | |||
[ $enabled = 1 ] || exit 0 | |||
[ $dhcp_host_white = 1 ] || global_dhcp_host_white=0 | |||
# timeout = 24.855 days | |||
ipset -! create wifidog-ng-mac hash:mac timeout 2147483 | |||
ipset -! create wifidog-ng-ip hash:ip | |||
modprobe wifidog-ng | |||
echo "enabled=1" > /proc/wifidog-ng/config | |||
procd_open_instance | |||
procd_set_param command $BIN | |||
procd_set_param respawn | |||
procd_close_instance | |||
} | |||
validate_server_section() { | |||
uci_load_validate wifidog-ng server "$1" "$2" \ | |||
'host:host' | |||
} | |||
parse_server() { | |||
[ "$2" = 0 ] || { | |||
echo "validation server failed" >&2 | |||
exit 1 | |||
} | |||
if validate_data ip4addr "$host" 2> /dev/null; then | |||
ipset add wifidog-ng-ip $host | |||
else | |||
echo "ipset=/$host/wifidog-ng-ip" >> /tmp/dnsmasq.d/wifidog-ng | |||
fi | |||
} | |||
validate_validated_user_section() { | |||
uci_load_validate wifidog-ng validated_user "$1" "$2" \ | |||
'mac:macaddr' | |||
} | |||
parse_validated_user() { | |||
[ "$2" = 0 ] || { | |||
echo "validation validated_user failed" >&2 | |||
exit 1 | |||
} | |||
[ -n "$mac" ] && ipset add wifidog-ng-mac $mac | |||
} | |||
validate_validated_domain_section() { | |||
uci_load_validate wifidog-ng validated_domain "$1" "$2" \ | |||
'domain:host' | |||
} | |||
parse_validated_domain() { | |||
[ "$2" = 0 ] || { | |||
echo "validation validated_domain failed" >&2 | |||
exit 1 | |||
} | |||
[ -n "$domain" ] && echo "ipset=/$domain/wifidog-ng-ip" >> /tmp/dnsmasq.d/wifidog-ng | |||
} | |||
validate_dhcp_host_section() { | |||
uci_load_validate dhcp host "$1" "$2" \ | |||
'mac:macaddr' | |||
} | |||
parse_dhcp_host() { | |||
[ "$2" = 0 ] || { | |||
echo "validation validated dhcp host failed" >&2 | |||
exit 1 | |||
} | |||
[ -n "$mac" ] && ipset add wifidog-ng-mac $mac | |||
} | |||
start_service() { | |||
config_load wifidog-ng | |||
config_foreach validate_gateway_section gateway start_wifidog | |||
echo -n > /tmp/dnsmasq.d/wifidog-ng | |||
config_foreach validate_server_section server parse_server | |||
config_foreach validate_validated_user_section validated_user parse_validated_user | |||
config_foreach validate_validated_domain_section validated_domain parse_validated_domain | |||
[ $global_dhcp_host_white = 1 ] && { | |||
config_load dhcp | |||
config_foreach validate_dhcp_host_section host parse_dhcp_host | |||
} | |||
/etc/init.d/dnsmasq restart & | |||
} | |||
stop_service() { | |||
rmmod wifidog-ng | |||
ipset destroy wifidog-ng-mac | |||
ipset destroy wifidog-ng-ip | |||
} | |||
service_triggers() { | |||
procd_add_reload_trigger "wifidog-ng" | |||
procd_open_validate | |||
validate_gateway_section | |||
validate_server_section | |||
validate_validated_user_section | |||
validate_validated_domain_section | |||
validate_dhcp_host_section | |||
procd_close_validate | |||
} |
@ -1,37 +0,0 @@ | |||
#!/usr/bin/env lua | |||
--[[ | |||
Copyright (C) 2018 Jianhui Zhao <jianhuizhao329@gmail.com> | |||
This program is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |||
USA | |||
--]] | |||
local uloop = require "uloop" | |||
local uh = require "uhttpd" | |||
local auth = require "wifidog-ng.auth" | |||
local ubus = require "wifidog-ng.ubus" | |||
local version = require "wifidog-ng.version" | |||
local heartbeat = require "wifidog-ng.heartbeat" | |||
uh.log(uh.LOG_INFO, "Version: " .. version.string()) | |||
uloop.init() | |||
ubus.init() | |||
auth.init() | |||
heartbeat.start() | |||
uloop.run() |
@ -1,221 +0,0 @@ | |||
--[[ | |||
Copyright (C) 2018 Jianhui Zhao <jianhuizhao329@gmail.com> | |||
This program is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |||
USA | |||
--]] | |||
local uh = require "uhttpd" | |||
local http = require "socket.http" | |||
local util = require "wifidog-ng.util" | |||
local config = require "wifidog-ng.config" | |||
local M = {} | |||
local apple_host = { | |||
["captive.apple.com"] = true, | |||
["www.apple.com"] = true, | |||
} | |||
local terms = {} | |||
local function is_authed_user(mac) | |||
local r = os.execute("ipset test wifidog-ng-mac " .. mac .. " 2> /dev/null") | |||
return r == 0 | |||
end | |||
local function allow_user(mac, temppass) | |||
if not temppass then | |||
terms[mac].authed = true | |||
os.execute("ipset add wifidog-ng-mac " .. mac) | |||
else | |||
local cfg = config.get() | |||
os.execute("ipset add wifidog-ng-mac " .. mac .. " timeout " .. cfg.temppass_time) | |||
end | |||
end | |||
local function deny_user(mac) | |||
os.execute("ipset del wifidog-ng-mac " .. mac) | |||
end | |||
function M.get_terms() | |||
local r = {} | |||
for k, v in pairs(terms) do | |||
if v.authed then | |||
r[k] = {ip = v.ip} | |||
end | |||
end | |||
return r | |||
end | |||
function M.new_term(ip, mac, token) | |||
terms[mac] = {ip = ip, token = token} | |||
if token then | |||
terms[mac].authed = true | |||
allow_user(mac) | |||
end | |||
end | |||
local function http_callback_auth(cl) | |||
local cfg = config.get() | |||
local token = cl:get_var("token") | |||
local ip = cl:get_remote_addr() | |||
local mac = util.arp_get(cfg.gw_ifname, ip) | |||
if not mac then | |||
uh.log(uh.LOG_ERR, "Not found macaddr for " .. ip) | |||
cl:send_error(401, "Unauthorized", "Not found your macaddr") | |||
return uh.REQUEST_DONE | |||
end | |||
if token and #token > 0 then | |||
if cl:get_var("logout") then | |||
local url = string.format("%s&stage=logout&ip=%s&mac=%s&token=%s", cfg.auth_url, ip, mac, token) | |||
http.request(url) | |||
deny_user(mac) | |||
else | |||
local url = string.format("%s&stage=login&ip=%s&mac=%s&token=%s", cfg.auth_url, ip, mac, token) | |||
local r = http.request(url) | |||
if not r then | |||
cl:send_error(401, "Unauthorized") | |||
return uh.REQUEST_DONE | |||
end | |||
local auth = r:match("Auth: (%d)") | |||
if auth == "1" then | |||
allow_user(mac) | |||
cl:redirect(302, string.format("%s&mac=%s", cfg.portal_url, mac)) | |||
else | |||
cl:redirect(302, string.format("%s&mac=%s", cfg.msg_url, mac)) | |||
return uh.REQUEST_DONE | |||
end | |||
end | |||
else | |||
cl:send_error(401, "Unauthorized") | |||
return uh.REQUEST_DONE | |||
end | |||
end | |||
local function http_callback_temppass(cl) | |||
local cfg = config.get() | |||
local ip = cl:get_remote_addr() | |||
local mac = util.arp_get(cfg.gw_ifname, ip) | |||
if not mac then | |||
uh.log(uh.LOG_ERR, "Not found macaddr for " .. ip) | |||
cl:send_error(401, "Unauthorized", "Not found your macaddr") | |||
return uh.REQUEST_DONE | |||
end | |||
local script = cl:get_var("script") or "" | |||
cl:send_header(200, "OK", -1) | |||
cl:header_end() | |||
allow_user(mac, true) | |||
cl:chunk_send(cl:get_var("script") or ""); | |||
cl:request_done() | |||
return uh.REQUEST_DONE | |||
end | |||
local function http_callback_404(cl, path) | |||
local cfg = config.get() | |||
if cl:get_http_method() ~= uh.HTTP_METHOD_GET then | |||
cl:send_error(401, "Unauthorized") | |||
return uh.REQUEST_DONE | |||
end | |||
local ip = cl:get_remote_addr() | |||
local mac = util.arp_get(cfg.gw_ifname, ip) | |||
if not mac then | |||
uh.log(uh.LOG_ERR, "Not found macaddr for " .. ip) | |||
cl:send_error(401, "Unauthorized", "Not found your macaddr") | |||
return uh.REQUEST_DONE | |||
end | |||
term = terms[mac] | |||
if not term then | |||
terms[mac] = {ip = ip} | |||
end | |||
term = terms[mac] | |||
if is_authed_user(mac) then | |||
cl:redirect(302, "%s&mac=%s", cfg.portal_url, mac) | |||
return uh.REQUEST_DONE | |||
end | |||
cl:send_header(200, "OK", -1) | |||
cl:header_end() | |||
local header_host = cl:get_header("host") | |||
if apple_host[header_host] then | |||
local http_ver = cl:get_http_version() | |||
if http_ver == uh.HTTP_VER_10 then | |||
if not term.apple then | |||
cl:chunk_send("fuck you") | |||
term.apple = true | |||
cl:request_done() | |||
return uh.REQUEST_DONE | |||
end | |||
end | |||
end | |||
local redirect_html = [[ | |||
<!doctype html><html><head><title>Success</title> | |||
<script type="text/javascript"> | |||
setTimeout(function() {location.replace('%s&ip=%s&mac=%s');}, 1);</script> | |||
<style type="text/css">body {color:#FFF}</style></head> | |||
<body>Success</body></html> | |||
]] | |||
cl:chunk_send(string.format(redirect_html, cfg.login_url, ip, mac)) | |||
cl:request_done() | |||
return uh.REQUEST_DONE | |||
end | |||
local function on_request(cl, path) | |||
if path == "/wifidog/auth" then | |||
return http_callback_auth(cl) | |||
elseif path == "/wifidog/temppass" then | |||
return http_callback_temppass(cl) | |||
end | |||
return uh.REQUEST_CONTINUE | |||
end | |||
function M.init() | |||
local cfg = config.get() | |||
local srv = uh.new(cfg.gw_address, cfg.gw_port) | |||
srv:on_request(on_request) | |||
srv:on_error404(http_callback_404) | |||
if uh.SSL_SUPPORTED then | |||
local srv_ssl = uh.new(cfg.gw_address, cfg.gw_ssl_port) | |||
srv_ssl:ssl_init("/etc/wifidog-ng/ssl.crt", "/etc/wifidog-ng/ssl.key") | |||
srv_ssl:on_request(on_request) | |||
srv_ssl:on_error404(http_callback_404) | |||
end | |||
end | |||
return M |
@ -1,158 +0,0 @@ | |||
--[[ | |||
Copyright (C) 2018 Jianhui Zhao <jianhuizhao329@gmail.com> | |||
This program is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |||
USA | |||
--]] | |||
local uci = require "uci" | |||
local util = require "wifidog-ng.util" | |||
local M = {} | |||
local cfg = {} | |||
function M.parse() | |||
local c = uci.cursor() | |||
c:foreach('wifidog-ng', 'gateway', function(s) | |||
local port = s.port or 2060 | |||
local ssl_port = s.ssl_port or 8443 | |||
local interface = s.interface or "lan" | |||
local checkinterval = s.checkinterval or 30 | |||
local client_timeout = s.client_timeout or 5 | |||
local temppass_time = s.temppass_time or 30 | |||
local id = s.id | |||
local address = s.address | |||
cfg.gw_port = tonumber(port) | |||
cfg.gw_ssl_port = tonumber(ssl_port) | |||
cfg.checkinterval = tonumber(checkinterval) | |||
cfg.client_timeout = tonumber(client_timeout) | |||
cfg.temppass_time = tonumber(temppass_time) | |||
cfg.gw_address = s.address | |||
cfg.gw_id = s.id | |||
local st = util.ubus("network.interface." .. interface, "status") | |||
cfg.gw_ifname = st.device | |||
if not cfg.gw_address then | |||
cfg.gw_address = st["ipv4-address"][1].address | |||
end | |||
if not cfg.gw_id then | |||
local devst = util.ubus("network.device", "status", {name = st.device}) | |||
local macaddr = devst.macaddr | |||
cfg.gw_id = macaddr:gsub(":", ""):upper() | |||
end | |||
end) | |||
c:foreach('wifidog-ng', 'server', function(s) | |||
local host = s.host | |||
local path = s.path or "/wifidog/" | |||
local gw_port = cfg.gw_port | |||
local gw_id = cfg.gw_id | |||
local gw_address = cfg.gw_address | |||
local ssid = cfg.ssid or "" | |||
local proto, port = "http", "" | |||
if s.port ~= "80" and s.port ~= "443" then | |||
port = ":" .. s.port | |||
end | |||
if s.ssl == "1" then | |||
proto = "https" | |||
end | |||
cfg.login_url = string.format("%s://%s%s%s%s?gw_address=%s&gw_port=%d&gw_id=%s&ssid=%s", | |||
proto, host, port, path, s.login_path, gw_address, gw_port, gw_id, ssid) | |||
cfg.auth_url = string.format("%s://%s%s%s%s?gw_id=%s", | |||
proto, host, port, path, s.auth_path, gw_id) | |||
cfg.ping_url = string.format("%s://%s%s%s%s?gw_id=%s", | |||
proto, host, port, path, s.ping_path, gw_id) | |||
cfg.portal_url = string.format("%s://%s%s%s%s?gw_id=%s", | |||
proto, host, port, path, s.portal_path, gw_id) | |||
cfg.msg_url = string.format("%s://%s%s%s%s?gw_id=%s", | |||
proto, host, port, path, s.msg_path, gw_id) | |||
end) | |||
cfg.parsed = true | |||
end | |||
function M.get() | |||
if not cfg.parsed then | |||
M.parse() | |||
end | |||
return cfg | |||
end | |||
function M.add_whitelist(typ, value) | |||
local c = uci.cursor() | |||
local opt | |||
if typ == "mac" then | |||
typ = "validated_user" | |||
opt = "mac" | |||
elseif typ == "domain" then | |||
typ = "validated_domain" | |||
opt = "domain" | |||
else | |||
return | |||
end | |||
local exist = false | |||
c:foreach("wifidog-ng", typ, function(s) | |||
if s[opt] == value then | |||
exist = true | |||
end | |||
end) | |||
if not exist then | |||
local s = c:add("wifidog-ng", typ) | |||
c:set("wifidog-ng", s, opt, value) | |||
c:commit("wifidog-ng") | |||
end | |||
end | |||
function M.del_whitelist(typ, value) | |||
local c = uci.cursor() | |||
local opt | |||
if typ == "mac" then | |||
typ = "validated_user" | |||
opt = "mac" | |||
elseif typ == "domain" then | |||
typ = "validated_domain" | |||
opt = "domain" | |||
else | |||
return | |||
end | |||
c:foreach("wifidog-ng", typ, function(s) | |||
if s[opt] == value then | |||
c:delete("wifidog-ng", s[".name"]) | |||
end | |||
end) | |||
c:commit("wifidog-ng") | |||
end | |||
return M |
@ -1,46 +0,0 @@ | |||
--[[ | |||
Copyright (C) 2018 Jianhui Zhao <jianhuizhao329@gmail.com> | |||
This program is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |||
USA | |||
--]] | |||
local uloop = require "uloop" | |||
local http = require "socket.http" | |||
local util = require "wifidog-ng.util" | |||
local config = require "wifidog-ng.config" | |||
local M = {} | |||
local timer = nil | |||
local start_time = os.time() | |||
local function heartbeat() | |||
local cfg = config.get() | |||
timer:set(1000 * cfg.checkinterval) | |||
local sysinfo = util.ubus("system", "info") | |||
local url = string.format("%s&sys_uptime=%d&sys_memfree=%d&sys_load=%d&wifidog_uptime=%d", | |||
cfg.ping_url, sysinfo.uptime, sysinfo.memory.free, sysinfo.load[1], os.time() - start_time) | |||
http.request(url) | |||
end | |||
function M.start() | |||
timer = uloop.timer(heartbeat, 1000) | |||
end | |||
return M |
@ -1,128 +0,0 @@ | |||
--[[ | |||
Copyright (C) 2018 Jianhui Zhao <jianhuizhao329@gmail.com> | |||
This program is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |||
USA | |||
--]] | |||
local uci = require "uci" | |||
local ubus = require "ubus" | |||
local http = require "socket.http" | |||
local auth = require "wifidog-ng.auth" | |||
local config = require "wifidog-ng.config" | |||
local M = {} | |||
local conn = nil | |||
local ubus_codes = { | |||
["INVALID_COMMAND"] = 1, | |||
["INVALID_ARGUMENT"] = 2, | |||
["METHOD_NOT_FOUND"] = 3, | |||
["NOT_FOUND"] = 4, | |||
["NO_DATA"] = 5, | |||
["PERMISSION_DENIED"] = 6, | |||
["TIMEOUT"] = 7, | |||
["NOT_SUPPORTED"] = 8, | |||
["UNKNOWN_ERROR"] = 9, | |||
["CONNECTION_FAILED"] = 10 | |||
} | |||
local function reload_validated_domain() | |||
local c = uci.cursor() | |||
local file = io.open("/tmp/dnsmasq.d/wifidog-ng", "w") | |||
c:foreach("wifidog-ng", "validated_domain", function(s) | |||
file:write("ipset=/" .. s.domain .. "/wifidog-ng-ip\n") | |||
end) | |||
file:close() | |||
os.execute("/etc/init.d/dnsmasq restart &") | |||
end | |||
local methods = { | |||
["wifidog-ng"] = { | |||
roam = { | |||
function(req, msg) | |||
local cfg = config.get() | |||
if not msg.ip or not msg.mac then | |||
return ubus_codes["INVALID_ARGUMENT"] | |||
end | |||
local url = string.format("%s&stage=roam&ip=%s&mac=%s", cfg.auth_url, msg.ip, msg.mac) | |||
local r = http.request(url) or "" | |||
local token = r:match("token=(%w+)") | |||
if token then | |||
auth.new_term(msg.ip, msg.mac, token) | |||
end | |||
end, {ip = ubus.STRING, mac = ubus.STRING } | |||
}, | |||
term = { | |||
function(req, msg) | |||
if msg.action == "show" then | |||
conn:reply(req, {terms = auth.get_terms()}); | |||
return | |||
end | |||
if not msg.action or not msg.mac then | |||
return ubus_codes["INVALID_ARGUMENT"] | |||
end | |||
if msg.action == "add" then | |||
auth.allow_user(mac) | |||
elseif msg.action == "del" then | |||
auth.deny_user(mac) | |||
end | |||
end, {action = ubus.STRING, mac = ubus.STRING } | |||
}, | |||
whitelist = { | |||
function(req, msg) | |||
if not msg.action or not msg.type or not msg.value then | |||
return ubus_codes["INVALID_ARGUMENT"] | |||
end | |||
if msg.action == "add" then | |||
config.add_whitelist(msg.type, msg.value) | |||
if msg.type == "mac" then | |||
auth.allow_user(msg.value) | |||
end | |||
elseif msg.action == "del" then | |||
config.del_whitelist(msg.type, msg.value) | |||
if msg.type == "mac" then | |||
auth.deny_user(msg.value) | |||
end | |||
end | |||
if msg.type == "domain" then | |||
reload_validated_domain() | |||
end | |||
end, {action = ubus.STRING, type = ubus.STRING, value = ubus.STRING } | |||
}, | |||
} | |||
} | |||
function M.init() | |||
conn = ubus.connect() | |||
if not conn then | |||
error("Failed to connect to ubus") | |||
end | |||
conn:add(methods) | |||
end | |||
return M |
@ -1,83 +0,0 @@ | |||
--[[ | |||
Copyright (C) 2018 Jianhui Zhao <jianhuizhao329@gmail.com> | |||
This program is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |||
USA | |||
--]] | |||
local _ubus = require "ubus" | |||
local _ubus_connection = nil | |||
local M = {} | |||
function M.arp_get(ifname, ipaddr) | |||
for l in io.lines("/proc/net/arp") do | |||
local f = {} | |||
for e in string.gmatch(l, "%S+") do | |||
f[#f + 1] = e | |||
end | |||
if f[1] == ipaddr and f[6] == ifname then | |||
return f[4] | |||
end | |||
end | |||
end | |||
function M.read_file(path, len) | |||
local file = io.open(path, "r") | |||
if not file then return nil end | |||
if not len then len = "*a" end | |||
local data = file:read(len) | |||
file:close() | |||
return data | |||
end | |||
local ubus_codes = { | |||
"INVALID_COMMAND", | |||
"INVALID_ARGUMENT", | |||
"METHOD_NOT_FOUND", | |||
"NOT_FOUND", | |||
"NO_DATA", | |||
"PERMISSION_DENIED", | |||
"TIMEOUT", | |||
"NOT_SUPPORTED", | |||
"UNKNOWN_ERROR", | |||
"CONNECTION_FAILED" | |||
} | |||
function M.ubus(object, method, data) | |||
if not _ubus_connection then | |||
_ubus_connection = _ubus.connect() | |||
assert(_ubus_connection, "Unable to establish ubus connection") | |||
end | |||
if object and method then | |||
if type(data) ~= "table" then | |||
data = { } | |||
end | |||
local rv, err = _ubus_connection:call(object, method, data) | |||
return rv, err, ubus_codes[err] | |||
elseif object then | |||
return _ubus_connection:signatures(object) | |||
else | |||
return _ubus_connection:objects() | |||
end | |||
end | |||
return M |
@ -1,30 +0,0 @@ | |||
--[[ | |||
Copyright (C) 2018 Jianhui Zhao <jianhuizhao329@gmail.com> | |||
This program is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | |||
USA | |||
--]] | |||
local M = { | |||
MAJOR = 2, | |||
MINOR = 0, | |||
PATCH = 0 | |||
} | |||
function M.string() | |||
return string.format("%d.%d.%d", M.MAJOR, M.MINOR, M.PATCH) | |||
end | |||
return M |
@ -1,18 +0,0 @@ | |||
ifeq ($(findstring openwrt, $(CC)),) | |||
ifneq ($(KERNELRELEASE),) | |||
wifidog-ng-objs := main.o config.o | |||
obj-m := wifidog-ng.o | |||
else | |||
KDIR = /lib/modules/$(shell uname -r)/build | |||
all: | |||
make -C $(KDIR) M=$(PWD) modules | |||
clean: | |||
rm -rf *.o *.ko *.mod.c Module.* modules.* .*.cmd .tmp* | |||
endif | |||
else | |||
wifidog-ng-objs := main.o config.o | |||
obj-m := wifidog-ng.o | |||
endif |
@ -1,188 +0,0 @@ | |||
/* | |||
* Copyright (C) 2017 jianhui zhao <zhaojh329@gmail.com> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
*/ | |||
#include <linux/uaccess.h> | |||
#include <linux/inetdevice.h> | |||
#include <linux/seq_file.h> | |||
#include <linux/version.h> | |||
#include "config.h" | |||
static struct proc_dir_entry *proc; | |||
static struct config conf; | |||
static int update_gw_interface(const char *interface) | |||
{ | |||
int ret = 0; | |||
struct net_device *dev; | |||
struct in_device *in_dev; | |||
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 21) | |||
const struct in_ifaddr *ifa; | |||
#endif | |||
dev = dev_get_by_name(&init_net, interface); | |||
if (!dev) { | |||
pr_err("Not found interface: %s\n", interface); | |||
return -ENOENT; | |||
} | |||
conf.interface_ifindex = dev->ifindex; | |||
in_dev = inetdev_by_index(dev_net(dev), conf.interface_ifindex); | |||
if (!in_dev) { | |||
pr_err("Not found in_dev on %s\n", interface); | |||
ret = -ENOENT; | |||
goto QUIT; | |||
} | |||
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 21) | |||
in_dev_for_each_ifa_rcu(ifa, in_dev) { | |||
if (ifa->ifa_flags & IFA_F_SECONDARY) | |||
continue; | |||
#else | |||
for_primary_ifa(in_dev) { | |||
#endif | |||
conf.interface_ipaddr = ifa->ifa_local; | |||
conf.interface_mask = ifa->ifa_mask; | |||
conf.interface_broadcast = ifa->ifa_broadcast; | |||
pr_info("Found ip from %s: %pI4\n", interface, &conf.interface_ipaddr); | |||
break; | |||
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 21) | |||
} | |||
#else | |||
} endfor_ifa(in_dev) | |||
#endif | |||
QUIT: | |||
dev_put(dev); | |||
return ret; | |||
} | |||
static int proc_config_show(struct seq_file *s, void *v) | |||
{ | |||
seq_printf(s, "enabled(RW) = %d\n", conf.enabled); | |||
seq_printf(s, "interface(RW) = %s\n", conf.interface); | |||
seq_printf(s, "ipaddr(RO) = %pI4\n", &conf.interface_ipaddr); | |||
seq_printf(s, "netmask(RO) = %pI4\n", &conf.interface_mask); | |||
seq_printf(s, "broadcast(RO) = %pI4\n", &conf.interface_broadcast); | |||
seq_printf(s, "port(RW) = %d\n", conf.port); | |||
seq_printf(s, "ssl_port(RW) = %d\n", conf.ssl_port); | |||
return 0; | |||
} | |||
static ssize_t proc_config_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) | |||
{ | |||
char data[128]; | |||
char *delim, *key; | |||
const char *value; | |||
int update = 0; | |||
if (size == 0) | |||
return -EINVAL; | |||
if (size > sizeof(data)) | |||
size = sizeof(data); | |||
if (copy_from_user(data, buf, size)) | |||
return -EFAULT; | |||
data[size - 1] = 0; | |||
key = data; | |||
while (key && *key) { | |||
while (*key && (*key == ' ')) | |||
key++; | |||
delim = strchr(key, '='); | |||
if (!delim) | |||
break; | |||
*delim++ = 0; | |||
value = delim; | |||
delim = strchr(value, '\n'); | |||
if (delim) | |||
*delim++ = 0; | |||
if (!strcmp(key, "enabled")) { | |||
conf.enabled = simple_strtol(value, NULL, 0); | |||
if (conf.enabled) | |||
update = 1; | |||
pr_info("wifidog %s\n", conf.enabled ? "enabled" : "disabled"); | |||
} else if (!strcmp(key, "interface")) { | |||
strncpy(conf.interface, value, sizeof(conf.interface) - 1); | |||
update = 1; | |||
} else if (!strcmp(key, "port")) { | |||
conf.port = simple_strtol(value, NULL, 0); | |||
} else if (!strcmp(key, "ssl_port")) { | |||
conf.ssl_port = simple_strtol(value, NULL, 0); | |||
} | |||
key = delim; | |||
} | |||
if (update) | |||
update_gw_interface(conf.interface); | |||
return size; | |||
} | |||
static int proc_config_open(struct inode *inode, struct file *file) | |||
{ | |||
return single_open(file, proc_config_show, NULL); | |||
} | |||
const static struct file_operations proc_config_ops = { | |||
.owner = THIS_MODULE, | |||
.open = proc_config_open, | |||
.read = seq_read, | |||
.write = proc_config_write, | |||
.llseek = seq_lseek, | |||
.release = single_release | |||
}; | |||
int init_config(void) | |||
{ | |||
int ret = 0; | |||
conf.interface_ifindex= -1; | |||
conf.port = 2060; | |||
conf.ssl_port = 8443; | |||
strcpy(conf.interface, "br-lan"); | |||
proc = proc_mkdir(PROC_DIR_NAME, NULL); | |||
if (!proc) { | |||
pr_err("can't create dir /proc/"PROC_DIR_NAME"/\n"); | |||
return -ENODEV;; | |||
} | |||
if (!proc_create("config", 0644, proc, &proc_config_ops)) { | |||
pr_err("can't create file /proc/"PROC_DIR_NAME"/config\n"); | |||
ret = -EINVAL; | |||
goto remove; | |||
} | |||
return 0; | |||
remove: | |||
remove_proc_entry(PROC_DIR_NAME, NULL); | |||
return ret; | |||
} | |||
void deinit_config(void) | |||
{ | |||
remove_proc_entry("config", proc); | |||
remove_proc_entry(PROC_DIR_NAME, NULL); | |||
} | |||
struct config *get_config(void) | |||
{ | |||
return &conf; | |||
} |
@ -1,31 +0,0 @@ | |||
/* | |||
* Copyright (C) 2017 jianhui zhao <zhaojh329@gmail.com> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
*/ | |||
#ifndef __CONFIG_H_ | |||
#define __CONFIG_H_ | |||
#include <linux/proc_fs.h> | |||
#define PROC_DIR_NAME "wifidog-ng" | |||
struct config { | |||
int enabled; | |||
char interface[32]; | |||
int interface_ifindex; | |||
__be32 interface_ipaddr; | |||
__be32 interface_mask; | |||
__be32 interface_broadcast; | |||
int port; | |||
int ssl_port; | |||
}; | |||
int init_config(void); | |||
void deinit_config(void); | |||
struct config *get_config(void); | |||
#endif |
@ -1,202 +0,0 @@ | |||
/* | |||
* Copyright (C) 2017 jianhui zhao <zhaojh329@gmail.com> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
*/ | |||
#include <linux/init.h> | |||
#include <linux/module.h> | |||
#include <linux/version.h> | |||
#include <linux/ip.h> | |||
#include <linux/tcp.h> | |||
#include <linux/udp.h> | |||
#include <net/netfilter/nf_nat.h> | |||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0) | |||
#include <net/netfilter/nf_nat_l3proto.h> | |||
#endif | |||
#include "utils.h" | |||
#include "config.h" | |||
#define IPS_HIJACKED (1 << 31) | |||
#define IPS_ALLOWED (1 << 30) | |||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 17, 19) | |||
static u32 wd_nat_setup_info(struct sk_buff *skb, struct nf_conn *ct) | |||
#else | |||
static u32 wd_nat_setup_info(void *priv, struct sk_buff *skb, | |||
const struct nf_hook_state *state, struct nf_conn *ct) | |||
#endif | |||
{ | |||
struct config *conf = get_config(); | |||
struct tcphdr *tcph = tcp_hdr(skb); | |||
union nf_conntrack_man_proto proto; | |||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 17, 19) | |||
struct nf_nat_range2 newrange = {}; | |||
#else | |||
struct nf_nat_range newrange = {}; | |||
#endif | |||
static uint16_t PORT_80 = htons(80); | |||
proto.tcp.port = (tcph->dest == PORT_80) ? htons(conf->port) : htons(conf->ssl_port); | |||
newrange.flags = NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED; | |||
newrange.min_addr.ip = conf->interface_ipaddr; | |||
newrange.max_addr.ip = conf->interface_ipaddr; | |||
newrange.min_proto = proto; | |||
newrange.max_proto = proto; | |||
ct->status |= IPS_HIJACKED; | |||
return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); | |||
} | |||
static u32 wifidog_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) | |||
{ | |||
struct config *conf = get_config(); | |||
struct iphdr *iph = ip_hdr(skb); | |||
struct nf_conn *ct; | |||
struct tcphdr *tcph; | |||
struct udphdr *udph; | |||
enum ip_conntrack_info ctinfo; | |||
static uint16_t PORT_80 = htons(80); /* http */ | |||
static uint16_t PORT_443 = htons(443); /* https */ | |||
static uint16_t PORT_67 = htons(67); /* dhcp */ | |||
static uint16_t PORT_53 = htons(53); /* dns */ | |||
if (unlikely(!conf->enabled)) | |||
return NF_ACCEPT; | |||
if (state->in->ifindex != conf->interface_ifindex) | |||
return NF_ACCEPT; | |||
/* Accept broadcast */ | |||
if (skb->pkt_type == PACKET_BROADCAST || skb->pkt_type == PACKET_MULTICAST) | |||
return NF_ACCEPT; | |||
/* Accept all to local area networks */ | |||
if ((iph->daddr | ~conf->interface_mask) == conf->interface_broadcast) | |||
return NF_ACCEPT; | |||
ct = nf_ct_get(skb, &ctinfo); | |||
if (!ct || (ct->status & IPS_ALLOWED)) | |||
return NF_ACCEPT; | |||
if (ct->status & IPS_HIJACKED) { | |||
if (is_allowed_mac(skb, state)) { | |||
/* Avoid duplication of authentication */ | |||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0) | |||
nf_reset(skb); | |||
#else | |||
nf_reset_ct(skb); | |||
#endif | |||
nf_ct_kill(ct); | |||
} | |||
return NF_ACCEPT; | |||
} else if (ctinfo == IP_CT_NEW && (is_allowed_dest_ip(skb, state) || is_allowed_mac(skb, state))) { | |||
ct->status |= IPS_ALLOWED; | |||
return NF_ACCEPT; | |||
} | |||
switch (iph->protocol) { | |||
case IPPROTO_TCP: | |||
tcph = tcp_hdr(skb); | |||
if(tcph->dest == PORT_53 || tcph->dest == PORT_67) { | |||
ct->status |= IPS_ALLOWED; | |||
return NF_ACCEPT; | |||
} | |||
if (tcph->dest == PORT_80 || tcph->dest == PORT_443) | |||
goto redirect; | |||
else | |||
return NF_DROP; | |||
case IPPROTO_UDP: | |||
udph = udp_hdr(skb); | |||
if(udph->dest == PORT_53 || udph->dest == PORT_67) { | |||
ct->status |= IPS_ALLOWED; | |||
return NF_ACCEPT; | |||
} | |||
return NF_DROP; | |||
default: | |||
ct->status |= IPS_ALLOWED; | |||
return NF_ACCEPT; | |||
} | |||
redirect: | |||
/* all packets from unknown client are dropped */ | |||
if (ctinfo != IP_CT_NEW || (ct->status & IPS_DST_NAT_DONE)) { | |||
pr_debug("dropping packets of suspect stream, src:%pI4, dst:%pI4\n", &iph->saddr, &iph->daddr); | |||
return NF_DROP; | |||
} | |||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 17, 19) | |||
return wd_nat_setup_info(skb, ct); | |||
#else | |||
return nf_nat_ipv4_in(priv, skb, state, wd_nat_setup_info); | |||
#endif | |||
} | |||
static struct nf_hook_ops wifidog_ops __read_mostly = { | |||
.hook = wifidog_hook, | |||
.pf = PF_INET, | |||
.hooknum = NF_INET_PRE_ROUTING, | |||
.priority = NF_IP_PRI_NAT_DST | |||
}; | |||
static int __init wifidog_init(void) | |||
{ | |||
int ret; | |||
ret = init_config(); | |||
if (ret) | |||
return ret; | |||
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 0, 21) | |||
ret = nf_nat_ipv4_register_fn(&init_net, &wifidog_ops); | |||
#elif LINUX_VERSION_CODE > KERNEL_VERSION(4, 17, 19) | |||
ret = nf_nat_l3proto_ipv4_register_fn(&init_net, &wifidog_ops); | |||
#elif LINUX_VERSION_CODE > KERNEL_VERSION(4, 12, 14) | |||
ret = nf_register_net_hook(&init_net, &wifidog_ops); | |||
#else | |||
ret = nf_register_hook(&wifidog_ops); | |||
#endif | |||
if (ret < 0) { | |||
pr_err("can't register hook\n"); | |||
goto remove_config; | |||
} | |||
pr_info("kmod of wifidog is started\n"); | |||
return 0; | |||
remove_config: | |||
deinit_config(); | |||
return ret; | |||
} | |||
static void __exit wifidog_exit(void) | |||
{ | |||
deinit_config(); | |||
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 0, 21) | |||
nf_nat_ipv4_unregister_fn(&init_net, &wifidog_ops); | |||
#elif LINUX_VERSION_CODE > KERNEL_VERSION(4, 17, 19) | |||
nf_nat_l3proto_ipv4_unregister_fn(&init_net, &wifidog_ops); | |||
#elif LINUX_VERSION_CODE > KERNEL_VERSION(4, 12, 14) | |||
nf_unregister_net_hook(&init_net, &wifidog_ops); | |||
#else | |||
nf_unregister_hook(&wifidog_ops); | |||
#endif | |||
pr_info("kmod of wifidog-ng is stop\n"); | |||
} | |||
module_init(wifidog_init); | |||
module_exit(wifidog_exit); | |||
MODULE_AUTHOR("jianhui zhao <zhaojh329@gmail.com>"); | |||
MODULE_LICENSE("GPL"); |
@ -1,60 +0,0 @@ | |||
/* | |||
* Copyright (C) 2017 jianhui zhao <zhaojh329@gmail.com> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License version 2 as | |||
* published by the Free Software Foundation. | |||
*/ | |||
#ifndef __UTILS_H_ | |||
#define __UTILS_H_ | |||
#include <linux/netfilter/ipset/ip_set.h> | |||
static inline int wd_ip_set_test(const char *name, const struct sk_buff *skb, | |||
struct ip_set_adt_opt *opt, const struct nf_hook_state *state) | |||
{ | |||
static struct xt_action_param par = { }; | |||
struct ip_set *set = NULL; | |||
ip_set_id_t index; | |||
int ret; | |||
index = ip_set_get_byname(state->net, name, &set); | |||
if (!set) | |||
return 0; | |||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) | |||
par.net = state->net; | |||
#else | |||
par.state = state; | |||
#endif | |||
ret = ip_set_test(index, skb, &par, opt); | |||
ip_set_put_byindex(state->net, index); | |||
return ret; | |||
} | |||
static inline int is_allowed_mac(struct sk_buff *skb, const struct nf_hook_state *state) | |||
{ | |||
static struct ip_set_adt_opt opt = { | |||
.family = NFPROTO_IPV4, | |||
.dim = IPSET_DIM_ONE, | |||
.flags = IPSET_DIM_ONE_SRC, | |||
.ext.timeout = UINT_MAX, | |||
}; | |||
return wd_ip_set_test("wifidog-ng-mac", skb, &opt, state); | |||
} | |||
static inline int is_allowed_dest_ip(struct sk_buff *skb, const struct nf_hook_state *state) | |||
{ | |||
static struct ip_set_adt_opt opt = { | |||
.family = NFPROTO_IPV4, | |||
.dim = IPSET_DIM_ONE, | |||
.ext.timeout = UINT_MAX, | |||
}; | |||
return wd_ip_set_test("wifidog-ng-ip", skb, &opt, state); | |||
} | |||
#endif |