mirror of
https://github.com/openNDS/openNDS.git
synced 2026-01-14 14:27:53 -05:00
Merge branch 'master' into production
This commit is contained in:
12
AUTHORS
12
AUTHORS
@@ -1,8 +1,12 @@
|
||||
On the Nodogsplash project:
|
||||
Moritz Warning <moritzwarning@web.de>
|
||||
Shiao-An Yuan <shiao.an.yuan@gmail.com>
|
||||
Fred Moyer <fred@slwifi.com>
|
||||
Paul Kube <nodogsplash@kokoro.ucsd.edu>
|
||||
Active:
|
||||
Alexander Couzens <lynxis@fe80.eu>
|
||||
Moritz Warning <moritzwarning@web.de>
|
||||
Rob White <dot@blue-wave.net>
|
||||
Inactive:
|
||||
Shiao-An Yuan <shiao.an.yuan@gmail.com>
|
||||
Fred Moyer <fred@slwifi.com>
|
||||
Paul Kube <nodogsplash@kokoro.ucsd.edu>
|
||||
|
||||
On the WifiDog project:
|
||||
Philippe April <papril777@yahoo.com>
|
||||
|
||||
45
ChangeLog
45
ChangeLog
@@ -1,3 +1,43 @@
|
||||
nodogsplash (3.0.0)
|
||||
|
||||
* Removed settings without implementation due to the change of the http library:
|
||||
DecongestHttpdThreads, HttpdThreadthreshold, HttpdThreaddelayms
|
||||
AuthenticateImmediately, RemoteAuthenticatorAction, EnablePreAuth,
|
||||
BinVoucher, ForceVoucher, PasswordAuthentication, UsernameAuthentication,
|
||||
PasswordAttempts, Username, Password
|
||||
* Add binauth feature as a replacement for the old binvoucher feature
|
||||
* call a script with username/password to decide the authentication
|
||||
* Replace ClientForceTimeout setting with SessionTimeout
|
||||
* Replace ClientTimeout settings with PreauthIdleTimeout and AuthedIdleTimeout
|
||||
|
||||
-- Moritz Warning <moritzwarning@web.de> Tue, 31 July 2018 19:19:00 +0000
|
||||
|
||||
nodogsplash (2.1.1)
|
||||
|
||||
* Update nodogsplash.conf for non-OpenWrt builds
|
||||
* Minor cosmetic changes
|
||||
|
||||
-- Rob White <dot@blue-wave.net> Sat, 12 May 2018 10:03:00 +0000
|
||||
|
||||
nodogsplash (2.1.0)
|
||||
|
||||
* Allow firewall rule chaining, PR #231 [bluewavenet]
|
||||
* OpenWrt: Add hook to allow firewall to restart nodogsplash after configuring additional rules, PR https://github.com/openwrt-routing/packages/pull/369 [bluewavenet]
|
||||
* OpenWrt: Add support for mwan3(v2) and sqm-scripts, PR https://github.com/openwrt-routing/packages/pull/359 [bluewavenet]
|
||||
* Update documentation [bluewavenet]
|
||||
* Enable TCP Fast Open, PR #237 [blogcin]
|
||||
* Avoid continuous thread creation for control interface, PR #238 [blogcin]
|
||||
* Fix possible memory corruption for long config file path, PR #240 [blogcin]
|
||||
|
||||
-- Moritz Warning <moritzwarning@web.de> Tue, 08 May 2018 19:19:00 +0000
|
||||
|
||||
nodogsplash (2.0.1)
|
||||
|
||||
* Added Forwarding Authentication Service (FAS). [bluewavenet]
|
||||
* Support for external (to NDS) authentication without using Binvoucher. [bluewavenet]
|
||||
* Fix crash when mimetype is not found. [azsde]
|
||||
|
||||
-- Rob White <dot@blue-wave.net> Thu, 28 Dec 2017 11:36:10 +0000
|
||||
|
||||
nodogsplash (2.0.0)
|
||||
|
||||
@@ -13,8 +53,11 @@ nodogsplash (2.0.0)
|
||||
* add debian support including systemd [efernandesng]
|
||||
* fix file descriptor leak [sfstudio]
|
||||
* fix uncomplete console output [mwarning]
|
||||
* update splash.html (#152) [bluewavenet]
|
||||
* fw_iptables: fix iptables syntax for 1.6.1 [mwarning]
|
||||
* fix CheckInterval option (#168) [zaolin]
|
||||
|
||||
-- Alexander Couzens <lynxis@fe80.eu> Thu, 10 Nov 2016 12:23:42 +0100
|
||||
-- Alexander Couzens <lynxis@fe80.eu> Mon, 29 May 2017 12:23:42 +0100
|
||||
|
||||
nodogsplash (1.0.0)
|
||||
|
||||
|
||||
10
Makefile
10
Makefile
@@ -12,7 +12,7 @@ NDS_OBJS=src/auth.o src/client_list.o src/commandline.o src/conf.o \
|
||||
src/debug.o src/firewall.o src/fw_iptables.o src/gateway.o src/http_microhttpd.o src/http_microhttpd_utils.o \
|
||||
src/ndsctl_thread.o src/safe.o src/tc.o src/util.o src/template.o
|
||||
|
||||
.PHONY: all clean install checkastyle fixstyle
|
||||
.PHONY: all clean install checkastyle fixstyle deb
|
||||
|
||||
all: nodogsplash ndsctl
|
||||
|
||||
@@ -33,7 +33,7 @@ install:
|
||||
#ifeq(yes,$(STRIP))
|
||||
strip nodogsplash
|
||||
strip ndsctl
|
||||
#endif
|
||||
#endif
|
||||
mkdir -p $(DESTDIR)/usr/bin/
|
||||
cp ndsctl $(DESTDIR)/usr/bin/
|
||||
cp nodogsplash $(DESTDIR)/usr/bin/
|
||||
@@ -70,10 +70,10 @@ fixstyle: checkastyle
|
||||
echo "\033[1;33mPrevious files have been corrected\033[00m" ; else \
|
||||
echo "\033[0;32mAll files are ok\033[00m" ; fi
|
||||
|
||||
DEBVERSION=$(shell dpkg-parsechangelog | grep ^Version |cut -f2 -d\ | sed -e 's/-[0-9]*$$//' )
|
||||
DEBVERSION=$(shell dpkg-parsechangelog | awk -F'[ -]' '/^Version/{print($$2); exit;}' )
|
||||
deb: clean
|
||||
mkdir -p dist/nodogsplash-$(DEBVERSION)
|
||||
tar --exclude dist --exclude ".git*" -cf - . | (cd dist/nodogsplash-$(DEBVERSION) && tar xf -)
|
||||
cd dist && tar cjf nodogsplash_$(DEBVERSION).orig.tar.bz2 nodogsplash-$(DEBVERSION)
|
||||
cd dist/nodogsplash-$(DEBVERSION) && dpkg-buildpackage -us -uc
|
||||
cd dist && tar cjf nodogsplash_$(DEBVERSION).orig.tar.bz2 nodogsplash-$(DEBVERSION) && cd -
|
||||
cd dist/nodogsplash-$(DEBVERSION) && dpkg-buildpackage -us -uc && cd -
|
||||
rm -rf dist/nodogsplash-$(DEBVERSION)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
##0. The Nodogsplash project
|
||||
## 0. The Nodogsplash project
|
||||
|
||||
Nodogsplash offers a simple way to provide restricted access to an internet
|
||||
connection. It is derived from the codebase of the Wifi Guard Dog project.
|
||||
@@ -12,7 +12,7 @@ Nodogsplash is released under the GNU General Public License.
|
||||
The following describes what Nodogsplash does, how to get it and run it, and
|
||||
how to customize its behavior for your application.
|
||||
|
||||
##1. Overview
|
||||
## 1. Overview
|
||||
|
||||
Nodogsplash offers a solution to this problem: You want to provide controlled
|
||||
and reasonably secure public access to an internet connection; and while you
|
||||
@@ -32,7 +32,7 @@ Specific features of Nodogsplash are configurable, by editing the configuration
|
||||
file and the splash page. The default installed configuration may be all you
|
||||
need, though.
|
||||
|
||||
##2. Documentation
|
||||
## 2. Documentation
|
||||
|
||||
For additonal documentation please look at https://nodogsplash.readthedocs.io/en/latest/
|
||||
|
||||
|
||||
5
debian/README.md
vendored
5
debian/README.md
vendored
@@ -1,9 +1,10 @@
|
||||
|
||||
To create a Debian package of NoDogSplash (a *.deb file),
|
||||
To create a Debian package of NoDogSplash (a \*.deb file),
|
||||
you first need to have installed the following programs and libraries:
|
||||
|
||||
```
|
||||
apt-get install build-essential debhelper devscripts hardening-includes
|
||||
apt install build-essential debhelper devscripts
|
||||
apt install libmicrohttpd-dev dh-systemd
|
||||
```
|
||||
|
||||
Run this command in the repository root folder to create the package:
|
||||
|
||||
31
debian/changelog
vendored
31
debian/changelog
vendored
@@ -1,5 +1,29 @@
|
||||
nodogsplash (2.1.1-1) stable; urgency=medium
|
||||
|
||||
nodogsplash (2.0.0) stable; urgency=low
|
||||
* Update nodogsplash.conf for non-OpenWrt builds [bluewavenet]
|
||||
* Minor cosmetic changes
|
||||
|
||||
-- Rob White <dot@blue-wave.net> Sat, 12 May 2018 10:03:00 +0000
|
||||
|
||||
nodogsplash (2.1.0-1) UNRELEASED; urgency=medium
|
||||
|
||||
* Allow firewall rule chaining, PR #231 [bluewavenet]
|
||||
* Update documentation [bluewavenet]
|
||||
* Enable TCP Fast Open, PR #237 [blogcin]
|
||||
* Avoid continuous thread creation for control interface, PR #238 [blogcin]
|
||||
* Fix possible memory corruption for long config file path, PR #240 [blogcin]
|
||||
|
||||
-- Moritz Warning <moritzwarning@web.de> Tue, 08 May 2018 19:19:00 +0000
|
||||
|
||||
nodogsplash (2.0.1-1) stable; urgency=medium
|
||||
|
||||
* Added Forwarding Authentication Service (FAS). [bluewavenet]
|
||||
* Support for external (to NDS) authentication without using Binvoucher. [bluewavenet]
|
||||
* Fix crash when mimetype is not found. [azsde]
|
||||
|
||||
-- Moritz Warning <moritzwarning@web.de> Tue, 02 Jan 2018 08:31:52 -0500
|
||||
|
||||
nodogsplash (2.0.0-1) stable; urgency=low
|
||||
|
||||
* replace libhttp by libmicrohttpd [lynxis]
|
||||
* implement string replace based template engine [lynxis]
|
||||
@@ -12,8 +36,11 @@ nodogsplash (2.0.0) stable; urgency=low
|
||||
* prevent possible divison by zero and negative durations [mwarning]
|
||||
* add debian support including systemd [efernandesng]
|
||||
* fix file descriptor leak [sfstudio]
|
||||
* update splash.html (#152) [bluewavenet]
|
||||
* fw_iptables: fix iptables syntax for 1.6.1 [mwarning]
|
||||
* fix CheckInterval option (#168) [zaolin]
|
||||
|
||||
-- Alexander Couzens <lynxis@fe80.eu> Thu, 10 Nov 2016 12:23:42 +0100
|
||||
-- Alexander Couzens <lynxis@fe80.eu> Mon, 29 May 2017 12:23:42 +0100
|
||||
|
||||
nodogsplash (1.0.0-1) stable; urgency=low
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
Authentication
|
||||
##############
|
||||
|
||||
Site-wide username and password
|
||||
*******************************
|
||||
|
||||
Nodogsplash can be configured to require a username and/or password to be
|
||||
entered on the splash page as part of the authentication process. Since the
|
||||
username and password are site-wide (not per user), and they are sent in the
|
||||
clear using HTTP GET, this is not a secure mechanism.
|
||||
To enable this, edit *nodogsplash.conf* to set parameters *PasswordAuthentication*,
|
||||
*UsernameAuthentication*, *Password*, *Username*, and *PasswordAttempts* as desired.
|
||||
Then the splash page must use a GET-method HTML form to send user-entered
|
||||
username and/or password as values of variables *nodoguser* and *nodogpass*
|
||||
respectively, along with others as required, to the server. For example:
|
||||
|
||||
.. code::
|
||||
|
||||
<form method='GET' action='$authaction'>
|
||||
<input type='hidden' name='tok' value='$tok'>
|
||||
<input type='hidden' name='redir' value='$redir'>
|
||||
username: <input type='text' name='nodoguser' value='' size='12' maxlength='12'>
|
||||
<br>
|
||||
password: <input type='password' name='nodogpass' value='' size='12' maxlength='10'>
|
||||
<br>
|
||||
<input type='submit' value='Enter'>
|
||||
</form>
|
||||
|
||||
Forwarding authentication
|
||||
*************************
|
||||
|
||||
Nodogsplash allows to call an external program for authentication using
|
||||
the options BinVoucher/EnablePreAuth/ForceVoucher in nodogsplash.conf.
|
||||
The given program for BinVoucher will be called using the clients MAC address as argument.
|
||||
The output is expected to be the number of seconds the client is to be authenticated.
|
||||
It may also contain the clients download and upload speed limit in KBits/s.
|
||||
See the example configuration file for further details.
|
||||
81
docs/source/binauth.rst
Normal file
81
docs/source/binauth.rst
Normal file
@@ -0,0 +1,81 @@
|
||||
BinAuth Option
|
||||
=================
|
||||
|
||||
**Key: BinAuth**
|
||||
|
||||
**Value: /path/to/executable/script**
|
||||
|
||||
Authenticate a client using an external program that get passed the (optional) username and password value.
|
||||
The exit code and output values of the program decide if and how a client is to be authenticated.
|
||||
|
||||
For the following examples, setting `binauth` in nodogsplash.conf is set to `/etc/nds_auth.sh`:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
METHOD="$1"
|
||||
MAC="$2"
|
||||
|
||||
case "$METHOD" in
|
||||
"client_auth")
|
||||
USERNAME="$3"
|
||||
PASSWORD="$4"
|
||||
if [ "$USERNAME" = "Bill" -a "$PASSWORD" = "tms" ]; then
|
||||
# Allow client to access the Internet for one hour (3600 seconds)
|
||||
# Further values are upload and download limits in bytes. 0 for no limit.
|
||||
echo 3600 0 0
|
||||
fi
|
||||
;;
|
||||
"idle_timeout")
|
||||
INGOING_BYTES="$3"
|
||||
OUTGOING_BYTES="$4"
|
||||
DURATION_SECONDS="$5"
|
||||
# The client was deauthenticated after DURATION_SECONDS seconds because of inactivity
|
||||
;;
|
||||
"session_end")
|
||||
INGOING_BYTES="$3"
|
||||
OUTGOING_BYTES="$4"
|
||||
DURATION_SECONDS="$5"
|
||||
# The client was deauthenticated after DURATION_SECONDS seconds because the session ended
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
The splash.html page contains the following code:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<form method='GET' action='$authaction'>
|
||||
<input type='hidden' name='tok' value='$tok'>
|
||||
<input type='hidden' name='redir' value='$redir'>
|
||||
username: <input type='text' name='username' value='' size='12' maxlength='12'>
|
||||
<br>
|
||||
password: <input type='password' name='password' value='' size='12' maxlength='10'>
|
||||
<br>
|
||||
<input type='submit' value='Enter'>
|
||||
</form>
|
||||
|
||||
If a client enters a username 'Bill' and password 'tms', then the configured `binauth` script is executed:
|
||||
|
||||
.. code::
|
||||
|
||||
/etc/nds_auth.sh client_auth 12:34:56:78:90 'Bill' 'tms'
|
||||
|
||||
For the authentication to be successful, the exit code of the script must be 0. The output can be up to three values. First the number of seconds the client is to authenticated, second and third the maximum number of upload and download bytes. Values not given to NDS will resort to default values. Note that the traffic shaping feature does not work right now.
|
||||
|
||||
Nodogsplash will also call the script when the client is deathenticated.
|
||||
|
||||
Client is deauthenticated due to inactivity:
|
||||
|
||||
.. code::
|
||||
|
||||
/etc/nds_auth.sh idle_timeout <mac> <incoming_bytes> <outgoing_bytes> <duration_seconds>
|
||||
|
||||
Client is deauthenticated due to the session end:
|
||||
|
||||
.. code::
|
||||
|
||||
/etc/nds_auth.sh session_end <mac> <incoming_bytes> <outgoing_bytes> <duration_seconds>
|
||||
10
docs/source/checkinterval.rst
Normal file
10
docs/source/checkinterval.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
CheckInterval Option
|
||||
====================
|
||||
|
||||
**Key: CheckInterval**
|
||||
|
||||
**Value: 1 - 2.147.483.647 in seconds**
|
||||
|
||||
This feature was introduced in previous versions of nodogsplash.
|
||||
It was used for the bin voucher support checking for invalidation
|
||||
of clients.
|
||||
@@ -12,8 +12,8 @@ Install libmicrohttpd including the header files (often call -dev package).
|
||||
cd nodogsplash
|
||||
make
|
||||
|
||||
If you installed the libmicrohttpd to another location please like /tmp/libmicrohttpd_install/
|
||||
replace the make call with
|
||||
If you installed the libmicrohttpd to another location (e.g. /tmp/libmicrohttpd_install/)
|
||||
replace path in the make call with
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -24,7 +24,7 @@ After compiling you can call ``make install`` to install nodogsplash to /usr/
|
||||
OpenWrt
|
||||
*******
|
||||
|
||||
To compile nodogsplash please ues the package definiton from the feeds package.
|
||||
To compile nodogsplash please use the package definiton from the feeds package.
|
||||
|
||||
.. code::
|
||||
|
||||
|
||||
@@ -26,6 +26,15 @@ You can, if you don't use:
|
||||
I would like to use QoS or TrafficControl on OpenWrt
|
||||
****************************************************
|
||||
|
||||
This feature is broken since OpenWrt 12.09 (Attitude Adjustment), because
|
||||
OpenWrt removed the IMQ (Intermediate queueing device) support. We're looking
|
||||
for somebody who want to fix that.
|
||||
The original pre version 1 feature has been broken since OpenWrt 12.09 (Attitude Adjustment), because
|
||||
OpenWrt removed the IMQ (Intermediate queueing device) support. We're looking for somebody who to fix this!
|
||||
|
||||
However the OpenWrt package, SQM Scripts, is fully compatible with Nodogsplash and if configured to operate on the Nodogsplash interface (br-lan by default) will provide efficient IP connection based traffic control to ensure fair usage of available bandwidth.
|
||||
|
||||
Is https:// redirection supported?
|
||||
**********************************
|
||||
|
||||
No. We believe this is the wrong way to do it, because all connections would have a critical certificate failure.
|
||||
Https web sites are now more or less a standard and to maintain security and user confidence it is essential that captive portals DO NOT attempt to capture port 443.
|
||||
|
||||
Captive Portal Detection (CPD) has evolved as an enhancement to the network manager component included with major Operating Systems (Linux, Android, iOS/macOS, Windows). Using a pre defined port 80 web page (depending on the vendor) the network manager will detect the presence of a captive portal hotspot and notify the user. In addition, most major browsers now support CPD.
|
||||
|
||||
49
docs/source/fas.rst
Normal file
49
docs/source/fas.rst
Normal file
@@ -0,0 +1,49 @@
|
||||
Forwarding Authentication Service (FAS)
|
||||
#######################################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
Nodogsplash (NDS) can support external (to NDS) authentication.
|
||||
The BinVoucher process was derived to support this and has been called Forwarding Authentication. This is a non trivial function and although partially implemented in early versions, is not implemented at all in version 2, at the time of writing.
|
||||
|
||||
Fortunately, Forwarding Authentication can be done without any modification to the core NDS code and in a way that is compatible with all versions, pre v1 beta through to the current release of v2.
|
||||
|
||||
The defacto industry standard Captive Portal Detection (CPD), present on almost all devices these days, invokes the NDS splash page with various parameters passed to the splash page by NDS, including the client access token.
|
||||
|
||||
It is a simple matter to pass this token to an external Forwarding Authentication Service (FAS) by using a redirect in the splash page.
|
||||
|
||||
For a client to access this external service, the ip address and port number of the service must be added to the NDS walled garden in nodogsplash.conf or its equivalent UCI config file if running under LEDE/OpenWrt.
|
||||
|
||||
Included are various configuration files and remote php scripts, intended as an example implementation of FAS to demonstrate the methods.
|
||||
|
||||
FAS Installation
|
||||
****************
|
||||
NOTE: USING HTTPS. Your FAS can be an https server, but self signed certificates will throw dire "Here Be Dragons" warnings on your client devices when the redirection to your FAS takes place. Also even if using a registered CA all browsers will still return a security error on returning to Nodogsplash. This can be prevented by using wget to return to Nodogsplash from your FAS script instead of an html GET.
|
||||
|
||||
The contents of the FAS etc folder should be placed in the /etc folder of your NoDogSplash router, overwriting existing files.
|
||||
|
||||
The following two files should be edited as follows.
|
||||
|
||||
1:
|
||||
/etc/config/nodogsplash should be edited to reflect the ip address and port of your FAS service as described in the comments in the example file.
|
||||
Your FAS can reside on your Nodogsplash router, a web server on your LAN, or a web server on the internet.
|
||||
|
||||
2:
|
||||
/etc/nodogsplash/htdocs/splash.html should also be edited to reflect the URL of your FAS service as indicated in the comments in the example file.
|
||||
Take note of the USING HTTPS warning above. A typical URL could be http://my-fas.net/nodog/fas.php?auth.... etc.
|
||||
|
||||
Running FAS on your Nodogsplash router:
|
||||
The example FAS service will run fairly well on uhttpd (the web server that serves Luci) on an LEDE/OpenWrt supported device with 8MB flash and 32MB ram but shortage of ram may well be an issue if more than two or three clients log in at the same time. For this reason a device with a minimum of 16MB flash and 64MB ram is recommended.
|
||||
|
||||
Running on uhttpd:
|
||||
Install the modules php7 and php7-cgi on LEDE for the simple example. Further modules may be required when you write your own php scripts depending on your requirements.
|
||||
To enable php in uhttpd you must add the line:
|
||||
list interpreter ".php=/usr/bin/php-cgi"
|
||||
to the /etc/config/uhttpd file in the config uhttpd 'main' or first section.
|
||||
|
||||
Finally, reboot the router to start NoDogSplash in FAS mode.
|
||||
|
||||
The example file "users.dat" contains a list of usernames and passwords.
|
||||
|
||||
NOTE: /etc/config/nodogsplash contains the line "option enabled 1". If you have done something wrong and locked yourself out, you can still SSH to your router and stop NoDogSplash (ndsctl stop) to fix the problem.
|
||||
@@ -28,7 +28,8 @@ Contents:
|
||||
compile
|
||||
faq
|
||||
howitworks
|
||||
authentication
|
||||
fas
|
||||
binauth
|
||||
ndsctl
|
||||
customize
|
||||
debug
|
||||
|
||||
@@ -1,49 +1,57 @@
|
||||
Installing nodogsplash
|
||||
Installing Nodogsplash
|
||||
######################
|
||||
|
||||
OpenWrt
|
||||
OpenWrt (LEDE)
|
||||
*******
|
||||
|
||||
* Have a router working with OpenWrt. Nodogsplash has been compiled against a
|
||||
OpenWrt Attitude Adjustment buildroot; it may or may not work on other versions
|
||||
of OpenWrt or on other kinds of Linux-based router firmware. For notes on
|
||||
using Nodogsplash with OpenWrt Kamikaze, see below.
|
||||
* Have a router working with OpenWrt. At the time of writing, Nodogsplash has been tested with OpenWrt/LEDE 17.01.4;
|
||||
it may or may not work on older versions of OpenWrt or on other kinds of Linux-based router firmware.
|
||||
* Make sure your router is basically working before you try to install
|
||||
nodogsplash. In particular, make sure your DHCP daemon is serving addresses
|
||||
on the interface that nodogsplash will manage (typically br-lan or eth1), and
|
||||
for the following use ssh or telnet access to your router over a different
|
||||
interface.
|
||||
* To install nodogsplash, obtain the nodogsplash*.ipk package you want to
|
||||
install from the project website, copy it to /tmp/ on your OpenWrt router,
|
||||
and, in as root on the router, run:
|
||||
Nodogsplash. In particular, make sure your DHCP daemon is serving addresses on the interface that nodogsplash will manage.
|
||||
The default is br-lan but can be changed to any interface by editing the /etc/config/nodogsplash file.
|
||||
* To install Nodogsplash, you may use the OpenWrt Luci web interface or alternatively, ssh to your router and run the command:
|
||||
|
||||
``opkg install /tmp/nodogsplash*.ipk``
|
||||
``opkg update``
|
||||
|
||||
followed by
|
||||
|
||||
``opkg install nodogsplash`` (for version 1x).
|
||||
|
||||
or
|
||||
|
||||
``opkg install nodogsplash2`` (for version 2x).
|
||||
|
||||
* Nodogsplash is enabled by default and will start automatically on reboot or can be started and stopped manually.
|
||||
|
||||
|
||||
(Note: to prevent installation of an older package, you may have to remove
|
||||
references to remote package repositories in your /etc/opkg.conf file)
|
||||
* If the interface that you want nodogsplash to manage is not br-lan,
|
||||
edit /etc/nodogsplash/nodogsplash.conf and set GatewayInterface.
|
||||
* To start nodogsplash, run the following, or just reboot the router:
|
||||
* If the interface that you want Nodogsplash to manage is not br-lan,
|
||||
edit /etc/config/nodogsplash and set GatewayInterface.
|
||||
* To start Nodogsplash, run the following, or just reboot the router:
|
||||
|
||||
``/etc/init.d/nodogsplash start``
|
||||
|
||||
* To test the installation, connect a client machine to the interface on your
|
||||
router that is managed by nodogsplash (for example, connect to the router's
|
||||
wireless lan) and in a browser on that machine, attempt to visit any website.
|
||||
You should see the nodogsplash splash page instead. Click on the icon; the
|
||||
browser should redirect to the initially requested website.
|
||||
* To stop nodogsplash:
|
||||
* To test the installation, connect a client device to the interface on your
|
||||
router that is managed by Nodogsplash (for example, connect to the router's
|
||||
wireless lan).
|
||||
Most client device operating systems and browsers support Captive Portal Detection (CPD) and the operating system or browser on that device will attempt to contact a pre defined port 80 web page.
|
||||
CPD will trigger Nodogsplash to serve the default splash page where you can click or tap Continue to access the Internet.
|
||||
|
||||
See the Authentication section for details of setting up a proper authentication process.
|
||||
|
||||
If your client device does not display the splash page it most likely does not support CPD. You should then manually trigger Nodogsplash by trying to access a port 80 web site (for example, google.com:80 is a good choice).
|
||||
|
||||
* To stop Nodogsplash:
|
||||
|
||||
``/etc/init.d/nodogsplash stop``
|
||||
|
||||
* To uninstall nodogsplash:
|
||||
* To uninstall Nodogsplash:
|
||||
|
||||
``opkg remove nodogsplash``
|
||||
|
||||
Debian
|
||||
******
|
||||
|
||||
There isn't a packet in the repostiory (yet). But we have support for a debian package.
|
||||
There isn't a package in the repository (yet). But we have support for a debian package.
|
||||
Requirements beside debian tools are:
|
||||
|
||||
- libmicrohttpd-dev (>= 0.9.51) [avaiable in **stretch**]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Overview
|
||||
########
|
||||
|
||||
Nodogsplash offers a solution to this problem: You want to provide controlled
|
||||
Nodogsplash (NDS) offers a solution to this problem: You want to provide controlled
|
||||
and reasonably secure public access to an internet connection; and while you
|
||||
want to require users to give some acknowledgment of the service you are
|
||||
providing, you don't need or want the complexity of user account names and
|
||||
@@ -18,3 +18,9 @@ you don't want to grant all of your available upload or download bandwidth.
|
||||
Specific features of Nodogsplash are configurable, by editing the configuration
|
||||
file and the splash page. The default installed configuration may be all you
|
||||
need, though.
|
||||
|
||||
Nodogsplash supports multiple means of authentication:
|
||||
|
||||
- hit the submit button (default)
|
||||
- call an external script that may accept username/password
|
||||
- forwarding authentication to an external service
|
||||
|
||||
62
forward_authentication_service/FAS-Docs/readme
Normal file
62
forward_authentication_service/FAS-Docs/readme
Normal file
@@ -0,0 +1,62 @@
|
||||
Forwarding Authentication Service (FAS)
|
||||
|
||||
Author: Rob White - BlueWave Projects and Services
|
||||
Copyright (C) 2015-2017 BlueWave Projects and Services. This software is released under the GNU GPL license.
|
||||
|
||||
Nodogsplash (NDS) can support external (to NDS) authentication.
|
||||
|
||||
The BinVoucher process was derived to support this and has been called Forwarding Authentication. This is a non trivial function and although partially implemented in early versions, is not implemented in version 2, at the time of writing.
|
||||
|
||||
########################################################################################
|
||||
Fortunately, Forwarding Authentication can be done without any modification to the core NDS code and in a way that is compatible with all versions, pre v1 beta through to the current release of v2.
|
||||
########################################################################################
|
||||
|
||||
The defacto industry standard Captive Portal Detection (CPD), present on almost all devices these days, invokes the NDS splash page with various parameters passed to it by NDS, including the client access token.
|
||||
|
||||
It is a simple matter to pass this token to an external Forwarding Authentication Service (FAS) by using a redirect in the splash page.
|
||||
|
||||
For a client to access this external service, the ip address and port number of the service must be added to the NDS walled garden in nodogsplash.conf or its equivalent UCI config file if running under LEDE/OpenWrt.
|
||||
|
||||
Included are various configuration files and remote php scripts, intended as an example implementation of FAS to demonstrate the methods.
|
||||
|
||||
############
|
||||
INSTALLATION
|
||||
############
|
||||
|
||||
NOTE: USING HTTPS
|
||||
Your FAS can be an https server, but self signed certificates will throw dire "Here Be Dragons" warnings on your client devices when the redirection to your FAS takes place. Also even if using a registered CA all browsers will still return a security error on returning to Nodogsplash. This can be prevented by using wget to return to Nodogsplash from your FAS script instead of an html GET.
|
||||
|
||||
The contents of the etc folder should be placed in the /etc folder of your NoDogSplash router, overwriting existing files.
|
||||
|
||||
The following two files should be edited as follows.
|
||||
|
||||
1:
|
||||
/etc/config/nodogsplash should be edited to reflect the ip address and port of your FAS service as described in the comments in the example file.
|
||||
Your FAS can reside on your Nodogsplash router, a web server on your LAN, or a web server on the internet.
|
||||
|
||||
2:
|
||||
/etc/nodogsplash/htdocs/splash.html should also be edited to reflect the URL of your FAS service as indicated in the comments in the example file.
|
||||
Take note of the https warning in 1: above. A typical URL could be http://my-fas.net/nodog/fas.php?auth.... etc.
|
||||
|
||||
3:
|
||||
Run the command "chmod +x /etc/init.d/nodogsplash" on your router.
|
||||
|
||||
Running FAS on your Nodogsplash router:
|
||||
The example FAS service will run fairly well on uhttpd (the web server that serves Luci) on an LEDE/OpenWrt supported device with 8MB flash and 32MB ram but shortage of ram may well be an issue if more than two or three clients log in at the same time. For this reason a device with a minimum of 16MB flash and 64MB ram is recommended.
|
||||
|
||||
Running on uhttpd:
|
||||
Install the modules php7 and php7-cgi on LEDE for the simple example. Further modules may be required when you write your own php scripts depending on your requirements.
|
||||
To enable php in uhttpd you must add the line:
|
||||
list interpreter ".php=/usr/bin/php-cgi"
|
||||
to the /etc/config/uhttpd file in the config uhttpd 'main' or first section.
|
||||
|
||||
Finally, reboot the router to start NoDogSplash in FAS mode.
|
||||
|
||||
The example file "users.dat" contains a list of usernames and passwords.
|
||||
|
||||
NOTE: /etc/config/nodogsplash contains the line "option enabled 1". If you have done something wrong and locked yourself out, you can still SSH to your router and stop NoDogSplash (ndsctl stop) to fix the problem.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
70
forward_authentication_service/etc/config/nodogsplash
Normal file
70
forward_authentication_service/etc/config/nodogsplash
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
# The options available here are an adaptation of the settings used in nodogsplash.conf.
|
||||
# See https://github.com/nodogsplash/nodogsplash/blob/master/resources/nodogsplash.conf
|
||||
# 2 Example entries added to allow preauthenticated clients access to the Forwarding Authentication Service
|
||||
|
||||
config nodogsplash
|
||||
# Set to 1 to enable nodogsplash
|
||||
option enabled 1
|
||||
|
||||
# Use plain configuration file
|
||||
#option config '/etc/nodogsplash/nodogsplash.conf'
|
||||
|
||||
# The network the users are connected to
|
||||
option network 'lan'
|
||||
option gatewayname 'NodogsplashFAS'
|
||||
option maxclients '250'
|
||||
option clientidletimeout '1200'
|
||||
|
||||
# Your router may have several interfaces, and you
|
||||
# probably want to keep them private from the network/gatewayinterface.
|
||||
# If so, you should block the entire subnets on those interfaces, e.g.:
|
||||
#list authenticated_users 'block to 192.168.0.0/16'
|
||||
#list authenticated_users 'block to 10.0.0.0/8'
|
||||
|
||||
# Typical ports you will probably want to open up.
|
||||
#list authenticated_users 'allow tcp port 22'
|
||||
#list authenticated_users 'allow tcp port 53'
|
||||
#list authenticated_users 'allow udp port 53'
|
||||
#list authenticated_users 'allow tcp port 80'
|
||||
#list authenticated_users 'allow tcp port 443'
|
||||
list authenticated_users 'allow all'
|
||||
|
||||
# For preauthenticated users to resolve IP addresses in their
|
||||
# initial request not using the router itself as a DNS server,
|
||||
#list preauthenticated_users 'allow tcp port 53'
|
||||
#list preauthenticated_users 'allow udp port 53'
|
||||
|
||||
############ FAS ############
|
||||
# Allow preauthenticated users access to the Forwarding Authentiation service
|
||||
#
|
||||
# The following line allows access to the FAS wherever it is running but must be the port and ip address of FAS
|
||||
# The example here [allow tcp port 80 to 46.32.240.37] was a live demonstration available at the time of writing
|
||||
# It may still be available, try it and see.
|
||||
list preauthenticated_users 'allow tcp port 80 to 46.32.240.37'
|
||||
|
||||
# The following line is REQUIRED if the FAS is running ON THE SAME DEVICE as NDS
|
||||
# and is the TCP *port* of the FAS service if not listed elsewhere in the users_to_router section
|
||||
#list users_to_router 'allow tcp port 4280'
|
||||
############ FAS ############
|
||||
|
||||
# Allow ports for SSH/Telnet/DNS/DHCP/HTTP/HTTPS
|
||||
list users_to_router 'allow tcp port 22'
|
||||
list users_to_router 'allow tcp port 23'
|
||||
list users_to_router 'allow tcp port 53'
|
||||
list users_to_router 'allow udp port 53'
|
||||
list users_to_router 'allow udp port 67'
|
||||
list users_to_router 'allow tcp port 80'
|
||||
list users_to_router 'allow tcp port 443'
|
||||
|
||||
|
||||
# MAC addresses that are / are not allowed to access the splash page
|
||||
# Value is either 'allow' or 'block'. The allowedmac or blockedmac list is used.
|
||||
#option macmechanism 'allow'
|
||||
#list allowedmac '00:00:C0:01:D0:0D'
|
||||
#list allowedmac '00:00:C0:01:D0:1D'
|
||||
#list blockedmac '00:00:C0:01:D0:2D'
|
||||
|
||||
#MAC addresses that do not need to authenticate
|
||||
#list trustedmac '00:00:C0:01:D0:1D'
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
The nodogsplash server may signal an exception by serving
|
||||
this page to the user, with variables title and content
|
||||
intended to indicate the category and detailed message
|
||||
corresponding to the exception.
|
||||
Available variables:
|
||||
gatewayname: $gatewayname
|
||||
version: $version
|
||||
title: $title
|
||||
content: $content
|
||||
imagesdir: $imagesdir
|
||||
pagesdir: $pagesdir
|
||||
userurl: $redir
|
||||
-->
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Something Went Wrong.</title>
|
||||
<style>
|
||||
body
|
||||
{
|
||||
background-color:lightgrey;
|
||||
color:black;
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
text-align: left;
|
||||
}
|
||||
input[type=button]
|
||||
{
|
||||
color:black;
|
||||
margin-left: 0%; margin-right: 5%;
|
||||
text-align:left;
|
||||
font-size: 1.0em; line-height: 2.5em;
|
||||
font-weight: bold;
|
||||
border: 1px solid;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p><b>$gatewayname Hotspot Gateway.</b>
|
||||
<br><br><b>
|
||||
<span style="color:red; font-style:normal;">
|
||||
Sorry! Something seems to have gone wrong.
|
||||
</span>
|
||||
</b></p>
|
||||
<hr><b>The most likely cause is that your connection timed out.<br>
|
||||
Please click the button to try again.</b><br><br>
|
||||
|
||||
<form>
|
||||
<input type="button" value="Continue" onClick="window.location.href='http://detectportal.firefox.com/'">
|
||||
</form>
|
||||
<hr>
|
||||
|
||||
<b>Received Error: $content<br>Software version: $version</b>
|
||||
|
||||
<hr>Copyright (C) 2004-2016. This software is released under the GNU GPL license.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- Edit the NDS config file, then edit the following line to reflect the location of fas.php eg URL='http://my-fas.net/nodog/fas.php?auth....-->
|
||||
<meta http-equiv="refresh" content="0;URL='http://onboard-wifi.net/nodog/fas.php?authaction=$authaction&gatewayname=$gatewayname&tok=$tok&redir=$redir&mac=$clientmac&ip=$clientip'" />
|
||||
<!-- The redirect URL above points to a demo FAS, available at the time of writing -->
|
||||
|
||||
<link rel='shortcut icon' href='images/splash.jpg' type='image/x-icon' />
|
||||
<title>Login Required On This Network</title>
|
||||
<style>
|
||||
body
|
||||
{
|
||||
background-color:lightgrey;
|
||||
color:black;
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
text-align: left;
|
||||
}
|
||||
hr
|
||||
{
|
||||
display: block;
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-style: inset;
|
||||
border-width: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<br><br>
|
||||
<hr>
|
||||
<b>Redirecting....</b>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
101
forward_authentication_service/nodog/css.php
Normal file
101
forward_authentication_service/nodog/css.php
Normal file
@@ -0,0 +1,101 @@
|
||||
body {
|
||||
background-color:lightgrey;
|
||||
color:black;
|
||||
font-family: Arial, 'Arial Black', sans-serif;
|
||||
}
|
||||
|
||||
input[type=text], input[type=email], input[type=password] {
|
||||
margin-left: 0%; margin-right: 0%;
|
||||
text-align:left;
|
||||
display: left;
|
||||
font-size: 1em;
|
||||
line-height: 1em;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
height: 1.5em;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
border: 1px solid #bbb;
|
||||
}
|
||||
|
||||
input[type=submit], input[type=button], input[type=file], button[type=link], select[type=list] {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
margin-left: 0%;
|
||||
margin-right: 5%;
|
||||
text-align:left;
|
||||
display: left;
|
||||
font-size: 1em;
|
||||
line-height: 1em;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
height: 1.5em;
|
||||
width: auto;
|
||||
max-width: 95%;
|
||||
background: #fdfdfd;
|
||||
background: -moz-linear-gradient(top, #fdfdfd 0%, #bebebe 100%);
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fdfdfd), color-stop(100%,#bebebe));
|
||||
background: -webkit-linear-gradient(top, #fdfdfd 0%,#bebebe 100%);
|
||||
background: -o-linear-gradient(top, #fdfdfd 0%,#bebebe 100%);
|
||||
background: -ms-linear-gradient(top, #fdfdfd 0%,#bebebe 100%);
|
||||
background: linear-gradient(to bottom, #fdfdfd 0%,#bebebe 100%);
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
}
|
||||
|
||||
.box
|
||||
{
|
||||
border: 2px solid #aaa;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
min-width:200px;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 500px) {
|
||||
.box {max-width:50%;}
|
||||
}
|
||||
|
||||
textarea
|
||||
{
|
||||
width: 97%;
|
||||
margin-left:0%;
|
||||
margin-right:0%;
|
||||
}
|
||||
|
||||
img
|
||||
{
|
||||
width: 100%;
|
||||
margin-left:0%;
|
||||
margin-right:0%;
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color:red;
|
||||
color:white;
|
||||
}
|
||||
|
||||
hr {
|
||||
display:block;
|
||||
margin-top:0.5em;
|
||||
margin-bottom:0.5em;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
border-style:inset;
|
||||
border-width:5px;
|
||||
}
|
||||
|
||||
.offset {
|
||||
max-width:400px;
|
||||
min-width:200px;
|
||||
margin: auto;
|
||||
|
||||
}
|
||||
|
||||
@media screen and (min-width: 2500px) {
|
||||
body {font-size: 2em;}
|
||||
}
|
||||
|
||||
|
||||
148
forward_authentication_service/nodog/fas.php
Normal file
148
forward_authentication_service/nodog/fas.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
// (c) Blue Wave Projects and Services 2015-2017." This software is released under the GNU GPL license.
|
||||
//Functions
|
||||
|
||||
//Set some defaults etc.
|
||||
date_default_timezone_set("UTC");
|
||||
$gatewayname=$tok=$tokchk=$redir=$orgurl=$authaction=$clientip=$clientmac=$username=$password="";
|
||||
|
||||
if(isset($_SERVER['HTTPS'])){$protocol="https://";}else{$protocol="http://";}
|
||||
$host=$_SERVER['HTTP_HOST'];
|
||||
$me=$_SERVER['SCRIPT_NAME'];
|
||||
$home=str_replace("fas.php","",$_SERVER['SCRIPT_NAME']);
|
||||
$redirscript=str_replace("fas.php","landing.php",$_SERVER['SCRIPT_NAME']);
|
||||
$landing=$protocol.$host.$redirscript;
|
||||
$validated="not tested";
|
||||
$header="Forwarding Authentication Service";
|
||||
if(isset($_GET['gatewayname'])){$gatewayname=$_GET['gatewayname'];}
|
||||
else{$gatewayname="NoDogSplash";}
|
||||
if(isset($_GET['tok'])){$tok=$_GET['tok'];}
|
||||
if(isset($_GET['tokchk'])){$tokchk=$_GET['tokchk'];}
|
||||
if(isset($_GET['redir'])){$redir=$_GET['redir'];}
|
||||
if(isset($_GET['orgurl'])){$orgurl=$_GET['orgurl'];}
|
||||
if(isset($_GET['authaction'])){$authaction=$_GET['authaction'];}
|
||||
if(isset($_GET['clientip'])){$clientip=$_GET['clientip'];}
|
||||
if(isset($_GET['clientmac'])){$clientmac=$_GET['clientmac'];}
|
||||
|
||||
if (isset($_POST['username']))
|
||||
{
|
||||
$username=$_POST['username'];
|
||||
$password=$_POST['password'];
|
||||
$gatewayname=$_POST['gatewayname'];
|
||||
$tok=$_POST['tok'];
|
||||
$tokchk=$_POST['tokchk'];
|
||||
$redir=$_POST['redir'];
|
||||
$orgurl=$_POST['orgurl'];
|
||||
$authaction=$_POST['authaction'];
|
||||
$clientip=$_POST['clientip'];
|
||||
$clientmac=$_POST['clientmac'];
|
||||
}
|
||||
$users=$_SERVER['DOCUMENT_ROOT'].$home."users.dat";
|
||||
|
||||
function read_terms() {
|
||||
//display the terms of sevrvice
|
||||
echo("\n<form>\n<input type=\"button\" VALUE=\"Read Terms of Service\" onClick=\"location.href='tos.php'\" >\n</form>\n");
|
||||
}
|
||||
|
||||
function acceptance($landing, $gatewayname, $tok, $tokchk, $redir, $orgurl, $authaction, $clientip, $clientmac, $username, $password) {
|
||||
read_terms();
|
||||
echo("\n<br>\n<form method='GET' action='" . $authaction . "'>\n");
|
||||
echo("<input type='hidden' name='tok' value='" . $tok . "'>\n");
|
||||
echo("<input type='hidden' name='redir' value='".$landing."?userurl=".$redir."&tok=".$tok."&orgurl=".$redir."&clientip=".$clientip."&clientmac=".$clientmac."&username=".$username."&gatewayname=".$gatewayname."&tokchk=true'>\n");
|
||||
echo("<input type='submit' value='Accept Terms of Service'>\n</form>\n");
|
||||
}//end of function acceptance
|
||||
|
||||
function login($gatewayname, $tok, $tokchk, $redir, $orgurl, $authaction, $clientip, $clientmac, $username, $password) {
|
||||
$me=$_SERVER['SCRIPT_NAME'];
|
||||
echo ("<form action=\"".$me."\" method=\"post\" >\n");
|
||||
echo ("<input type=\"hidden\" name=\"gatewayname\" value=\"" . $gatewayname . "\">\n");
|
||||
echo ("<input type=\"hidden\" name=\"tok\" value=\"" . $tok . "\">\n");
|
||||
echo ("<input type=\"hidden\" name=\"tokchk\" value=\"" . $tokchk . "\">\n");
|
||||
echo ("<input type=\"hidden\" name=\"redir\" value=\"" . $redir . "\">\n");
|
||||
echo ("<input type=\"hidden\" name=\"orgurl\" value=\"" . $orgurl . "\">\n");
|
||||
echo ("<input type=\"hidden\" name=\"authaction\" value=\"" . $authaction . "\">\n");
|
||||
echo ("<input type=\"hidden\" name=\"clientip\" value=\"" . $clientip . "\">\n");
|
||||
echo ("<input type=\"hidden\" name=\"clientmac\" value=\"" . $clientmac . "\">\n");
|
||||
echo"<hr>Username:<br>";
|
||||
echo ("<input type=\"text\" name=\"username\" value=\"" . htmlentities($username) . "\">\n<br>\n");
|
||||
echo"Password:<br>";
|
||||
echo ("<input type=\"password\" name=\"password\" value=\"" . htmlentities($password) . "\">\n<br><br>\n");
|
||||
echo ("<input type=\"submit\" value=\"Log In\">\n</form>\n<hr>\n");
|
||||
}//end of function login
|
||||
|
||||
// Add headers to stop browsers from cacheing
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Cache-Control: no-cache");
|
||||
header("Pragma: no-cache");
|
||||
|
||||
//Output our responsive page
|
||||
echo"<!DOCTYPE html>\n<html>\n<head>\n";
|
||||
echo"<meta charset=\"utf-8\" />\n";
|
||||
echo"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
|
||||
echo"<title>".$header.".</title>\n";
|
||||
echo"<style>\n";
|
||||
include("css.php");
|
||||
echo"\n</style>\n</head>\n<body>\n";
|
||||
|
||||
//page header
|
||||
echo "<div class=\"offset\">\n";
|
||||
echo "<hr><b style=\"color:blue;\">".$gatewayname." </b><br><b>".$header."</b><br><hr>\n";
|
||||
echo"<div class=\"box\" style=\"max-width:100%;\">\n";
|
||||
//end of page header
|
||||
|
||||
################## check for invalid token return in NDS V2 ###################
|
||||
#NDS V2 does not check for invalid (timed out) tokens so we have to check here#
|
||||
if (isset($_GET['tokchk'])){
|
||||
$userurl=$_GET['orgurl'];
|
||||
include "oops-ndsv2.php";
|
||||
}
|
||||
############### end of check for invalid token return in NDS V2 ###############
|
||||
|
||||
//Example Simple Login Form that checks in a plain text file for username and login
|
||||
if (isset($_POST['username']))//Validate user supplied username and password
|
||||
{
|
||||
if ($username!="")//username is set to something
|
||||
{
|
||||
if (file_exists($users))//read the file line by line
|
||||
{
|
||||
$handle=fopen($users,'r');
|
||||
|
||||
while(! feof($handle))
|
||||
{
|
||||
$line=fgets($handle);
|
||||
if (feof($handle)){break;}
|
||||
list($user,$pass)=explode(", ",$line);
|
||||
if($username==trim($user) and $password==trim($pass)){$validated="yes"; break;}
|
||||
}//end while not eof
|
||||
if($validated!="yes"){$validated="no";}
|
||||
fclose($handle);
|
||||
|
||||
}//end if user database exists
|
||||
else{echo"<br><b>Missing User Database</b><br>";}
|
||||
}//end if username is set to something
|
||||
else{$validated="no";}
|
||||
}//end if username set
|
||||
else{//Initial Form
|
||||
echo"<b>Enter Username and Password</b>";
|
||||
login($gatewayname, $tok, $tokchk, $redir, $orgurl, $authaction, $clientip, $clientmac, $username, $password);
|
||||
}//end else initial form
|
||||
|
||||
if($validated=="yes")
|
||||
{
|
||||
echo"<b style=\"color:red;\">Successful Login</b><hr>";
|
||||
acceptance($landing, $gatewayname, $tok, $tokchk, $redir, $orgurl, $authaction, $clientip, $clientmac, $username, $password);
|
||||
}
|
||||
if($validated=="no")
|
||||
{
|
||||
echo"<b style=\"color:red;\">Invalid login attempt</b>";
|
||||
login($gatewayname, $tok, $tokchk, $redir, $orgurl, $authaction, $clientip, $clientmac, $username, "");
|
||||
}
|
||||
|
||||
echo"</div>\n";
|
||||
echo "<div style=\"font-size:0.7em;\">\n";
|
||||
echo "© Blue Wave Projects and Services 2015-".date("Y")." This software is released under the GNU GPL license.\n";
|
||||
echo"</div>\n";
|
||||
echo"</div>\n";
|
||||
|
||||
echo"</body>\n</html>\n";
|
||||
?>
|
||||
56
forward_authentication_service/nodog/landing.php
Normal file
56
forward_authentication_service/nodog/landing.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
// (c) Blue Wave Projects and Services 2015-2017." This software is released under the GNU GPL license.
|
||||
//Set some defaults etc.
|
||||
date_default_timezone_set("UTC");
|
||||
$gatewayname=$tok=$tokchk=$orgurl=$clientip=$clientmac=$username=$password="";
|
||||
$scriptname=str_replace("landing.php","css.php",$_SERVER['SCRIPT_NAME']);
|
||||
$css=$_SERVER['DOCUMENT_ROOT'].$scriptname;
|
||||
|
||||
$header="Forwarding Authentication Landing Page";
|
||||
|
||||
function read_terms() {
|
||||
//display the terms of sevrvice
|
||||
echo("\n<form>\n<input type=\"button\" VALUE=\"Read Terms of Service\" onClick=\"location.href='tos.php'\" >\n</form>\n");
|
||||
}
|
||||
|
||||
|
||||
if(isset($_GET['gatewayname'])){$gatewayname=$_GET['gatewayname'];}
|
||||
else{$gatewayname="NoDogSplash";}
|
||||
if(isset($_GET['tok'])){$tok=$_GET['tok'];}
|
||||
if(isset($_GET['tokchk'])){$tokchk=$_GET['tokchk'];}
|
||||
if(isset($_GET['orgurl'])){$orgurl=$_GET['orgurl'];}
|
||||
if(isset($_GET['clientip'])){$clientip=$_GET['clientip'];}
|
||||
if(isset($_GET['clientmac'])){$clientmac=$_GET['clientmac'];}
|
||||
if(isset($_GET['username'])){$username=$_GET['username'];}
|
||||
|
||||
// Add headers to stop browsers from cacheing
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Cache-Control: no-cache");
|
||||
header("Pragma: no-cache");
|
||||
|
||||
//Output our responsive page
|
||||
echo"<!DOCTYPE html>\n<html>\n<head>\n";
|
||||
echo"<meta charset=\"utf-8\" />\n";
|
||||
echo"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
|
||||
echo"<title>".$header.".</title>\n";
|
||||
echo"<style>\n";
|
||||
include("css.php");
|
||||
echo"\n</style>\n</head>\n<body>\n";
|
||||
|
||||
//page header
|
||||
echo "<div class=\"offset\">\n";
|
||||
echo "<hr><b style=\"color:blue;\">".$gatewayname." </b><br><b>".$header."</b><br><hr>\n";
|
||||
echo"<div class=\"box\" style=\"max-width:100%;\">\n";
|
||||
//end of page header
|
||||
|
||||
echo"<hr><b style=\"font-size:1.25em;color:red;\">Welcome \"".$username."\".<br> You are logged in.</b><br><hr>";
|
||||
echo"<b style=\"font-size:1em;color:black;\">Thank you for accepting the Terms of Service.<br><br>You can now use your browser and device APPs as you normally would.</b><hr>";
|
||||
read_terms();
|
||||
|
||||
echo"<hr></div>\n";
|
||||
echo "<div style=\"font-size:0.7em;\">\n";
|
||||
echo "© Blue Wave Projects and Services 2015-".date("Y")." This software is released under the GNU GPL license.";
|
||||
echo"</div>\n";
|
||||
echo"</body></html>";
|
||||
?>
|
||||
|
||||
11
forward_authentication_service/nodog/oops-ndsv2.php
Normal file
11
forward_authentication_service/nodog/oops-ndsv2.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
echo"<b><span style=\"color:red; font-style:normal;\">Sorry! Something seems to have gone wrong!</span></b>";
|
||||
echo"<br><b>Most likely your connection timed out.<br>Please click the button to try again.</b>";
|
||||
echo"<form>";
|
||||
echo"<INPUT TYPE=\"button\" VALUE=\"Continue\" onClick=\"window.location.href='".$orgurl."'\">";
|
||||
echo"</form>";
|
||||
exit();
|
||||
?>
|
||||
|
||||
|
||||
|
||||
91
forward_authentication_service/nodog/tos.php
Normal file
91
forward_authentication_service/nodog/tos.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Terms of Service</title>
|
||||
|
||||
<style>
|
||||
<?php
|
||||
$scriptname=str_replace("tos.php","css.php",$_SERVER['SCRIPT_NAME']);
|
||||
$css=$_SERVER['DOCUMENT_ROOT'].$scriptname;
|
||||
include("css.php");
|
||||
?>
|
||||
p {text-align: left; margin-left: 0%; margin-right: 0%}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
echo "<div class=\"offset\">";
|
||||
echo"<hr><b>Terms of Service for use of this Hotspot.</b> <hr><b>Access is granted on a basis of trust that you will NOT misuse or abuse that access in any way.</b><hr><b>";
|
||||
|
||||
echo"<b>Please scroll down to read the Terms of Service in full or click the Continue button to return to the Acceptance Page</b>";
|
||||
#echo"<hr>";
|
||||
echo"<FORM>";
|
||||
echo"<INPUT TYPE=\"button\" VALUE=\"Continue\" onClick=\"history.go(-1);return true;\">";
|
||||
echo"</FORM>";
|
||||
|
||||
echo"<hr><b>Proper Use</b>";
|
||||
|
||||
echo"<p>This Hotspot provides a wireless network that allows you to connect to the Internet. <br>
|
||||
<b>Use of this Internet connection is provided in return for your FULL acceptance of these Terms Of Service.</b></p>";
|
||||
|
||||
echo "<p><b>You agree</b> that you are responsible for providing security measures that are suited for your intended use of the Service. For example, you shall take full responsibility for taking adequate measures to safeguard your data from loss.</p>";
|
||||
|
||||
echo "<p>While the Hotspot uses commercially reasonable efforts to provide a secure service, the effectiveness of those efforts cannot be guaranteed.
|
||||
</p>";
|
||||
|
||||
echo "<p> <b>You may</b> use the technology provided to you by this Hotspot for the sole purpose of using the Service as described here. You must immediately notify the Owner of any unauthorized use of the Service or any other security breach.<br><br>We will give you an IP address each time you access the Hotspot, and it may change.
|
||||
<br><b>You shall not</b> program any other IP or MAC address into your device that accesses the Hotspot. You may not use the Service for any other reason, including reselling any aspect of the Service. Other examples of improper activities include, without limitation:</p>";
|
||||
?>
|
||||
<ol>
|
||||
<li>downloading or uploading such large volumes of data that the performance of the Service becomes noticeably degraded for other users for a significant period;</li>
|
||||
|
||||
<li>attempting to break security, access, tamper with or use any unauthorized areas of the Service;</li>
|
||||
|
||||
<li>removing any copyright, trademark or other proprietary rights notices contained in or on the Service;</li>
|
||||
|
||||
<li>attempting to collect or maintain any information about other users of the Service (including usernames and/or email addresses) or other third parties for unauthorized purposes; </li>
|
||||
|
||||
<li>logging onto the Service under false or fraudulent pretenses;</li>
|
||||
|
||||
<li>creating or transmitting unwanted electronic communications such as SPAM or chain letters to other users or otherwise interfering with other user's enjoyment of the service;</li>
|
||||
|
||||
<li>transmitting any viruses, worms, defects, Trojan Horses or other items of a destructive nature; or </li>
|
||||
|
||||
<li>using the Service for any unlawful, harassing, abusive, criminal or fraudulent purpose. </li>
|
||||
</ol>
|
||||
|
||||
<hr><b>Content Disclaimer</b>
|
||||
|
||||
<?php
|
||||
echo"<p>The Hotspot Owners do not control and are not responsible for data, content, services, or products that are accessed or downloaded through the Service. The Owners may, but are not obliged to, block data transmissions to protect the Owner and the Public. </p>
|
||||
The Owners, their suppliers and their licensors expressly disclaim to the fullest extent permitted by law, all express, implied, and statutary warranties, including, without limitation, the warranties of merchantability or fitness for a particular purpose.
|
||||
<br><br>The Owners, their suppliers and their licensors expressly disclaim to the fullest extent permitted by law any liability for infringement of proprietory rights and/or infringement of Copyright by any user of the system. Login details and device identities may be stored and be used as evidence in a Court of Law against such users.<br>";
|
||||
|
||||
echo"<hr><b>Limitation of Liability</b>
|
||||
<p>Under no circumstances shall the Owners, their suppliers or their licensors be liable to any user or any third party on account of that party's use or misuse of or reliance on the Service.
|
||||
</p>";
|
||||
|
||||
echo "<hr><b>Changes to Terms of Service and Termination</b>\n<p>We may modify or terminate the Service and these Terms of Service and any accompanying policies, for any reason, and without notice, including the right to terminate with or without notice, without liability to you, any user or any third party. Please review these Terms of Service from time to time so that you will be apprised of any changes.</p>\n";
|
||||
|
||||
echo "<p>We reserve the right to terminate your use of the Service, for any reason, and without notice. Upon any such termination, any and all rights granted to you by this Hotspot Owner shall terminate.</p>\n";
|
||||
|
||||
echo"<hr><b>Indemnity</b>";
|
||||
$indemnitystr="<p><b>You agree</b> to hold harmless and indemnify the Owners of this Hotspot, their suppliers and licensors from and against any third party claim arising from or in any way related to your use of the Service, including any liability or expense arising from all claims, losses, damages (actual and consequential), suits, judgments, litigation costs and legal fees, of every kind and nature.</p>\n";
|
||||
echo $indemnitystr;
|
||||
|
||||
echo"<hr>";
|
||||
echo"<form>";
|
||||
echo"<INPUT TYPE=\"button\" VALUE=\"Continue\" onClick=\"history.go(-1);return true;\">";
|
||||
echo"</form>\n<hr>\n";
|
||||
echo"</div>\n";
|
||||
echo("</body>\n</html>\n");
|
||||
?>
|
||||
|
||||
|
||||
|
||||
|
||||
6
forward_authentication_service/nodog/users.dat
Normal file
6
forward_authentication_service/nodog/users.dat
Normal file
@@ -0,0 +1,6 @@
|
||||
tom, letmein
|
||||
dick, 123456
|
||||
harry, abcdefg
|
||||
gemima, puddleduck23
|
||||
jennie, StarShipFreedom
|
||||
judith, heyjude1968
|
||||
6
forward_authentication_service/readme
Normal file
6
forward_authentication_service/readme
Normal file
@@ -0,0 +1,6 @@
|
||||
Forwarding Authentication Service (FAS)
|
||||
|
||||
Author: Rob White @bluewavenet - BlueWave Projects and Services
|
||||
Copyright (C) 2015-2017 BlueWave Projects and Services. This software is released under the GNU GPL license.
|
||||
|
||||
Nodogsplash (NDS) can support external (to NDS) authentication without using the Binvoucher functionality.
|
||||
@@ -8,8 +8,7 @@
|
||||
# GatewayInterface is not autodetected, has no default, and must be set here.
|
||||
# Set GatewayInterface to the interface on your router
|
||||
# that is to be managed by Nodogsplash.
|
||||
# Typically br0 for the wired and wireless lan on OpenWrt White Russian.
|
||||
# May be br-lan on OpenWrt Kamikaze.
|
||||
# Typically br-lan for the wired and wireless lan.
|
||||
#
|
||||
GatewayInterface br-lan
|
||||
|
||||
@@ -31,32 +30,33 @@ GatewayInterface br-lan
|
||||
#
|
||||
FirewallRuleSet authenticated-users {
|
||||
|
||||
# You may want to open access to a machine on a local
|
||||
# subnet that is otherwise blocked (for example, to
|
||||
# serve a redirect page; see RedirectURL). If so,
|
||||
# allow that explicitly here, e.g:
|
||||
# FirewallRule allow tcp port 80 to 192.168.254.254
|
||||
# You may want to open access to a machine on a local
|
||||
# subnet that is otherwise blocked (for example, to
|
||||
# serve a redirect page; see RedirectURL). If so,
|
||||
# allow that explicitly here, e.g:
|
||||
# FirewallRule allow tcp port 80 to 192.168.254.254
|
||||
|
||||
# Your router may have several interfaces, and you
|
||||
# probably want to keep them private from the GatewayInterface.
|
||||
# If so, you should block the entire subnets on those interfaces, e.g.:
|
||||
FirewallRule block to 192.168.0.0/16
|
||||
FirewallRule block to 10.0.0.0/8
|
||||
# Your router may have several interfaces, and you
|
||||
# probably want to keep them private from the GatewayInterface.
|
||||
# If so, you should block the entire subnets on those interfaces, e.g.:
|
||||
# FirewallRule block to 192.168.0.0/16
|
||||
# FirewallRule block to 10.0.0.0/8
|
||||
|
||||
# Typical ports you will probably want to open up include
|
||||
# 53 udp and tcp for DNS,
|
||||
# 80 for http,
|
||||
# 443 for https,
|
||||
# 22 for ssh:
|
||||
FirewallRule allow tcp port 53
|
||||
FirewallRule allow udp port 53
|
||||
FirewallRule allow tcp port 80
|
||||
FirewallRule allow tcp port 443
|
||||
FirewallRule allow tcp port 22
|
||||
|
||||
# You might use ipset to easily allow/block range of ips, e.g.:
|
||||
# FirewallRule allow ipset WHITELISTED_IPS
|
||||
# FirewallRule allow tcp port 80 ipset WHITELISTED_IPS
|
||||
# Typical ports you will probably want to open up include
|
||||
# 53 udp and tcp for DNS,
|
||||
# 80 for http,
|
||||
# 443 for https,
|
||||
# 22 for ssh:
|
||||
# FirewallRule allow tcp port 53
|
||||
# FirewallRule allow udp port 53
|
||||
# FirewallRule allow tcp port 80
|
||||
# FirewallRule allow tcp port 443
|
||||
# FirewallRule allow tcp port 22
|
||||
# Or for happy customers allow all
|
||||
FirewallRule allow all
|
||||
# You might use ipset to easily allow/block range of ips, e.g.:
|
||||
# FirewallRule allow ipset WHITELISTED_IPS
|
||||
# FirewallRule allow tcp port 80 ipset WHITELISTED_IPS
|
||||
}
|
||||
# end FirewallRuleSet authenticated-users
|
||||
|
||||
@@ -78,18 +78,19 @@ FirewallRuleSet authenticated-users {
|
||||
# the authenticated-users and users-to-router rulesets.
|
||||
#
|
||||
FirewallRuleSet preauthenticated-users {
|
||||
# For preauthenticated users to resolve IP addresses in their initial
|
||||
# request not using the router itself as a DNS server,
|
||||
# you probably want to allow port 53 udp and tcp for DNS.
|
||||
FirewallRule allow tcp port 53
|
||||
FirewallRule allow udp port 53
|
||||
# For splash page content not hosted on the router, you
|
||||
# will want to allow port 80 tcp to the remote host here.
|
||||
# Doing so circumvents the usual capture and redirect of
|
||||
# any port 80 request to this remote host.
|
||||
# Note that the remote host's numerical IP address must be known
|
||||
# and used here.
|
||||
# FirewallRule allow tcp port 80 to 123.321.123.321
|
||||
# For preauthenticated users to resolve IP addresses in their
|
||||
# initial request not using the router itself as a DNS server.
|
||||
# Leave commented to help prevent DNS tunnelling
|
||||
# FirewallRule allow tcp port 53
|
||||
# FirewallRule allow udp port 53
|
||||
#
|
||||
# For splash page content not hosted on the router, you
|
||||
# will want to allow port 80 tcp to the remote host here.
|
||||
# Doing so circumvents the usual capture and redirect of
|
||||
# any port 80 request to this remote host.
|
||||
# Note that the remote host's numerical IP address must be known
|
||||
# and used here.
|
||||
# FirewallRule allow tcp port 80 to 123.321.123.321
|
||||
}
|
||||
# end FirewallRuleSet preauthenticated-users
|
||||
|
||||
@@ -120,9 +121,9 @@ FirewallRuleSet users-to-router {
|
||||
# You may want to allow ssh, http, and https to the router
|
||||
# for administration from the GatewayInterface. If not,
|
||||
# comment these out.
|
||||
FirewallRule allow tcp port 22
|
||||
FirewallRule allow tcp port 80
|
||||
FirewallRule allow tcp port 443
|
||||
FirewallRule allow tcp port 22
|
||||
FirewallRule allow tcp port 80
|
||||
FirewallRule allow tcp port 443
|
||||
}
|
||||
# end FirewallRuleSet users-to-router
|
||||
|
||||
@@ -197,34 +198,29 @@ FirewallRuleSet users-to-router {
|
||||
# connect at any time. (Does not include users on the TrustedMACList,
|
||||
# who do not authenticate.)
|
||||
#
|
||||
# MaxClients 20
|
||||
MaxClients 250
|
||||
|
||||
# ClientIdleTimeout
|
||||
# Parameter: ClientIdleTimeout
|
||||
# Default: 10
|
||||
# Parameter: SessionTimeout
|
||||
# Default: 0
|
||||
#
|
||||
# Set ClientIdleTimeout to the desired of number of minutes
|
||||
# of inactivity before a user is automatically 'deauthenticated'.
|
||||
# Set the default session length in seconds. A value of 0 is for
|
||||
# sessions without an end.
|
||||
#
|
||||
# ClientIdleTimeout 10
|
||||
|
||||
# Parameter: ClientForceTimeout
|
||||
# Default: 360
|
||||
# Parameter: PreAuthIdleTimeout
|
||||
# Default: 300
|
||||
#
|
||||
# Set ClientForceTimeout to the desired number of minutes before
|
||||
# a user is automatically 'deauthenticated', whether active or not
|
||||
# Set PreAuthIdleTimeout to the desired number of seconds before
|
||||
# an pre-authenticated user is automatically removed from the client list.
|
||||
#
|
||||
# ClientForceTimeout 360
|
||||
|
||||
# Parameter: AuthenticateImmediately
|
||||
# Default: no
|
||||
# Parameter: AuthedIdleTimeout
|
||||
# Default: 7200
|
||||
#
|
||||
# Set to yes (or true or 1), to immediately authenticate users
|
||||
# who make a http port 80 request on the GatewayInterface (that is,
|
||||
# do not serve a splash page, just redirect to the user's request,
|
||||
# or to RedirectURL if set).
|
||||
# Set AuthedIdleTimeout to the desired number of seconds before
|
||||
# an authenticated user is automatically 'deauthenticated'
|
||||
# and removed from the client list.
|
||||
#
|
||||
# AuthenticateImmediately no
|
||||
|
||||
# Parameter: MACMechanism
|
||||
# Default: block
|
||||
@@ -264,47 +260,6 @@ FirewallRuleSet users-to-router {
|
||||
#
|
||||
# TrustedMACList 00:00:CA:FE:BA:BE, 00:00:C0:01:D0:0D
|
||||
|
||||
|
||||
# Parameter: PasswordAuthentication
|
||||
# Default: no
|
||||
# Set to yes (or true or 1), to require a password matching
|
||||
# the Password parameter to be supplied when authenticating.
|
||||
#
|
||||
#
|
||||
# PasswordAuthentication no
|
||||
|
||||
# Parameter: Password
|
||||
# Default: none
|
||||
# Whitespace delimited string that is compared to user-supplied
|
||||
# password when authenticating.
|
||||
#
|
||||
#
|
||||
# Password nodog
|
||||
|
||||
# Parameter: UsernameAuthentication
|
||||
# Default: no
|
||||
# Set to yes (or true or 1), to require a username matching
|
||||
# the Username parameter to be supplied when authenticating.
|
||||
#
|
||||
#
|
||||
# UsernameAuthentication no
|
||||
|
||||
# Parameter: Username
|
||||
# Default: none
|
||||
# Whitespace delimited string that is compared to user-supplied
|
||||
# username when authenticating.
|
||||
#
|
||||
#
|
||||
# Username guest
|
||||
|
||||
# Parameter: PasswordAttempts
|
||||
# Default: 5
|
||||
# Integer number of failed password/username entries before
|
||||
# a user is forced to reauthenticate.
|
||||
#
|
||||
#
|
||||
# PasswordAttempts 5
|
||||
|
||||
# Parameter: TrafficControl
|
||||
# Default: no
|
||||
#
|
||||
@@ -355,49 +310,27 @@ FirewallRuleSet users-to-router {
|
||||
#
|
||||
# ImagesDir images
|
||||
|
||||
# Parameter: BinVoucher
|
||||
# Parameter: BinAuth
|
||||
# Default: None
|
||||
#
|
||||
# Enable Voucher Support.
|
||||
# If set, an alphanumeric voucher HTTP parameter is accepted
|
||||
# and passed to a command line call along with the clients MAC:
|
||||
# Enable BinAuth Support.
|
||||
# If set, a program is called with several parameters on authentication or timeout on inactivity.
|
||||
#
|
||||
# $<BinVoucher> auth_voucher <mac> <voucher>
|
||||
# $<BinAuth> client_auth <mac> '<username>' '<password>''
|
||||
# $<BinAuth> idle_timeout <mac> <incoming_bytes> <outgoing_bytes> <duration_seconds>
|
||||
# $<BinAuth> session_end <mac> <incoming_bytes> <outgoing_bytes> <duration_seconds>
|
||||
#
|
||||
# BinVoucher must point to a program that will be called as described above.
|
||||
# The call is expected to output the number of seconds the client
|
||||
# is to be authenticated. Zero or negative seconds will cause the
|
||||
# authentification request to be rejected.
|
||||
# BinAuth must point to a program that will be called in one of the ways described above.
|
||||
# The username and password values may be empty strings and are URL encoded.
|
||||
# The program is expected to output the number of seconds the client
|
||||
# is to be authenticated. Zero or negative seconds will cause the authentification request
|
||||
# to be rejected. The same goes for an exit code that is not 0.
|
||||
# The output may contain a user specific download and upload limit in KBit/s:
|
||||
# <seconds> <upload> <download>
|
||||
#
|
||||
# BinVoucher "/bin/myauth"
|
||||
|
||||
# Parameter: ForceVoucher
|
||||
# Default: no
|
||||
#
|
||||
# Force the use of a voucher. Authentification is not possible without voucher.
|
||||
#
|
||||
# ForceVoucher no
|
||||
|
||||
# Parameter: EnablePreAuth
|
||||
# Default: no
|
||||
#
|
||||
# Enable pre-authentication support.
|
||||
# Pass the MAC of a client to a command line call before the splash page
|
||||
# would be send:
|
||||
#
|
||||
# $<BinVoucher> auth_status <mac>
|
||||
#
|
||||
# The call is expected to output the number of seconds the client
|
||||
# is to be authenticated. Zero or negative seconds will cause the
|
||||
# splash page to be displayed.
|
||||
# The output may contain a user specific download and upload limit in KBit/s:
|
||||
# <seconds> <download> <upload>
|
||||
#
|
||||
# EnablePreAuth no
|
||||
|
||||
# BinAuth "/bin/myauth.sh"
|
||||
|
||||
# Nodogsplash uses specific values to mark packets using iptables.
|
||||
# Parameter: FW_MARK_BLOCKED
|
||||
# Default: 0x100
|
||||
#
|
||||
@@ -407,6 +340,7 @@ FirewallRuleSet users-to-router {
|
||||
# Parameter: FW_MARK_AUTHENTICATED
|
||||
# Default: 0x400
|
||||
#
|
||||
# Nodogsplash uses specific values to mark packet using iptables.
|
||||
# In rare cases these might conflict with other programs and need
|
||||
# to be changed.
|
||||
# Set FW_MARK for compatibilty with other Packages eg mwan3, sqm etc.
|
||||
fw_mark_authenticated 30000
|
||||
fw_mark_trusted 20000
|
||||
fw_mark_blocked 10000
|
||||
|
||||
@@ -27,10 +27,8 @@ Available variables:
|
||||
|
||||
Additional Variables that can also be passed back via HTTP get.
|
||||
Or just append them to the authentication link:
|
||||
nodoguser
|
||||
nodogpass
|
||||
info
|
||||
voucher
|
||||
username
|
||||
password
|
||||
-->
|
||||
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
|
||||
17
src/auth.c
17
src/auth.c
@@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
/* Defined in clientlist.c */
|
||||
extern pthread_mutex_t client_list_mutex;
|
||||
extern pthread_mutex_t client_list_mutex;
|
||||
|
||||
/* Count number of authentications */
|
||||
unsigned int authenticated_since_start = 0;
|
||||
@@ -61,7 +61,7 @@ thread_client_timeout_check(void *arg)
|
||||
{
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
struct timespec timeout;
|
||||
struct timespec timeout;
|
||||
|
||||
while (1) {
|
||||
debug(LOG_DEBUG, "Running fw_refresh_client_list()");
|
||||
@@ -95,12 +95,11 @@ auth_client_action(const char ip[], const char mac[], t_authaction action)
|
||||
|
||||
LOCK_CLIENT_LIST();
|
||||
|
||||
client = client_list_find(ip,mac);
|
||||
client = client_list_find(ip, mac);
|
||||
|
||||
/* Client should already have hit the server and be on the client list */
|
||||
if (client == NULL) {
|
||||
debug(LOG_ERR, "Client %s %s action %d is not on client list",
|
||||
ip, mac, action);
|
||||
debug(LOG_ERR, "Client %s %s action %d is not on client list", ip, mac, action);
|
||||
UNLOCK_CLIENT_LIST();
|
||||
return;
|
||||
}
|
||||
@@ -108,7 +107,7 @@ auth_client_action(const char ip[], const char mac[], t_authaction action)
|
||||
switch(action) {
|
||||
|
||||
case AUTH_MAKE_AUTHENTICATED:
|
||||
if(client->fw_connection_state != FW_MARK_AUTHENTICATED) {
|
||||
if (client->fw_connection_state != FW_MARK_AUTHENTICATED) {
|
||||
client->fw_connection_state = FW_MARK_AUTHENTICATED;
|
||||
iptables_fw_access(AUTH_MAKE_AUTHENTICATED, client);
|
||||
authenticated_since_start++;
|
||||
@@ -118,15 +117,15 @@ auth_client_action(const char ip[], const char mac[], t_authaction action)
|
||||
break;
|
||||
|
||||
case AUTH_MAKE_DEAUTHENTICATED:
|
||||
if(client->fw_connection_state == FW_MARK_AUTHENTICATED) {
|
||||
if (client->fw_connection_state == FW_MARK_AUTHENTICATED) {
|
||||
iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, client);
|
||||
}
|
||||
client_list_delete(client);
|
||||
break;
|
||||
|
||||
default:
|
||||
debug(LOG_ERR, "Unknown auth action: %d",action);
|
||||
debug(LOG_ERR, "Unknown auth action: %d", action);
|
||||
}
|
||||
|
||||
UNLOCK_CLIENT_LIST();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ _client_list_append(const char ip[], const char mac[], const char token[])
|
||||
|
||||
config = config_get_config();
|
||||
maxclients = config->maxclients;
|
||||
if(client_count >= maxclients) {
|
||||
if (client_count >= maxclients) {
|
||||
debug(LOG_NOTICE, "Already list %d clients, cannot add %s %s", client_count, ip, mac);
|
||||
return NULL;
|
||||
}
|
||||
@@ -133,11 +133,15 @@ _client_list_append(const char ip[], const char mac[], const char token[])
|
||||
client->mac = safe_strdup(mac);
|
||||
client->token = token ? safe_strdup(token) : NULL;
|
||||
client->fw_connection_state = FW_MARK_PREAUTHENTICATED;
|
||||
client->counters.incoming = client->counters.incoming_history = 0;
|
||||
client->counters.outgoing = client->counters.outgoing_history = 0;
|
||||
client->counters.incoming = 0;
|
||||
client->counters.incoming_history = 0;
|
||||
client->counters.outgoing = 0;
|
||||
client->counters.outgoing_history = 0;
|
||||
last_client_time = time(NULL);
|
||||
client->counters.last_updated = last_client_time;
|
||||
client->added_time = last_client_time;
|
||||
/* Session has not started and not ended yet */
|
||||
client->session_start = 0;
|
||||
client->session_end = 0;
|
||||
|
||||
for (i = 0; i < maxclients; i++) {
|
||||
if (client_arr[i])
|
||||
@@ -171,7 +175,7 @@ _client_list_append(const char ip[], const char mac[], const char token[])
|
||||
char *
|
||||
_client_list_make_auth_token(const char ip[], const char mac[])
|
||||
{
|
||||
char *token;
|
||||
char *token = NULL;
|
||||
|
||||
safe_asprintf(&token,"%04hx%04hx", rand16(), rand16());
|
||||
|
||||
@@ -190,7 +194,7 @@ client_list_add_client(const char ip[])
|
||||
t_client *client;
|
||||
char *mac, *token;
|
||||
|
||||
if(!check_ip_format(ip)) {
|
||||
if (!check_ip_format(ip)) {
|
||||
/* Inappropriate format in IP address */
|
||||
debug(LOG_NOTICE, "Illegal IP format [%s]", ip);
|
||||
return NULL;
|
||||
@@ -207,14 +211,13 @@ client_list_add_client(const char ip[])
|
||||
client = _client_list_append(ip, mac, token);
|
||||
free(token);
|
||||
} else {
|
||||
debug(LOG_INFO, "Client %s %s token %s already on client list",
|
||||
ip, mac, client->token);
|
||||
debug(LOG_INFO, "Client %s %s token %s already on client list", ip, mac, client->token);
|
||||
}
|
||||
free(mac);
|
||||
return client;
|
||||
}
|
||||
|
||||
/** Finds a client by its IP and MAC, returns NULL if the client could not
|
||||
/** Finds a client by its IP and MAC, returns NULL if the client could not
|
||||
* be found
|
||||
* @param ip IP we are looking for in the linked list
|
||||
* @param mac MAC we are looking for in the linked list
|
||||
@@ -258,9 +261,9 @@ client_list_find_by_ip(const char ip[])
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a client by its Mac, returns NULL if the client could not
|
||||
* Finds a client by its MAC, returns NULL if the client could not
|
||||
* be found
|
||||
* @param mac Mac we are looking for in the linked list
|
||||
* @param mac MAC we are looking for in the linked list
|
||||
* @return Pointer to the client, or NULL if not found
|
||||
*/
|
||||
t_client *
|
||||
@@ -304,15 +307,15 @@ client_list_find_by_token(const char token[])
|
||||
* @param client Points to the client to be freed
|
||||
*/
|
||||
void
|
||||
_client_list_free_node(t_client * client)
|
||||
_client_list_free_node(t_client *client)
|
||||
{
|
||||
if (client->mac != NULL)
|
||||
if (client->mac)
|
||||
free(client->mac);
|
||||
|
||||
if (client->ip != NULL)
|
||||
if (client->ip)
|
||||
free(client->ip);
|
||||
|
||||
if (client->token != NULL)
|
||||
if (client->token)
|
||||
free(client->token);
|
||||
|
||||
if (client_arr[client->idx] == client)
|
||||
@@ -329,7 +332,7 @@ _client_list_free_node(t_client * client)
|
||||
* @param client Points to the client to be deleted
|
||||
*/
|
||||
void
|
||||
client_list_delete(t_client * client)
|
||||
client_list_delete(t_client *client)
|
||||
{
|
||||
t_client *ptr;
|
||||
|
||||
|
||||
@@ -30,27 +30,26 @@
|
||||
/** Counters struct for a client's bandwidth usage (in bytes)
|
||||
*/
|
||||
typedef struct _t_counters {
|
||||
unsigned long long incoming; /**< @brief Incoming data total*/
|
||||
unsigned long long outgoing; /**< @brief Outgoing data total*/
|
||||
unsigned long long incoming_history; /**< @brief Incoming data before nodogsplash restarted*/
|
||||
unsigned long long outgoing_history; /**< @brief Outgoing data before nodogsplash restarted*/
|
||||
time_t last_updated; /**< @brief Last update of the counters */
|
||||
unsigned long long incoming; /**< @brief Incoming data total*/
|
||||
unsigned long long outgoing; /**< @brief Outgoing data total*/
|
||||
unsigned long long incoming_history; /**< @brief Incoming data before nodogsplash restarted*/
|
||||
unsigned long long outgoing_history; /**< @brief Outgoing data before nodogsplash restarted*/
|
||||
time_t last_updated; /**< @brief Last update of the counters */
|
||||
} t_counters;
|
||||
|
||||
/** Client node for the connected client linked list.
|
||||
*/
|
||||
typedef struct _t_client {
|
||||
struct _t_client *next; /**< @brief Pointer to the next client */
|
||||
char *ip; /**< @brief Client Ip address */
|
||||
char *mac; /**< @brief Client Mac address */
|
||||
char *token; /**< @brief Client token */
|
||||
unsigned int fw_connection_state; /**< @brief Connection state in the firewall */
|
||||
time_t added_time; /**< @brief Time client added to list */
|
||||
t_counters counters; /**< @brief Counters for input/output of
|
||||
the client. */
|
||||
int attempts; /**< @brief Number of authentication attempts */
|
||||
int download_limit; /**< @brief Download limit, kb/s */
|
||||
int upload_limit; /**< @brief Upload limit, kb/s */
|
||||
typedef struct _t_client {
|
||||
struct _t_client *next; /**< @brief Pointer to the next client */
|
||||
char *ip; /**< @brief Client IP address */
|
||||
char *mac; /**< @brief Client MAC address */
|
||||
char *token; /**< @brief Client token */
|
||||
unsigned int fw_connection_state; /**< @brief Connection state in the firewall */
|
||||
time_t session_start; /**< @brief Time the client was authenticated */
|
||||
time_t session_end; /**< @brief Time until client will be deauthenticated */
|
||||
t_counters counters; /**< @brief Counters for input/output of the client. */
|
||||
int download_limit; /**< @brief Download limit, kb/s */
|
||||
int upload_limit; /**< @brief Upload limit, kb/s */
|
||||
int idx;
|
||||
} t_client;
|
||||
|
||||
@@ -71,10 +70,9 @@ t_client *client_list_add_client(const char ip[]);
|
||||
t_client *client_list_find(const char ip[], const char mac[]);
|
||||
|
||||
/** @brief Finds a client only by its IP */
|
||||
t_client *client_list_find_by_ip(const char ip[]); /* needed by fw_iptables.c, auth.c
|
||||
* and ndsctl_thread.c */
|
||||
t_client *client_list_find_by_ip(const char ip[]); /* needed by fw_iptables.c, auth.c * and ndsctl_thread.c */
|
||||
|
||||
/** @brief Finds a client only by its Mac */
|
||||
/** @brief Finds a client only by its MAC */
|
||||
t_client *client_list_find_by_mac(const char mac[]); /* needed by ndsctl_thread.c */
|
||||
|
||||
/** @brief Finds a client by its token */
|
||||
|
||||
@@ -44,16 +44,17 @@ static void usage(void);
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("Usage: nodogsplash [options]\n");
|
||||
printf("\n");
|
||||
printf(" -c [filename] Use this config file\n");
|
||||
printf(" -f Run in foreground\n");
|
||||
printf(" -d <level> Debug level\n");
|
||||
printf(" -s Log to syslog\n");
|
||||
printf(" -w <path> Ndsctl socket path\n");
|
||||
printf(" -h Print usage\n");
|
||||
printf(" -v Print version information\n");
|
||||
printf("\n");
|
||||
printf("Usage: nodogsplash [options]\n"
|
||||
"\n"
|
||||
" -c [filename] Use this config file\n"
|
||||
" -f Run in foreground\n"
|
||||
" -d <level> Debug level\n"
|
||||
" -s Log to syslog\n"
|
||||
" -w <path> Ndsctl socket path\n"
|
||||
" -h Print usage\n"
|
||||
" -v Print version information\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
/** Uses getopt() to parse the command line and set configuration values
|
||||
@@ -75,7 +76,7 @@ void parse_commandline(int argc, char **argv)
|
||||
|
||||
case 'c':
|
||||
if (optarg) {
|
||||
strncpy(config->configfile, optarg, sizeof(config->configfile));
|
||||
strncpy(config->configfile, optarg, sizeof(config->configfile)-1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -101,7 +102,7 @@ void parse_commandline(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
printf("This is nodogsplash version " VERSION "\n");
|
||||
printf("This is Nodogsplash version " VERSION "\n");
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
|
||||
324
src/conf.c
324
src/conf.c
@@ -34,6 +34,9 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ether.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "safe.h"
|
||||
@@ -47,7 +50,7 @@
|
||||
|
||||
/** @internal
|
||||
* Holds the current configuration of the gateway */
|
||||
static s_config config;
|
||||
static s_config config = { 0 };
|
||||
|
||||
/**
|
||||
* Mutex for the configuration file, used by the auth_servers related
|
||||
@@ -63,6 +66,7 @@ static int missing_parms;
|
||||
The different configuration options */
|
||||
typedef enum {
|
||||
oBadOption,
|
||||
oSessionTimeout,
|
||||
oDaemon,
|
||||
oDebugLevel,
|
||||
oMaxClients,
|
||||
@@ -71,25 +75,15 @@ typedef enum {
|
||||
oGatewayIPRange,
|
||||
oGatewayAddress,
|
||||
oGatewayPort,
|
||||
oRemoteAuthenticatorAction,
|
||||
oEnablePreAuth,
|
||||
oBinVoucher,
|
||||
oForceVoucher,
|
||||
oPasswordAuthentication,
|
||||
oUsernameAuthentication,
|
||||
oPasswordAttempts,
|
||||
oUsername,
|
||||
oPassword,
|
||||
oHTTPDMaxConn,
|
||||
oWebRoot,
|
||||
oSplashPage,
|
||||
oImagesDir,
|
||||
oPagesDir,
|
||||
oRedirectURL,
|
||||
oClientIdleTimeout,
|
||||
oClientForceTimeout,
|
||||
oPreauthIdleTimeout,
|
||||
oAuthedIdleTimeout,
|
||||
oCheckInterval,
|
||||
oAuthenticateImmediately,
|
||||
oSetMSS,
|
||||
oMSSValue,
|
||||
oTrafficControl,
|
||||
@@ -97,9 +91,6 @@ typedef enum {
|
||||
oUploadLimit,
|
||||
oUploadIFB,
|
||||
oNdsctlSocket,
|
||||
oDecongestHttpdThreads,
|
||||
oHttpdThreadThreshold,
|
||||
oHttpdThreadDelayMS,
|
||||
oSyslogFacility,
|
||||
oFirewallRule,
|
||||
oFirewallRuleSet,
|
||||
@@ -110,7 +101,8 @@ typedef enum {
|
||||
oAllowedMACList,
|
||||
oFWMarkAuthenticated,
|
||||
oFWMarkTrusted,
|
||||
oFWMarkBlocked
|
||||
oFWMarkBlocked,
|
||||
oBinAuth
|
||||
} OpCodes;
|
||||
|
||||
/** @internal
|
||||
@@ -120,6 +112,7 @@ static const struct {
|
||||
OpCodes opcode;
|
||||
int required;
|
||||
} keywords[] = {
|
||||
{ "sessiontimeout", oSessionTimeout },
|
||||
{ "daemon", oDaemon },
|
||||
{ "debuglevel", oDebugLevel },
|
||||
{ "maxclients", oMaxClients },
|
||||
@@ -128,24 +121,14 @@ static const struct {
|
||||
{ "gatewayiprange", oGatewayIPRange },
|
||||
{ "gatewayaddress", oGatewayAddress },
|
||||
{ "gatewayport", oGatewayPort },
|
||||
{ "remoteauthenticatoraction", oRemoteAuthenticatorAction },
|
||||
{ "enablepreauth", oEnablePreAuth },
|
||||
{ "binvoucher", oBinVoucher },
|
||||
{ "forcevoucher", oForceVoucher },
|
||||
{ "passwordauthentication", oPasswordAuthentication },
|
||||
{ "usernameauthentication", oUsernameAuthentication },
|
||||
{ "passwordattempts", oPasswordAttempts },
|
||||
{ "username", oUsername },
|
||||
{ "password", oPassword },
|
||||
{ "webroot", oWebRoot },
|
||||
{ "splashpage", oSplashPage },
|
||||
{ "imagesdir", oImagesDir },
|
||||
{ "pagesdir", oPagesDir },
|
||||
{ "redirectURL", oRedirectURL },
|
||||
{ "clientidletimeout", oClientIdleTimeout },
|
||||
{ "clientforcetimeout", oClientForceTimeout },
|
||||
{ "preauthidletimeout", oPreauthIdleTimeout },
|
||||
{ "authedidletimeout", oAuthedIdleTimeout },
|
||||
{ "checkinterval", oCheckInterval },
|
||||
{ "authenticateimmediately", oAuthenticateImmediately },
|
||||
{ "setmss", oSetMSS },
|
||||
{ "mssvalue", oMSSValue },
|
||||
{ "trafficcontrol", oTrafficControl },
|
||||
@@ -153,11 +136,7 @@ static const struct {
|
||||
{ "uploadlimit", oUploadLimit },
|
||||
{ "ifb", oUploadIFB },
|
||||
{ "syslogfacility", oSyslogFacility },
|
||||
{ "syslogfacility", oSyslogFacility },
|
||||
{ "ndsctlsocket", oNdsctlSocket },
|
||||
{ "decongesthttpdthreads", oDecongestHttpdThreads },
|
||||
{ "httpdthreadthreshold", oHttpdThreadThreshold },
|
||||
{ "httpdthreaddelayms", oHttpdThreadDelayMS },
|
||||
{ "firewallruleset", oFirewallRuleSet },
|
||||
{ "firewallrule", oFirewallRule },
|
||||
{ "emptyrulesetpolicy", oEmptyRuleSetPolicy },
|
||||
@@ -168,6 +147,7 @@ static const struct {
|
||||
{ "FW_MARK_AUTHENTICATED", oFWMarkAuthenticated },
|
||||
{ "FW_MARK_TRUSTED", oFWMarkTrusted },
|
||||
{ "FW_MARK_BLOCKED", oFWMarkBlocked },
|
||||
{ "binauth", oBinAuth },
|
||||
{ NULL, oBadOption },
|
||||
};
|
||||
|
||||
@@ -200,7 +180,8 @@ config_init(void)
|
||||
t_firewall_ruleset *rs;
|
||||
|
||||
debug(LOG_DEBUG, "Setting default config parameters");
|
||||
strncpy(config.configfile, DEFAULT_CONFIGFILE, sizeof(config.configfile));
|
||||
strncpy(config.configfile, DEFAULT_CONFIGFILE, sizeof(config.configfile)-1);
|
||||
config.session_timeout = DEFAULT_SESSION_TIMEOUT;
|
||||
config.debuglevel = DEFAULT_DEBUGLEVEL;
|
||||
config.maxclients = DEFAULT_MAXCLIENTS;
|
||||
config.gw_name = safe_strdup(DEFAULT_GATEWAYNAME);
|
||||
@@ -208,7 +189,6 @@ config_init(void)
|
||||
config.gw_iprange = safe_strdup(DEFAULT_GATEWAY_IPRANGE);
|
||||
config.gw_address = NULL;
|
||||
config.gw_port = DEFAULT_GATEWAYPORT;
|
||||
config.remote_auth_action = NULL;
|
||||
config.webroot = safe_strdup(DEFAULT_WEBROOT);
|
||||
config.splashpage = safe_strdup(DEFAULT_SPLASHPAGE);
|
||||
config.infoskelpage = safe_strdup(DEFAULT_INFOSKELPAGE);
|
||||
@@ -217,16 +197,10 @@ config_init(void)
|
||||
config.authdir = safe_strdup(DEFAULT_AUTHDIR);
|
||||
config.denydir = safe_strdup(DEFAULT_DENYDIR);
|
||||
config.redirectURL = NULL;
|
||||
config.clienttimeout = DEFAULT_CLIENTTIMEOUT;
|
||||
config.clientforceout = DEFAULT_CLIENTFORCEOUT;
|
||||
config.preauth_idle_timeout = DEFAULT_PREAUTH_IDLE_TIMEOUT,
|
||||
config.authed_idle_timeout = DEFAULT_AUTHED_IDLE_TIMEOUT,
|
||||
config.checkinterval = DEFAULT_CHECKINTERVAL;
|
||||
config.daemon = -1;
|
||||
config.passwordauth = DEFAULT_PASSWORD_AUTH;
|
||||
config.usernameauth = DEFAULT_USERNAME_AUTH;
|
||||
config.passwordattempts = DEFAULT_PASSWORD_ATTEMPTS;
|
||||
config.username = NULL;
|
||||
config.password = NULL;
|
||||
config.authenticate_immediately = DEFAULT_AUTHENTICATE_IMMEDIATELY;
|
||||
config.set_mss = DEFAULT_SET_MSS;
|
||||
config.mss_value = DEFAULT_MSS_VALUE;
|
||||
config.traffic_control = DEFAULT_TRAFFIC_CONTROL;
|
||||
@@ -237,9 +211,6 @@ config_init(void)
|
||||
config.log_syslog = DEFAULT_LOG_SYSLOG;
|
||||
config.ndsctl_sock = safe_strdup(DEFAULT_NDSCTL_SOCK);
|
||||
config.internal_sock = safe_strdup(DEFAULT_INTERNAL_SOCK);
|
||||
config.decongest_httpd_threads = DEFAULT_DECONGEST_HTTPD_THREADS;
|
||||
config.httpd_thread_threshold = DEFAULT_HTTPD_THREAD_THRESHOLD;
|
||||
config.httpd_thread_delay_ms = DEFAULT_HTTPD_THREAD_DELAY_MS;
|
||||
config.rulesets = NULL;
|
||||
config.trustedmaclist = NULL;
|
||||
config.blockedmaclist = NULL;
|
||||
@@ -249,6 +220,7 @@ config_init(void)
|
||||
config.FW_MARK_TRUSTED = DEFAULT_FW_MARK_TRUSTED;
|
||||
config.FW_MARK_BLOCKED = DEFAULT_FW_MARK_BLOCKED;
|
||||
config.ip6 = DEFAULT_IP6;
|
||||
config.bin_auth = NULL;
|
||||
|
||||
/* Set up default FirewallRuleSets, and their empty ruleset policies */
|
||||
rs = add_ruleset("trusted-users");
|
||||
@@ -269,7 +241,9 @@ config_init(void)
|
||||
void
|
||||
config_init_override(void)
|
||||
{
|
||||
if (config.daemon == -1) config.daemon = DEFAULT_DAEMON;
|
||||
if (config.daemon == -1) {
|
||||
config.daemon = DEFAULT_DAEMON;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -280,12 +254,13 @@ config_parse_opcode(const char *cp, const char *filename, int linenum)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; keywords[i].name; i++)
|
||||
if (strcasecmp(cp, keywords[i].name) == 0)
|
||||
for (i = 0; keywords[i].name; i++) {
|
||||
if (strcasecmp(cp, keywords[i].name) == 0) {
|
||||
return keywords[i].opcode;
|
||||
}
|
||||
}
|
||||
|
||||
debug(LOG_ERR, "%s: line %d: Bad configuration option: %s",
|
||||
filename, linenum, cp);
|
||||
debug(LOG_ERR, "%s: line %d: Bad configuration option: %s", filename, linenum, cp);
|
||||
return oBadOption;
|
||||
}
|
||||
|
||||
@@ -321,7 +296,7 @@ add_ruleset(const char rulesetname[])
|
||||
|
||||
ruleset = get_ruleset(rulesetname);
|
||||
|
||||
if(ruleset != NULL) {
|
||||
if (ruleset != NULL) {
|
||||
debug(LOG_DEBUG, "add_ruleset(): FirewallRuleSet %s already exists.", rulesetname);
|
||||
return ruleset;
|
||||
}
|
||||
@@ -338,7 +313,6 @@ add_ruleset(const char rulesetname[])
|
||||
return ruleset;
|
||||
}
|
||||
|
||||
|
||||
/** @internal
|
||||
Parses an empty ruleset policy directive
|
||||
*/
|
||||
@@ -358,7 +332,7 @@ parse_empty_ruleset_policy(char *ptr, const char *filename, int lineno)
|
||||
/* get the ruleset struct with this name; error if it doesn't exist */
|
||||
debug(LOG_DEBUG, "Parsing EmptyRuleSetPolicy for %s", rulesetname);
|
||||
ruleset = get_ruleset(rulesetname);
|
||||
if(ruleset == NULL) {
|
||||
if (ruleset == NULL) {
|
||||
debug(LOG_ERR, "Unrecognized FirewallRuleSet name: %s at line %d in %s", rulesetname, lineno, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
@@ -377,7 +351,7 @@ parse_empty_ruleset_policy(char *ptr, const char *filename, int lineno)
|
||||
"block" means iptables REJECT
|
||||
*/
|
||||
if (ruleset->emptyrulesetpolicy != NULL) free(ruleset->emptyrulesetpolicy);
|
||||
if(!strcasecmp(policy,"passthrough")) {
|
||||
if (!strcasecmp(policy,"passthrough")) {
|
||||
ruleset->emptyrulesetpolicy = safe_strdup("RETURN");
|
||||
} else if (!strcasecmp(policy,"allow")) {
|
||||
ruleset->emptyrulesetpolicy = safe_strdup("ACCEPT");
|
||||
@@ -406,13 +380,13 @@ parse_firewall_ruleset(const char *rulesetname, FILE *fd, const char *filename,
|
||||
|
||||
/* find whitespace delimited word in ruleset string; this is its name */
|
||||
p1 = strchr(rulesetname,' ');
|
||||
if(p1) *p1 = '\0';
|
||||
if (p1) *p1 = '\0';
|
||||
p1 = strchr(rulesetname,'\t');
|
||||
if(p1) *p1 = '\0';
|
||||
if (p1) *p1 = '\0';
|
||||
|
||||
debug(LOG_DEBUG, "Parsing FirewallRuleSet %s", rulesetname);
|
||||
ruleset = get_ruleset(rulesetname);
|
||||
if(ruleset == NULL) {
|
||||
if (ruleset == NULL) {
|
||||
debug(LOG_ERR, "Unrecognized FirewallRuleSet name: %s", rulesetname);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
@@ -424,10 +398,10 @@ parse_firewall_ruleset(const char *rulesetname, FILE *fd, const char *filename,
|
||||
p1 = _strip_whitespace(line);
|
||||
|
||||
/* if nothing left, get next line */
|
||||
if(p1[0] == '\0') continue;
|
||||
if (p1[0] == '\0') continue;
|
||||
|
||||
/* if closing brace, we are done */
|
||||
if(p1[0] == '}') break;
|
||||
if (p1[0] == '}') break;
|
||||
|
||||
/* next, we coopt the parsing of the regular config */
|
||||
|
||||
@@ -435,7 +409,7 @@ parse_firewall_ruleset(const char *rulesetname, FILE *fd, const char *filename,
|
||||
p2 = p1;
|
||||
while ((*p2 != '\0') && (!isblank(*p2))) p2++;
|
||||
/* if this is end of line, it's a problem */
|
||||
if(p2[0] == '\0') {
|
||||
if (p2[0] == '\0') {
|
||||
debug(LOG_ERR, "FirewallRule incomplete on line %d in %s", *linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
@@ -525,7 +499,7 @@ _parse_firewall_rule(t_firewall_ruleset *ruleset, char *leftover)
|
||||
|
||||
/* Get the optional port or port range */
|
||||
if (strncmp(leftover, "port", 4) == 0) {
|
||||
if(protocol == NULL ||
|
||||
if (protocol == NULL ||
|
||||
!(strncmp(protocol, "tcp", 3) == 0 || strncmp(protocol, "udp", 3) == 0)) {
|
||||
debug(LOG_ERR, "Port without tcp or udp protocol");
|
||||
return -3; /*< Fail */
|
||||
@@ -619,7 +593,7 @@ get_empty_ruleset_policy(const char *rulesetname)
|
||||
{
|
||||
t_firewall_ruleset *rs;
|
||||
rs = get_ruleset(rulesetname);
|
||||
if(rs == NULL) return NULL;
|
||||
if (rs == NULL) return NULL;
|
||||
return rs->emptyrulesetpolicy;
|
||||
}
|
||||
|
||||
@@ -683,6 +657,7 @@ config_read(const char *filename)
|
||||
FILE *fd;
|
||||
char line[MAX_BUF], *s, *p1, *p2;
|
||||
int linenum = 0, opcode, value;
|
||||
struct stat sb;
|
||||
|
||||
debug(LOG_INFO, "Reading configuration file '%s'", filename);
|
||||
|
||||
@@ -697,7 +672,7 @@ config_read(const char *filename)
|
||||
s = _strip_whitespace(line);
|
||||
|
||||
/* if nothing left, get next line */
|
||||
if(s[0] == '\0') continue;
|
||||
if (s[0] == '\0') continue;
|
||||
|
||||
/* now we require the line must have form: <option><whitespace><arg>
|
||||
* even if <arg> is just a left brace, for example
|
||||
@@ -707,7 +682,7 @@ config_read(const char *filename)
|
||||
p1 = s;
|
||||
while ((*p1 != '\0') && (!isspace(*p1))) p1++;
|
||||
/* if this is end of line, it's a problem */
|
||||
if(p1[0] == '\0') {
|
||||
if (p1[0] == '\0') {
|
||||
debug(LOG_ERR, "Option %s requires argument on line %d in %s", s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
@@ -724,20 +699,27 @@ config_read(const char *filename)
|
||||
opcode = config_parse_opcode(s, filename, linenum);
|
||||
|
||||
switch(opcode) {
|
||||
case oSessionTimeout:
|
||||
if (sscanf(p1, "%d", &config.session_timeout) < 0) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oDaemon:
|
||||
if (config.daemon == -1 && ((value = parse_boolean_value(p1)) != -1)) {
|
||||
config.daemon = value;
|
||||
}
|
||||
break;
|
||||
case oDebugLevel:
|
||||
if(sscanf(p1, "%d", &config.debuglevel) < 1 || config.debuglevel < LOG_EMERG || config.debuglevel > LOG_DEBUG) {
|
||||
if (sscanf(p1, "%d", &config.debuglevel) < 1 || config.debuglevel < LOG_EMERG || config.debuglevel > LOG_DEBUG) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s. Valid debuglevel %d..%d", p1, s, linenum, filename, LOG_EMERG, LOG_DEBUG);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oMaxClients:
|
||||
if(sscanf(p1, "%d", &config.maxclients) < 1) {
|
||||
if (sscanf(p1, "%d", &config.maxclients) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
@@ -756,27 +738,19 @@ config_read(const char *filename)
|
||||
config.gw_address = safe_strdup(p1);
|
||||
break;
|
||||
case oGatewayPort:
|
||||
if(sscanf(p1, "%u", &config.gw_port) < 1) {
|
||||
if (sscanf(p1, "%u", &config.gw_port) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oRemoteAuthenticatorAction:
|
||||
config.remote_auth_action = safe_strdup(p1);
|
||||
break;
|
||||
case oEnablePreAuth:
|
||||
value = parse_boolean_value(p1);
|
||||
if (value != - 1)
|
||||
config.enable_preauth = value;
|
||||
break;
|
||||
case oBinVoucher:
|
||||
config.bin_voucher = safe_strdup(p1);
|
||||
break;
|
||||
case oForceVoucher:
|
||||
value = parse_boolean_value(p1);
|
||||
if (value != - 1)
|
||||
config.force_voucher = value;
|
||||
case oBinAuth:
|
||||
config.bin_auth = safe_strdup(p1);
|
||||
if (!((stat(p1, &sb) == 0) && S_ISREG(sb.st_mode) && (sb.st_mode & S_IXUSR))) {
|
||||
debug(LOG_ERR, "binauth program does not exist or is not executeable: %s", p1);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oFirewallRuleSet:
|
||||
parse_firewall_ruleset(p1, fd, filename, &linenum);
|
||||
@@ -794,8 +768,8 @@ config_read(const char *filename)
|
||||
parse_allowed_mac_list(p1);
|
||||
break;
|
||||
case oMACmechanism:
|
||||
if(!strcasecmp("allow",p1)) config.macmechanism = MAC_ALLOW;
|
||||
else if(!strcasecmp("block",p1)) config.macmechanism = MAC_BLOCK;
|
||||
if (!strcasecmp("allow",p1)) config.macmechanism = MAC_ALLOW;
|
||||
else if (!strcasecmp("block",p1)) config.macmechanism = MAC_BLOCK;
|
||||
else {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
@@ -819,87 +793,24 @@ config_read(const char *filename)
|
||||
case oRedirectURL:
|
||||
config.redirectURL = safe_strdup(p1);
|
||||
break;
|
||||
case oAuthedIdleTimeout:
|
||||
if (sscanf(p1, "%d", &config.authed_idle_timeout) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oPreauthIdleTimeout:
|
||||
if (sscanf(p1, "%d", &config.preauth_idle_timeout) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oNdsctlSocket:
|
||||
free(config.ndsctl_sock);
|
||||
config.ndsctl_sock = safe_strdup(p1);
|
||||
break;
|
||||
case oDecongestHttpdThreads:
|
||||
if ((value = parse_boolean_value(p1)) != -1) {
|
||||
config.decongest_httpd_threads = value;
|
||||
} else {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oHttpdThreadThreshold:
|
||||
if(sscanf(p1, "%d", &config.httpd_thread_threshold) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oHttpdThreadDelayMS:
|
||||
if(sscanf(p1, "%d", &config.httpd_thread_delay_ms) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oClientIdleTimeout:
|
||||
if(sscanf(p1, "%d", &config.clienttimeout) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oClientForceTimeout:
|
||||
if(sscanf(p1, "%d", &config.clientforceout) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oAuthenticateImmediately:
|
||||
if ((value = parse_boolean_value(p1)) != -1) {
|
||||
config.authenticate_immediately = value;
|
||||
} else {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oPasswordAuthentication:
|
||||
if ((value = parse_boolean_value(p1)) != -1) {
|
||||
config.passwordauth = value;
|
||||
} else {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oUsernameAuthentication:
|
||||
if ((value = parse_boolean_value(p1)) != -1) {
|
||||
config.usernameauth = value;
|
||||
} else {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oPasswordAttempts:
|
||||
if(sscanf(p1, "%d", &config.passwordattempts) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oUsername:
|
||||
set_username(p1);
|
||||
break;
|
||||
case oPassword:
|
||||
set_password(p1);
|
||||
break;
|
||||
case oSetMSS:
|
||||
if ((value = parse_boolean_value(p1)) != -1) {
|
||||
config.set_mss = value;
|
||||
@@ -910,7 +821,7 @@ config_read(const char *filename)
|
||||
}
|
||||
break;
|
||||
case oMSSValue:
|
||||
if(sscanf(p1, "%d", &config.mss_value) < 1) {
|
||||
if (sscanf(p1, "%d", &config.mss_value) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
@@ -926,14 +837,14 @@ config_read(const char *filename)
|
||||
}
|
||||
break;
|
||||
case oDownloadLimit:
|
||||
if(sscanf(p1, "%d", &config.download_limit) < 1) {
|
||||
if (sscanf(p1, "%d", &config.download_limit) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oUploadLimit:
|
||||
if(sscanf(p1, "%d", &config.upload_limit) < 1) {
|
||||
if (sscanf(p1, "%d", &config.upload_limit) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
@@ -947,7 +858,7 @@ config_read(const char *filename)
|
||||
}
|
||||
break;
|
||||
case oFWMarkAuthenticated:
|
||||
if(sscanf(p1, "%x", &config.FW_MARK_AUTHENTICATED) < 1 ||
|
||||
if (sscanf(p1, "%x", &config.FW_MARK_AUTHENTICATED) < 1 ||
|
||||
config.FW_MARK_AUTHENTICATED == 0 ||
|
||||
config.FW_MARK_AUTHENTICATED == config.FW_MARK_BLOCKED ||
|
||||
config.FW_MARK_AUTHENTICATED == config.FW_MARK_TRUSTED) {
|
||||
@@ -957,7 +868,7 @@ config_read(const char *filename)
|
||||
}
|
||||
break;
|
||||
case oFWMarkBlocked:
|
||||
if(sscanf(p1, "%x", &config.FW_MARK_BLOCKED) < 1 ||
|
||||
if (sscanf(p1, "%x", &config.FW_MARK_BLOCKED) < 1 ||
|
||||
config.FW_MARK_BLOCKED == 0 ||
|
||||
config.FW_MARK_BLOCKED == config.FW_MARK_AUTHENTICATED ||
|
||||
config.FW_MARK_BLOCKED == config.FW_MARK_TRUSTED) {
|
||||
@@ -967,7 +878,7 @@ config_read(const char *filename)
|
||||
}
|
||||
break;
|
||||
case oFWMarkTrusted:
|
||||
if(sscanf(p1, "%x", &config.FW_MARK_TRUSTED) < 1 ||
|
||||
if (sscanf(p1, "%x", &config.FW_MARK_TRUSTED) < 1 ||
|
||||
config.FW_MARK_TRUSTED == 0 ||
|
||||
config.FW_MARK_TRUSTED == config.FW_MARK_AUTHENTICATED ||
|
||||
config.FW_MARK_TRUSTED == config.FW_MARK_BLOCKED) {
|
||||
@@ -976,9 +887,15 @@ config_read(const char *filename)
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case oCheckInterval:
|
||||
if (sscanf(p1, "%i", &config.checkinterval) < 1 || config.checkinterval < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case oSyslogFacility:
|
||||
if(sscanf(p1, "%d", &config.syslog_facility) < 1) {
|
||||
if (sscanf(p1, "%d", &config.syslog_facility) < 1) {
|
||||
debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename);
|
||||
debug(LOG_ERR, "Exiting...");
|
||||
exit(-1);
|
||||
@@ -1022,21 +939,14 @@ parse_boolean_value(char *line)
|
||||
/* Parse a string to see if it is valid decimal dotted quad IP V4 format */
|
||||
int check_ip_format(const char *possibleip)
|
||||
{
|
||||
unsigned int a1,a2,a3,a4;
|
||||
|
||||
return (sscanf(possibleip,"%u.%u.%u.%u",&a1,&a2,&a3,&a4) == 4
|
||||
&& a1 < 256 && a2 < 256 && a3 < 256 && a4 < 256);
|
||||
unsigned char buf[sizeof(struct in6_addr)];
|
||||
return inet_pton(AF_INET, possibleip, buf) > 0;
|
||||
}
|
||||
|
||||
|
||||
/* Parse a string to see if it is valid MAC address format */
|
||||
int check_mac_format(const char possiblemac[])
|
||||
{
|
||||
char hex2[3];
|
||||
return
|
||||
sscanf(possiblemac,
|
||||
"%2[A-Fa-f0-9]:%2[A-Fa-f0-9]:%2[A-Fa-f0-9]:%2[A-Fa-f0-9]:%2[A-Fa-f0-9]:%2[A-Fa-f0-9]",
|
||||
hex2,hex2,hex2,hex2,hex2,hex2) == 6;
|
||||
return ether_aton(possiblemac) != NULL;
|
||||
}
|
||||
|
||||
int add_to_trusted_mac_list(const char possiblemac[])
|
||||
@@ -1056,7 +966,7 @@ int add_to_trusted_mac_list(const char possiblemac[])
|
||||
|
||||
/* See if MAC is already on the list; don't add duplicates */
|
||||
for (p = config.trustedmaclist; p != NULL; p = p->next) {
|
||||
if (!strcasecmp(p->mac,mac)) {
|
||||
if (!strcasecmp(p->mac, mac)) {
|
||||
debug(LOG_INFO, "MAC address [%s] already on trusted list", mac);
|
||||
free(mac);
|
||||
return 1;
|
||||
@@ -1134,7 +1044,9 @@ void parse_trusted_mac_list(const char ptr[])
|
||||
ptrcopyptr = ptrcopy = safe_strdup(ptr);
|
||||
|
||||
while ((possiblemac = strsep(&ptrcopy, ", \t"))) {
|
||||
if(strlen(possiblemac)>0) add_to_trusted_mac_list(possiblemac);
|
||||
if (strlen(possiblemac) > 0) {
|
||||
add_to_trusted_mac_list(possiblemac);
|
||||
}
|
||||
}
|
||||
|
||||
free(ptrcopyptr);
|
||||
@@ -1251,7 +1163,9 @@ void parse_blocked_mac_list(const char ptr[])
|
||||
ptrcopyptr = ptrcopy = safe_strdup(ptr);
|
||||
|
||||
while ((possiblemac = strsep(&ptrcopy, ", \t"))) {
|
||||
if(strlen(possiblemac)>0) add_to_blocked_mac_list(possiblemac);
|
||||
if (strlen(possiblemac) > 0) {
|
||||
add_to_blocked_mac_list(possiblemac);
|
||||
}
|
||||
}
|
||||
|
||||
free(ptrcopyptr);
|
||||
@@ -1283,7 +1197,7 @@ int add_to_allowed_mac_list(const char possiblemac[])
|
||||
|
||||
/* See if MAC is already on the list; don't add duplicates */
|
||||
for (p = config.allowedmaclist; p != NULL; p = p->next) {
|
||||
if (!strcasecmp(p->mac,mac)) {
|
||||
if (!strcasecmp(p->mac, mac)) {
|
||||
debug(LOG_INFO, "MAC address [%s] already on allowed list", mac);
|
||||
free(mac);
|
||||
return 1;
|
||||
@@ -1367,7 +1281,7 @@ void parse_allowed_mac_list(const char ptr[])
|
||||
ptrcopyptr = ptrcopy = safe_strdup(ptr);
|
||||
|
||||
while ((possiblemac = strsep(&ptrcopy, ", \t"))) {
|
||||
if(strlen(possiblemac) > 0) {
|
||||
if (strlen(possiblemac) > 0) {
|
||||
add_to_allowed_mac_list(possiblemac);
|
||||
}
|
||||
}
|
||||
@@ -1386,34 +1300,6 @@ int set_log_level(int level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set the gateway password.
|
||||
* Return 0 on success.
|
||||
*/
|
||||
int set_password(const char s[])
|
||||
{
|
||||
char *old = config.password;
|
||||
if(s) {
|
||||
config.password = safe_strdup(s);
|
||||
if(old) free(old);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Set the gateway username.
|
||||
* Return 0 on success.
|
||||
*/
|
||||
int set_username(const char s[])
|
||||
{
|
||||
char *old = config.username;
|
||||
if(s) {
|
||||
config.username = safe_strdup(s);
|
||||
if(old) free(old);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Verifies if the configuration is complete and valid. Terminates the program if it isn't */
|
||||
void
|
||||
config_validate(void)
|
||||
@@ -1424,6 +1310,18 @@ config_validate(void)
|
||||
debug(LOG_ERR, "Configuration is not complete, exiting...");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (config.checkinterval >= config.preauth_idle_timeout / 2) {
|
||||
debug(LOG_ERR, "Setting checkinterval (%ds) must be smaller than half of preauth_idle_timeout (%ds)",
|
||||
config.checkinterval, config.preauth_idle_timeout);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (config.checkinterval >= config.authed_idle_timeout / 2) {
|
||||
debug(LOG_ERR, "Setting checkinterval (%ds) must be smaller than half of authed_idle_timeout (%ds)",
|
||||
config.checkinterval, config.authed_idle_timeout);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal
|
||||
|
||||
48
src/conf.h
48
src/conf.h
@@ -27,7 +27,7 @@
|
||||
#ifndef _CONF_H_
|
||||
#define _CONF_H_
|
||||
|
||||
#define VERSION "2.0.0-git"
|
||||
#define VERSION "3.0.0"
|
||||
|
||||
/*@{*/
|
||||
/** Defines */
|
||||
@@ -53,9 +53,10 @@
|
||||
#define DEFAULT_GATEWAYNAME "NoDogSplash"
|
||||
#define DEFAULT_GATEWAYPORT 2050
|
||||
#define DEFAULT_REMOTE_AUTH_PORT 80
|
||||
#define DEFAULT_CHECKINTERVAL 60
|
||||
#define DEFAULT_CLIENTTIMEOUT 10
|
||||
#define DEFAULT_CLIENTFORCEOUT 360
|
||||
#define DEFAULT_CHECKINTERVAL 30
|
||||
#define DEFAULT_SESSION_TIMEOUT 0
|
||||
#define DEFAULT_PREAUTH_IDLE_TIMEOUT (5 * 60)
|
||||
#define DEFAULT_AUTHED_IDLE_TIMEOUT (2 * 60 * 60)
|
||||
#define DEFAULT_WEBROOT "/etc/nodogsplash/htdocs"
|
||||
#define DEFAULT_SPLASHPAGE "splash.html"
|
||||
#define DEFAULT_INFOSKELPAGE "infoskel.html"
|
||||
@@ -64,10 +65,6 @@
|
||||
#define DEFAULT_AUTHDIR "nodogsplash_auth"
|
||||
#define DEFAULT_DENYDIR "nodogsplash_deny"
|
||||
#define DEFAULT_MACMECHANISM MAC_BLOCK
|
||||
#define DEFAULT_PASSWORD_AUTH 0
|
||||
#define DEFAULT_USERNAME_AUTH 0
|
||||
#define DEFAULT_PASSWORD_ATTEMPTS 5
|
||||
#define DEFAULT_AUTHENTICATE_IMMEDIATELY 0
|
||||
#define DEFAULT_SET_MSS 1
|
||||
#define DEFAULT_MSS_VALUE 0
|
||||
#define DEFAULT_TRAFFIC_CONTROL 0
|
||||
@@ -81,9 +78,6 @@
|
||||
#define DEFAULT_FW_MARK_AUTHENTICATED 0x400
|
||||
#define DEFAULT_FW_MARK_TRUSTED 0x200
|
||||
#define DEFAULT_FW_MARK_BLOCKED 0x100
|
||||
#define DEFAULT_DECONGEST_HTTPD_THREADS 0
|
||||
#define DEFAULT_HTTPD_THREAD_THRESHOLD 3
|
||||
#define DEFAULT_HTTPD_THREAD_DELAY_MS 200
|
||||
/* N.B.: default policies here must be ACCEPT, REJECT, or RETURN
|
||||
* In the .conf file, they must be allow, block, or passthrough
|
||||
* Mapping between these enforced by parse_empty_ruleset_policy() */
|
||||
@@ -153,10 +147,6 @@ typedef struct {
|
||||
char *gw_address; /**< @brief Internal IP address for our web server */
|
||||
char *gw_mac; /**< @brief MAC address of the interface we manage */
|
||||
unsigned int gw_port; /**< @brief Port the webserver will run on */
|
||||
char *remote_auth_action; /**< @brief Path for remote auth */
|
||||
char enable_preauth; /**< @brief enable pre-authentication support */
|
||||
char *bin_voucher; /**< @brief enable voucher support */
|
||||
char force_voucher; /**< @brief force voucher */
|
||||
char *webroot; /**< @brief Directory containing splash pages, etc. */
|
||||
char *splashpage; /**< @brief Name of main splash page */
|
||||
char *infoskelpage; /**< @brief Name of info skeleton page */
|
||||
@@ -165,18 +155,10 @@ typedef struct {
|
||||
char *redirectURL; /**< @brief URL to direct client to after authentication */
|
||||
char *authdir; /**< @brief Notional relative dir for authentication URL */
|
||||
char *denydir; /**< @brief Notional relative dir for denial URL */
|
||||
int passwordauth; /**< @brief boolean, whether to use password authentication */
|
||||
int usernameauth; /**< @brief boolean, whether to use username authentication */
|
||||
char *username; /**< @brief Username for username authentication */
|
||||
char *password; /**< @brief Password for password authentication */
|
||||
int passwordattempts; /**< @brief Number of attempted password authentications allowed */
|
||||
int clienttimeout; /**< @brief How many CheckIntervals before an inactive client
|
||||
must be re-authenticated */
|
||||
int clientforceout; /**< @brief How many CheckIntervals before a client
|
||||
must be re-authenticated */
|
||||
int checkinterval; /**< @brief Period the the client timeout check
|
||||
thread will run, in seconds */
|
||||
int authenticate_immediately; /**< @brief boolean, whether to auth noninteractively */
|
||||
int session_timeout; /**< @brief Seconds of the default session length */
|
||||
int preauth_idle_timeout; /**< @brief Seconds a preauthenticated client will be kept in the system */
|
||||
int authed_idle_timeout; /**< @brief Seconds a authenticated client will be kept in the system */
|
||||
int checkinterval; /**< @brief Period the the client timeout check thread will run, in seconds */
|
||||
int set_mss; /**< @brief boolean, whether to set mss */
|
||||
int mss_value; /**< @brief int, mss value; <= 0 clamp to pmtu */
|
||||
int traffic_control; /**< @brief boolean, whether to do tc */
|
||||
@@ -185,18 +167,16 @@ typedef struct {
|
||||
int upload_ifb; /**< @brief Number of IFB handling upload */
|
||||
int log_syslog; /**< @brief boolean, whether to log to syslog */
|
||||
int syslog_facility; /**< @brief facility to use when using syslog for logging */
|
||||
int decongest_httpd_threads; /**< @brief boolean, whether to avoid httpd thread congestion */
|
||||
int httpd_thread_threshold; /**< @brief number of concurrent httpd threads before trying decongestion */
|
||||
int httpd_thread_delay_ms; /**< @brief ms delay before starting a httpd thread after threshold */
|
||||
int macmechanism; /**< @brief mechanism wrt MAC addrs */
|
||||
t_firewall_ruleset *rulesets; /**< @brief firewall rules */
|
||||
t_MAC *trustedmaclist; /**< @brief list of trusted macs */
|
||||
t_MAC *blockedmaclist; /**< @brief list of blocked macs */
|
||||
t_MAC *allowedmaclist; /**< @brief list of allowed macs */
|
||||
unsigned int FW_MARK_AUTHENTICATED; /**< @brief iptables mark for authenticated packets */
|
||||
unsigned int FW_MARK_BLOCKED; /**< @brief iptables mark for blocked packets */
|
||||
unsigned int FW_MARK_TRUSTED; /**< @brief iptables mark for trusted packets */
|
||||
unsigned int FW_MARK_AUTHENTICATED; /**< @brief iptables mark for authenticated packets */
|
||||
unsigned int FW_MARK_BLOCKED; /**< @brief iptables mark for blocked packets */
|
||||
unsigned int FW_MARK_TRUSTED; /**< @brief iptables mark for trusted packets */
|
||||
int ip6; /**< @brief enable IPv6 */
|
||||
char *bin_auth; /**< @brief external authentication program */
|
||||
} s_config;
|
||||
|
||||
/** @brief Get the current gateway configuration */
|
||||
@@ -247,8 +227,6 @@ int check_mac_format(const char[]);
|
||||
|
||||
/** config API, used in commandline.c */
|
||||
int set_log_level(int);
|
||||
int set_password(const char[]);
|
||||
int set_username(const char[]);
|
||||
|
||||
#define LOCK_CONFIG() do { \
|
||||
debug(LOG_DEBUG, "Locking config"); \
|
||||
|
||||
@@ -31,8 +31,10 @@
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "conf.h"
|
||||
|
||||
|
||||
/** @internal
|
||||
Do not use directly, use the debug macro */
|
||||
void
|
||||
@@ -53,15 +55,13 @@ _debug(const char filename[], int line, int level, const char *format, ...)
|
||||
sigprocmask(SIG_BLOCK, &block_chld, NULL);
|
||||
|
||||
if (level <= LOG_WARNING) {
|
||||
fprintf(stderr, "[%d][%.24s][%u](%s:%d) ", level, ctime_r(&ts, buf), getpid(),
|
||||
filename, line);
|
||||
fprintf(stderr, "[%d][%.24s][%u](%s:%d) ", level, format_time(&ts, buf), getpid(), filename, line);
|
||||
va_start(vlist, format);
|
||||
vfprintf(stderr, format, vlist);
|
||||
va_end(vlist);
|
||||
fputc('\n', stderr);
|
||||
} else if (!config->daemon) {
|
||||
fprintf(stdout, "[%d][%.24s][%u](%s:%d) ", level, ctime_r(&ts, buf), getpid(),
|
||||
filename, line);
|
||||
fprintf(stdout, "[%d][%.24s][%u](%s:%d) ", level, format_time(&ts, buf), getpid(), filename, line);
|
||||
va_start(vlist, format);
|
||||
vfprintf(stdout, format, vlist);
|
||||
va_end(vlist);
|
||||
|
||||
109
src/firewall.c
109
src/firewall.c
@@ -66,6 +66,7 @@
|
||||
#include "firewall.h"
|
||||
#include "fw_iptables.h"
|
||||
#include "auth.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
extern pthread_mutex_t client_list_mutex;
|
||||
@@ -140,10 +141,11 @@ fw_destroy(void)
|
||||
void
|
||||
fw_refresh_client_list(void)
|
||||
{
|
||||
char *ip, *mac;
|
||||
t_client *cp1, *cp2;
|
||||
time_t now, added_time, last_updated;
|
||||
s_config *config = config_get_config();
|
||||
const int preauth_idle_timeout = config->preauth_idle_timeout;
|
||||
const int authed_idle_timeout = config->authed_idle_timeout;
|
||||
const time_t now = time(NULL);
|
||||
|
||||
/* Update all the counters */
|
||||
if (-1 == iptables_fw_counters_update()) {
|
||||
@@ -156,38 +158,68 @@ fw_refresh_client_list(void)
|
||||
for (cp1 = cp2 = client_get_first_client(); NULL != cp1; cp1 = cp2) {
|
||||
cp2 = cp1->next;
|
||||
|
||||
ip = safe_strdup(cp1->ip);
|
||||
mac = safe_strdup(cp1->mac);
|
||||
|
||||
if (!(cp1 = client_list_find(ip, mac))) {
|
||||
debug(LOG_ERR, "Node %s was freed while being re-validated!", ip);
|
||||
} else {
|
||||
now = time(NULL);
|
||||
last_updated = cp1->counters.last_updated;
|
||||
added_time = cp1->added_time;
|
||||
if (last_updated + (config->checkinterval * config->clienttimeout) <= now) {
|
||||
/* Timing out inactive user */
|
||||
debug(LOG_NOTICE, "%s %s inactive %d secs. kB in: %llu kB out: %llu",
|
||||
cp1->ip, cp1->mac, config->checkinterval * config->clienttimeout,
|
||||
cp1->counters.incoming/1000, cp1->counters.outgoing/1000);
|
||||
if(cp1->fw_connection_state == FW_MARK_AUTHENTICATED) {
|
||||
iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1);
|
||||
}
|
||||
client_list_delete(cp1);
|
||||
} else if (added_time + (config->checkinterval * config->clientforceout) <= now) {
|
||||
/* Forcing out user */
|
||||
debug(LOG_NOTICE, "%s %s connected %d secs. kB in: %llu kB out: %llu",
|
||||
cp1->ip, cp1->mac, config->checkinterval * config->clientforceout,
|
||||
cp1->counters.incoming/1000, cp1->counters.outgoing/1000);
|
||||
if(cp1->fw_connection_state == FW_MARK_AUTHENTICATED) {
|
||||
iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1);
|
||||
}
|
||||
client_list_delete(cp1);
|
||||
}
|
||||
if (!(cp1 = client_list_find(cp1->ip, cp1->mac))) {
|
||||
debug(LOG_ERR, "Client was freed while being re-validated!");
|
||||
continue;
|
||||
}
|
||||
|
||||
free(ip);
|
||||
free(mac);
|
||||
int conn_state = cp1->fw_connection_state;
|
||||
int last_updated = cp1->counters.last_updated;
|
||||
|
||||
if (cp1->session_end > 0 && cp1->session_end <= now) {
|
||||
/* Session ended (only > 0 for FW_MARK_AUTHENTICATED by binauth) */
|
||||
debug(LOG_NOTICE, "Force out user: %s %s, connected: %ds, in: %llukB, out: %llukB",
|
||||
cp1->ip, cp1->mac, now - cp1->session_end,
|
||||
cp1->counters.incoming / 1000, cp1->counters.outgoing / 1000);
|
||||
|
||||
/* All client here should be authenticated anyway */
|
||||
if (conn_state == FW_MARK_AUTHENTICATED) {
|
||||
if (config->bin_auth) {
|
||||
// Client will be deauthenticated...
|
||||
execute("%s session_end %s %llu %llu %d",
|
||||
config->bin_auth,
|
||||
cp1->mac,
|
||||
cp1->counters.incoming,
|
||||
cp1->counters.outgoing,
|
||||
now - cp1->session_start
|
||||
);
|
||||
}
|
||||
iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1);
|
||||
}
|
||||
client_list_delete(cp1);
|
||||
} else if (preauth_idle_timeout > 0
|
||||
&& conn_state == FW_MARK_PREAUTHENTICATED
|
||||
&& (last_updated + preauth_idle_timeout) <= now) {
|
||||
/* Timeout inactive user */
|
||||
debug(LOG_NOTICE, "Timeout preauthenticated idle user: %s %s, inactive: %ds, in: %llukB, out: %llukB",
|
||||
cp1->ip, cp1->mac, now - last_updated,
|
||||
cp1->counters.incoming / 1000, cp1->counters.outgoing / 1000);
|
||||
|
||||
client_list_delete(cp1);
|
||||
} else if (authed_idle_timeout > 0
|
||||
&& conn_state == FW_MARK_AUTHENTICATED
|
||||
&& (last_updated + authed_idle_timeout) <= now) {
|
||||
/* Timeout inactive user */
|
||||
debug(LOG_NOTICE, "Timeout authenticated idle user: %s %s, inactive: %ds, in: %llukB, out: %llukB",
|
||||
cp1->ip, cp1->mac, now - last_updated,
|
||||
cp1->counters.incoming / 1000, cp1->counters.outgoing / 1000);
|
||||
|
||||
/* All clients here should be authenticated for sure */
|
||||
if (conn_state == FW_MARK_AUTHENTICATED) {
|
||||
if (config->bin_auth) {
|
||||
// Client will be deauthenticated...
|
||||
execute("%s idle_timeout %s %llu %llu %d",
|
||||
config->bin_auth,
|
||||
cp1->mac,
|
||||
cp1->counters.incoming,
|
||||
cp1->counters.outgoing,
|
||||
now - cp1->session_start
|
||||
);
|
||||
}
|
||||
iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1);
|
||||
}
|
||||
client_list_delete(cp1);
|
||||
}
|
||||
}
|
||||
UNLOCK_CLIENT_LIST();
|
||||
}
|
||||
@@ -196,10 +228,13 @@ fw_refresh_client_list(void)
|
||||
const char *
|
||||
fw_connection_state_as_string(int mark)
|
||||
{
|
||||
if(mark == FW_MARK_PREAUTHENTICATED) return "Preauthenticated";
|
||||
if(mark == FW_MARK_AUTHENTICATED) return "Authenticated";
|
||||
if(mark == FW_MARK_TRUSTED) return "Trusted";
|
||||
if(mark == FW_MARK_BLOCKED) return "Blocked";
|
||||
if (mark == FW_MARK_PREAUTHENTICATED)
|
||||
return "Preauthenticated";
|
||||
if (mark == FW_MARK_AUTHENTICATED)
|
||||
return "Authenticated";
|
||||
if (mark == FW_MARK_TRUSTED)
|
||||
return "Trusted";
|
||||
if (mark == FW_MARK_BLOCKED)
|
||||
return "Blocked";
|
||||
return "ERROR: unrecognized mark";
|
||||
}
|
||||
|
||||
|
||||
@@ -51,12 +51,12 @@
|
||||
#include "util.h"
|
||||
#include "tc.h"
|
||||
|
||||
static char * _iptables_compile(const char[], const char[], t_firewall_rule *);
|
||||
static char *_iptables_compile(const char[], const char[], t_firewall_rule *);
|
||||
static int _iptables_append_ruleset(const char[], const char[], const char[]);
|
||||
static int _iptables_init_marks(void);
|
||||
|
||||
extern pthread_mutex_t client_list_mutex;
|
||||
extern pthread_mutex_t config_mutex;
|
||||
extern pthread_mutex_t client_list_mutex;
|
||||
extern pthread_mutex_t config_mutex;
|
||||
|
||||
/**
|
||||
* Make nonzero to supress the error output of the firewall during destruction.
|
||||
@@ -99,17 +99,17 @@ _iptables_init_marks()
|
||||
FW_MARK_MASK = FW_MARK_BLOCKED | FW_MARK_TRUSTED | FW_MARK_AUTHENTICATED;
|
||||
|
||||
debug(LOG_INFO,"Iptables mark %s: 0x%x",
|
||||
fw_connection_state_as_string(FW_MARK_PREAUTHENTICATED),
|
||||
FW_MARK_PREAUTHENTICATED);
|
||||
fw_connection_state_as_string(FW_MARK_PREAUTHENTICATED),
|
||||
FW_MARK_PREAUTHENTICATED);
|
||||
debug(LOG_INFO,"Iptables mark %s: 0x%x",
|
||||
fw_connection_state_as_string(FW_MARK_AUTHENTICATED),
|
||||
FW_MARK_AUTHENTICATED);
|
||||
fw_connection_state_as_string(FW_MARK_AUTHENTICATED),
|
||||
FW_MARK_AUTHENTICATED);
|
||||
debug(LOG_INFO,"Iptables mark %s: 0x%x",
|
||||
fw_connection_state_as_string(FW_MARK_TRUSTED),
|
||||
FW_MARK_TRUSTED);
|
||||
fw_connection_state_as_string(FW_MARK_TRUSTED),
|
||||
FW_MARK_TRUSTED);
|
||||
debug(LOG_INFO,"Iptables mark %s: 0x%x",
|
||||
fw_connection_state_as_string(FW_MARK_BLOCKED),
|
||||
FW_MARK_BLOCKED);
|
||||
fw_connection_state_as_string(FW_MARK_BLOCKED),
|
||||
FW_MARK_BLOCKED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -125,23 +125,23 @@ _iptables_check_mark_masking()
|
||||
debug(LOG_DEBUG, "Kernel supports --or-mark.");
|
||||
markop = "--or-mark";
|
||||
} else {
|
||||
debug(LOG_INFO,"Kernel does not support iptables --or-mark. Using --set-mark instead.");
|
||||
debug(LOG_INFO,"Kernel does not support iptables --or-mark. Using --set-mark instead.");
|
||||
markop = "--set-mark";
|
||||
}
|
||||
|
||||
/* See if kernel supports mark masking */
|
||||
if(0 == iptables_do_command("-t filter -I FORWARD 1 -m mark --mark 0x%x/0x%x -j REJECT", FW_MARK_BLOCKED, FW_MARK_MASK)) {
|
||||
if (0 == iptables_do_command("-t filter -I FORWARD 1 -m mark --mark 0x%x/0x%x -j REJECT", FW_MARK_BLOCKED, FW_MARK_MASK)) {
|
||||
iptables_do_command("-t filter -D FORWARD 1"); /* delete test rule we just inserted */
|
||||
debug(LOG_DEBUG,"Kernel supports mark masking.");
|
||||
debug(LOG_DEBUG, "Kernel supports mark masking.");
|
||||
char *tmp = NULL;
|
||||
safe_asprintf(&tmp,"/0x%x",FW_MARK_MASK);
|
||||
markmask = tmp;
|
||||
} else {
|
||||
debug(LOG_INFO,"Kernel does not support iptables mark masking. Using empty mask.");
|
||||
debug(LOG_INFO, "Kernel does not support iptables mark masking. Using empty mask.");
|
||||
markmask = "";
|
||||
}
|
||||
|
||||
debug(LOG_INFO,"Iptables mark op \"%s\" and mark mask \"%s\".", markop, markmask);
|
||||
debug(LOG_INFO, "Iptables mark op \"%s\" and mark mask \"%s\".", markop, markmask);
|
||||
|
||||
fw_quiet = 0; /* restore verbosity */
|
||||
|
||||
@@ -153,8 +153,9 @@ int
|
||||
iptables_do_command(const char *format, ...)
|
||||
{
|
||||
va_list vlist;
|
||||
char *fmt_cmd, *cmd;
|
||||
char *fmt_cmd = NULL;
|
||||
s_config *config;
|
||||
char *iptables;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
@@ -164,18 +165,15 @@ iptables_do_command(const char *format, ...)
|
||||
|
||||
config = config_get_config();
|
||||
|
||||
if(config->ip6) {
|
||||
safe_asprintf(&cmd, "ip6tables %s", fmt_cmd);
|
||||
} else {
|
||||
safe_asprintf(&cmd, "iptables %s", fmt_cmd);
|
||||
}
|
||||
|
||||
free(fmt_cmd);
|
||||
|
||||
debug(LOG_DEBUG, "Executing command: %s", cmd);
|
||||
iptables = config->ip6 ? "ip6tables" : "iptables";
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
rc = execute(cmd, fw_quiet);
|
||||
if (fw_quiet) {
|
||||
rc = execute("%s --wait %s &> /dev/null", iptables, fmt_cmd);
|
||||
} else {
|
||||
rc = execute("%s --wait %s", iptables, fmt_cmd);
|
||||
}
|
||||
|
||||
if (rc == 4) {
|
||||
/* iptables error code 4 indicates a resource problem that might
|
||||
* be temporary. So we retry to insert the rule a few times. (Mitar) */
|
||||
@@ -184,11 +182,8 @@ iptables_do_command(const char *format, ...)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!fw_quiet && rc != 0) {
|
||||
debug(LOG_ERR, "Nonzero exit status %d from command: %s", rc, cmd);
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
free(fmt_cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -212,23 +207,23 @@ _iptables_compile(const char table[], const char chain[], t_firewall_rule *rule)
|
||||
|
||||
switch (rule->target) {
|
||||
case TARGET_DROP:
|
||||
mode = safe_strdup("DROP");
|
||||
mode = "DROP";
|
||||
break;
|
||||
case TARGET_REJECT:
|
||||
mode = safe_strdup("REJECT");
|
||||
mode = "REJECT";
|
||||
break;
|
||||
case TARGET_ACCEPT:
|
||||
mode = safe_strdup("ACCEPT");
|
||||
mode = "ACCEPT";
|
||||
break;
|
||||
case TARGET_LOG:
|
||||
mode = safe_strdup("LOG");
|
||||
mode = "LOG";
|
||||
break;
|
||||
case TARGET_ULOG:
|
||||
mode = safe_strdup("ULOG");
|
||||
mode = "ULOG";
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(command, sizeof(command), "-t %s -A %s ",table, chain);
|
||||
snprintf(command, sizeof(command), "-t %s -A %s ", table, chain);
|
||||
if (rule->mask != NULL) {
|
||||
snprintf((command + strlen(command)),
|
||||
(sizeof(command) - strlen(command)),
|
||||
@@ -253,8 +248,6 @@ _iptables_compile(const char table[], const char chain[], t_firewall_rule *rule)
|
||||
(sizeof(command) - strlen(command)),
|
||||
"-j %s", mode);
|
||||
|
||||
free(mode);
|
||||
|
||||
/* XXX The buffer command, an automatic variable, will get cleaned
|
||||
* off of the stack when we return, so we strdup() it. */
|
||||
return(safe_strdup(command));
|
||||
@@ -329,9 +322,9 @@ int
|
||||
iptables_fw_init(void)
|
||||
{
|
||||
s_config *config;
|
||||
char * gw_interface = NULL;
|
||||
char * gw_address = NULL;
|
||||
char * gw_iprange = NULL;
|
||||
char *gw_interface = NULL;
|
||||
char *gw_address = NULL;
|
||||
char *gw_iprange = NULL;
|
||||
int gw_port = 0;
|
||||
int traffic_control;
|
||||
int set_mss, mss_value;
|
||||
@@ -389,31 +382,30 @@ iptables_fw_init(void)
|
||||
}
|
||||
|
||||
/* Rules to mark as blocked MAC address packets in mangle PREROUTING */
|
||||
if(MAC_BLOCK == macmechanism) {
|
||||
if (MAC_BLOCK == macmechanism) {
|
||||
/* with the MAC_BLOCK mechanism,
|
||||
* MAC's on the block list are marked as blocked;
|
||||
* everything else passes */
|
||||
for (; pb != NULL; pb = pb->next) {
|
||||
rc |= iptables_block_mac(pb->mac);
|
||||
}
|
||||
} else if(MAC_ALLOW == macmechanism) {
|
||||
} else if (MAC_ALLOW == macmechanism) {
|
||||
/* with the MAC_ALLOW mechanism,
|
||||
* MAC's on the allow list pass;
|
||||
* everything else is to be marked as blocked */
|
||||
/* So, append at end of chain a rule to mark everything blocked */
|
||||
// So, append at end of chain a rule to mark everything blocked
|
||||
rc |= iptables_do_command("-t mangle -A " CHAIN_BLOCKED " -j MARK %s 0x%x", markop, FW_MARK_BLOCKED);
|
||||
/* But insert at beginning of chain rules to pass allowed MAC's */
|
||||
// But insert at beginning of chain rules to pass allowed MAC's
|
||||
for (; pa != NULL; pa = pa->next) {
|
||||
rc |= iptables_allow_mac(pa->mac);
|
||||
}
|
||||
} else {
|
||||
debug(LOG_ERR, "Unknown MAC mechanism: %d",
|
||||
macmechanism);
|
||||
debug(LOG_ERR, "Unknown MAC mechanism: %d", macmechanism);
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
/* Set up for traffic control */
|
||||
if(traffic_control) {
|
||||
if (traffic_control) {
|
||||
rc |= tc_init_tc();
|
||||
}
|
||||
|
||||
@@ -436,18 +428,18 @@ iptables_fw_init(void)
|
||||
* nat PREROUTING chain
|
||||
*/
|
||||
|
||||
/* packets coming in on gw_interface jump to CHAIN_OUTGOING */
|
||||
// packets coming in on gw_interface jump to CHAIN_OUTGOING
|
||||
rc |= iptables_do_command("-t nat -I PREROUTING -i %s -s %s -j " CHAIN_OUTGOING, gw_interface, gw_iprange);
|
||||
/* CHAIN_OUTGOING, packets marked TRUSTED ACCEPT */
|
||||
rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -m mark --mark 0x%x%s -j ACCEPT", FW_MARK_TRUSTED, markmask);
|
||||
/* CHAIN_OUTGOING, packets marked AUTHENTICATED ACCEPT */
|
||||
rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -m mark --mark 0x%x%s -j ACCEPT",FW_MARK_AUTHENTICATED, markmask);
|
||||
/* CHAIN_OUTGOING, append the "preauthenticated-users" ruleset */
|
||||
// CHAIN_OUTGOING, packets marked TRUSTED ACCEPT
|
||||
rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -m mark --mark 0x%x%s -j RETURN", FW_MARK_TRUSTED, markmask);
|
||||
// CHAIN_OUTGOING, packets marked AUTHENTICATED ACCEPT
|
||||
rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -m mark --mark 0x%x%s -j RETURN", FW_MARK_AUTHENTICATED, markmask);
|
||||
// CHAIN_OUTGOING, append the "preauthenticated-users" ruleset
|
||||
rc |= _iptables_append_ruleset("nat", "preauthenticated-users", CHAIN_OUTGOING);
|
||||
|
||||
/* CHAIN_OUTGOING, packets for tcp port 80, redirect to gw_port on primary address for the iface */
|
||||
// CHAIN_OUTGOING, packets for tcp port 80, redirect to gw_port on primary address for the iface
|
||||
rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -p tcp --dport 80 -j DNAT --to-destination %s:%d", gw_address, gw_port);
|
||||
/* CHAIN_OUTGOING, other packets ACCEPT */
|
||||
// CHAIN_OUTGOING, other packets ACCEPT
|
||||
rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -j ACCEPT");
|
||||
|
||||
/*
|
||||
@@ -462,7 +454,7 @@ iptables_fw_init(void)
|
||||
*
|
||||
*/
|
||||
|
||||
/* Create new chains in the filter table */
|
||||
// Create new chains in the filter table
|
||||
rc |= iptables_do_command("-t filter -N " CHAIN_TO_INTERNET);
|
||||
rc |= iptables_do_command("-t filter -N " CHAIN_TO_ROUTER);
|
||||
rc |= iptables_do_command("-t filter -N " CHAIN_AUTHENTICATED);
|
||||
@@ -473,47 +465,47 @@ iptables_fw_init(void)
|
||||
* filter INPUT chain
|
||||
*/
|
||||
|
||||
/* packets coming in on gw_interface jump to CHAIN_TO_ROUTER */
|
||||
// packets coming in on gw_interface jump to CHAIN_TO_ROUTER
|
||||
rc |= iptables_do_command("-t filter -I INPUT -i %s -s %s -j " CHAIN_TO_ROUTER, gw_interface, gw_iprange);
|
||||
/* CHAIN_TO_ROUTER packets marked BLOCKED DROP */
|
||||
// CHAIN_TO_ROUTER packets marked BLOCKED DROP
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m mark --mark 0x%x%s -j DROP", FW_MARK_BLOCKED, markmask);
|
||||
/* CHAIN_TO_ROUTER, invalid packets DROP */
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m state --state INVALID -j DROP");
|
||||
/* CHAIN_TO_ROUTER, related and established packets ACCEPT */
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m state --state RELATED,ESTABLISHED -j ACCEPT");
|
||||
/* CHAIN_TO_ROUTER, bogus SYN packets DROP */
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -p tcp --tcp-flags SYN SYN \\! --tcp-option 2 -j DROP");
|
||||
// CHAIN_TO_ROUTER, invalid packets DROP
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m conntrack --ctstate INVALID -j DROP");
|
||||
// CHAIN_TO_ROUTER, related and established packets ACCEPT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
|
||||
// CHAIN_TO_ROUTER, bogus SYN packets DROP
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -p tcp --tcp-flags SYN SYN \\! --tcp-option 2 -j DROP");
|
||||
|
||||
/* CHAIN_TO_ROUTER, packets to HTTP listening on gw_port on router ACCEPT */
|
||||
// CHAIN_TO_ROUTER, packets to HTTP listening on gw_port on router ACCEPT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -p tcp --dport %d -j ACCEPT", gw_port);
|
||||
|
||||
/* CHAIN_TO_ROUTER, packets marked TRUSTED: */
|
||||
// CHAIN_TO_ROUTER, packets marked TRUSTED:
|
||||
|
||||
/* if trusted-users-to-router ruleset is empty:
|
||||
* use empty ruleset policy
|
||||
* else:
|
||||
* jump to CHAIN_TRUSTED_TO_ROUTER, and load and use users-to-router ruleset
|
||||
*/
|
||||
if(is_empty_ruleset("trusted-users-to-router")) {
|
||||
if (is_empty_ruleset("trusted-users-to-router")) {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m mark --mark 0x%x%s -j %s", FW_MARK_TRUSTED, markmask, get_empty_ruleset_policy("trusted-users-to-router"));
|
||||
} else {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m mark --mark 0x%x%s -j " CHAIN_TRUSTED_TO_ROUTER, FW_MARK_TRUSTED, markmask);
|
||||
/* CHAIN_TRUSTED_TO_ROUTER, related and established packets ACCEPT */
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED_TO_ROUTER " -m state --state RELATED,ESTABLISHED -j ACCEPT");
|
||||
/* CHAIN_TRUSTED_TO_ROUTER, append the "trusted-users-to-router" ruleset */
|
||||
// CHAIN_TRUSTED_TO_ROUTER, related and established packets ACCEPT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED_TO_ROUTER " -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
|
||||
// CHAIN_TRUSTED_TO_ROUTER, append the "trusted-users-to-router" ruleset
|
||||
rc |= _iptables_append_ruleset("filter", "trusted-users-to-router", CHAIN_TRUSTED_TO_ROUTER);
|
||||
/* CHAIN_TRUSTED_TO_ROUTER, any packets not matching that ruleset REJECT */
|
||||
// CHAIN_TRUSTED_TO_ROUTER, any packets not matching that ruleset REJECT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED_TO_ROUTER " -j REJECT --reject-with icmp-port-unreachable");
|
||||
}
|
||||
|
||||
/* CHAIN_TO_ROUTER, other packets: */
|
||||
// CHAIN_TO_ROUTER, other packets:
|
||||
|
||||
/* if users-to-router ruleset is empty:
|
||||
* use empty ruleset policy
|
||||
* else:
|
||||
* load and use users-to-router ruleset
|
||||
*/
|
||||
if(is_empty_ruleset("users-to-router")) {
|
||||
if (is_empty_ruleset("users-to-router")) {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -j %s", get_empty_ruleset_policy("users-to-router"));
|
||||
} else {
|
||||
/* CHAIN_TO_ROUTER, append the "users-to-router" ruleset */
|
||||
@@ -527,13 +519,13 @@ iptables_fw_init(void)
|
||||
* filter FORWARD chain
|
||||
*/
|
||||
|
||||
/* packets coming in on gw_interface jump to CHAIN_TO_INTERNET */
|
||||
// packets coming in on gw_interface jump to CHAIN_TO_INTERNET
|
||||
rc |= iptables_do_command("-t filter -I FORWARD -i %s -s %s -j " CHAIN_TO_INTERNET, gw_interface, gw_iprange);
|
||||
/* CHAIN_TO_INTERNET packets marked BLOCKED DROP */
|
||||
// CHAIN_TO_INTERNET packets marked BLOCKED DROP
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j DROP", FW_MARK_BLOCKED, markmask);
|
||||
/* CHAIN_TO_INTERNET, invalid packets DROP */
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m state --state INVALID -j DROP");
|
||||
/* CHAIN_TO_INTERNET, deal with MSS */
|
||||
// CHAIN_TO_INTERNET, invalid packets DROP
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m conntrack --ctstate INVALID -j DROP");
|
||||
// CHAIN_TO_INTERNET, deal with MSS
|
||||
if (set_mss) {
|
||||
/* XXX this mangles, so 'should' be done in the mangle POSTROUTING chain.
|
||||
* However OpenWRT standard S35firewall does it in filter FORWARD,
|
||||
@@ -552,15 +544,15 @@ iptables_fw_init(void)
|
||||
* else:
|
||||
* jump to CHAIN_TRUSTED, and load and use trusted-users ruleset
|
||||
*/
|
||||
if(is_empty_ruleset("trusted-users")) {
|
||||
if (is_empty_ruleset("trusted-users")) {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j %s", FW_MARK_TRUSTED, markmask, get_empty_ruleset_policy("trusted-users"));
|
||||
} else {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j " CHAIN_TRUSTED, FW_MARK_TRUSTED, markmask);
|
||||
/* CHAIN_TRUSTED, related and established packets ACCEPT */
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED " -m state --state RELATED,ESTABLISHED -j ACCEPT");
|
||||
/* CHAIN_TRUSTED, append the "trusted-users" ruleset */
|
||||
// CHAIN_TRUSTED, related and established packets ACCEPT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED " -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
|
||||
// CHAIN_TRUSTED, append the "trusted-users" ruleset
|
||||
rc |= _iptables_append_ruleset("filter", "trusted-users", CHAIN_TRUSTED);
|
||||
/* CHAIN_TRUSTED, any packets not matching that ruleset REJECT */
|
||||
// CHAIN_TRUSTED, any packets not matching that ruleset REJECT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED " -j REJECT --reject-with icmp-port-unreachable");
|
||||
}
|
||||
|
||||
@@ -572,15 +564,15 @@ iptables_fw_init(void)
|
||||
* else:
|
||||
* jump to CHAIN_AUTHENTICATED, and load and use authenticated-users ruleset
|
||||
*/
|
||||
if(is_empty_ruleset("authenticated-users")) {
|
||||
if (is_empty_ruleset("authenticated-users")) {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j %s", FW_MARK_AUTHENTICATED, markmask, get_empty_ruleset_policy("authenticated-users"));
|
||||
} else {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j " CHAIN_AUTHENTICATED, FW_MARK_AUTHENTICATED, markmask);
|
||||
/* CHAIN_AUTHENTICATED, related and established packets ACCEPT */
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_AUTHENTICATED " -m state --state RELATED,ESTABLISHED -j ACCEPT");
|
||||
/* CHAIN_AUTHENTICATED, append the "authenticated-users" ruleset */
|
||||
// CHAIN_AUTHENTICATED, related and established packets ACCEPT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_AUTHENTICATED " -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
|
||||
// CHAIN_AUTHENTICATED, append the "authenticated-users" ruleset
|
||||
rc |= _iptables_append_ruleset("filter", "authenticated-users", CHAIN_AUTHENTICATED);
|
||||
/* CHAIN_AUTHENTICATED, any packets not matching that ruleset REJECT */
|
||||
// CHAIN_AUTHENTICATED, any packets not matching that ruleset REJECT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_AUTHENTICATED " -j REJECT --reject-with icmp-port-unreachable");
|
||||
}
|
||||
|
||||
@@ -591,12 +583,12 @@ iptables_fw_init(void)
|
||||
* else:
|
||||
* load and use authenticated-users ruleset
|
||||
*/
|
||||
if(is_empty_ruleset("preauthenticated-users")) {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -j %s ", get_empty_ruleset_policy("preauthenticated-users"));
|
||||
if (is_empty_ruleset("preauthenticated-users")) {
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -j %s ", get_empty_ruleset_policy("preauthenticated-users"));
|
||||
} else {
|
||||
rc |= _iptables_append_ruleset("filter", "preauthenticated-users", CHAIN_TO_INTERNET);
|
||||
}
|
||||
/* CHAIN_TO_INTERNET, all other packets REJECT */
|
||||
// CHAIN_TO_INTERNET, all other packets REJECT
|
||||
rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -j REJECT --reject-with icmp-port-unreachable");
|
||||
|
||||
/*
|
||||
@@ -627,18 +619,14 @@ iptables_fw_destroy(void)
|
||||
traffic_control = config->traffic_control;
|
||||
UNLOCK_CONFIG();
|
||||
|
||||
if(traffic_control) {
|
||||
if (traffic_control) {
|
||||
debug(LOG_DEBUG, "Destroying our tc hooks");
|
||||
tc_destroy_tc();
|
||||
}
|
||||
|
||||
debug(LOG_DEBUG, "Destroying our iptables entries");
|
||||
|
||||
/*
|
||||
*
|
||||
* Everything in the mangle table
|
||||
*
|
||||
*/
|
||||
/* Everything in the mangle table */
|
||||
debug(LOG_DEBUG, "Destroying chains in the MANGLE table");
|
||||
iptables_fw_destroy_mention("mangle", "PREROUTING", CHAIN_TRUSTED);
|
||||
iptables_fw_destroy_mention("mangle", "PREROUTING", CHAIN_BLOCKED);
|
||||
@@ -656,22 +644,14 @@ iptables_fw_destroy(void)
|
||||
iptables_do_command("-t mangle -X " CHAIN_OUTGOING);
|
||||
iptables_do_command("-t mangle -X " CHAIN_INCOMING);
|
||||
|
||||
/*
|
||||
*
|
||||
* Everything in the nat table
|
||||
*
|
||||
*/
|
||||
/* Everything in the nat table */
|
||||
|
||||
debug(LOG_DEBUG, "Destroying chains in the NAT table");
|
||||
iptables_fw_destroy_mention("nat", "PREROUTING", CHAIN_OUTGOING);
|
||||
iptables_do_command("-t nat -F " CHAIN_OUTGOING);
|
||||
iptables_do_command("-t nat -X " CHAIN_OUTGOING);
|
||||
|
||||
/*
|
||||
*
|
||||
* Everything in the filter table
|
||||
*
|
||||
*/
|
||||
/* Everything in the filter table */
|
||||
|
||||
debug(LOG_DEBUG, "Destroying chains in the FILTER table");
|
||||
iptables_fw_destroy_mention("filter", "INPUT", CHAIN_TO_ROUTER);
|
||||
@@ -687,6 +667,8 @@ iptables_fw_destroy(void)
|
||||
iptables_do_command("-t filter -X " CHAIN_TRUSTED);
|
||||
iptables_do_command("-t filter -X " CHAIN_TRUSTED_TO_ROUTER);
|
||||
|
||||
fw_quiet = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -698,9 +680,9 @@ iptables_fw_destroy(void)
|
||||
*/
|
||||
int
|
||||
iptables_fw_destroy_mention(
|
||||
const char * table,
|
||||
const char * chain,
|
||||
const char * mention
|
||||
const char *table,
|
||||
const char *chain,
|
||||
const char *mention
|
||||
)
|
||||
{
|
||||
FILE *p = NULL;
|
||||
@@ -755,12 +737,10 @@ iptables_fw_access(t_authaction action, t_client *client)
|
||||
{
|
||||
int rc = 0, download_limit, upload_limit, traffic_control;
|
||||
s_config *config;
|
||||
char *upload_ifbname;
|
||||
|
||||
fw_quiet = 0;
|
||||
char upload_ifbname[16];
|
||||
|
||||
config = config_get_config();
|
||||
safe_asprintf(&upload_ifbname,"ifb%d",config->upload_ifb); /* must free */
|
||||
safe_asprintf(upload_ifbname, "ifb%d" , config->upload_ifb);
|
||||
|
||||
LOCK_CONFIG();
|
||||
traffic_control = config->traffic_control;
|
||||
@@ -781,6 +761,7 @@ iptables_fw_access(t_authaction action, t_client *client)
|
||||
rc |= iptables_do_command("-t mangle -A " CHAIN_INCOMING " -d %s -j MARK %s 0x%x", client->ip, markop, FW_MARK_AUTHENTICATED);
|
||||
/* This rule is just for download (incoming) byte counting, see iptables_fw_counters_update() */
|
||||
rc |= iptables_do_command("-t mangle -A " CHAIN_INCOMING " -d %s -j ACCEPT", client->ip);
|
||||
|
||||
if(traffic_control) {
|
||||
rc |= tc_attach_client(config->gw_interface, download_limit, upload_ifbname, upload_limit, client->idx, client->ip);
|
||||
}
|
||||
@@ -791,6 +772,7 @@ iptables_fw_access(t_authaction action, t_client *client)
|
||||
rc |= iptables_do_command("-t mangle -D " CHAIN_OUTGOING " -s %s -m mac --mac-source %s -j MARK %s 0x%x", client->ip, client->mac, markop, FW_MARK_AUTHENTICATED);
|
||||
rc |= iptables_do_command("-t mangle -D " CHAIN_INCOMING " -d %s -j MARK %s 0x%x", client->ip, markop, FW_MARK_AUTHENTICATED);
|
||||
rc |= iptables_do_command("-t mangle -D " CHAIN_INCOMING " -d %s -j ACCEPT", client->ip);
|
||||
|
||||
if(traffic_control) {
|
||||
rc |= tc_detach_client(config->gw_interface, download_limit, upload_ifbname, upload_limit, client->idx);
|
||||
}
|
||||
@@ -800,8 +782,6 @@ iptables_fw_access(t_authaction action, t_client *client)
|
||||
break;
|
||||
}
|
||||
|
||||
free(upload_ifbname);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -816,7 +796,7 @@ iptables_fw_total_upload()
|
||||
unsigned long long int counter;
|
||||
|
||||
/* Look for outgoing traffic */
|
||||
script = "iptables -v -n -x -t mangle -L PREROUTING";
|
||||
script = "iptables -v -n -x -t mangle -L PREROUTING";
|
||||
output = popen(script, "r");
|
||||
if (!output) {
|
||||
debug(LOG_ERR, "popen(): %s", strerror(errno));
|
||||
@@ -827,7 +807,7 @@ iptables_fw_total_upload()
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
|
||||
while ( !(feof(output) )) {
|
||||
while (!feof(output)) {
|
||||
rc = fscanf(output, "%*d %llu %s ", &counter, target);
|
||||
if (2 == rc && !strcmp(target,CHAIN_OUTGOING)) {
|
||||
debug(LOG_DEBUG, "Total outgoing Bytes=%llu", counter);
|
||||
@@ -839,7 +819,7 @@ iptables_fw_total_upload()
|
||||
}
|
||||
|
||||
pclose(output);
|
||||
debug(LOG_ERR, "Can't find target %s in mangle table",CHAIN_OUTGOING);
|
||||
debug(LOG_WARNING, "Can't find target %s in mangle table", CHAIN_OUTGOING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -854,7 +834,7 @@ iptables_fw_total_download()
|
||||
unsigned long long int counter;
|
||||
|
||||
/* Look for incoming traffic */
|
||||
script = "iptables -v -n -x -t mangle -L POSTROUTING";
|
||||
script = "iptables -v -n -x -t mangle -L POSTROUTING";
|
||||
output = popen(script, "r");
|
||||
if (!output) {
|
||||
debug(LOG_ERR, "popen(): %s", strerror(errno));
|
||||
@@ -865,7 +845,7 @@ iptables_fw_total_download()
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
|
||||
while ( !(feof(output) )) {
|
||||
while (!feof(output)) {
|
||||
rc = fscanf(output, "%*s %llu %s ", &counter, target);
|
||||
if (2 == rc && !strcmp(target,CHAIN_INCOMING)) {
|
||||
debug(LOG_DEBUG, "Total incoming Bytes=%llu", counter);
|
||||
@@ -877,7 +857,7 @@ iptables_fw_total_download()
|
||||
}
|
||||
|
||||
pclose(output);
|
||||
debug(LOG_ERR, "Can't find target %s in mangle table",CHAIN_INCOMING);
|
||||
debug(LOG_WARNING, "Can't find target %s in mangle table", CHAIN_INCOMING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -886,9 +866,9 @@ int
|
||||
iptables_fw_counters_update(void)
|
||||
{
|
||||
FILE *output;
|
||||
char *script,
|
||||
ip[INET6_ADDRSTRLEN],
|
||||
target[MAX_BUF];
|
||||
char *script;
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
char target[MAX_BUF];
|
||||
int rc;
|
||||
int af;
|
||||
s_config *config;
|
||||
@@ -912,11 +892,11 @@ iptables_fw_counters_update(void)
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
|
||||
while ( !(feof(output) )) {
|
||||
rc = fscanf(output, "%*s %llu %s %*s %*s %*s %*s %15[0-9.]", &counter,target,ip);
|
||||
while (!feof(output)) {
|
||||
rc = fscanf(output, "%*s %llu %s %*s %*s %*s %*s %15[0-9.]", &counter, target, ip);
|
||||
/* eat rest of line */
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
if (3 == rc && !strcmp(target,"MARK")) {
|
||||
if (3 == rc && !strcmp(target, "MARK")) {
|
||||
/* Sanity*/
|
||||
if (!inet_pton(af, ip, &tempaddr)) {
|
||||
debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
|
||||
@@ -951,11 +931,11 @@ iptables_fw_counters_update(void)
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
|
||||
while ( !(feof(output) )) {
|
||||
rc = fscanf(output, "%*s %llu %s %*s %*s %*s %*s %*s %15[0-9.]", &counter,target,ip);
|
||||
while (!feof(output)) {
|
||||
rc = fscanf(output, "%*s %llu %s %*s %*s %*s %*s %*s %15[0-9.]", &counter, target, ip);
|
||||
/* eat rest of line */
|
||||
while (('\n' != fgetc(output)) && !feof(output)) {}
|
||||
if (3 == rc && !strcmp(target,"ACCEPT")) {
|
||||
if (3 == rc && !strcmp(target, "ACCEPT")) {
|
||||
/* Sanity*/
|
||||
if (!inet_pton(af, ip, &tempaddr)) {
|
||||
debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
@author Copyright (C) 2008 Paul Kube <nodogsplash@kokoro.ucsd.edu>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -61,6 +63,11 @@
|
||||
|
||||
#include <microhttpd.h>
|
||||
|
||||
// Check for libmicrohttp version >= 0.9.51
|
||||
#if MHD_VERSION < 0x00095100
|
||||
#error libmicrohttp version >= 0.9.51 required
|
||||
#endif
|
||||
|
||||
/** XXX Ugly hack
|
||||
* We need to remember the thread IDs of threads that simulate wait with pthread_cond_timedwait
|
||||
* so we can explicitly kill them in the termination handler
|
||||
@@ -73,15 +80,6 @@ struct MHD_Daemon * webserver = NULL;
|
||||
/* Time when nodogsplash started */
|
||||
time_t started_time = 0;
|
||||
|
||||
|
||||
/* Avoid race condition of folloing variables */
|
||||
pthread_mutex_t httpd_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* Total number of httpd request handling threads started */
|
||||
int created_httpd_threads;
|
||||
/* Number of current httpd request handling threads */
|
||||
int current_httpd_threads;
|
||||
|
||||
|
||||
/**@internal
|
||||
* @brief Handles SIGCHLD signals to avoid zombie processes
|
||||
*
|
||||
@@ -99,8 +97,8 @@ sigchld_handler(int s)
|
||||
|
||||
rc = waitpid(-1, &status, WNOHANG | WUNTRACED);
|
||||
|
||||
if(rc == -1) {
|
||||
if(errno == ECHILD) {
|
||||
if (rc == -1) {
|
||||
if (errno == ECHILD) {
|
||||
debug(LOG_DEBUG, "SIGCHLD handler: waitpid(): No child exists now.");
|
||||
} else {
|
||||
debug(LOG_ERR, "SIGCHLD handler: Error reaping child (waitpid() returned -1): %s", strerror(errno));
|
||||
@@ -108,12 +106,12 @@ sigchld_handler(int s)
|
||||
return;
|
||||
}
|
||||
|
||||
if(WIFEXITED(status)) {
|
||||
if (WIFEXITED(status)) {
|
||||
debug(LOG_DEBUG, "SIGCHLD handler: Process PID %d exited normally, status %d", (int)rc, WEXITSTATUS(status));
|
||||
return;
|
||||
}
|
||||
|
||||
if(WIFSIGNALED(status)) {
|
||||
if (WIFSIGNALED(status)) {
|
||||
debug(LOG_DEBUG, "SIGCHLD handler: Process PID %d exited due to signal %d", (int)rc, WTERMSIG(status));
|
||||
return;
|
||||
}
|
||||
@@ -127,7 +125,7 @@ sigchld_handler(int s)
|
||||
void
|
||||
termination_handler(int s)
|
||||
{
|
||||
static pthread_mutex_t sigterm_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t sigterm_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
debug(LOG_NOTICE, "Handler for termination caught signal %d", s);
|
||||
|
||||
@@ -218,7 +216,7 @@ static void
|
||||
main_loop(void)
|
||||
{
|
||||
int result = 0;
|
||||
pthread_t tid;
|
||||
pthread_t tid;
|
||||
s_config *config;
|
||||
|
||||
config = config_get_config();
|
||||
@@ -248,13 +246,13 @@ main_loop(void)
|
||||
|
||||
/* Initializes the web server */
|
||||
if ((webserver = MHD_start_daemon(
|
||||
MHD_USE_EPOLL_INTERNALLY,
|
||||
config->gw_port,
|
||||
NULL, NULL,
|
||||
libmicrohttpd_cb, NULL,
|
||||
MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
|
||||
MHD_OPTION_LISTENING_ADDRESS_REUSE, 1,
|
||||
MHD_OPTION_END)) == NULL) {
|
||||
MHD_USE_EPOLL_INTERNALLY | MHD_USE_TCP_FASTOPEN,
|
||||
config->gw_port,
|
||||
NULL, NULL,
|
||||
libmicrohttpd_cb, NULL,
|
||||
MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
|
||||
MHD_OPTION_LISTENING_ADDRESS_REUSE, 1,
|
||||
MHD_OPTION_END)) == NULL) {
|
||||
debug(LOG_ERR, "Could not create web server: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
@@ -271,7 +269,7 @@ main_loop(void)
|
||||
fw_destroy();
|
||||
/* Then initialize it */
|
||||
debug(LOG_NOTICE, "Initializing firewall rules");
|
||||
if( fw_init() != 0 ) {
|
||||
if (fw_init() != 0) {
|
||||
debug(LOG_ERR, "Error initializing firewall rules! Cleaning up");
|
||||
fw_destroy();
|
||||
debug(LOG_ERR, "Exiting because of error initializing firewall rules");
|
||||
@@ -287,7 +285,7 @@ main_loop(void)
|
||||
pthread_detach(tid_client_check);
|
||||
|
||||
/* Start control thread */
|
||||
result = pthread_create(&tid, NULL, thread_ndsctl, (void *)safe_strdup(config->ndsctl_sock));
|
||||
result = pthread_create(&tid, NULL, thread_ndsctl, (void *)(config->ndsctl_sock));
|
||||
if (result != 0) {
|
||||
debug(LOG_ERR, "FATAL: Failed to create thread_ndsctl - exiting");
|
||||
termination_handler(1);
|
||||
@@ -316,11 +314,11 @@ int main(int argc, char **argv)
|
||||
config_read(config->configfile);
|
||||
config_validate();
|
||||
|
||||
/* Initializes the linked list of connected clients */
|
||||
// Initializes the linked list of connected clients
|
||||
client_list_init();
|
||||
|
||||
/* Init the signals to catch chld/quit/etc */
|
||||
debug(LOG_NOTICE,"Initializing signal handlers");
|
||||
// Init the signals to catch chld/quit/etc
|
||||
debug(LOG_NOTICE, "Initializing signal handlers");
|
||||
init_signals();
|
||||
|
||||
if (config->daemon) {
|
||||
@@ -328,12 +326,12 @@ int main(int argc, char **argv)
|
||||
debug(LOG_NOTICE, "Starting as daemon, forking to background");
|
||||
|
||||
switch(safe_fork()) {
|
||||
case 0: /* child */
|
||||
case 0: // child
|
||||
setsid();
|
||||
main_loop();
|
||||
break;
|
||||
|
||||
default: /* parent */
|
||||
default: // parent
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
@@ -341,5 +339,5 @@ int main(int argc, char **argv)
|
||||
main_loop();
|
||||
}
|
||||
|
||||
return(0); /* never reached */
|
||||
return(0); // never reached
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free:Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
/************************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free:Software Foundation; either version 2 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 *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
\********************************************************************/
|
||||
* GNU General Public License for more details. *
|
||||
\************************************************************************/
|
||||
|
||||
/** @internal
|
||||
* @file http_microhttpd.c
|
||||
@@ -48,7 +48,8 @@
|
||||
static t_client *add_client(const char *ip_addr);
|
||||
static int authenticated(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *url, t_client *client);
|
||||
static int preauthenticated(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *url, t_client *client);
|
||||
static int authenticate_client(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *url, t_client *client);
|
||||
static int authenticate_client_binauth(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *redirect_url, t_client *client);
|
||||
static int authenticate_client(struct MHD_Connection *connection, const char *ip_addr, const char *mac, const char *redirect_url, t_client *client);
|
||||
static int get_host_value_callback(void *cls, enum MHD_ValueKind kind, const char *key, const char *value);
|
||||
static int serve_file(struct MHD_Connection *connection, t_client *client, const char *url);
|
||||
static int show_splashpage(struct MHD_Connection *connection, t_client *client);
|
||||
@@ -56,51 +57,68 @@ static int encode_and_redirect_to_splashpage(struct MHD_Connection *connection,
|
||||
static int redirect_to_splashpage(struct MHD_Connection *connection, t_client *client, const char *host, const char *url);
|
||||
static int send_error(struct MHD_Connection *connection, int error);
|
||||
static int send_redirect_temp(struct MHD_Connection *connection, const char *url);
|
||||
static int send_refresh(struct MHD_Connection *connection);
|
||||
static int is_foreign_hosts(struct MHD_Connection *connection, const char *host);
|
||||
static int is_splashpage(const char *host, const char *url);
|
||||
static int get_query(struct MHD_Connection *connection, char **collect_query);
|
||||
static const char *get_redirect_url(struct MHD_Connection *connection);
|
||||
|
||||
static const char *lookup_mimetype(const char *filename);
|
||||
|
||||
|
||||
/* Get client settings from binauth */
|
||||
static int set_binauth_data(const char *buf, s_config *config, t_client *client)
|
||||
{
|
||||
int seconds = config->session_timeout;
|
||||
int upload = 0;
|
||||
int download = 0;
|
||||
int rc;
|
||||
|
||||
rc = sscanf(buf, "%d %d %d", &seconds, &upload, &download);
|
||||
|
||||
switch (rc) {
|
||||
case 3:
|
||||
if (download < 0)
|
||||
goto err;
|
||||
case 2:
|
||||
if (upload < 0)
|
||||
goto err;
|
||||
case 1:
|
||||
if (seconds < 0)
|
||||
goto err;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
|
||||
client->download_limit = download;
|
||||
client->upload_limit = upload;
|
||||
client->session_start = time(NULL);
|
||||
|
||||
if (seconds) {
|
||||
client->session_end = client->session_start + seconds;
|
||||
} else {
|
||||
client->session_end = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct collect_query {
|
||||
int i;
|
||||
char **elements;
|
||||
};
|
||||
|
||||
struct collect_query_key {
|
||||
const char *key;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
static int collect_query_key(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
|
||||
{
|
||||
struct collect_query_key *query_key = cls;
|
||||
query_key->value = NULL;
|
||||
|
||||
if (!query_key)
|
||||
return MHD_NO;
|
||||
|
||||
if (!key) {
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
if (!strcmp(key, query_key->key)) {
|
||||
query_key->value = value;
|
||||
/* stop execution of iterator */
|
||||
return MHD_NO;
|
||||
}
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
static int collect_query_string(void *cls, enum MHD_ValueKind kind, const char *key, const char * value)
|
||||
{
|
||||
/* what happens when '?=foo' supplied? */
|
||||
struct collect_query *collect_query = cls;
|
||||
if (key && !value) {
|
||||
collect_query->elements[collect_query->i] = safe_strdup(key);
|
||||
} else if(key && value) {
|
||||
} else if (key && value) {
|
||||
safe_asprintf(&(collect_query->elements[collect_query->i]), "%s=%s", key, value);
|
||||
}
|
||||
collect_query->i++;
|
||||
@@ -142,7 +160,7 @@ static int is_splashpage(const char *host, const char *url)
|
||||
if (host == NULL) {
|
||||
/* no hostname given
|
||||
* '/' -> splash
|
||||
* '' -> splash [is this even possible with MHD?
|
||||
* '' -> splash [is this even possible with MHD?
|
||||
*/
|
||||
if (strlen(url) == 0 ||
|
||||
!strcmp("/", url)) {
|
||||
@@ -157,7 +175,7 @@ static int is_splashpage(const char *host, const char *url)
|
||||
}
|
||||
|
||||
/* '/' -> splash
|
||||
* '' -> splash
|
||||
* '' -> splash
|
||||
*/
|
||||
if (strlen(url) == 0 ||
|
||||
!strcmp("/", url)) {
|
||||
@@ -184,7 +202,7 @@ get_ip(struct MHD_Connection *connection)
|
||||
const union MHD_ConnectionInfo *connection_info;
|
||||
char *ip_addr = NULL;
|
||||
const struct sockaddr *client_addr;
|
||||
const struct sockaddr_in *addrin;
|
||||
const struct sockaddr_in *addrin;
|
||||
const struct sockaddr_in6 *addrin6;
|
||||
if (!(connection_info = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS))) {
|
||||
return NULL;
|
||||
@@ -198,7 +216,10 @@ get_ip(struct MHD_Connection *connection)
|
||||
switch(client_addr->sa_family) {
|
||||
case AF_INET:
|
||||
ip_addr = calloc(1, INET_ADDRSTRLEN+1);
|
||||
if(!inet_ntop(addrin->sin_family, &(addrin->sin_addr), ip_addr , sizeof(struct sockaddr_in))) {
|
||||
if (ip_addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!inet_ntop(addrin->sin_family, &(addrin->sin_addr), ip_addr, sizeof(struct sockaddr_in))) {
|
||||
free(ip_addr);
|
||||
return NULL;
|
||||
}
|
||||
@@ -206,7 +227,10 @@ get_ip(struct MHD_Connection *connection)
|
||||
|
||||
case AF_INET6:
|
||||
ip_addr = calloc(1, INET6_ADDRSTRLEN+1);
|
||||
if(!inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr), ip_addr , sizeof(struct sockaddr_in6))) {
|
||||
if (ip_addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr), ip_addr, sizeof(struct sockaddr_in6))) {
|
||||
free(ip_addr);
|
||||
return NULL;
|
||||
}
|
||||
@@ -230,11 +254,11 @@ get_ip(struct MHD_Connection *connection)
|
||||
*/
|
||||
int
|
||||
libmicrohttpd_cb(void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
const char *url,
|
||||
const char *method,
|
||||
const char *version,
|
||||
const char *upload_data, size_t *upload_data_size, void **ptr)
|
||||
struct MHD_Connection *connection,
|
||||
const char *url,
|
||||
const char *method,
|
||||
const char *version,
|
||||
const char *upload_data, size_t *upload_data_size, void **ptr)
|
||||
{
|
||||
|
||||
t_client *client;
|
||||
@@ -242,9 +266,13 @@ libmicrohttpd_cb(void *cls,
|
||||
char *mac;
|
||||
int ret;
|
||||
|
||||
debug(LOG_DEBUG, "access: %s %s", method, url);
|
||||
|
||||
/* only allow get */
|
||||
if(0 != strcmp(method, "GET"))
|
||||
if (0 != strcmp(method, "GET")) {
|
||||
debug(LOG_DEBUG, "Unsupported http method %s", method);
|
||||
return send_error(connection, 503);
|
||||
}
|
||||
|
||||
/* switch between preauth, authenticated */
|
||||
/* - always - set caching headers
|
||||
@@ -257,8 +285,8 @@ libmicrohttpd_cb(void *cls,
|
||||
mac = arp_get(ip_addr);
|
||||
|
||||
client = client_list_find(ip_addr, mac);
|
||||
if(client) {
|
||||
if(client->fw_connection_state == FW_MARK_AUTHENTICATED ||
|
||||
if (client) {
|
||||
if (client->fw_connection_state == FW_MARK_AUTHENTICATED ||
|
||||
client->fw_connection_state == FW_MARK_TRUSTED) {
|
||||
/* client already authed - dangerous!!! This should never happen */
|
||||
ret = authenticated(connection, ip_addr, mac, url, client);
|
||||
@@ -267,6 +295,7 @@ libmicrohttpd_cb(void *cls,
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = preauthenticated(connection, ip_addr, mac, url, client);
|
||||
free(mac);
|
||||
free(ip_addr);
|
||||
@@ -296,19 +325,11 @@ static int check_authdir_match(const char *url, const char *authdir)
|
||||
static int check_token_is_valid(struct MHD_Connection *connection, t_client *client)
|
||||
{
|
||||
/* token check */
|
||||
struct collect_query_key query_key = { .key = "token" };
|
||||
const char *token = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "token");
|
||||
const char *tok = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "tok");
|
||||
|
||||
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &query_key);
|
||||
|
||||
/* token not found in query string */
|
||||
if (!query_key.value)
|
||||
return 0;
|
||||
|
||||
/* token doesn't match */
|
||||
if (strcmp(client->token, query_key.value))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
/* return true if token or tok match client->token */
|
||||
return ((token && !strcmp(client->token, token))) || (tok && !strcmp(client->token, tok));
|
||||
}
|
||||
|
||||
|
||||
@@ -332,13 +353,16 @@ static int try_to_authenticate(struct MHD_Connection *connection, t_client *clie
|
||||
if (check_authdir_match(url, config->authdir)) {
|
||||
/* matched to authdir */
|
||||
if (check_token_is_valid(connection, client)) {
|
||||
return 1; /* valid token */
|
||||
return 1;
|
||||
}
|
||||
} else if (check_authdir_match(url, config->denydir)) {
|
||||
/* matched to deauth */
|
||||
/* TODO: do we need denydir? */
|
||||
}
|
||||
|
||||
/* //TODO: do we need denydir?
|
||||
if (check_authdir_match(url, config->denydir)) {
|
||||
// matched to deauth
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -352,14 +376,18 @@ static int try_to_authenticate(struct MHD_Connection *connection, t_client *clie
|
||||
* @return
|
||||
*/
|
||||
static int authenticate_client(struct MHD_Connection *connection,
|
||||
const char *ip_addr,
|
||||
const char *mac,
|
||||
const char *redirect_url,
|
||||
t_client *client)
|
||||
const char *ip_addr,
|
||||
const char *mac,
|
||||
const char *redirect_url,
|
||||
t_client *client)
|
||||
{
|
||||
/* TODO: handle redirect_url == NULL */
|
||||
auth_client_action(ip_addr, mac, AUTH_MAKE_AUTHENTICATED);
|
||||
return send_redirect_temp(connection, redirect_url);
|
||||
if (redirect_url) {
|
||||
return send_redirect_temp(connection, redirect_url);
|
||||
} else {
|
||||
return send_error(connection, 200);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,17 +399,17 @@ static int authenticate_client(struct MHD_Connection *connection,
|
||||
* @param client
|
||||
* @return
|
||||
*
|
||||
* It's unsual to received request from clients which are already authed.
|
||||
* It's unsual to received request from clients which are already authenticated.
|
||||
* Happens when the user:
|
||||
* - clicked in multiple windows on "accept" -> redirect to origin - no checking
|
||||
* - when the user reloaded a splashpage -> redirect to origin
|
||||
* - when a user calls deny url -> deauth it
|
||||
*/
|
||||
static int authenticated(struct MHD_Connection *connection,
|
||||
const char *ip_addr,
|
||||
const char *mac,
|
||||
const char *url,
|
||||
t_client *client)
|
||||
const char *ip_addr,
|
||||
const char *mac,
|
||||
const char *url,
|
||||
t_client *client)
|
||||
{
|
||||
s_config *config = config_get_config();
|
||||
const char *redirect_url;
|
||||
@@ -390,24 +418,73 @@ static int authenticated(struct MHD_Connection *connection,
|
||||
|
||||
MHD_get_connection_values(connection, MHD_HEADER_KIND, get_host_value_callback, &host);
|
||||
|
||||
if (is_splashpage(host, url) ||
|
||||
check_authdir_match(url, config->authdir)) {
|
||||
if (is_splashpage(host, url) || check_authdir_match(url, config->authdir)) {
|
||||
redirect_url = get_redirect_url(connection);
|
||||
/* TODO: what should we do when we get such request? */
|
||||
if (redirect_url == NULL || strlen(redirect_url) == 0)
|
||||
if (redirect_url == NULL || strlen(redirect_url) == 0) {
|
||||
return show_splashpage(connection, client);
|
||||
else
|
||||
} else {
|
||||
return authenticate_client(connection, ip_addr, mac, redirect_url, client);
|
||||
}
|
||||
} else if (check_authdir_match(url, config->denydir)) {
|
||||
auth_client_action(ip_addr, mac, AUTH_MAKE_DEAUTHENTICATED);
|
||||
snprintf(redirect_to_us, 128, "http://%s:%u/", config->gw_address, config->gw_port);
|
||||
return send_redirect_temp(connection, redirect_to_us);
|
||||
}
|
||||
|
||||
|
||||
/* check if this is an late request meaning the user tries to get the internet, but ended up here,
|
||||
* because the iptables rule came to late */
|
||||
if (is_foreign_hosts(connection, host)) {
|
||||
/* might happen if the firewall rule isn't yet installed */
|
||||
return send_refresh(connection);
|
||||
}
|
||||
|
||||
/* user doesn't wants the splashpage or tried to auth itself */
|
||||
return serve_file(connection, client, url);
|
||||
}
|
||||
|
||||
static int authenticate_client_binauth(
|
||||
struct MHD_Connection *connection,
|
||||
const char *ip_addr,
|
||||
const char *mac,
|
||||
const char *redirect_url,
|
||||
t_client *client)
|
||||
{
|
||||
char username_enc[64] = {0};
|
||||
char password_enc[64] = {0};
|
||||
char msg[255] = {0};
|
||||
int rc;
|
||||
|
||||
s_config *config = config_get_config();
|
||||
|
||||
const char *username = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "username");
|
||||
const char *password = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "password");
|
||||
|
||||
if ((username && uh_urlencode(username_enc, sizeof(username_enc), username, strlen(username)) == -1)
|
||||
|| (password && uh_urlencode(password_enc, sizeof(password_enc), password, strlen(password)) == -1)) {
|
||||
debug(LOG_ERR, "Failed to encode username and password for binauth");
|
||||
return encode_and_redirect_to_splashpage(connection, redirect_url);
|
||||
}
|
||||
|
||||
rc = execute_ret(msg, sizeof(msg) - 1, "%s client_auth '%s' '%s' '%s'",
|
||||
config->bin_auth, mac, username_enc, password_enc);
|
||||
|
||||
if (rc != 0) {
|
||||
return encode_and_redirect_to_splashpage(connection, redirect_url);
|
||||
}
|
||||
|
||||
rc = set_binauth_data(msg, config, client);
|
||||
|
||||
if (rc != 0) {
|
||||
return encode_and_redirect_to_splashpage(connection, redirect_url);
|
||||
}
|
||||
|
||||
debug(LOG_NOTICE, "Remote auth data: client [%s, %s] authenticated", mac, client->ip);
|
||||
|
||||
return authenticate_client(connection, ip_addr, mac, redirect_url, client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief preauthenticated - called for all request of a client in this state.
|
||||
* @param connection
|
||||
@@ -421,7 +498,7 @@ static int preauthenticated(struct MHD_Connection *connection,
|
||||
const char *url,
|
||||
t_client *client)
|
||||
{
|
||||
char *host = NULL;
|
||||
const char *host = NULL;
|
||||
const char *redirect_url;
|
||||
s_config *config = config_get_config();
|
||||
|
||||
@@ -433,33 +510,46 @@ static int preauthenticated(struct MHD_Connection *connection,
|
||||
|
||||
MHD_get_connection_values(connection, MHD_HEADER_KIND, get_host_value_callback, &host);
|
||||
|
||||
/* check if this is a redirect querty with a foreign host as target */
|
||||
if(is_foreign_hosts(connection, host)) {
|
||||
/* check if this is a redirect query with a foreign host as target */
|
||||
if (is_foreign_hosts(connection, host)) {
|
||||
return redirect_to_splashpage(connection, client, host, url);
|
||||
}
|
||||
|
||||
/* request is directed to us */
|
||||
/* check if client wants to be authenticated */
|
||||
if(check_authdir_match(url, config->authdir)) {
|
||||
|
||||
if (check_authdir_match(url, config->authdir)) {
|
||||
/* Only the first request will redirected to config->redirectURL.
|
||||
* When the client reloads a page when it's authenticated, it should be redirected
|
||||
* to their origin url
|
||||
*/
|
||||
if (config->redirectURL)
|
||||
if (config->redirectURL) {
|
||||
redirect_url = config->redirectURL;
|
||||
else
|
||||
redirect_url = get_redirect_url(connection);
|
||||
|
||||
if (try_to_authenticate(connection, client, host, url)) {
|
||||
return authenticate_client(connection, ip_addr, mac, redirect_url, client);
|
||||
} else {
|
||||
redirect_url = get_redirect_url(connection);
|
||||
}
|
||||
|
||||
if (!try_to_authenticate(connection, client, host, url)) {
|
||||
/* user used an invalid token, redirect to splashpage but hold query "redir" intact */
|
||||
return encode_and_redirect_to_splashpage(connection, redirect_url);
|
||||
}
|
||||
|
||||
if (config->bin_auth) {
|
||||
return authenticate_client_binauth(connection, ip_addr, mac, redirect_url, client);
|
||||
} else {
|
||||
client->session_start = time(NULL);
|
||||
|
||||
if (config->session_timeout) {
|
||||
client->session_end = client->session_start + config->session_timeout;
|
||||
} else {
|
||||
/* Session has no end */
|
||||
client->session_end = 0;
|
||||
}
|
||||
|
||||
return authenticate_client(connection, ip_addr, mac, redirect_url, client);
|
||||
}
|
||||
}
|
||||
|
||||
if(is_splashpage(host, url)) {
|
||||
if (is_splashpage(host, url)) {
|
||||
return show_splashpage(connection, client);
|
||||
}
|
||||
|
||||
@@ -481,18 +571,28 @@ static int encode_and_redirect_to_splashpage(struct MHD_Connection *connection,
|
||||
int ret;
|
||||
s_config *config = config_get_config();
|
||||
|
||||
|
||||
memset(encoded, 0, sizeof(encoded));
|
||||
if (uh_urlencode(encoded, 2048, originurl, strlen(originurl)) == -1) {
|
||||
debug(LOG_WARNING, "could not encode url");
|
||||
if (originurl) {
|
||||
if (uh_urlencode(encoded, sizeof(encoded), originurl, strlen(originurl)) == -1) {
|
||||
debug(LOG_WARNING, "could not encode url");
|
||||
} else {
|
||||
debug(LOG_DEBUG, "originurl: %s", originurl);
|
||||
}
|
||||
}
|
||||
|
||||
if (encoded[0]) {
|
||||
safe_asprintf(&splashpageurl, "http://%s:%u/%s?redir=%s",
|
||||
config->gw_address, config->gw_port, config->splashpage, encoded);
|
||||
} else {
|
||||
safe_asprintf(&splashpageurl, "http://%s:%u/%s",
|
||||
config->gw_address, config->gw_port, config->splashpage);
|
||||
}
|
||||
|
||||
safe_asprintf(&splashpageurl, "http://%s:%u%s?redir=%s", config->gw_address , config->gw_port, "/splash.html", encoded);
|
||||
debug(LOG_DEBUG, "originurl: %s", originurl);
|
||||
debug(LOG_DEBUG, "splashpageurl: %s", splashpageurl);
|
||||
|
||||
ret = send_redirect_temp(connection, splashpageurl);
|
||||
free(splashpageurl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -507,13 +607,20 @@ static int encode_and_redirect_to_splashpage(struct MHD_Connection *connection,
|
||||
static int redirect_to_splashpage(struct MHD_Connection *connection, t_client *client, const char *host, const char *url)
|
||||
{
|
||||
char *originurl = NULL;
|
||||
char *query = "";
|
||||
char *query = NULL;
|
||||
int ret = 0;
|
||||
|
||||
get_query(connection, &query);
|
||||
if (!query) {
|
||||
/* no mem */
|
||||
return send_error(connection, 503);
|
||||
}
|
||||
|
||||
safe_asprintf(&originurl, "http://%s%s%s%s", host, url, strlen(query) ? "?" : "" , query);
|
||||
|
||||
return encode_and_redirect_to_splashpage(connection, originurl);
|
||||
ret = encode_and_redirect_to_splashpage(connection, originurl);
|
||||
free(originurl);
|
||||
free(query);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -527,7 +634,7 @@ static int redirect_to_splashpage(struct MHD_Connection *connection, t_client *c
|
||||
static t_client *
|
||||
add_client(const char *ip_addr)
|
||||
{
|
||||
t_client *client;
|
||||
t_client *client;
|
||||
|
||||
LOCK_CLIENT_LIST();
|
||||
client = client_list_add_client(ip_addr);
|
||||
@@ -539,7 +646,7 @@ int send_redirect_temp(struct MHD_Connection *connection, const char *url)
|
||||
{
|
||||
struct MHD_Response *response;
|
||||
int ret;
|
||||
char *redirect;
|
||||
char *redirect = NULL;
|
||||
|
||||
const char *redirect_body = "<html><head></head><body><a href='%s'>Click here to continue to<br>%s</a></body></html>";
|
||||
safe_asprintf(&redirect, redirect_body, url, url);
|
||||
@@ -548,7 +655,7 @@ int send_redirect_temp(struct MHD_Connection *connection, const char *url)
|
||||
if (!response)
|
||||
return send_error(connection, 503);
|
||||
|
||||
// MHD_set_response_options(response, MHD_RF_HTTP_VERSION_1_0_ONLY, MHD_RO_END);
|
||||
// MHD_set_response_options(response, MHD_RF_HTTP_VERSION_1_0_ONLY, MHD_RO_END);
|
||||
MHD_add_response_header(response, "Location", url);
|
||||
MHD_add_response_header(response, "Connection", "close");
|
||||
ret = MHD_queue_response(connection, MHD_HTTP_TEMPORARY_REDIRECT, response);
|
||||
@@ -567,16 +674,11 @@ int send_redirect_temp(struct MHD_Connection *connection, const char *url)
|
||||
*/
|
||||
static const char *get_redirect_url(struct MHD_Connection *connection)
|
||||
{
|
||||
struct collect_query_key query_key = { .key = "redir" };
|
||||
|
||||
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &collect_query_key, &query_key);
|
||||
|
||||
if (!query_key.value)
|
||||
return NULL;
|
||||
|
||||
return query_key.value;
|
||||
return MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "redir");
|
||||
}
|
||||
|
||||
/* save the query or empty string into **query.
|
||||
* the call must free query later */
|
||||
static int get_query(struct MHD_Connection *connection, char **query)
|
||||
{
|
||||
int element_counter;
|
||||
@@ -592,26 +694,36 @@ static int get_query(struct MHD_Connection *connection, char **query)
|
||||
return 0;
|
||||
}
|
||||
elements = calloc(element_counter, sizeof(char *));
|
||||
if (elements == NULL) {
|
||||
return 0;
|
||||
}
|
||||
collect_query.i = 0;
|
||||
collect_query.elements = elements;
|
||||
|
||||
// static int get_host_value_callback(void *cls, enum MHD_ValueKind kind, const char *key, const char *value) {
|
||||
// static int get_host_value_callback(void *cls, enum MHD_ValueKind kind, const char *key, const char *value) {
|
||||
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, collect_query_string, &collect_query);
|
||||
|
||||
for(i=0; i<element_counter; i++) {
|
||||
if(!elements[i])
|
||||
if (!elements[i])
|
||||
continue;
|
||||
length += strlen(elements[i]);
|
||||
|
||||
if(i >0) /* q=foo&o=bar the '&' need also some space */
|
||||
if (i >0) /* q=foo&o=bar the '&' need also some space */
|
||||
length++;
|
||||
}
|
||||
|
||||
/* don't miss the zero terminator */
|
||||
*query = calloc(1, length+1);
|
||||
if (*query == NULL) {
|
||||
for(i=0; i < element_counter; i++) {
|
||||
free(elements[i]);
|
||||
}
|
||||
free(elements);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(i=0, j=0; i<element_counter; i++) {
|
||||
if(!elements[i])
|
||||
if (!elements[i])
|
||||
continue;
|
||||
strncpy(*query + j, elements[i], length-j);
|
||||
free(elements[i]);
|
||||
@@ -621,10 +733,27 @@ static int get_query(struct MHD_Connection *connection, char **query)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_refresh(struct MHD_Connection *connection)
|
||||
{
|
||||
struct MHD_Response *response = NULL;
|
||||
|
||||
const char *refresh = "<html><meta http-equiv=\"refresh\" content=\"1\"><head/></html>";
|
||||
const char *mimetype = lookup_mimetype("foo.html");
|
||||
int ret;
|
||||
|
||||
response = MHD_create_response_from_buffer(strlen(refresh), (char *)refresh, MHD_RESPMEM_PERSISTENT);
|
||||
MHD_add_response_header(response, "Content-Type", mimetype);
|
||||
MHD_add_response_header (response, MHD_HTTP_HEADER_CONNECTION, "close");
|
||||
ret = MHD_queue_response(connection, 200, response);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int send_error(struct MHD_Connection *connection, int error)
|
||||
{
|
||||
struct MHD_Response *response = NULL;
|
||||
// cannot automate since cannot translate automagically between error number and MHD's status codes -- and cannot rely on MHD_HTTP_ values to provide an upper bound for an array
|
||||
const char *page_200 = "<html><header><title>Authenticated</title><body><h1>Authenticated</h1></body></html>";
|
||||
const char *page_400 = "<html><head><title>Error 400</title></head><body><h1>Error 400 - Bad Request</h1></body></html>";
|
||||
const char *page_403 = "<html><head><title>Error 403</title></head><body><h1>Error 403 - Forbidden</h1></body></html>";
|
||||
const char *page_404 = "<html><head><title>Error 404</title></head><body><h1>Error 404 - Not Found</h1></body></html>";
|
||||
@@ -637,6 +766,12 @@ static int send_error(struct MHD_Connection *connection, int error)
|
||||
int ret = MHD_NO;
|
||||
|
||||
switch (error) {
|
||||
case 200:
|
||||
response = MHD_create_response_from_buffer(strlen(page_200), (char *)page_200, MHD_RESPMEM_PERSISTENT);
|
||||
MHD_add_response_header(response, "Content-Type", mimetype);
|
||||
ret = MHD_queue_response(connection, error, response);
|
||||
break;
|
||||
|
||||
case 400:
|
||||
response = MHD_create_response_from_buffer(strlen(page_400), (char *)page_400, MHD_RESPMEM_PERSISTENT);
|
||||
MHD_add_response_header(response, "Content-Type", mimetype);
|
||||
@@ -688,19 +823,20 @@ static int send_error(struct MHD_Connection *connection, int error)
|
||||
*/
|
||||
static int get_host_value_callback(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
|
||||
{
|
||||
char **host = (char **)cls;
|
||||
const char **host = (const char **)cls;
|
||||
if (MHD_HEADER_KIND != kind) {
|
||||
*host = NULL;
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
if (!strcmp("Host", key)) {
|
||||
*host = safe_strdup(value);
|
||||
*host = value;
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief show_splashpage is called when the client clicked on Ok as well when the client doesn't know us yet.
|
||||
* @param connection
|
||||
@@ -720,7 +856,7 @@ static int show_splashpage(struct MHD_Connection *connection, t_client *client)
|
||||
char *splashpage_result;
|
||||
char *splashpage_tmpl;
|
||||
|
||||
snprintf(filename, PATH_MAX, "%s/%s",config->webroot ,config->splashpage);
|
||||
snprintf(filename, PATH_MAX, "%s/%s", config->webroot, config->splashpage);
|
||||
|
||||
splashpage_fd = open(filename, O_RDONLY);
|
||||
if (splashpage_fd < 0)
|
||||
@@ -734,10 +870,20 @@ static int show_splashpage(struct MHD_Connection *connection, t_client *client)
|
||||
|
||||
/* we TMPLVAR_SIZE for template variables */
|
||||
splashpage_tmpl = calloc(1, size);
|
||||
if (splashpage_tmpl == NULL) {
|
||||
close(splashpage_fd);
|
||||
return send_error(connection, 503);
|
||||
}
|
||||
|
||||
splashpage_result = calloc(1, size + TMPLVAR_SIZE);
|
||||
if (splashpage_result == NULL) {
|
||||
close(splashpage_fd);
|
||||
free(splashpage_tmpl);
|
||||
return send_error(connection, 503);
|
||||
}
|
||||
|
||||
while (bytes < size) {
|
||||
ret = read(splashpage_fd, splashpage_tmpl+bytes, size-bytes);
|
||||
ret = read(splashpage_fd, splashpage_tmpl + bytes, size - bytes);
|
||||
if (ret < 0) {
|
||||
free(splashpage_result);
|
||||
free(splashpage_tmpl);
|
||||
@@ -754,22 +900,16 @@ static int show_splashpage(struct MHD_Connection *connection, t_client *client)
|
||||
char *authaction = NULL;
|
||||
char *authtarget = NULL;
|
||||
const char *redirect_url = NULL;
|
||||
char redirect_url_encoded[2048];
|
||||
char *imagesdir = NULL;
|
||||
char *pagesdir = NULL;
|
||||
|
||||
memset(redirect_url_encoded, 0, sizeof(redirect_url_encoded));
|
||||
redirect_url = get_redirect_url(connection);
|
||||
if (redirect_url) {
|
||||
uh_urlencode(redirect_url_encoded, sizeof(redirect_url_encoded), redirect_url, strlen(redirect_url));
|
||||
}
|
||||
|
||||
safe_asprintf(&nclients, "%d", get_client_list_length());
|
||||
safe_asprintf(&maxclients, "%d", config->maxclients);
|
||||
safe_asprintf(&denyaction, "http://%s:%d/%s/", config->gw_address, config->gw_port, config->denydir);
|
||||
safe_asprintf(&authaction, "http://%s:%d/%s/", config->gw_address, config->gw_port, config->authdir);
|
||||
safe_asprintf(&authtarget, "http://%s:%d/%s/?token=%s&redir=%s", config->gw_address, config->gw_port, config->authdir, client->token, redirect_url_encoded);
|
||||
safe_asprintf(&authaction, "http://%s:%d/%s/", config->gw_address, config->gw_port, config->authdir);
|
||||
safe_asprintf(&authtarget, "http://%s:%d/%s/?token=%s&redir=%s", config->gw_address, config->gw_port, config->authdir, client->token, redirect_url);
|
||||
safe_asprintf(&pagesdir, "/%s", config->pagesdir);
|
||||
safe_asprintf(&imagesdir, "/%s", config->imagesdir);
|
||||
|
||||
@@ -778,7 +918,6 @@ static int show_splashpage(struct MHD_Connection *connection, t_client *client)
|
||||
tmpl_set_variable(&templor, "authtarget", authtarget);
|
||||
tmpl_set_variable(&templor, "clientip", client->ip);
|
||||
tmpl_set_variable(&templor, "clientmac", client->mac);
|
||||
// tmpl_set_variable(&templor, "content", VERSION);
|
||||
tmpl_set_variable(&templor, "denyaction", denyaction);
|
||||
tmpl_set_variable(&templor, "error_msg", "");
|
||||
|
||||
@@ -793,16 +932,19 @@ static int show_splashpage(struct MHD_Connection *connection, t_client *client)
|
||||
|
||||
tmpl_set_variable(&templor, "redir", redirect_url);
|
||||
tmpl_set_variable(&templor, "tok", client->token);
|
||||
tmpl_set_variable(&templor, "token", client->token);
|
||||
tmpl_set_variable(&templor, "uptime", uptime);
|
||||
tmpl_set_variable(&templor, "version", VERSION);
|
||||
|
||||
tmpl_parse(&templor, splashpage_result, size + TMPLVAR_SIZE, splashpage_tmpl, size);
|
||||
free(authaction);
|
||||
free(denyaction);
|
||||
free(maxclients);
|
||||
free(nclients);
|
||||
free(uptime);
|
||||
free(splashpage_tmpl);
|
||||
free(uptime);
|
||||
free(nclients);
|
||||
free(maxclients);
|
||||
free(denyaction);
|
||||
free(authaction);
|
||||
free(authtarget);
|
||||
free(pagesdir);
|
||||
free(imagesdir);
|
||||
|
||||
response = MHD_create_response_from_buffer(strlen(splashpage_result), (void *)splashpage_result, MHD_RESPMEM_MUST_FREE);
|
||||
@@ -848,20 +990,22 @@ const char *lookup_mimetype(const char *filename)
|
||||
int i;
|
||||
const char *extension;
|
||||
|
||||
if(!filename) {
|
||||
if (!filename) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extension = get_extension(filename);
|
||||
if(!extension)
|
||||
if (!extension)
|
||||
return DEFAULT_MIME_TYPE;
|
||||
|
||||
for(i=0; i< ARRAY_SIZE(uh_mime_types); i++) {
|
||||
if(strcmp(extension, uh_mime_types[i].extn) == 0) {
|
||||
if (strcmp(extension, uh_mime_types[i].extn) == 0) {
|
||||
return uh_mime_types[i].mime;
|
||||
}
|
||||
}
|
||||
|
||||
debug(LOG_INFO, "Could not find corresponding mimetype for %s extension", extension);
|
||||
|
||||
return DEFAULT_MIME_TYPE;
|
||||
}
|
||||
|
||||
@@ -873,15 +1017,31 @@ const char *lookup_mimetype(const char *filename)
|
||||
*/
|
||||
static int serve_file(struct MHD_Connection *connection, t_client *client, const char *url)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
s_config *config = config_get_config();
|
||||
struct MHD_Response *response;
|
||||
char filename[PATH_MAX];
|
||||
int ret = MHD_NO;
|
||||
const char *mimetype = NULL;
|
||||
size_t size;
|
||||
off_t size;
|
||||
|
||||
snprintf(filename, PATH_MAX, "%s/%s", config->webroot, url);
|
||||
|
||||
/* check if file exists and is not a directory */
|
||||
ret = stat(filename, &stat_buf);
|
||||
if (ret) {
|
||||
/* stat failed */
|
||||
return send_error(connection, 404);
|
||||
}
|
||||
|
||||
if (!S_ISREG(stat_buf.st_mode)) {
|
||||
#ifdef S_ISLNK
|
||||
/* ignore links */
|
||||
if (!S_ISLNK(stat_buf.st_mode))
|
||||
#endif /* S_ISLNK */
|
||||
return send_error(connection, 404);
|
||||
}
|
||||
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return send_error(connection, 404);
|
||||
@@ -890,6 +1050,9 @@ static int serve_file(struct MHD_Connection *connection, t_client *client, const
|
||||
|
||||
/* serving file and creating response */
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
if (size < 0)
|
||||
return send_error(connection, 404);
|
||||
|
||||
response = MHD_create_response_from_fd(size, fd);
|
||||
if (!response)
|
||||
return send_error(connection, 503);
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
struct MHD_Connection;
|
||||
|
||||
int libmicrohttpd_cb (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
const char *url,
|
||||
const char *method,
|
||||
const char *version,
|
||||
const char *upload_data, size_t *upload_data_size, void **ptr);
|
||||
struct MHD_Connection *connection,
|
||||
const char *url,
|
||||
const char *method,
|
||||
const char *version,
|
||||
const char *upload_data, size_t *upload_data_size, void **ptr);
|
||||
|
||||
|
||||
#endif // NDS_MICROHTTPD_H
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* blen is the size of buf; slen is the length of src. The input-string need
|
||||
** not be, and the output string will not be, null-terminated. Returns the
|
||||
/* blen is the size of buf; slen is the length of src. The input-string need
|
||||
** not be, and the output string will not be, null-terminated. Returns the
|
||||
** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */
|
||||
int uh_urldecode(char *buf, int blen, const char *src, int slen)
|
||||
{
|
||||
@@ -59,13 +59,13 @@ int uh_urlencode(char *buf, int blen, const char *src, int slen)
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
|
||||
for (i = 0; (i < slen) && (len < blen); i++) {
|
||||
if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
|
||||
(src[i] == '.') || (src[i] == '~') ) {
|
||||
if (isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
|
||||
(src[i] == '.') || (src[i] == '~')) {
|
||||
buf[len++] = src[i];
|
||||
} else if ((len+3) <= blen) {
|
||||
buf[len++] = '%';
|
||||
buf[len++] = hex[(src[i] >> 4) & 15];
|
||||
buf[len++] = hex[ src[i] & 15];
|
||||
buf[len++] = hex[ src[i] & 15];
|
||||
} else {
|
||||
len = -1;
|
||||
break;
|
||||
@@ -79,7 +79,7 @@ int uh_b64decode(char *buf, int blen, const void *src, int slen)
|
||||
{
|
||||
const unsigned char *str = src;
|
||||
unsigned int cout = 0;
|
||||
unsigned int cin = 0;
|
||||
unsigned int cin = 0;
|
||||
int len = 0;
|
||||
int i = 0;
|
||||
|
||||
|
||||
@@ -27,68 +27,73 @@ struct mimetype {
|
||||
|
||||
static const struct mimetype uh_mime_types[] = {
|
||||
|
||||
{ "txt", "text/plain" },
|
||||
{ "log", "text/plain" },
|
||||
{ "txt", "text/plain" },
|
||||
{ "log", "text/plain" },
|
||||
{ "js", "text/javascript" },
|
||||
{ "css", "text/css" },
|
||||
{ "htm", "text/html; charset=utf-8" },
|
||||
{ "css", "text/css" },
|
||||
{ "htm", "text/html; charset=utf-8" },
|
||||
{ "html", "text/html; charset=utf-8" },
|
||||
{ "diff", "text/x-patch" },
|
||||
{ "patch", "text/x-patch" },
|
||||
{ "c", "text/x-csrc" },
|
||||
{ "h", "text/x-chdr" },
|
||||
{ "o", "text/x-object" },
|
||||
{ "patch", "text/x-patch" },
|
||||
{ "c", "text/x-csrc" },
|
||||
{ "h", "text/x-chdr" },
|
||||
{ "o", "text/x-object" },
|
||||
{ "ko", "text/x-object" },
|
||||
|
||||
{ "bmp", "image/bmp" },
|
||||
{ "gif", "image/gif" },
|
||||
{ "png", "image/png" },
|
||||
{ "jpg", "image/jpeg" },
|
||||
{ "bmp", "image/bmp" },
|
||||
{ "gif", "image/gif" },
|
||||
{ "png", "image/png" },
|
||||
{ "jpg", "image/jpeg" },
|
||||
{ "jpeg", "image/jpeg" },
|
||||
{ "svg", "image/svg+xml" },
|
||||
{ "svg", "image/svg+xml" },
|
||||
|
||||
{ "json", "application/json" },
|
||||
{ "jsonp", "application/javascript" },
|
||||
{ "zip", "application/zip" },
|
||||
{ "pdf", "application/pdf" },
|
||||
{ "xml", "application/xml" },
|
||||
{ "xsl", "application/xml" },
|
||||
{ "doc", "application/msword" },
|
||||
{ "ppt", "application/vnd.ms-powerpoint" },
|
||||
{ "xls", "application/vnd.ms-excel" },
|
||||
{ "odt", "application/vnd.oasis.opendocument.text" },
|
||||
{ "odp", "application/vnd.oasis.opendocument.presentation" },
|
||||
{ "jsonp", "application/javascript" },
|
||||
{ "zip", "application/zip" },
|
||||
{ "pdf", "application/pdf" },
|
||||
{ "xml", "application/xml" },
|
||||
{ "xsl", "application/xml" },
|
||||
{ "doc", "application/msword" },
|
||||
{ "ppt", "application/vnd.ms-powerpoint" },
|
||||
{ "xls", "application/vnd.ms-excel" },
|
||||
{ "odt", "application/vnd.oasis.opendocument.text" },
|
||||
{ "odp", "application/vnd.oasis.opendocument.presentation" },
|
||||
{ "pl", "application/x-perl" },
|
||||
{ "sh", "application/x-shellscript" },
|
||||
{ "php", "application/x-php" },
|
||||
{ "deb", "application/x-deb" },
|
||||
{ "iso", "application/x-cd-image" },
|
||||
{ "tar.gz", "application/x-compressed-tar" },
|
||||
{ "tgz", "application/x-compressed-tar" },
|
||||
{ "php", "application/x-php" },
|
||||
{ "deb", "application/x-deb" },
|
||||
{ "iso", "application/x-cd-image" },
|
||||
{ "tar.gz", "application/x-compressed-tar" },
|
||||
{ "tgz", "application/x-compressed-tar" },
|
||||
{ "gz", "application/x-gzip" },
|
||||
{ "tar.bz2", "application/x-bzip-compressed-tar" },
|
||||
{ "tbz", "application/x-bzip-compressed-tar" },
|
||||
{ "bz2", "application/x-bzip" },
|
||||
{ "tar", "application/x-tar" },
|
||||
{ "rar", "application/x-rar-compressed" },
|
||||
{ "tar.bz2", "application/x-bzip-compressed-tar" },
|
||||
{ "tbz", "application/x-bzip-compressed-tar" },
|
||||
{ "bz2", "application/x-bzip" },
|
||||
{ "tar", "application/x-tar" },
|
||||
{ "rar", "application/x-rar-compressed" },
|
||||
|
||||
{ "mp3", "audio/mpeg" },
|
||||
{ "ogg", "audio/x-vorbis+ogg" },
|
||||
{ "mp3", "audio/mpeg" },
|
||||
{ "ogg", "audio/x-vorbis+ogg" },
|
||||
{ "wav", "audio/x-wav" },
|
||||
|
||||
{ "mpg", "video/mpeg" },
|
||||
{ "mpg", "video/mpeg" },
|
||||
{ "mpeg", "video/mpeg" },
|
||||
{ "avi", "video/x-msvideo" },
|
||||
{ "avi", "video/x-msvideo" },
|
||||
|
||||
{ "README", "text/plain" },
|
||||
{ "log", "text/plain" },
|
||||
{ "cfg", "text/plain" },
|
||||
{ "README", "text/plain" },
|
||||
{ "log", "text/plain" },
|
||||
{ "cfg", "text/plain" },
|
||||
{ "conf", "text/plain" },
|
||||
|
||||
{ "pac", "application/x-ns-proxy-autoconfig" },
|
||||
{ "wpad.dat", "application/x-ns-proxy-autoconfig" },
|
||||
|
||||
{ NULL, NULL }
|
||||
{ "woff", "application/x-font-woff" },
|
||||
{ "woff2", "application/x-font-woff2" },
|
||||
{ "ttf", "application/x-font-ttf" },
|
||||
{ "eot", "application/vnd.ms-fontobject" },
|
||||
{ "svg", "image/svg+xml" },
|
||||
{ "otf", "application/x-font-opentype" },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
185
src/ndsctl.c
185
src/ndsctl.c
@@ -64,8 +64,6 @@ static void ndsctl_untrust(void);
|
||||
static void ndsctl_auth(void);
|
||||
static void ndsctl_deauth(void);
|
||||
static void ndsctl_loglevel(void);
|
||||
static void ndsctl_username(void);
|
||||
static void ndsctl_password(void);
|
||||
|
||||
/** @internal
|
||||
* @brief Print usage
|
||||
@@ -75,29 +73,29 @@ static void ndsctl_password(void);
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("Usage: ndsctl [options] command [arguments]\n");
|
||||
printf("\n");
|
||||
printf("options:\n");
|
||||
printf(" -s <path> Path to the socket\n");
|
||||
printf(" -h Print usage\n");
|
||||
printf("\n");
|
||||
printf("commands:\n");
|
||||
printf(" status View the status of nodogsplash\n");
|
||||
printf(" clients Display machine-readable client list\n");
|
||||
printf(" json Display machine-readable client list in json format\n");
|
||||
printf(" stop Stop the running nodogsplash\n");
|
||||
printf(" auth mac|ip|token Authenticate user with specified mac, ip or token\n");
|
||||
printf(" deauth mac|ip|token Deauthenticate user with specified mac, ip or token\n");
|
||||
printf(" block mac Block the given MAC address\n");
|
||||
printf(" unblock mac Unblock the given MAC address\n");
|
||||
printf(" allow mac Allow the given MAC address\n");
|
||||
printf(" unallow mac Unallow the given MAC address\n");
|
||||
printf(" trust mac Trust the given MAC address\n");
|
||||
printf(" untrust mac Untrust the given MAC address\n");
|
||||
printf(" loglevel n Set logging level to n\n");
|
||||
printf(" password pass Set gateway password\n");
|
||||
printf(" username name Set gateway username\n");
|
||||
printf("\n");
|
||||
printf(
|
||||
"Usage: ndsctl [options] command [arguments]\n"
|
||||
"\n"
|
||||
"options:\n"
|
||||
" -s <path> Path to the socket\n"
|
||||
" -h Print usage\n"
|
||||
"\n"
|
||||
"commands:\n"
|
||||
" status View the status of nodogsplash\n"
|
||||
" clients Display machine-readable client list\n"
|
||||
" json Display machine-readable client list in json format\n"
|
||||
" stop Stop the running nodogsplash\n"
|
||||
" auth mac|ip|token Authenticate user with specified mac, ip or token\n"
|
||||
" deauth mac|ip|token Deauthenticate user with specified mac, ip or token\n"
|
||||
" block mac Block the given MAC address\n"
|
||||
" unblock mac Unblock the given MAC address\n"
|
||||
" allow mac Allow the given MAC address\n"
|
||||
" unallow mac Unallow the given MAC address\n"
|
||||
" trust mac Trust the given MAC address\n"
|
||||
" untrust mac Untrust the given MAC address\n"
|
||||
" loglevel n Set logging level to n\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -153,15 +151,12 @@ parse_commandline(int argc, char **argv)
|
||||
config.command = NDSCTL_CLIENTS;
|
||||
} else if (strcmp(*(argv + optind), "json") == 0) {
|
||||
config.command = NDSCTL_JSON;
|
||||
}
|
||||
|
||||
else if (strcmp(*(argv + optind), "stop") == 0) {
|
||||
} else if (strcmp(*(argv + optind), "stop") == 0) {
|
||||
config.command = NDSCTL_STOP;
|
||||
} else if (strcmp(*(argv + optind), "block") == 0) {
|
||||
config.command = NDSCTL_BLOCK;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a "
|
||||
"MAC address to block\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a MAC address to block\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -169,8 +164,7 @@ parse_commandline(int argc, char **argv)
|
||||
} else if (strcmp(*(argv + optind), "unblock") == 0) {
|
||||
config.command = NDSCTL_UNBLOCK;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a "
|
||||
"MAC address to unblock\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a MAC address to unblock\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -178,8 +172,7 @@ parse_commandline(int argc, char **argv)
|
||||
} else if (strcmp(*(argv + optind), "allow") == 0) {
|
||||
config.command = NDSCTL_ALLOW;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a "
|
||||
"MAC address to allow\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a MAC address to allow\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -187,8 +180,7 @@ parse_commandline(int argc, char **argv)
|
||||
} else if (strcmp(*(argv + optind), "unallow") == 0) {
|
||||
config.command = NDSCTL_UNALLOW;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a "
|
||||
"MAC address to unallow\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a MAC address to unallow\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -196,8 +188,7 @@ parse_commandline(int argc, char **argv)
|
||||
} else if (strcmp(*(argv + optind), "trust") == 0) {
|
||||
config.command = NDSCTL_TRUST;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a "
|
||||
"MAC address to trust\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a MAC address to trust\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -205,8 +196,7 @@ parse_commandline(int argc, char **argv)
|
||||
} else if (strcmp(*(argv + optind), "untrust") == 0) {
|
||||
config.command = NDSCTL_UNTRUST;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a "
|
||||
"MAC address to untrust\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a MAC address to untrust\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -214,8 +204,7 @@ parse_commandline(int argc, char **argv)
|
||||
} else if (strcmp(*(argv + optind), "auth") == 0) {
|
||||
config.command = NDSCTL_AUTH;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify an IP "
|
||||
"address to auth\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify an IP address to auth\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -223,8 +212,7 @@ parse_commandline(int argc, char **argv)
|
||||
} else if (strcmp(*(argv + optind), "deauth") == 0) {
|
||||
config.command = NDSCTL_DEAUTH;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify an IP "
|
||||
"or a Mac address to deauth\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify an IP or a MAC address to deauth\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -232,24 +220,7 @@ parse_commandline(int argc, char **argv)
|
||||
} else if (strcmp(*(argv + optind), "loglevel") == 0) {
|
||||
config.command = NDSCTL_LOGLEVEL;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify an integer "
|
||||
"loglevel to loglevel\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
config.param = strdup(*(argv + optind + 1));
|
||||
} else if (strcmp(*(argv + optind), "password") == 0) {
|
||||
config.command = NDSCTL_PASSWORD;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a password\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
config.param = strdup(*(argv + optind + 1));
|
||||
} else if (strcmp(*(argv + optind), "username") == 0) {
|
||||
config.command = NDSCTL_USERNAME;
|
||||
if ((argc - (optind + 1)) <= 0) {
|
||||
fprintf(stderr, "ndsctl: Error: You must specify a username\n");
|
||||
fprintf(stderr, "ndsctl: Error: You must specify an integer loglevel to loglevel\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
@@ -265,7 +236,7 @@ static int
|
||||
connect_to_server(const char sock_name[])
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_un sa_un;
|
||||
struct sockaddr_un sa_un;
|
||||
|
||||
/* Connect to socket */
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
@@ -273,8 +244,7 @@ connect_to_server(const char sock_name[])
|
||||
sa_un.sun_family = AF_UNIX;
|
||||
strncpy(sa_un.sun_path, sock_name, (sizeof(sa_un.sun_path) - 1));
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&sa_un,
|
||||
strlen(sa_un.sun_path) + sizeof(sa_un.sun_family))) {
|
||||
if (connect(sock, (struct sockaddr *)&sa_un, strlen(sa_un.sun_path) + sizeof(sa_un.sun_family))) {
|
||||
fprintf(stderr, "ndsctl: nodogsplash probably not started (Error: %s)\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
@@ -285,14 +255,13 @@ connect_to_server(const char sock_name[])
|
||||
static int
|
||||
send_request(int sock, const char request[])
|
||||
{
|
||||
ssize_t len, written;
|
||||
ssize_t len, written;
|
||||
|
||||
len = 0;
|
||||
while (len != strlen(request)) {
|
||||
written = write(sock, (request + len), strlen(request) - len);
|
||||
if (written == -1) {
|
||||
fprintf(stderr, "Write to nodogsplash failed: %s\n",
|
||||
strerror(errno));
|
||||
fprintf(stderr, "Write to nodogsplash failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
len += written;
|
||||
@@ -316,8 +285,7 @@ ndsctl_action(const char cmd[], const char ifyes[], const char ifno[])
|
||||
|
||||
sock = connect_to_server(config.socket);
|
||||
|
||||
snprintf(request, sizeof(request)-strlen(NDSCTL_TERMINATOR),
|
||||
"%s %s", cmd, config.param);
|
||||
snprintf(request, sizeof(request)-strlen(NDSCTL_TERMINATOR), "%s %s", cmd, config.param);
|
||||
strcat(request, NDSCTL_TERMINATOR);
|
||||
|
||||
len = send_request(sock, request);
|
||||
@@ -325,11 +293,11 @@ ndsctl_action(const char cmd[], const char ifyes[], const char ifno[])
|
||||
len = 0;
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
while ((len < sizeof(buffer)) && ((rlen = read(sock, (buffer + len),
|
||||
(sizeof(buffer) - len))) > 0)) {
|
||||
(sizeof(buffer) - len))) > 0)) {
|
||||
len += rlen;
|
||||
}
|
||||
|
||||
if(rlen<0) {
|
||||
if (rlen < 0) {
|
||||
fprintf(stderr, "ndsctl: Error reading socket: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
@@ -338,8 +306,7 @@ ndsctl_action(const char cmd[], const char ifyes[], const char ifno[])
|
||||
} else if (strcmp(buffer, "No") == 0) {
|
||||
printf(ifno, config.param);
|
||||
} else {
|
||||
fprintf(stderr, "ndsctl: Error: nodogsplash sent an abnormal "
|
||||
"reply.\n");
|
||||
fprintf(stderr, "ndsctl: Error: nodogsplash sent an abnormal reply.\n");
|
||||
}
|
||||
|
||||
shutdown(sock, 2);
|
||||
@@ -359,7 +326,7 @@ ndsctl_print(const char cmd[])
|
||||
|
||||
sock = connect_to_server(config.socket);
|
||||
|
||||
snprintf(request, sizeof(request)-strlen(NDSCTL_TERMINATOR), "%s", cmd);
|
||||
snprintf(request, sizeof(request) - strlen(NDSCTL_TERMINATOR), "%s", cmd);
|
||||
strcat(request, NDSCTL_TERMINATOR);
|
||||
|
||||
len = send_request(sock, request);
|
||||
@@ -369,7 +336,7 @@ ndsctl_print(const char cmd[])
|
||||
printf("%s", buffer);
|
||||
}
|
||||
|
||||
if(len<0) {
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "ndsctl: Error reading socket: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
@@ -405,88 +372,72 @@ void
|
||||
ndsctl_loglevel(void)
|
||||
{
|
||||
ndsctl_action("loglevel",
|
||||
"Log level set to %s.\n",
|
||||
"Failed to set log level to %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_password(void)
|
||||
{
|
||||
ndsctl_action("password",
|
||||
"Password set to %s.\n",
|
||||
"Failed to set password to %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_username(void)
|
||||
{
|
||||
ndsctl_action("username",
|
||||
"Username set to %s.\n",
|
||||
"Failed to set username to %s.\n");
|
||||
"Log level set to %s.\n",
|
||||
"Failed to set log level to %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_deauth(void)
|
||||
{
|
||||
ndsctl_action("deauth",
|
||||
"Client %s deauthenticated.\n",
|
||||
"Client %s not found.\n");
|
||||
"Client %s deauthenticated.\n",
|
||||
"Client %s not found.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_auth(void)
|
||||
{
|
||||
ndsctl_action("auth",
|
||||
"Client %s authenticated.\n",
|
||||
"Failed to authenticate client %s.\n");
|
||||
"Client %s authenticated.\n",
|
||||
"Failed to authenticate client %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_block(void)
|
||||
{
|
||||
ndsctl_action("block",
|
||||
"MAC %s blocked.\n",
|
||||
"Failed to block MAC %s.\n");
|
||||
"MAC %s blocked.\n",
|
||||
"Failed to block MAC %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_unblock(void)
|
||||
{
|
||||
ndsctl_action("unblock",
|
||||
"MAC %s unblocked.\n",
|
||||
"Failed to unblock MAC %s.\n");
|
||||
"MAC %s unblocked.\n",
|
||||
"Failed to unblock MAC %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_allow(void)
|
||||
{
|
||||
ndsctl_action("allow",
|
||||
"MAC %s allowed.\n",
|
||||
"Failed to allow MAC %s.\n");
|
||||
"MAC %s allowed.\n",
|
||||
"Failed to allow MAC %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_unallow(void)
|
||||
{
|
||||
ndsctl_action("unallow",
|
||||
"MAC %s unallowed.\n",
|
||||
"Failed to unallow MAC %s.\n");
|
||||
"MAC %s unallowed.\n",
|
||||
"Failed to unallow MAC %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_trust(void)
|
||||
{
|
||||
ndsctl_action("trust",
|
||||
"MAC %s trusted.\n",
|
||||
"Failed to trust MAC %s.\n");
|
||||
"MAC %s trusted.\n",
|
||||
"Failed to trust MAC %s.\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_untrust(void)
|
||||
{
|
||||
ndsctl_action("untrust",
|
||||
"MAC %s untrusted.\n",
|
||||
"Failed to untrust MAC %s.\n");
|
||||
"MAC %s untrusted.\n",
|
||||
"Failed to untrust MAC %s.\n");
|
||||
}
|
||||
|
||||
int
|
||||
@@ -549,19 +500,11 @@ main(int argc, char **argv)
|
||||
ndsctl_loglevel();
|
||||
break;
|
||||
|
||||
case NDSCTL_PASSWORD:
|
||||
ndsctl_password();
|
||||
break;
|
||||
|
||||
case NDSCTL_USERNAME:
|
||||
ndsctl_username();
|
||||
break;
|
||||
|
||||
default:
|
||||
/* XXX NEVER REACHED */
|
||||
fprintf(stderr, "Unknown opcode: %d\n", config.command);
|
||||
exit(1);
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
exit(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
10
src/ndsctl.h
10
src/ndsctl.h
@@ -27,7 +27,7 @@
|
||||
#ifndef _NDSCTL_H_
|
||||
#define _NDSCTL_H_
|
||||
|
||||
#define DEFAULT_SOCK "/tmp/ndsctl.sock"
|
||||
#define DEFAULT_SOCK "/tmp/ndsctl.sock"
|
||||
|
||||
#define NDSCTL_TERMINATOR "\r\n\r\n"
|
||||
|
||||
@@ -45,16 +45,14 @@
|
||||
#define NDSCTL_AUTH 11
|
||||
#define NDSCTL_DEAUTH 12
|
||||
#define NDSCTL_LOGLEVEL 13
|
||||
#define NDSCTL_PASSWORD 14
|
||||
#define NDSCTL_USERNAME 15
|
||||
#define NDSCTL_CLIENTS 16
|
||||
#define NDSCTL_JSON 17
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *socket;
|
||||
int command;
|
||||
char *param;
|
||||
char *socket;
|
||||
int command;
|
||||
char *param;
|
||||
} s_config;
|
||||
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
@@ -52,28 +54,25 @@
|
||||
|
||||
#include "ndsctl_thread.h"
|
||||
|
||||
#define MAX_EVENT_SIZE 30
|
||||
|
||||
/* Defined in clientlist.c */
|
||||
extern pthread_mutex_t client_list_mutex;
|
||||
extern pthread_mutex_t config_mutex;
|
||||
|
||||
static void *thread_ndsctl_handler(void *);
|
||||
static void ndsctl_stop(pthread_t);
|
||||
static void ndsctl_block(int, char *);
|
||||
static void ndsctl_unblock(int, char *);
|
||||
static void ndsctl_allow(int, char *);
|
||||
static void ndsctl_unallow(int, char *);
|
||||
static void ndsctl_trust(int, char *);
|
||||
static void ndsctl_untrust(int, char *);
|
||||
static void ndsctl_auth(int, char *);
|
||||
static void ndsctl_deauth(int, char *);
|
||||
static void ndsctl_loglevel(int, char *);
|
||||
static void ndsctl_password(int, char *);
|
||||
static void ndsctl_username(int, char *);
|
||||
static void ndsctl_handler(int fd);
|
||||
static void ndsctl_stop();
|
||||
static void ndsctl_block(FILE *fp, char *arg);
|
||||
static void ndsctl_unblock(FILE *fp, char *arg);
|
||||
static void ndsctl_allow(FILE *fp, char *arg);
|
||||
static void ndsctl_unallow(FILE *fp, char *arg);
|
||||
static void ndsctl_trust(FILE *fp, char *arg);
|
||||
static void ndsctl_untrust(FILE *fp, char *arg);
|
||||
static void ndsctl_auth(FILE *fp, char *arg);
|
||||
static void ndsctl_deauth(FILE *fp, char *arg);
|
||||
static void ndsctl_loglevel(FILE *fp, char *arg);
|
||||
|
||||
struct ndsctl_args {
|
||||
int fd;
|
||||
pthread_t ndsctl_master_id;
|
||||
};
|
||||
static int socket_set_non_blocking(int sockfd);
|
||||
|
||||
/** Launches a thread that monitors the control socket for request
|
||||
@param arg Must contain a pointer to a string containing the Unix domain socket to open
|
||||
@@ -82,13 +81,15 @@ struct ndsctl_args {
|
||||
void*
|
||||
thread_ndsctl(void *arg)
|
||||
{
|
||||
int sock, fd;
|
||||
char *sock_name;
|
||||
struct sockaddr_un sa_un;
|
||||
int result;
|
||||
pthread_t tid;
|
||||
int sock, fd, epoll_fd;
|
||||
const char *sock_name;
|
||||
struct sockaddr_un sa_un;
|
||||
socklen_t len;
|
||||
struct ndsctl_args *child_thread_args;
|
||||
struct epoll_event ev;
|
||||
struct epoll_event *events;
|
||||
int current_fd_count;
|
||||
int number_of_count;
|
||||
int i;
|
||||
|
||||
debug(LOG_DEBUG, "Starting ndsctl.");
|
||||
|
||||
@@ -111,12 +112,10 @@ thread_ndsctl(void *arg)
|
||||
unlink(sock_name);
|
||||
|
||||
debug(LOG_DEBUG, "Filling sockaddr_un");
|
||||
strcpy(sa_un.sun_path, sock_name); /* XXX No size check because we
|
||||
* check a few lines before. */
|
||||
strcpy(sa_un.sun_path, sock_name); /* XXX No size check because we check a few lines before. */
|
||||
sa_un.sun_family = AF_UNIX;
|
||||
|
||||
debug(LOG_DEBUG, "Binding socket (%s) (%d)", sa_un.sun_path,
|
||||
strlen(sock_name));
|
||||
debug(LOG_DEBUG, "Binding socket (%s) (%d)", sa_un.sun_path, strlen(sock_name));
|
||||
|
||||
/* Which to use, AF_UNIX, PF_UNIX, AF_LOCAL, PF_LOCAL? */
|
||||
if (bind(sock, (struct sockaddr *)&sa_un, strlen(sock_name) + sizeof(sa_un.sun_family))) {
|
||||
@@ -129,47 +128,106 @@ thread_ndsctl(void *arg)
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
memset(&ev, 0, sizeof(struct epoll_event));
|
||||
epoll_fd = epoll_create(MAX_EVENT_SIZE);
|
||||
|
||||
ev.events = EPOLLIN|EPOLLET;
|
||||
ev.data.fd = sock;
|
||||
|
||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) < 0) {
|
||||
debug(LOG_ERR, "Could not insert socket fd to epoll set: %s", strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
events = (struct epoll_event*)calloc(MAX_EVENT_SIZE, sizeof(struct epoll_event));
|
||||
|
||||
if (!events) {
|
||||
close(sock);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
current_fd_count = 1;
|
||||
|
||||
while (1) {
|
||||
memset(&sa_un, 0, sizeof(sa_un));
|
||||
len = (socklen_t) sizeof(sa_un);
|
||||
if ((fd = accept(sock, (struct sockaddr *)&sa_un, &len)) == -1) {
|
||||
debug(LOG_ERR, "Accept failed on control socket: %s", strerror(errno));
|
||||
|
||||
number_of_count = epoll_wait(epoll_fd, events, current_fd_count, -1);
|
||||
|
||||
if (number_of_count == -1) {
|
||||
debug(LOG_ERR, "Failed to wait epoll events: %s", strerror(errno));
|
||||
free(events);
|
||||
pthread_exit(NULL);
|
||||
} else {
|
||||
debug(LOG_DEBUG, "Accepted connection on ndsctl socket %d (%s)", fd, sa_un.sun_path);
|
||||
child_thread_args = calloc(1, sizeof(struct ndsctl_args));
|
||||
child_thread_args->fd = fd;
|
||||
child_thread_args->ndsctl_master_id = pthread_self();
|
||||
result = pthread_create(&tid, NULL, &thread_ndsctl_handler, (void *) child_thread_args);
|
||||
if (result != 0) {
|
||||
debug(LOG_ERR, "FATAL: Failed to create a new thread (ndsctl handler) - exiting");
|
||||
termination_handler(0);
|
||||
}
|
||||
|
||||
for (i = 0; i < number_of_count; i++) {
|
||||
|
||||
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) ||
|
||||
(!(events[i].events & EPOLLIN))) {
|
||||
debug(LOG_ERR, "Socket is not ready for communication : %s", strerror(errno));
|
||||
|
||||
if (events[i].data.fd > 0) {
|
||||
shutdown(events[i].data.fd, 2);
|
||||
close(events[i].data.fd);
|
||||
events[i].data.fd = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (events[i].data.fd == sock) {
|
||||
if ((fd = accept(events[i].data.fd, (struct sockaddr *)&sa_un, &len)) == -1) {
|
||||
debug(LOG_ERR, "Accept failed on control socket: %s", strerror(errno));
|
||||
free(events);
|
||||
pthread_exit(NULL);
|
||||
} else {
|
||||
socket_set_non_blocking(fd);
|
||||
ev.events = EPOLLIN|EPOLLET;
|
||||
ev.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
|
||||
debug(LOG_ERR, "Could not insert socket fd to epoll set: %s", strerror(errno));
|
||||
free(events);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
current_fd_count += 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
ndsctl_handler(fd);
|
||||
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, &ev);
|
||||
current_fd_count -= 1;
|
||||
|
||||
/* socket was closed on 'ndsctl_handler' */
|
||||
if (events[i].data.fd > 0) {
|
||||
events[i].data.fd = 0;
|
||||
}
|
||||
|
||||
}
|
||||
pthread_detach(tid);
|
||||
}
|
||||
}
|
||||
|
||||
free(events);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
thread_ndsctl_handler(void *arg)
|
||||
static void
|
||||
ndsctl_handler(int fd)
|
||||
{
|
||||
int done, i;
|
||||
char request[MAX_BUF];
|
||||
ssize_t read_bytes, len;
|
||||
struct ndsctl_args *args = arg;
|
||||
pthread_t ndsctl_master = args->ndsctl_master_id;
|
||||
int fd = args->fd;
|
||||
free(args);
|
||||
FILE* fp;
|
||||
|
||||
debug(LOG_DEBUG, "Entering thread_ndsctl_handler....");
|
||||
debug(LOG_DEBUG, "Read bytes and stuff from %d", fd);
|
||||
debug(LOG_DEBUG, "Read bytes and stuff from descriptor %d", fd);
|
||||
|
||||
/* Init variables */
|
||||
read_bytes = 0;
|
||||
done = 0;
|
||||
memset(request, 0, sizeof(request));
|
||||
fp = fdopen(fd, "w");
|
||||
|
||||
/* Read.... */
|
||||
while (!done && read_bytes < (sizeof(request) - 1)) {
|
||||
@@ -190,64 +248,55 @@ thread_ndsctl_handler(void *arg)
|
||||
debug(LOG_DEBUG, "ndsctl request received: [%s]", request);
|
||||
|
||||
if (strncmp(request, "status", 6) == 0) {
|
||||
ndsctl_status(fd);
|
||||
ndsctl_status(fp);
|
||||
} else if (strncmp(request, "clients", 7) == 0) {
|
||||
ndsctl_clients(fd);
|
||||
ndsctl_clients(fp);
|
||||
} else if (strncmp(request, "json", 4) == 0) {
|
||||
ndsctl_json(fd);
|
||||
ndsctl_json(fp);
|
||||
} else if (strncmp(request, "stop", 4) == 0) {
|
||||
ndsctl_stop(ndsctl_master);
|
||||
ndsctl_stop();
|
||||
} else if (strncmp(request, "block", 5) == 0) {
|
||||
ndsctl_block(fd, (request + 6));
|
||||
ndsctl_block(fp, (request + 6));
|
||||
} else if (strncmp(request, "unblock", 7) == 0) {
|
||||
ndsctl_unblock(fd, (request + 8));
|
||||
ndsctl_unblock(fp, (request + 8));
|
||||
} else if (strncmp(request, "allow", 5) == 0) {
|
||||
ndsctl_allow(fd, (request + 6));
|
||||
ndsctl_allow(fp, (request + 6));
|
||||
} else if (strncmp(request, "unallow", 7) == 0) {
|
||||
ndsctl_unallow(fd, (request + 8));
|
||||
ndsctl_unallow(fp, (request + 8));
|
||||
} else if (strncmp(request, "trust", 5) == 0) {
|
||||
ndsctl_trust(fd, (request + 6));
|
||||
ndsctl_trust(fp, (request + 6));
|
||||
} else if (strncmp(request, "untrust", 7) == 0) {
|
||||
ndsctl_untrust(fd, (request + 8));
|
||||
ndsctl_untrust(fp, (request + 8));
|
||||
} else if (strncmp(request, "auth", 4) == 0) {
|
||||
ndsctl_auth(fd, (request + 5));
|
||||
ndsctl_auth(fp, (request + 5));
|
||||
} else if (strncmp(request, "deauth", 6) == 0) {
|
||||
ndsctl_deauth(fd, (request + 7));
|
||||
ndsctl_deauth(fp, (request + 7));
|
||||
} else if (strncmp(request, "loglevel", 8) == 0) {
|
||||
ndsctl_loglevel(fd, (request + 9));
|
||||
} else if (strncmp(request, "password", 8) == 0) {
|
||||
ndsctl_password(fd, (request + 9));
|
||||
} else if (strncmp(request, "username", 8) == 0) {
|
||||
ndsctl_username(fd, (request + 9));
|
||||
ndsctl_loglevel(fp, (request + 9));
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
debug(LOG_ERR, "Invalid ndsctl request.");
|
||||
shutdown(fd, 2);
|
||||
close(fd);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
debug(LOG_DEBUG, "ndsctl request processed: [%s]", request);
|
||||
|
||||
shutdown(fd, 2);
|
||||
close(fd);
|
||||
debug(LOG_DEBUG, "Exiting thread_ndsctl_handler....");
|
||||
|
||||
return NULL;
|
||||
/* Close and flush fp, also closes underlying fd */
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/** A bit of an hack, self kills.... */
|
||||
static void
|
||||
ndsctl_stop(pthread_t ndsctl_master_id)
|
||||
ndsctl_stop()
|
||||
{
|
||||
pthread_cancel(ndsctl_master_id);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_auth(int fd, char *arg)
|
||||
ndsctl_auth(FILE *fp, char *arg)
|
||||
{
|
||||
t_client *client;
|
||||
t_client *client;
|
||||
char *ip, *mac;
|
||||
debug(LOG_DEBUG, "Entering ndsctl_auth...");
|
||||
|
||||
@@ -262,7 +311,7 @@ ndsctl_auth(int fd, char *arg)
|
||||
else {
|
||||
debug(LOG_DEBUG, "Client not found.");
|
||||
UNLOCK_CLIENT_LIST();
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,15 +324,15 @@ ndsctl_auth(int fd, char *arg)
|
||||
|
||||
free(ip);
|
||||
free(mac);
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
|
||||
debug(LOG_DEBUG, "Exiting ndsctl_auth...");
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_deauth(int fd, char *arg)
|
||||
ndsctl_deauth(FILE *fp, char *arg)
|
||||
{
|
||||
t_client *client;
|
||||
t_client *client;
|
||||
char *ip, *mac;
|
||||
debug(LOG_DEBUG, "Entering ndsctl_deauth...");
|
||||
|
||||
@@ -298,7 +347,7 @@ ndsctl_deauth(int fd, char *arg)
|
||||
else {
|
||||
debug(LOG_DEBUG, "Client not found.");
|
||||
UNLOCK_CLIENT_LIST();
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,13 +360,13 @@ ndsctl_deauth(int fd, char *arg)
|
||||
|
||||
free(ip);
|
||||
free(mac);
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
|
||||
debug(LOG_DEBUG, "Exiting ndsctl_deauth...");
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_block(int fd, char *arg)
|
||||
ndsctl_block(FILE *fp, char *arg)
|
||||
{
|
||||
debug(LOG_DEBUG, "Entering ndsctl_block...");
|
||||
|
||||
@@ -325,9 +374,9 @@ ndsctl_block(int fd, char *arg)
|
||||
debug(LOG_DEBUG, "Argument: [%s]", arg);
|
||||
|
||||
if (!add_to_blocked_mac_list(arg) && !iptables_block_mac(arg)) {
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
@@ -336,7 +385,7 @@ ndsctl_block(int fd, char *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_unblock(int fd, char *arg)
|
||||
ndsctl_unblock(FILE *fp, char *arg)
|
||||
{
|
||||
debug(LOG_DEBUG, "Entering ndsctl_unblock...");
|
||||
|
||||
@@ -344,9 +393,9 @@ ndsctl_unblock(int fd, char *arg)
|
||||
debug(LOG_DEBUG, "Argument: [%s]", arg);
|
||||
|
||||
if (!remove_from_blocked_mac_list(arg) && !iptables_unblock_mac(arg)) {
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
@@ -355,7 +404,7 @@ ndsctl_unblock(int fd, char *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_allow(int fd, char *arg)
|
||||
ndsctl_allow(FILE *fp, char *arg)
|
||||
{
|
||||
debug(LOG_DEBUG, "Entering ndsctl_allow...");
|
||||
|
||||
@@ -363,9 +412,9 @@ ndsctl_allow(int fd, char *arg)
|
||||
debug(LOG_DEBUG, "Argument: [%s]", arg);
|
||||
|
||||
if (!add_to_allowed_mac_list(arg) && !iptables_allow_mac(arg)) {
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
@@ -374,7 +423,7 @@ ndsctl_allow(int fd, char *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_unallow(int fd, char *arg)
|
||||
ndsctl_unallow(FILE *fp, char *arg)
|
||||
{
|
||||
debug(LOG_DEBUG, "Entering ndsctl_unallow...");
|
||||
|
||||
@@ -382,9 +431,9 @@ ndsctl_unallow(int fd, char *arg)
|
||||
debug(LOG_DEBUG, "Argument: [%s]", arg);
|
||||
|
||||
if (!remove_from_allowed_mac_list(arg) && !iptables_unallow_mac(arg)) {
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
@@ -393,7 +442,7 @@ ndsctl_unallow(int fd, char *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_trust(int fd, char *arg)
|
||||
ndsctl_trust(FILE *fp, char *arg)
|
||||
{
|
||||
debug(LOG_DEBUG, "Entering ndsctl_trust...");
|
||||
|
||||
@@ -401,9 +450,9 @@ ndsctl_trust(int fd, char *arg)
|
||||
debug(LOG_DEBUG, "Argument: [%s]", arg);
|
||||
|
||||
if (!add_to_trusted_mac_list(arg) && !iptables_trust_mac(arg)) {
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
@@ -412,7 +461,7 @@ ndsctl_trust(int fd, char *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_untrust(int fd, char *arg)
|
||||
ndsctl_untrust(FILE *fp, char *arg)
|
||||
{
|
||||
debug(LOG_DEBUG, "Entering ndsctl_untrust...");
|
||||
|
||||
@@ -420,9 +469,9 @@ ndsctl_untrust(int fd, char *arg)
|
||||
debug(LOG_DEBUG, "Argument: [%s]", arg);
|
||||
|
||||
if (!remove_from_trusted_mac_list(arg) && !iptables_untrust_mac(arg)) {
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
@@ -431,7 +480,7 @@ ndsctl_untrust(int fd, char *arg)
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_loglevel(int fd, char *arg)
|
||||
ndsctl_loglevel(FILE *fp, char *arg)
|
||||
{
|
||||
int level = atoi(arg);
|
||||
|
||||
@@ -442,10 +491,10 @@ ndsctl_loglevel(int fd, char *arg)
|
||||
|
||||
|
||||
if (!set_log_level(level)) {
|
||||
write(fd, "Yes", 3);
|
||||
fprintf(fp, "Yes");
|
||||
debug(LOG_NOTICE, "Set debug loglevel to %d.", level);
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
fprintf(fp, "No");
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
@@ -453,44 +502,17 @@ ndsctl_loglevel(int fd, char *arg)
|
||||
debug(LOG_DEBUG, "Exiting ndsctl_loglevel.");
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_password(int fd, char *arg)
|
||||
static int
|
||||
socket_set_non_blocking(int sockfd)
|
||||
{
|
||||
debug(LOG_DEBUG, "Entering ndsctl_password...");
|
||||
int rc;
|
||||
|
||||
LOCK_CONFIG();
|
||||
debug(LOG_DEBUG, "Argument: [%s]", arg);
|
||||
rc = fcntl(sockfd, F_GETFL, 0);
|
||||
|
||||
|
||||
if (!set_password(arg)) {
|
||||
write(fd, "Yes", 3);
|
||||
debug(LOG_NOTICE, "Set password to %s.", arg);
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
if (rc) {
|
||||
rc |= O_NONBLOCK;
|
||||
rc = fcntl(sockfd, F_SETFL, rc);
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
|
||||
debug(LOG_DEBUG, "Exiting ndsctl_password.");
|
||||
}
|
||||
|
||||
static void
|
||||
ndsctl_username(int fd, char *arg)
|
||||
{
|
||||
debug(LOG_DEBUG, "Entering ndsctl_username...");
|
||||
|
||||
LOCK_CONFIG();
|
||||
debug(LOG_DEBUG, "Argument: [%s]", arg);
|
||||
|
||||
|
||||
if (!set_username(arg)) {
|
||||
write(fd, "Yes", 3);
|
||||
debug(LOG_NOTICE, "Set username to %s.", arg);
|
||||
} else {
|
||||
write(fd, "No", 2);
|
||||
}
|
||||
|
||||
UNLOCK_CONFIG();
|
||||
|
||||
debug(LOG_DEBUG, "Exiting ndsctl_username.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define _NDSCTL_THREAD_H_
|
||||
|
||||
|
||||
#define DEFAULT_NDSCTL_SOCK "/tmp/ndsctl.sock"
|
||||
#define DEFAULT_NDSCTL_SOCK "/tmp/ndsctl.sock"
|
||||
|
||||
/** @brief Listen for nodogsplash control messages on a unix domain socket */
|
||||
void *thread_ndsctl(void *arg);
|
||||
|
||||
@@ -41,7 +41,7 @@ void * safe_malloc (size_t size)
|
||||
void * retval = NULL;
|
||||
retval = malloc(size);
|
||||
if (!retval) {
|
||||
debug(LOG_CRIT, "Failed to malloc %d bytes of memory: %s. Bailing out", size, strerror(errno));
|
||||
debug(LOG_CRIT, "Failed to malloc %d bytes of memory: %s. Bailing out.", size, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
return (retval);
|
||||
@@ -51,12 +51,12 @@ char * safe_strdup(const char s[])
|
||||
{
|
||||
char * retval = NULL;
|
||||
if (!s) {
|
||||
debug(LOG_CRIT, "safe_strdup called with NULL which would have crashed strdup. Bailing out");
|
||||
debug(LOG_CRIT, "safe_strdup called with NULL which would have crashed strdup. Bailing out.");
|
||||
exit(1);
|
||||
}
|
||||
retval = strdup(s);
|
||||
if (!retval) {
|
||||
debug(LOG_CRIT, "Failed to duplicate a string: %s. Bailing out", strerror(errno));
|
||||
debug(LOG_CRIT, "Failed to duplicate a string: %s. Bailing out.", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
return (retval);
|
||||
@@ -84,6 +84,7 @@ int safe_vasprintf(char **strp, const char *fmt, va_list ap)
|
||||
debug(LOG_CRIT, "Failed to vasprintf: %s. Bailing out", strerror(errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
\********************************************************************/
|
||||
|
||||
/** @file safe.h
|
||||
@brief Safe versions of stdlib/string functions that error out and exit if memory allocation fails
|
||||
@author Copyright (C) 2005 Mina Naguib <mina@ilesansfil.org>
|
||||
@brief Safe versions of stdlib/string functions that error out and exit if memory allocation fails
|
||||
@author Copyright (C) 2005 Mina Naguib <mina@ilesansfil.org>
|
||||
*/
|
||||
|
||||
#ifndef _SAFE_H_
|
||||
|
||||
137
src/tc.c
137
src/tc.c
@@ -45,38 +45,6 @@
|
||||
#include "tc.h"
|
||||
|
||||
|
||||
/**
|
||||
* Make this nonzero to supress the error output during destruction.
|
||||
*/
|
||||
static int tc_quiet = 0;
|
||||
|
||||
|
||||
/** @internal */
|
||||
static int
|
||||
tc_do_command(const char format[], ...)
|
||||
{
|
||||
va_list vlist;
|
||||
char *fmt_cmd;
|
||||
char *cmd;
|
||||
int rc;
|
||||
|
||||
va_start(vlist, format);
|
||||
safe_vasprintf(&fmt_cmd, format, vlist);
|
||||
va_end(vlist);
|
||||
|
||||
safe_asprintf(&cmd, "tc %s", fmt_cmd);
|
||||
|
||||
free(fmt_cmd);
|
||||
|
||||
debug(LOG_DEBUG, "Executing command: %s", cmd);
|
||||
|
||||
rc = execute(cmd, tc_quiet);
|
||||
|
||||
free(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
tc_attach_client(const char down_dev[], int download_limit, const char up_dev[], int upload_limit, int idx, const char ip[])
|
||||
{
|
||||
@@ -88,46 +56,46 @@ tc_attach_client(const char down_dev[], int download_limit, const char up_dev[],
|
||||
|
||||
if (dlimit > 0) {
|
||||
/* guarantee 20% bandwidth, upper limit 100% */
|
||||
rc |= tc_do_command("class add dev %s parent 1:1 classid 1:%d hfsc sc rate %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc class add dev %s parent 1:1 classid 1:%d hfsc sc rate %dkbit ul rate %dkbit",
|
||||
down_dev, id, dlimit / 5, dlimit);
|
||||
/* low latency class for DNS and ICMP */
|
||||
rc |= tc_do_command("class add dev %s parent 1:%d classid 1:%d hfsc rt m1 %dkbit d 25ms m2 %dkbit ls m1 %dkbit d 25ms m2 %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc class add dev %s parent 1:%d classid 1:%d hfsc rt m1 %dkbit d 25ms m2 %dkbit ls m1 %dkbit d 25ms m2 %dkbit ul rate %dkbit",
|
||||
down_dev, id, id + 1, (dlimit / 5) * 4, dlimit / 20, dlimit / 10, dlimit / 10, dlimit);
|
||||
rc |= tc_do_command("filter add dev %s protocol ip parent 1: prio %d u32 match ip dst %s match ip protocol %d 0xff flowid 1:%d",
|
||||
rc |= excute("tc filter add dev %s protocol ip parent 1: prio %d u32 match ip dst %s match ip protocol %d 0xff flowid 1:%d",
|
||||
down_dev, id, ip, 1, id + 1);
|
||||
rc |= tc_do_command("filter add dev %s protocol ip parent 1: prio %d u32 match ip dst %s match ip sport %d 0xffff flowid 1:%d",
|
||||
rc |= excute("tc filter add dev %s protocol ip parent 1: prio %d u32 match ip dst %s match ip sport %d 0xffff flowid 1:%d",
|
||||
down_dev, id + 1, ip, 53, id + 1);
|
||||
/* bulk traffic class */
|
||||
rc |= tc_do_command("class add dev %s parent 1:%d classid 1:%d hfsc ls m1 0kbit d 100ms m2 %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc class add dev %s parent 1:%d classid 1:%d hfsc ls m1 0kbit d 100ms m2 %dkbit ul rate %dkbit",
|
||||
down_dev, id, id + 2, dlimit / 5, dlimit);
|
||||
rc |= tc_do_command("filter add dev %s protocol ip parent 1: prio %d u32 match ip dst %s flowid 1:%d",
|
||||
rc |= execute("tc filter add dev %s protocol ip parent 1: prio %d u32 match ip dst %s flowid 1:%d",
|
||||
down_dev, id + 2, ip, id + 2);
|
||||
/* codel for each leaf class */
|
||||
rc |= tc_do_command("qdisc add dev %s parent 1:%d handle %d: fq_codel limit 800 quantum 300 ecn",
|
||||
rc |= execute("tc qdisc add dev %s parent 1:%d handle %d: fq_codel limit 800 quantum 300 ecn",
|
||||
down_dev, id + 1, id + 1);
|
||||
rc |= tc_do_command("qdisc add dev %s parent 1:%d handle %d: fq_codel limit 800 quantum 300 ecn",
|
||||
rc |= execute("tc qdisc add dev %s parent 1:%d handle %d: fq_codel limit 800 quantum 300 ecn",
|
||||
down_dev, id + 2, id + 2);
|
||||
}
|
||||
if (ulimit > 0) {
|
||||
/* guarantee 20% bandwidth, upper limit 100% */
|
||||
rc |= tc_do_command("class add dev %s parent 1:1 classid 1:%d hfsc sc rate %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc class add dev %s parent 1:1 classid 1:%d hfsc sc rate %dkbit ul rate %dkbit",
|
||||
up_dev, id, ulimit / 5, ulimit);
|
||||
/* low latency class for DNS and ICMP */
|
||||
rc |= tc_do_command("class add dev %s parent 1:%d classid 1:%d hfsc rt m1 %dkbit d 25ms m2 %dkbit ls m1 %dkbit d 25ms m2 %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc class add dev %s parent 1:%d classid 1:%d hfsc rt m1 %dkbit d 25ms m2 %dkbit ls m1 %dkbit d 25ms m2 %dkbit ul rate %dkbit",
|
||||
up_dev, id, id + 1, (ulimit / 5) * 4, ulimit / 20, ulimit / 10, ulimit / 10, ulimit);
|
||||
rc |= tc_do_command("filter add dev %s protocol ip parent 1: prio %d u32 match ip src %s match ip protocol %d 0xff flowid 1:%d",
|
||||
rc |= execute("tc filter add dev %s protocol ip parent 1: prio %d u32 match ip src %s match ip protocol %d 0xff flowid 1:%d",
|
||||
up_dev, id, ip, 1, id + 1);
|
||||
rc |= tc_do_command("filter add dev %s protocol ip parent 1: prio %d u32 match ip src %s match ip dport %d 0xffff flowid 1:%d",
|
||||
rc |= execite("tc filter add dev %s protocol ip parent 1: prio %d u32 match ip src %s match ip dport %d 0xffff flowid 1:%d",
|
||||
up_dev, id + 1, ip, 53, id + 1);
|
||||
/* bulk traffic class */
|
||||
rc |= tc_do_command("class add dev %s parent 1:%d classid 1:%d hfsc ls m1 0kbit d 100ms m2 %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc class add dev %s parent 1:%d classid 1:%d hfsc ls m1 0kbit d 100ms m2 %dkbit ul rate %dkbit",
|
||||
up_dev, id, id + 2, ulimit / 5, ulimit);
|
||||
rc |= tc_do_command("filter add dev %s protocol ip parent 1: prio %d u32 match ip src %s flowid 1:%d",
|
||||
rc |= execute("tc filter add dev %s protocol ip parent 1: prio %d u32 match ip src %s flowid 1:%d",
|
||||
up_dev, id + 2, ip, id + 2);
|
||||
/* codel for each leaf class */
|
||||
rc |= tc_do_command("qdisc add dev %s parent 1:%d handle %d: fq_codel limit 800 quantum 300 ecn",
|
||||
rc |= execute("tc qdisc add dev %s parent 1:%d handle %d: fq_codel limit 800 quantum 300 ecn",
|
||||
up_dev, id + 1, id + 1);
|
||||
rc |= tc_do_command("qdisc add dev %s parent 1:%d handle %d: fq_codel limit 800 quantum 300 ecn",
|
||||
rc |= execute("tc qdisc add dev %s parent 1:%d handle %d: fq_codel limit 800 quantum 300 ecn",
|
||||
up_dev, id + 2, id + 2);
|
||||
}
|
||||
|
||||
@@ -141,20 +109,21 @@ tc_detach_client(const char down_dev[], int download_limit, const char up_dev[],
|
||||
int id = 3 * idx + 10;
|
||||
|
||||
if (download_limit > 0) {
|
||||
for (n=2;n>=0;n--)
|
||||
rc |= tc_do_command("filter del dev %s parent 1: prio %d", down_dev, id + n);
|
||||
for (n=2;n>=1;n--)
|
||||
rc |= tc_do_command("qdisc del dev %s parent 1:%d", down_dev, id + n);
|
||||
for (n=2;n>=0;n--)
|
||||
rc |= tc_do_command("class del dev %s parent 1: classid 1:%d", down_dev, id + n);
|
||||
for (n = 2; n >= 0; n--)
|
||||
rc |= execute("filter del dev %s parent 1: prio %d", down_dev, id + n);
|
||||
for (n = 2; n >= 1; n--)
|
||||
rc |= execute("qdisc del dev %s parent 1:%d", down_dev, id + n);
|
||||
for (n = 2; n >= 0; n--)
|
||||
rc |= execute("class del dev %s parent 1: classid 1:%d", down_dev, id + n);
|
||||
}
|
||||
|
||||
if (upload_limit > 0) {
|
||||
for (n=2;n>=0;n--)
|
||||
rc |= tc_do_command("filter del dev %s parent 1: prio %d", up_dev, id + n);
|
||||
for (n=2;n>=1;n--)
|
||||
rc |= tc_do_command("qdisc del dev %s parent 1:%d", up_dev, id + n);
|
||||
for (n=2;n>=0;n--)
|
||||
rc |= tc_do_command("class del dev %s parent 1: classid 1:%d", up_dev, id + n);
|
||||
for (n = 2; n >= 0; n--)
|
||||
rc |= execute("filter del dev %s parent 1: prio %d", up_dev, id + n);
|
||||
for (n = 2;n >= 1; n--)
|
||||
rc |= execute("qdisc del dev %s parent 1:%d", up_dev, id + n);
|
||||
for (n = 2; n >= 0; n--)
|
||||
rc |= execute("class del dev %s parent 1: classid 1:%d", up_dev, id + n);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -172,19 +141,19 @@ tc_attach_upload_qdisc(const char dev[], const char ifb_dev[], int upload_limit)
|
||||
int rc = 0;
|
||||
|
||||
/* clear rules just in case */
|
||||
tc_do_command("qdisc del dev %s root", ifb_dev);
|
||||
tc_do_command("qdisc del dev %s ingress", dev);
|
||||
execute("tc qdisc del dev %s root", ifb_dev);
|
||||
execute("tc qdisc del dev %s ingress", dev);
|
||||
|
||||
/* main upload qdisc */
|
||||
rc |= tc_do_command("qdisc add dev %s root handle 1: hfsc default 2", ifb_dev);
|
||||
rc |= tc_do_command("class add dev %s parent 1: classid 1:1 hfsc sc rate %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc qdisc add dev %s root handle 1: hfsc default 2", ifb_dev);
|
||||
rc |= execute("tc class add dev %s parent 1: classid 1:1 hfsc sc rate %dkbit ul rate %dkbit",
|
||||
ifb_dev, upload_limit, upload_limit);
|
||||
/* default class used for preauth clients */
|
||||
rc |= tc_do_command("class add dev %s parent 1:1 classid 1:2 hfsc sc rate %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc class add dev %s parent 1:1 classid 1:2 hfsc sc rate %dkbit ul rate %dkbit",
|
||||
ifb_dev, upload_limit / 10, upload_limit / 10);
|
||||
/* redirect ingress from main interface to ifb interface */
|
||||
rc |= tc_do_command("qdisc add dev %s ingress", dev);
|
||||
rc |= tc_do_command("filter add dev %s parent ffff: protocol ip prio 1 u32 match u32 0 0 flowid 1:1 action connmark action mirred egress redirect dev %s",
|
||||
rc |= execute("tc qdisc add dev %s ingress", dev);
|
||||
rc |= execute("tc filter add dev %s parent ffff: protocol ip prio 1 u32 match u32 0 0 flowid 1:1 action connmark action mirred egress redirect dev %s",
|
||||
dev, ifb_dev);
|
||||
|
||||
return rc;
|
||||
@@ -202,17 +171,16 @@ tc_attach_download_qdisc(const char dev[], const char ifb_dev[], int download_li
|
||||
int rc = 0;
|
||||
|
||||
/* clear rules just in case */
|
||||
tc_do_command("qdisc del dev %s root", dev);
|
||||
execute("tc qdisc del dev %s root", dev);
|
||||
|
||||
/* main download qdisc */
|
||||
rc |= tc_do_command("qdisc add dev %s root handle 1: hfsc default 2", dev);
|
||||
rc |= tc_do_command("class add dev %s parent 1: classid 1:1 hfsc sc rate %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc qdisc add dev %s root handle 1: hfsc default 2", dev);
|
||||
rc |= execute("tc class add dev %s parent 1: classid 1:1 hfsc sc rate %dkbit ul rate %dkbit",
|
||||
dev, download_limit, download_limit);
|
||||
/* default class used for preauth clients */
|
||||
rc |= tc_do_command("class add dev %s parent 1:1 classid 1:2 hfsc sc rate %dkbit ul rate %dkbit",
|
||||
rc |= execute("tc class add dev %s parent 1:1 classid 1:2 hfsc sc rate %dkbit ul rate %dkbit",
|
||||
dev, download_limit / 10, download_limit / 10);
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -228,7 +196,8 @@ tc_init_tc()
|
||||
int upload_ifb, download_ifb;
|
||||
char *upload_ifbname, *cmd;
|
||||
s_config *config;
|
||||
int rc = 0, ret = 0;
|
||||
int rc = 0;
|
||||
int ret = 0;
|
||||
|
||||
config = config_get_config();
|
||||
download_limit = config->download_limit;
|
||||
@@ -259,35 +228,23 @@ tc_init_tc()
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove qdiscs from intermediate queueing devices, and bring IFB's down
|
||||
*/
|
||||
int
|
||||
tc_destroy_tc()
|
||||
{
|
||||
int rc = 0, old_tc_quiet;
|
||||
|
||||
old_tc_quiet = tc_quiet;
|
||||
tc_quiet = 1;
|
||||
s_config *config;
|
||||
char *upload_ifbname, *cmd;
|
||||
char upload_ifbname[16];
|
||||
|
||||
config = config_get_config();
|
||||
safe_asprintf(&upload_ifbname,"ifb%d",config->upload_ifb); /* must free */
|
||||
sprintf(&upload_ifbname, "ifb%d", config->upload_ifb);
|
||||
|
||||
/* remove qdiscs from ifb's */
|
||||
rc |= tc_do_command("qdisc del dev %s root",config->gw_interface);
|
||||
rc |= tc_do_command("qdisc del dev %s root",upload_ifbname);
|
||||
rc |= execute("tc qdisc del dev %s root &> /dev/null", config->gw_interface);
|
||||
rc |= execute("tc qdisc del dev %s root &> /dev/null", upload_ifbname);
|
||||
/* bring down ifb's */
|
||||
safe_asprintf(&cmd,"ip link set %s down", upload_ifbname);
|
||||
debug(LOG_DEBUG, "Executing command: %s", cmd);
|
||||
rc |= execute(cmd,tc_quiet);
|
||||
free(cmd);
|
||||
|
||||
free(upload_ifbname);
|
||||
|
||||
tc_quiet = old_tc_quiet;
|
||||
rc |= execute("ip link set %s down", upload_ifbname);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -11,12 +11,11 @@
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
const char *variable_names[18] = {
|
||||
const char *variable_names[19] = {
|
||||
"authaction",
|
||||
"authtarget",
|
||||
"clientip",
|
||||
"clientmac",
|
||||
"content",
|
||||
"denyaction",
|
||||
"error_msg",
|
||||
"gatewaymac",
|
||||
@@ -28,6 +27,7 @@ const char *variable_names[18] = {
|
||||
"redir",
|
||||
"title",
|
||||
"tok",
|
||||
"token",
|
||||
"uptime",
|
||||
"version"
|
||||
};
|
||||
@@ -36,9 +36,8 @@ static int get_variable_index(const char *name)
|
||||
{
|
||||
int j;
|
||||
|
||||
for(j=0; j < ARRAY_SIZE(variable_names); j++) {
|
||||
if(strcmp(name, variable_names[j]) == 0) {
|
||||
fprintf(stderr, "vari %s = %s %d", name, variable_names[j], j);
|
||||
for (j = 0; j < ARRAY_SIZE(variable_names); j++) {
|
||||
if (strcmp(name, variable_names[j]) == 0) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
@@ -56,14 +55,14 @@ int tmpl_parse(struct templater *templor, char *dst, size_t dst_len, const char
|
||||
int dst_i = 0;
|
||||
int varlen;
|
||||
int valuelen;
|
||||
char varname[32]; /* contain the varname */
|
||||
char varname[32]; /* contains the varname */
|
||||
const char *varnameptr; /* intermediate pointer */
|
||||
int varidx; /* the position of the variable in variable_names */
|
||||
|
||||
memset(dst, 0x0, dst_len);
|
||||
while((src_i < src_len) && (dst_i < dst_len)) {
|
||||
if(src[src_i] != '$') {
|
||||
dst[dst_i] = src[src_i];
|
||||
while ((src_i < src_len) && (dst_i < dst_len)) {
|
||||
if (src[src_i] != '$') {
|
||||
dst[dst_i] = src[src_i];
|
||||
dst_i++;
|
||||
src_i++;
|
||||
continue;
|
||||
@@ -72,15 +71,15 @@ int tmpl_parse(struct templater *templor, char *dst, size_t dst_len, const char
|
||||
/* we know it's a '$'. But we are interest in the next char */
|
||||
src_i++;
|
||||
|
||||
/* read the whole variablename */
|
||||
/* read the whole variable name */
|
||||
varnameptr = src + src_i;
|
||||
for(varlen=0; (varlen < (src_len-src_i)) &&
|
||||
for (varlen = 0; (varlen < (src_len-src_i)) &&
|
||||
(isalnum(varnameptr[varlen]) || varnameptr[varlen] == '_')
|
||||
; varlen++)
|
||||
;
|
||||
|
||||
/* variable to long, cant be a valid variable */
|
||||
if(varlen > sizeof(varname)-1) {
|
||||
/* variable too long, can't be a valid variable */
|
||||
if (varlen > sizeof(varname)-1) {
|
||||
/* we already parsed the varname and can skip these chars
|
||||
* but we need to copy these first to the output buffer */
|
||||
strncpy(dst + dst_i, varnameptr, varlen > dst_len-dst_i ? dst_len-dst_i : varlen);
|
||||
@@ -102,7 +101,7 @@ int tmpl_parse(struct templater *templor, char *dst, size_t dst_len, const char
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check if variable name is empty */
|
||||
/* check if variable name is empty */
|
||||
if (templor->variables[varidx] == NULL ||
|
||||
strlen(templor->variables[varidx]) == 0) {
|
||||
src_i += varlen;
|
||||
@@ -122,27 +121,28 @@ int tmpl_set_variable(struct templater *templor, const char *name, const char *v
|
||||
{
|
||||
int idx;
|
||||
|
||||
if(!templor)
|
||||
if (!templor)
|
||||
return -1;
|
||||
|
||||
if(!value)
|
||||
if (!value)
|
||||
return -1;
|
||||
|
||||
idx = get_variable_index(name);
|
||||
if(idx < 0)
|
||||
if (idx < 0)
|
||||
return -1;
|
||||
|
||||
if(templor->variables[idx])
|
||||
if (templor->variables[idx])
|
||||
free((void *)templor->variables[idx]);
|
||||
|
||||
templor->variables[idx] = safe_strdup(value);
|
||||
templor->variables[idx] = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tmpl_init_templor(struct templater *templor)
|
||||
{
|
||||
if(!templor)
|
||||
if (!templor)
|
||||
return;
|
||||
|
||||
memset(templor, 0x0, sizeof(*templor));
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
/**
|
||||
* @brief holds all valid variable names
|
||||
*/
|
||||
extern const char *variable_names[18];
|
||||
extern const char *variable_names[19];
|
||||
|
||||
struct templater {
|
||||
const char *variables[18]; /* must have the same size of variable_names */
|
||||
const char *variables[19]; /* must have the same size of variable_names */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
451
src/util.c
451
src/util.c
@@ -84,25 +84,15 @@ extern int created_httpd_threads;
|
||||
extern int current_httpd_threads;
|
||||
|
||||
|
||||
/** Fork a child and execute a shell command.
|
||||
* The parent process waits for the child to return,
|
||||
* and returns the child's exit() value.
|
||||
* @return Return code of the command
|
||||
*/
|
||||
int
|
||||
execute(const char cmd_line[], int quiet)
|
||||
static int _execute_ret(char* msg, int msg_len, const char *cmd)
|
||||
{
|
||||
int status, retval;
|
||||
pid_t pid, rc;
|
||||
struct sigaction sa, oldsa;
|
||||
const char *new_argv[4];
|
||||
new_argv[0] = "/bin/sh";
|
||||
new_argv[1] = "-c";
|
||||
new_argv[2] = cmd_line;
|
||||
new_argv[3] = NULL;
|
||||
FILE *fp;
|
||||
int rc;
|
||||
|
||||
/* Temporarily get rid of SIGCHLD handler (see gateway.c), until child exits.
|
||||
* Will handle SIGCHLD here with waitpid() in the parent. */
|
||||
debug(LOG_DEBUG, "Executing command: %s", cmd);
|
||||
|
||||
/* Temporarily get rid of SIGCHLD handler (see gateway.c), until child exits. */
|
||||
debug(LOG_DEBUG,"Setting default SIGCHLD handler SIG_DFL");
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
@@ -111,52 +101,74 @@ execute(const char cmd_line[], int quiet)
|
||||
debug(LOG_ERR, "sigaction() failed to set default SIGCHLD handler: %s", strerror(errno));
|
||||
}
|
||||
|
||||
pid = safe_fork();
|
||||
|
||||
if (pid == 0) { /* for the child process: */
|
||||
if (quiet) close(2); /* Close stderr if quiet flag is on */
|
||||
if (execvp("/bin/sh", (char *const *)new_argv) == -1) { /* execute the command */
|
||||
debug(LOG_ERR, "execvp(): %s", strerror(errno));
|
||||
} else {
|
||||
debug(LOG_ERR, "execvp() failed");
|
||||
}
|
||||
exit(1);
|
||||
|
||||
} else { /* for the parent: */
|
||||
debug(LOG_DEBUG, "Waiting for PID %d to exit", (int)pid);
|
||||
do {
|
||||
rc = waitpid(pid, &status, 0);
|
||||
if(rc == -1) {
|
||||
if(errno == ECHILD) {
|
||||
debug(LOG_DEBUG, "waitpid(): No child exists now. Assuming normal exit for PID %d", (int)pid);
|
||||
retval = 0;
|
||||
} else {
|
||||
debug(LOG_ERR, "Error waiting for child (waitpid() returned -1): %s", strerror(errno));
|
||||
retval = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(WIFEXITED(status)) {
|
||||
debug(LOG_DEBUG, "Process PID %d exited normally, status %d", (int)rc, WEXITSTATUS(status));
|
||||
retval = (WEXITSTATUS(status));
|
||||
}
|
||||
if(WIFSIGNALED(status)) {
|
||||
debug(LOG_DEBUG, "Process PID %d exited due to signal %d", (int)rc, WTERMSIG(status));
|
||||
retval = -1;
|
||||
}
|
||||
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||
|
||||
debug(LOG_DEBUG, "Restoring previous SIGCHLD handler");
|
||||
if (sigaction(SIGCHLD, &oldsa, NULL) == -1) {
|
||||
debug(LOG_ERR, "sigaction() failed to restore SIGCHLD handler! Error %s", strerror(errno));
|
||||
}
|
||||
|
||||
return retval;
|
||||
fp = popen(cmd, "r");
|
||||
if (fp == NULL) {
|
||||
debug(LOG_ERR, "popen(): %s", strerror(errno));
|
||||
rc = -1;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (msg && msg_len > 0) {
|
||||
fgets(msg, msg_len - 1, fp);
|
||||
}
|
||||
|
||||
rc = pclose(fp);
|
||||
|
||||
if (WIFSIGNALED(rc) != 0) {
|
||||
debug(LOG_WARNING, "Command process exited due to signal %d", WTERMSIG(rc));
|
||||
}
|
||||
|
||||
rc = WEXITSTATUS(rc);
|
||||
|
||||
abort:
|
||||
|
||||
/* Restore signal handler */
|
||||
if (sigaction(SIGCHLD, &oldsa, NULL) == -1) {
|
||||
debug(LOG_ERR, "sigaction() failed to restore SIGCHLD handler! Error %s", strerror(errno));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int execute(const char fmt[], ...)
|
||||
{
|
||||
char cmd[512];
|
||||
va_list vlist;
|
||||
int rc;
|
||||
|
||||
va_start(vlist, fmt);
|
||||
rc = vsnprintf(cmd, sizeof(cmd), fmt, vlist);
|
||||
va_end(vlist);
|
||||
|
||||
if (rc < 0 || rc >= sizeof(cmd)) {
|
||||
debug(LOG_ERR, "Format string too small or encoding error.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _execute_ret(NULL, 0, cmd);
|
||||
}
|
||||
|
||||
int execute_ret(char* msg, int msg_len, const char fmt[], ...)
|
||||
{
|
||||
char cmd[512];
|
||||
va_list vlist;
|
||||
int rc;
|
||||
|
||||
va_start(vlist, fmt);
|
||||
rc = vsnprintf(cmd, sizeof(cmd), fmt, vlist);
|
||||
va_end(vlist);
|
||||
|
||||
if (rc < 0 || rc >= sizeof(cmd)) {
|
||||
debug(LOG_ERR, "Format string too small or encoding error.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _execute_ret(msg, msg_len, cmd);
|
||||
}
|
||||
|
||||
struct in_addr *
|
||||
wd_gethostbyname(const char name[]) {
|
||||
wd_gethostbyname(const char name[])
|
||||
{
|
||||
struct hostent *he;
|
||||
struct in_addr *h_addr, *in_addr_temp;
|
||||
|
||||
@@ -190,7 +202,7 @@ get_iface_ip(const char ifname[])
|
||||
struct ifaddrs *addrs;
|
||||
s_config *config;
|
||||
|
||||
if(getifaddrs(&addrs) < 0) {
|
||||
if (getifaddrs(&addrs) < 0) {
|
||||
debug(LOG_ERR, "getifaddrs(): %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
@@ -203,14 +215,14 @@ get_iface_ip(const char ifname[])
|
||||
/* Iterate all interfaces */
|
||||
cur = addrs;
|
||||
while(cur != NULL) {
|
||||
if( (cur->ifa_addr != NULL) && (strcmp( cur->ifa_name, ifname ) == 0) ) {
|
||||
if ( (cur->ifa_addr != NULL) && (strcmp( cur->ifa_name, ifname ) == 0) ) {
|
||||
|
||||
if(config->ip6 && cur->ifa_addr->sa_family == AF_INET6) {
|
||||
if (config->ip6 && cur->ifa_addr->sa_family == AF_INET6) {
|
||||
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addrbuf, sizeof(addrbuf));
|
||||
break;
|
||||
}
|
||||
|
||||
if(!config->ip6 && cur->ifa_addr->sa_family == AF_INET) {
|
||||
if (!config->ip6 && cur->ifa_addr->sa_family == AF_INET) {
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in *)cur->ifa_addr)->sin_addr, addrbuf, sizeof(addrbuf));
|
||||
break;
|
||||
}
|
||||
@@ -296,16 +308,16 @@ out:
|
||||
* Caller must free.
|
||||
*/
|
||||
char *
|
||||
get_ext_iface (void)
|
||||
get_ext_iface(void)
|
||||
{
|
||||
#ifdef __linux__
|
||||
FILE *input;
|
||||
char *device, *gw;
|
||||
int i = 1;
|
||||
int keep_detecting = 1;
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
struct timespec timeout;
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
struct timespec timeout;
|
||||
device = (char *)malloc(16);
|
||||
gw = (char *)malloc(16);
|
||||
debug(LOG_DEBUG, "get_ext_iface(): Autodectecting the external interface from routing table");
|
||||
@@ -346,12 +358,20 @@ get_ext_iface (void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Malloc's */
|
||||
char *
|
||||
format_time(unsigned long int secs)
|
||||
format_duration(time_t from, time_t to, char buf[64])
|
||||
{
|
||||
unsigned int days, hours, minutes, seconds;
|
||||
char * str;
|
||||
int days, hours, minutes, seconds;
|
||||
long long int secs;
|
||||
|
||||
if (from <= to) {
|
||||
secs = to - from;
|
||||
} else {
|
||||
secs = from - to;
|
||||
// Prepend minus sign
|
||||
buf[0] = '-';
|
||||
buf += 1;
|
||||
}
|
||||
|
||||
days = secs / (24 * 60 * 60);
|
||||
secs -= days * (24 * 60 * 60);
|
||||
@@ -361,41 +381,39 @@ format_time(unsigned long int secs)
|
||||
secs -= minutes * 60;
|
||||
seconds = secs;
|
||||
|
||||
safe_asprintf(&str,"%ud %uh %um %us", days, hours, minutes, seconds);
|
||||
return str;
|
||||
if (days > 0) {
|
||||
sprintf(buf, "%dd %dh %dm %ds", days, hours, minutes, seconds);
|
||||
} else if (hours > 0) {
|
||||
sprintf(buf, "%dh %dm %ds", hours, minutes, seconds);
|
||||
} else if (minutes > 0) {
|
||||
sprintf(buf, "%dm %ds", minutes, seconds);
|
||||
} else {
|
||||
sprintf(buf, "%ds", seconds);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *
|
||||
format_time(time_t *time, char buf[64])
|
||||
{
|
||||
strftime(buf, 64, "%a %b %d %H:%M:%S %Y", localtime(time));
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Caller must free. */
|
||||
char *
|
||||
get_uptime_string()
|
||||
{
|
||||
return format_time(time(NULL)-started_time);
|
||||
}
|
||||
|
||||
/* Custom print format string to file descriptor */
|
||||
void
|
||||
cprintf( int fd, const char *format, ... ) {
|
||||
char buffer[256];
|
||||
va_list vlist;
|
||||
int rc;
|
||||
|
||||
va_start( vlist, format );
|
||||
rc = vsnprintf( buffer, sizeof(buffer), format, vlist );
|
||||
va_end( vlist );
|
||||
|
||||
if (rc > 0 && rc < sizeof(buffer)) {
|
||||
printf("#%s", buffer);
|
||||
write(fd, buffer, strlen(buffer));
|
||||
} else {
|
||||
debug(LOG_ERR, "failed to write format string: %s", format);
|
||||
}
|
||||
char *buf = malloc(64);
|
||||
return format_duration(started_time, time(NULL), buf);
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_status(int fd)
|
||||
ndsctl_status(FILE *fp)
|
||||
{
|
||||
char timebuf[32];
|
||||
char *str;
|
||||
char durationbuf[128];
|
||||
s_config *config;
|
||||
t_client *client;
|
||||
int indx;
|
||||
@@ -407,120 +425,107 @@ ndsctl_status(int fd)
|
||||
|
||||
config = config_get_config();
|
||||
|
||||
cprintf(fd, "==================\nNoDogSplash Status\n====\n");
|
||||
fprintf(fp, "==================\nNoDogSplash Status\n====\n");
|
||||
|
||||
now = time(NULL);
|
||||
uptimesecs = now - started_time;
|
||||
|
||||
cprintf(fd, "Version: " VERSION "\n");
|
||||
fprintf(fp, "Version: " VERSION "\n");
|
||||
|
||||
str = format_time(uptimesecs);
|
||||
cprintf(fd, "Uptime: %s\n", str);
|
||||
free(str);
|
||||
format_duration(started_time, now, durationbuf);
|
||||
fprintf(fp, "Uptime: %s\n", durationbuf);
|
||||
|
||||
cprintf(fd, "Gateway Name: %s\n", config->gw_name);
|
||||
cprintf(fd, "Managed interface: %s\n", config->gw_interface);
|
||||
cprintf(fd, "Managed IP range: %s\n", config->gw_iprange);
|
||||
cprintf(fd, "Server listening: %s:%d\n", config->gw_address, config->gw_port);
|
||||
fprintf(fp, "Gateway Name: %s\n", config->gw_name);
|
||||
fprintf(fp, "Managed interface: %s\n", config->gw_interface);
|
||||
fprintf(fp, "Managed IP range: %s\n", config->gw_iprange);
|
||||
fprintf(fp, "Server listening: %s:%d\n", config->gw_address, config->gw_port);
|
||||
fprintf(fp, "Client Check Interval: %ds\n", config->checkinterval);
|
||||
fprintf(fp, "Preauth Idle Timeout: %ds\n", config->preauth_idle_timeout);
|
||||
fprintf(fp, "Authed Idle Timeout: %ds\n", config->authed_idle_timeout);
|
||||
|
||||
if(config->authenticate_immediately) {
|
||||
cprintf(fd, "Authenticate immediately: yes\n");
|
||||
} else {
|
||||
cprintf(fd, "Splashpage: %s/%s\n", config->webroot, config->splashpage);
|
||||
if (config->redirectURL) {
|
||||
fprintf(fp, "Redirect URL: %s\n", config->redirectURL);
|
||||
}
|
||||
|
||||
if(config->redirectURL) {
|
||||
cprintf(fd, "Redirect URL: %s\n", config->redirectURL);
|
||||
}
|
||||
fprintf(fp, "Traffic control: %s\n", config->traffic_control ? "yes" : "no");
|
||||
|
||||
if(config->passwordauth) {
|
||||
cprintf(fd, "Gateway password: %s\n", config->password);
|
||||
}
|
||||
|
||||
if(config->usernameauth) {
|
||||
cprintf(fd, "Gateway username: %s\n", config->username);
|
||||
}
|
||||
|
||||
cprintf(fd, "Traffic control: %s\n", config->traffic_control ? "yes" : "no");
|
||||
|
||||
if(config->traffic_control) {
|
||||
if(config->download_limit > 0) {
|
||||
cprintf(fd, "Download rate limit: %d kbit/s\n", config->download_limit);
|
||||
if (config->traffic_control) {
|
||||
if (config->download_limit > 0) {
|
||||
fprintf(fp, "Download rate limit: %d kbit/s\n", config->download_limit);
|
||||
} else {
|
||||
cprintf(fd, "Download rate limit: none\n");
|
||||
fprintf(fp, "Download rate limit: none\n");
|
||||
}
|
||||
if(config->upload_limit > 0) {
|
||||
cprintf(fd, "Upload rate limit: %d kbit/s\n", config->upload_limit);
|
||||
if (config->upload_limit > 0) {
|
||||
fprintf(fp, "Upload rate limit: %d kbit/s\n", config->upload_limit);
|
||||
} else {
|
||||
cprintf(fd, "Upload rate limit: none\n");
|
||||
fprintf(fp, "Upload rate limit: none\n");
|
||||
}
|
||||
}
|
||||
|
||||
download_bytes = iptables_fw_total_download();
|
||||
cprintf(fd, "Total download: %llu kByte", download_bytes/1000);
|
||||
cprintf(fd, "; avg: %.6g kbit/s\n", ((double) download_bytes) / 125 / uptimesecs);
|
||||
fprintf(fp, "Total download: %llu kByte", download_bytes / 1000);
|
||||
fprintf(fp, "; avg: %.2f kbit/s\n", ((double) download_bytes) / 125 / uptimesecs);
|
||||
|
||||
upload_bytes = iptables_fw_total_upload();
|
||||
cprintf(fd, "Total upload: %llu kByte", upload_bytes/1000);
|
||||
cprintf(fd, "; avg: %.6g kbit/s\n", ((double) upload_bytes) / 125 / uptimesecs);
|
||||
cprintf(fd, "====\n");
|
||||
cprintf(fd, "Client authentications since start: %u\n", authenticated_since_start);
|
||||
cprintf(fd, "Httpd request threads created/current: %d/%d\n", created_httpd_threads, current_httpd_threads);
|
||||
|
||||
if(config->decongest_httpd_threads) {
|
||||
cprintf(fd, "Httpd thread decongest threshold: %d threads\n", config->httpd_thread_threshold);
|
||||
cprintf(fd, "Httpd thread decongest delay: %d ms\n", config->httpd_thread_delay_ms);
|
||||
}
|
||||
fprintf(fp, "Total upload: %llu kByte", upload_bytes / 1000);
|
||||
fprintf(fp, "; avg: %.2f kbit/s\n", ((double) upload_bytes) / 125 / uptimesecs);
|
||||
fprintf(fp, "====\n");
|
||||
fprintf(fp, "Client authentications since start: %u\n", authenticated_since_start);
|
||||
|
||||
/* Update the client's counters so info is current */
|
||||
iptables_fw_counters_update();
|
||||
|
||||
LOCK_CLIENT_LIST();
|
||||
|
||||
cprintf(fd, "Current clients: %d\n", get_client_list_length());
|
||||
fprintf(fp, "Current clients: %d\n", get_client_list_length());
|
||||
|
||||
client = client_get_first_client();
|
||||
if(client) {
|
||||
cprintf(fd, "\n");
|
||||
if (client) {
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
indx = 0;
|
||||
while (client != NULL) {
|
||||
cprintf(fd, "Client %d\n", indx);
|
||||
fprintf(fp, "Client %d\n", indx);
|
||||
|
||||
cprintf(fd, " IP: %s MAC: %s\n", client->ip, client->mac);
|
||||
fprintf(fp, " IP: %s MAC: %s\n", client->ip, client->mac);
|
||||
|
||||
ctime_r(&(client->added_time),timebuf);
|
||||
cprintf(fd, " Added: %s", timebuf);
|
||||
format_time(&client->counters.last_updated, timebuf);
|
||||
format_duration(client->counters.last_updated, now, durationbuf);
|
||||
fprintf(fp, " Last Activity: %s (%s ago)\n", timebuf, durationbuf);
|
||||
|
||||
ctime_r(&(client->counters.last_updated),timebuf);
|
||||
cprintf(fd, " Active: %s", timebuf);
|
||||
|
||||
str = format_time(client->counters.last_updated - client->added_time);
|
||||
cprintf(fd, " Active duration: %s\n", str);
|
||||
free(str);
|
||||
|
||||
if(now > client->added_time) {
|
||||
durationsecs = now - client->added_time;
|
||||
if (client->session_start) {
|
||||
format_time(&client->session_start, timebuf);
|
||||
format_duration(client->session_start, now, durationbuf);
|
||||
fprintf(fp, " Session Start: %s (%s ago)\n", timebuf, durationbuf);
|
||||
} else {
|
||||
// prevent divison by 0 later
|
||||
fprintf(fp, " Session Start: -\n");
|
||||
}
|
||||
|
||||
if (client->session_end) {
|
||||
format_time(&client->session_end, timebuf);
|
||||
format_duration(now, client->session_end, durationbuf);
|
||||
fprintf(fp, " Session End: %s (%s left)\n", timebuf, durationbuf);
|
||||
} else {
|
||||
fprintf(fp, " Session End: -\n");
|
||||
}
|
||||
|
||||
fprintf(fp, " Token: %s\n", client->token ? client->token : "none");
|
||||
|
||||
fprintf(fp, " State: %s\n", fw_connection_state_as_string(client->fw_connection_state));
|
||||
|
||||
download_bytes = client->counters.incoming;
|
||||
upload_bytes = client->counters.outgoing;
|
||||
durationsecs = now - client->session_start;
|
||||
|
||||
// prevent divison by 0
|
||||
if (durationsecs < 1) {
|
||||
durationsecs = 1;
|
||||
}
|
||||
|
||||
str = format_time(durationsecs);
|
||||
cprintf(fd, " Added duration: %s\n", str);
|
||||
free(str);
|
||||
|
||||
cprintf(fd, " Token: %s\n", client->token ? client->token : "none");
|
||||
|
||||
cprintf(fd, " State: %s\n", fw_connection_state_as_string(client->fw_connection_state));
|
||||
|
||||
download_bytes = client->counters.incoming;
|
||||
upload_bytes = client->counters.outgoing;
|
||||
|
||||
cprintf(fd, " Download: %llu kByte; avg: %.6g kbit/s\n Upload: %llu kByte; avg: %.6g kbit/s\n\n",
|
||||
download_bytes/1000, ((double)download_bytes)/125/durationsecs,
|
||||
upload_bytes/1000, ((double)upload_bytes)/125/durationsecs);
|
||||
fprintf(fp, " Download: %llu kByte; avg: %.2f kbit/s\n Upload: %llu kByte; avg: %.2f kbit/s\n\n",
|
||||
download_bytes / 1000, ((double)download_bytes) / 125 / durationsecs,
|
||||
upload_bytes / 1000, ((double)upload_bytes) / 125 / durationsecs);
|
||||
|
||||
indx++;
|
||||
client = client->next;
|
||||
@@ -528,50 +533,50 @@ ndsctl_status(int fd)
|
||||
|
||||
UNLOCK_CLIENT_LIST();
|
||||
|
||||
cprintf(fd, "====\n");
|
||||
fprintf(fp, "====\n");
|
||||
|
||||
cprintf(fd, "Blocked MAC addresses:");
|
||||
fprintf(fp, "Blocked MAC addresses:");
|
||||
|
||||
if(config->macmechanism == MAC_ALLOW) {
|
||||
cprintf(fd, " N/A\n");
|
||||
if (config->macmechanism == MAC_ALLOW) {
|
||||
fprintf(fp, " N/A\n");
|
||||
} else if (config->blockedmaclist != NULL) {
|
||||
cprintf(fd, "\n");
|
||||
fprintf(fp, "\n");
|
||||
for (block_mac = config->blockedmaclist; block_mac != NULL; block_mac = block_mac->next) {
|
||||
cprintf(fd, " %s\n", block_mac->mac);
|
||||
fprintf(fp, " %s\n", block_mac->mac);
|
||||
}
|
||||
} else {
|
||||
cprintf(fd, " none\n");
|
||||
fprintf(fp, " none\n");
|
||||
}
|
||||
|
||||
cprintf(fd, "Allowed MAC addresses:");
|
||||
fprintf(fp, "Allowed MAC addresses:");
|
||||
|
||||
if(config->macmechanism == MAC_BLOCK) {
|
||||
cprintf(fd, " N/A\n");
|
||||
if (config->macmechanism == MAC_BLOCK) {
|
||||
fprintf(fp, " N/A\n");
|
||||
} else if (config->allowedmaclist != NULL) {
|
||||
cprintf(fd, "\n");
|
||||
fprintf(fp, "\n");
|
||||
for (allow_mac = config->allowedmaclist; allow_mac != NULL; allow_mac = allow_mac->next) {
|
||||
cprintf(fd, " %s\n", allow_mac->mac);
|
||||
fprintf(fp, " %s\n", allow_mac->mac);
|
||||
}
|
||||
} else {
|
||||
cprintf(fd, " none\n");
|
||||
fprintf(fp, " none\n");
|
||||
}
|
||||
|
||||
cprintf(fd, "Trusted MAC addresses:");
|
||||
fprintf(fp, "Trusted MAC addresses:");
|
||||
|
||||
if (config->trustedmaclist != NULL) {
|
||||
cprintf(fd, "\n");
|
||||
fprintf(fp, "\n");
|
||||
for (trust_mac = config->trustedmaclist; trust_mac != NULL; trust_mac = trust_mac->next) {
|
||||
cprintf(fd, " %s\n", trust_mac->mac);
|
||||
fprintf(fp, " %s\n", trust_mac->mac);
|
||||
}
|
||||
} else {
|
||||
cprintf(fd, " none\n");
|
||||
fprintf(fp, " none\n");
|
||||
}
|
||||
|
||||
cprintf(fd, "========\n");
|
||||
fprintf(fp, "========\n");
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_clients(int fd)
|
||||
ndsctl_clients(FILE *fp)
|
||||
{
|
||||
t_client *client;
|
||||
int indx;
|
||||
@@ -585,30 +590,31 @@ ndsctl_clients(int fd)
|
||||
|
||||
LOCK_CLIENT_LIST();
|
||||
|
||||
cprintf(fd, "%d\n", get_client_list_length());
|
||||
fprintf(fp, "%d\n", get_client_list_length());
|
||||
|
||||
client = client_get_first_client();
|
||||
if(client) {
|
||||
cprintf(fd, "\n");
|
||||
if (client) {
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
indx = 0;
|
||||
while (client != NULL) {
|
||||
cprintf(fd, "client_id=%d\n", indx);
|
||||
cprintf(fd, "ip=%s\nmac=%s\n", client->ip, client->mac);
|
||||
cprintf(fd, "added=%lld\n", (long long) client->added_time);
|
||||
cprintf(fd, "active=%lld\n", (long long) client->counters.last_updated);
|
||||
cprintf(fd, "duration=%lu\n", now - client->added_time);
|
||||
cprintf(fd, "token=%s\n", client->token ? client->token : "none");
|
||||
cprintf(fd, "state=%s\n", fw_connection_state_as_string(client->fw_connection_state));
|
||||
fprintf(fp, "client_id=%d\n", indx);
|
||||
fprintf(fp, "ip=%s\nmac=%s\n", client->ip, client->mac);
|
||||
fprintf(fp, "added=%lld\n", (long long) client->session_start);
|
||||
fprintf(fp, "active=%lld\n", (long long) client->counters.last_updated);
|
||||
fprintf(fp, "duration=%lu\n", now - client->session_start);
|
||||
fprintf(fp, "token=%s\n", client->token ? client->token : "none");
|
||||
fprintf(fp, "state=%s\n", fw_connection_state_as_string(client->fw_connection_state));
|
||||
|
||||
durationsecs = now - client->added_time;
|
||||
durationsecs = now - client->session_start;
|
||||
download_bytes = client->counters.incoming;
|
||||
upload_bytes = client->counters.outgoing;
|
||||
|
||||
cprintf(fd, "downloaded=%llu\navg_down_speed=%.6g\nuploaded=%llu\navg_up_speed=%.6g\n\n",
|
||||
download_bytes/1000, ((double)download_bytes)/125/durationsecs,
|
||||
upload_bytes/1000, ((double)upload_bytes)/125/durationsecs);
|
||||
fprintf(fp, "downloaded=%llu\n", download_bytes/1000);
|
||||
fprintf(fp, "avg_down_speed=%.2f\n", ((double)download_bytes) / 125 / durationsecs);
|
||||
fprintf(fp, "uploaded=%llu\n", upload_bytes/1000);
|
||||
fprintf(fp, "avg_up_speed=%.2f\n\n", ((double)upload_bytes) / 125 / durationsecs);
|
||||
|
||||
indx++;
|
||||
client = client->next;
|
||||
@@ -618,7 +624,7 @@ ndsctl_clients(int fd)
|
||||
}
|
||||
|
||||
void
|
||||
ndsctl_json(int fd)
|
||||
ndsctl_json(FILE *fp)
|
||||
{
|
||||
t_client *client;
|
||||
int indx;
|
||||
@@ -632,41 +638,42 @@ ndsctl_json(int fd)
|
||||
|
||||
LOCK_CLIENT_LIST();
|
||||
|
||||
cprintf(fd, "{\n\"client_length\": %d,\n", get_client_list_length());
|
||||
fprintf(fp, "{\n\"client_length\": %d,\n", get_client_list_length());
|
||||
|
||||
client = client_get_first_client();
|
||||
indx = 0;
|
||||
|
||||
cprintf(fd, "\"clients\":{\n");
|
||||
fprintf(fp, "\"clients\":{\n");
|
||||
|
||||
while (client != NULL) {
|
||||
cprintf(fd, "\"%s\":{\n", client->mac);
|
||||
cprintf(fd, "\"client_id\":%d,\n", indx);
|
||||
cprintf(fd, "\"ip\":\"%s\",\n\"mac\":\"%s\",\n", client->ip, client->mac);
|
||||
cprintf(fd, "\"added\":%lld,\n", (long long) client->added_time);
|
||||
cprintf(fd, "\"active\":%lld,\n", (long long) client->counters.last_updated);
|
||||
cprintf(fd, "\"duration\":%lu,\n", now - client->added_time);
|
||||
cprintf(fd, "\"token\":\"%s\",\n", client->token ? client->token : "none");
|
||||
cprintf(fd, "\"state\":\"%s\",\n", fw_connection_state_as_string(client->fw_connection_state));
|
||||
fprintf(fp, "\"%s\":{\n", client->mac);
|
||||
fprintf(fp, "\"client_id\":%d,\n", indx);
|
||||
fprintf(fp, "\"ip\":\"%s\",\n\"mac\":\"%s\",\n", client->ip, client->mac);
|
||||
fprintf(fp, "\"added\":%lld,\n", (long long) client->session_start);
|
||||
fprintf(fp, "\"active\":%lld,\n", (long long) client->counters.last_updated);
|
||||
fprintf(fp, "\"duration\":%lu,\n", now - client->session_start);
|
||||
fprintf(fp, "\"token\":\"%s\",\n", client->token ? client->token : "none");
|
||||
fprintf(fp, "\"state\":\"%s\",\n", fw_connection_state_as_string(client->fw_connection_state));
|
||||
|
||||
durationsecs = now - client->added_time;
|
||||
durationsecs = now - client->session_start;
|
||||
download_bytes = client->counters.incoming;
|
||||
upload_bytes = client->counters.outgoing;
|
||||
|
||||
cprintf(fd, "\"downloaded\":\"%llu\",\n\"avg_down_speed\":\"%.6g\",\n\"uploaded\":\"%llu\",\n\"avg_up_speed\":\"%.6g\"\n",
|
||||
download_bytes/1000, ((double)download_bytes)/125/durationsecs,
|
||||
upload_bytes/1000, ((double)upload_bytes)/125/durationsecs);
|
||||
fprintf(fp, "\"downloaded\":\"%llu\",\n", download_bytes / 1000);
|
||||
fprintf(fp, "\"avg_down_speed\":\"%.2f\",\n", ((double)download_bytes) / 125 / durationsecs);
|
||||
fprintf(fp, "\"uploaded\":\"%llu\",\n", upload_bytes / 1000);
|
||||
fprintf(fp, "\"avg_up_speed\":\"%.2f\"\n", ((double)upload_bytes)/ 125 / durationsecs);
|
||||
|
||||
indx++;
|
||||
client = client->next;
|
||||
|
||||
cprintf(fd, "}");
|
||||
if(client) {
|
||||
cprintf(fd, ",\n");
|
||||
fprintf(fp, "}");
|
||||
if (client) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
}
|
||||
|
||||
cprintf(fd, "}}" );
|
||||
fprintf(fp, "}}");
|
||||
|
||||
UNLOCK_CLIENT_LIST();
|
||||
}
|
||||
|
||||
16
src/util.h
16
src/util.h
@@ -26,9 +26,10 @@
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
/** @brief Execute a shell command
|
||||
*/
|
||||
int execute(const char cmd_line[], int quiet);
|
||||
/* @brief Execute a shell command */
|
||||
int execute(const char fmt[], ...);
|
||||
int execute_ret(char* msg, int msg_len, const char fmt[], ...);
|
||||
|
||||
struct in_addr *wd_gethostbyname(const char name[]);
|
||||
|
||||
/* @brief Get IP address of an interface */
|
||||
@@ -54,6 +55,9 @@ void mark_auth_offline();
|
||||
/* @brief Returns a guess (true or false) on whether we're an auth server is online or not based on previous calls to mark_auth_online and mark_auth_offline */
|
||||
int is_auth_online();
|
||||
|
||||
/* @brief Format a time_t value to 'Fri Jul 27 18:52:22 2018' */
|
||||
char *format_time(time_t *time, char buf[64]);
|
||||
|
||||
/*
|
||||
* @brief Mallocs and returns nodogsplash uptime string
|
||||
*/
|
||||
@@ -61,16 +65,16 @@ char *get_uptime_string();
|
||||
/*
|
||||
* @brief Writes a human-readable paragraph of the status of the nodogsplash process
|
||||
*/
|
||||
void ndsctl_status(int fd);
|
||||
void ndsctl_status(FILE *fp);
|
||||
/*
|
||||
* @brief Writes a machine-readable dump of currently connected clients
|
||||
*/
|
||||
void ndsctl_clients(int fd);
|
||||
void ndsctl_clients(FILE *fp);
|
||||
|
||||
/*
|
||||
* @brief Writes a machine-readable json of currently connected clients
|
||||
*/
|
||||
void ndsctl_json(int fd);
|
||||
void ndsctl_json(FILE *fp);
|
||||
|
||||
/** @brief cheap random */
|
||||
unsigned short rand16(void);
|
||||
|
||||
Reference in New Issue
Block a user