#!/bin/sh /etc/rc.common # # description: Startup/shutdown script for nodogsplash captive portal # # Alexander Couzens 2014 # P. Kube 2007 # # (Based on wifidog startup script # Date : 2004-08-25 # Version : 1.0 # Comment by that author: Could be better, but it's working as expected) # START=95 STOP=95 USE_PROCD=1 IPT=/usr/sbin/iptables WD_DIR=/usr/bin # -s -d 5 runs in background, with level 5 (not so verbose) messages to syslog # -f -d 7 runs in foreground, with level 7 (verbose) debug messages to terminal OPTIONS="-s -f -d 5" CONFIGFILE="/tmp/invalid_nodogsplash.conf" # nolog(loglevel message ...) nolog() { local level=$1 shift logger -s -t nodogsplash -p daemon.$level $@ } # append_config_option_map [] # append "$config_counterpart $value" to cfgfile if option_name exists # e.g. append_config_option "$CONFIGFILE" "$cfg" bind_address BindAddress 0.0.0.0 # will append "BindAddress 192.168.1.1" if uci bind_address is '192.168.1.1' append_config_option_map() { local val="" local config_file="$1" local cfg="$2" local option_name="$3" local config_counterpart="$4" local default="$5" config_get val "$cfg" "$option_name" "$default" [ -n "$val" ] && echo "$config_counterpart $val" >> $config_file } # append_config_option [] # append "$option_name $value" to cfgfile if option_name exists # e.g. append_config_option "$CONFIGFILE" "$cfg" bind_address 0.0.0.0 # will append "bind_address 192.168.1.1" if uci bind_address is '192.168.1.1' # if uci bind_address is unset append "bind_address 0.0.0.0" append_config_option() { local val="" local config_file="$1" local cfg="$2" local option_name="$3" local default="$4" config_get val "$cfg" "$option_name" "$default" [ -n "$val" ] && echo "$option_name $val" >> $config_file } setup_user_authentication() { local cfg="$1" local val config_get_bool val "$cfg" authenticate_immediately 0 [ $val -gt 0 ] && echo "AuthenticateImmediately yes" >> $CONFIGFILE config_get val "$cfg" username if [ -n "$val" ] ; then echo "UsernameAuthentication 1" >> $CONFIGFILE echo "Username $val" >> $CONFIGFILE fi config_get val "$cfg" password if [ -n "$val" ] ; then echo "PasswordAuthentication 1" >> $CONFIGFILE echo "Password $val" >> $CONFIGFILE fi } setup_mac_lists() { local cfg="$1" local MAC="" local val append_mac() { append MAC "$1" "," } config_get val "$cfg" macmechanism if [ -z "$val" ] ; then # check if we have AllowedMACList or BlockedMACList defined they will be ignored config_get val "$cfg" allowedmac if [ -n "$val" ] ; then echo "Ignoring allowedmac - macmechanism not \"allow\"" >&2 fi config_get val "$cfg" blockedmac if [ -n "$val" ] ; then echo "Ignoring blockedmac - macmechanism not \"block\"" >&2 fi elif [ "$val" == "allow" ] ; then MAC="" config_list_foreach "$cfg" allowedmac append_mac echo "AllowedMACList $MAC" >> $CONFIGFILE elif [ "$val" == "block" ] ; then MAC="" config_list_foreach "$cfg" blockedmac append_mac echo "BlockedMACList $MAC" >> $CONFIGFILE else nolog error "$cfg Invalid macmechanism '$val' - allow or block are valid." return 1 fi MAC="" config_list_foreach "$cfg" trustedmac append_mac [ -n "$MAC" ] && echo "TrustedMACList $MAC" >> $CONFIGFILE } setup_firewall() { local cfg="$1" local uciname local val append_firewall() { echo " FirewallRule $1" >> $CONFIGFILE } for rule in $(echo authenticated-users preauthenticated-users users-to-router trusted-users trusted-users-to-router) do uci_name=${rule//-/_} # uci does not allow - dashes echo "FirewallRuleSet $rule {" >> $CONFIGFILE config_list_foreach "$cfg" ${uci_name} append_firewall echo "}" >> $CONFIGFILE config_get val "$cfg" policy_${uci_name} [ -n "$val" ] && echo "EmptyRuleSetPolicy $rule $val" >> $CONFIGFILE done } generate_uci_config() { local cfg="$1" local val local ifname local download local upload CONFIGFILE="/tmp/etc/nodogsplash_$cfg.conf" echo "# auto-generated config file from /etc/config/nodogsplash" > $CONFIGFILE config_get val "$cfg" config if [ -n "$val" ] ; then if [ -f "$val" ] ; then nolog error "Configuration file '$file' doesn't exist" return 0 fi cat $val > CONFIGFILE fi config_get val "$cfg" network if [ -n "$val" ] ; then if ! network_get_device ifname "$val" ; then nolog error "$cfg can not find ifname for network '$val'" return 1 fi fi config_get val "$cfg" gatewayinterface if [ -n "$val" ] ; then if [ -n "$ifname" ] ; then nolog error "$cfg cannot use both option network and gatewayinterface" return 1 fi ifname="$val" fi if [ -z "$ifname" ] ; then nolog error "$cfg option network or gatewayinterface missing" return 1 fi echo "GatewayInterface $ifname" >> $CONFIGFILE append_config_option "$CONFIGFILE" "$cfg" gatewayname append_config_option "$CONFIGFILE" "$cfg" gatewayaddress append_config_option "$CONFIGFILE" "$cfg" gatewayport append_config_option "$CONFIGFILE" "$cfg" maxclients append_config_option "$CONFIGFILE" "$cfg" webroot append_config_option "$CONFIGFILE" "$cfg" debuglevel append_config_option "$CONFIGFILE" "$cfg" splashpage append_config_option "$CONFIGFILE" "$cfg" pagesdir append_config_option "$CONFIGFILE" "$cfg" checkinterval append_config_option "$CONFIGFILE" "$cfg" syslogfacility append_config_option "$CONFIGFILE" "$cfg" gatewayiprange append_config_option "$CONFIGFILE" "$cfg" imagedir append_config_option "$CONFIGFILE" "$cfg" redirecturl append_config_option "$CONFIGFILE" "$cfg" clientidletimeout append_config_option "$CONFIGFILE" "$cfg" clientforcetimeout append_config_option "$CONFIGFILE" "$cfg" gatewayiprange append_config_option "$CONFIGFILE" "$cfg" passwordattempts append_config_option "$CONFIGFILE" "$cfg" macmechanism append_config_option "$CONFIGFILE" "$cfg" uploadlimit append_config_option "$CONFIGFILE" "$cfg" downloadlimit append_config_option "$CONFIGFILE" "$cfg" remoteauthenticatoraction append_config_option "$CONFIGFILE" "$cfg" enablepreauth append_config_option "$CONFIGFILE" "$cfg" binvoucher append_config_option "$CONFIGFILE" "$cfg" forcevoucher append_config_option "$CONFIGFILE" "$cfg" passwordauthentication append_config_option "$CONFIGFILE" "$cfg" usernameauthentication append_config_option "$CONFIGFILE" "$cfg" passwordattempts append_config_option "$CONFIGFILE" "$cfg" username append_config_option "$CONFIGFILE" "$cfg" password append_config_option "$CONFIGFILE" "$cfg" authenticateimmediately append_config_option "$CONFIGFILE" "$cfg" decongesthttpdthreads append_config_option "$CONFIGFILE" "$cfg" httpdthreadthreshold append_config_option "$CONFIGFILE" "$cfg" httpdthreaddelayms append_config_option "$CONFIGFILE" "$cfg" fw_mark_authenticated append_config_option "$CONFIGFILE" "$cfg" fw_mark_trusted append_config_option "$CONFIGFILE" "$cfg" fw_mark_blocked config_get download "$cfg" downloadlimit config_get upload "$cfg" uploadlimit [ -n "$upload" -o -n "$download" ] && echo "TrafficControl yes" >> $CONFIGFILE setup_mac_lists "$cfg" setup_user_authentication "$cfg" setup_firewall "$cfg" } # setup configuration and start instance create_instance() { local cfg="$1" local manual_config local val config_get_bool val "$cfg" enabled 0 [ $val -gt 0 ] || return 0 generate_uci_config "$cfg" if ! test_module ; then logger -s -t nodogsplash -p daemon.error "nodogsplash is missing some kernel modules" fi procd_open_instance $cfg procd_set_param command /usr/bin/nodogsplash -c $CONFIGFILE $OPTIONS procd_set_param respawn procd_set_param file $CONFIGFILE procd_close_instance } start_service() { include /lib/functions mkdir -p /tmp/etc/ config_load nodogsplash config_foreach create_instance instance } stop_service() { # nodogsplash doesn't exit fast enought, when procd terminates it. # otherwise procd will restart nodogsplash twice. first time starting nodogsplash fails, second time it succeeds sleep 1 } status() { $WD_DIR/ndsctl status } # Test if we got all modules loaded test_module() { ### Test ipt_mark with iptables test_ipt_mark () { ($IPT -A FORWARD -m mark --mark 2 -j ACCEPT 2>&1) > /dev/null IPTABLES_OK=$? if [ "$IPTABLES_OK" -eq 0 ]; then ($IPT -D FORWARD -m mark --mark 2 -j ACCEPT 2>&1) > /dev/null return 0 else return 1 fi } ### Test ipt_mac with iptables test_ipt_mac () { ($IPT -A INPUT -m mac --mac-source 00:00:00:00:00:00 -j ACCEPT 2>&1) > /dev/null IPTABLES_OK=$? if [ "$IPTABLES_OK" -eq 0 ]; then ($IPT -D INPUT -m mac --mac-source 00:00:00:00:00:00 -j ACCEPT 2>&1) > /dev/null return 0 else return 1 fi } ### Test ipt_IMQ with iptables test_ipt_IMQ () { ($IPT -t mangle -A PREROUTING -j IMQ --todev 0 2>&1) > /dev/null IPTABLES_OK=$? if [ "$IPTABLES_OK" -eq 0 ]; then ($IPT -t mangle -D PREROUTING -j IMQ --todev 0 2>&1) > /dev/null return 0 else return 1 fi } ### Test imq with ip test_imq () { (ip link set imq0 up 2>&1) > /dev/null IMQ0_OK=$? (ip link set imq1 up 2>&1) > /dev/null IMQ1_OK=$? if [ "$IMQ0_OK" -eq 0 -a "$IMQ1_OK" -eq 0 ]; then (ip link set imq0 down 2>&1) > /dev/null (ip link set imq1 down 2>&1) > /dev/null return 0 else return 1 fi } ### Test sch_htb with tc; requires imq0 test_sch_htb () { (tc qdisc del dev imq0 root 2>&1) > /dev/null (tc qdisc add dev imq0 root htb 2>&1) > /dev/null TC_OK=$? if [ "$TC_OK" -eq 0 ]; then (tc qdisc del dev imq0 root 2>&1) > /dev/null return 0 else return 1 fi } ### Find a module on disk module_exists () { EXIST=$(find /lib/modules/`uname -r` -name $1.*o 2> /dev/null) if [ -n "$EXIST" ]; then return 0 else return 1 fi } ### Test if a module is in memory module_in_memory () { MODULE=$(lsmod | grep $1 | awk '{print $1}') if [ "$MODULE" = "$1" ]; then return 0 else return 1 fi } ### Test functionality of a module; load if necessary do_module_tests () { echo " Testing module $1 $2" "test_$1" if [ $? -ne 0 ]; then echo " Module $1 $2 needed" echo " Scanning disk for $1 module" module_exists $1 if [ $? -ne 0 ]; then echo " $1 module missing: please install it" exit 1 else echo " $1 exists, trying to load" insmod $1 $2 > /dev/null if [ $? -ne 0 ]; then echo " Error: insmod $1 $2 failed" exit 1 else echo " $1 $2 loaded successfully" fi fi else echo " $1 is working" fi } echo " Testing required modules" do_module_tests "ipt_mac" do_module_tests "ipt_mark" # test for imq modules, only if TrafficControl is enabled in conf if ( grep -q -E '^[[:space:]]*TrafficControl[[:space:]]+(yes|true|1)' "$CONFIGFILE" ) ; then do_module_tests "imq" "numdevs=2" do_module_tests "ipt_IMQ" do_module_tests "sch_htb" fi }