#!/bin/sh /etc/rc.common
START=99

[ -z "$ROOT" ] && ROOT=/www
CONFIG=$ROOT/config
SCRIPT=$ROOT/script
PRIVOXY=$ROOT/privoxy

[ -f $CONFIG/ng.conf ] && source $CONFIG/ng.conf
source $CONFIG/ap.conf
source $CONFIG/api.conf

source $SCRIPT/utils/stat.sh
source $SCRIPT/utils/wifi.sh
source $SCRIPT/utils/wifi-extend.sh
source $SCRIPT/utils/network.sh
source $SCRIPT/utils/hotspot.sh
source $SCRIPT/utils/qos.sh

radios=`getRadioCount`
physdev="`lsmod | grep physdev`"

ebt="ebtables --concurrent"
ipt="iptables -w"

stopJobs() {
  echo -n "  Killing daemon processes..."
  jobPids="`ps | grep -e jobs -e "/usr/bin/nc" -e "/usr/bin/openssl" -e "dd bs" | grep -v grep | awk '{print $1}'`"
  for pid in $jobPids ; do
    kill -9 "$pid" 2>/dev/null
  done

  rm -rf /tmp/bish-bosh.*
}

startJobs() {
  export PATH="$PATH:$ROOT/bish-bosh"
  [ "`which bish-bosh`" ] || return

  echo "Start daemon process"
  $SCRIPT/jobs.sh >/dev/null 2>/dev/null &
}

syncTime() {
  echo "  Sync time from cloud"

  echo "ICT-7" > /tmp/TZ
  local serverTime=`wget --no-check-certificate -T 5 -qO - "$CLOUD_ADDRESS/time"`
  if [ ! -z "$serverTime" ] ; then
    serverTime=`echo "$serverTime" | sed 's/T/ /g' | cut -c0-19`
    date -u -s "$serverTime"

    $SCRIPT/setup/setup-schedule.sh
  fi
}

restoreSessionDataOnSsid() {
  local ssid="$1"

  # Restore old sessions
  local sessionDir="/var/stats/ssid${ssid}/sessions"
  [ -d "$sessionDir" ] || return
  cd "$sessionDir"
  for mac in `ls` ; do
    [ -s "$mac/authenticated" ] && resetTimeoutOfIpInIpset $ssid $mac 3600
  done
}

setupHotspotOnSsid() {
  local ssid="$1"
  local isBridge=`isSsidInBridgeMode $ssid`;
  eval local autoLogin="\$SSID${ssid}_AUTO_LOGIN"

  local hotspotPort=$((8079 + ssid))

  local baseChain="HOTSPOT$ssid"
  local authenticatedSet="authenticated$ssid"
  local allowedClientSet="allowed${ssid}"
  local walledGargenSet="wallgarden${ssid}"
  local restrictedSet="restricted${ssid}"
  local autologinSet="autologin${ssid}"

  ipset create -! "$authenticatedSet" hash:mac timeout 3600 counters
  ipset create -! "$allowedClientSet" hash:mac
  ipset create -! "$walledGargenSet" hash:net
  ipset create -! "$restrictedSet" hash:net
  ipset create -! "$autologinSet" hash:ip timeout 5

  $ipt -t nat -N "${baseChain}"
  $ipt -t nat -N "${baseChain}_REDIRECT"
  $ipt -N "${baseChain}_IN"
  $ipt -N "${baseChain}_OUT"

  if [ -z "$physdev" ] ; then
    local infName=`getSsidInf $ssid`
    $ipt -t nat -A HOTSPOT -p udp --dport 53 -i $infName -j "$baseChain"
    $ipt -t nat -A HOTSPOT -p tcp --dport 80 -i $infName -j "$baseChain"
    $ipt -A HOTSPOT -i $infName -j "${baseChain}_IN"
    $ipt -A HOTSPOT -o $infName -j "${baseChain}_OUT"
  else
    local infName=`getSsidWirelessInf $ssid`
    for inf in $infName ; do
      $ipt -t nat -A HOTSPOT -p udp --dport 53 -m physdev --physdev-in $inf -j "$baseChain"
      $ipt -t nat -A HOTSPOT -p tcp --dport 80 -m physdev --physdev-in $inf -j "$baseChain"
      $ipt -A HOTSPOT -m physdev --physdev-in $inf -j "${baseChain}_IN"
      $ipt -A HOTSPOT -m physdev --physdev-out $inf -j "${baseChain}_OUT"
    done
  fi

  local dnsPort=$((5300 + ssid))
  local autoLoginPort=$((8069 + ssid))
  local loginPort=$((8079 + ssid))

  $ipt -t nat -A "${baseChain}_REDIRECT" -p udp --dport 53 -j REDIRECT --to-ports $dnsPort
  # $ipt -t nat -A "${baseChain}_REDIRECT" -p tcp -m set --match-set keepcna src -j REDIRECT --to-port 8090
  $ipt -t nat -A "${baseChain}_REDIRECT" -p tcp -m set --match-set $autologinSet src -j REDIRECT --to-ports $autoLoginPort
  $ipt -t nat -A "${baseChain}_REDIRECT" -p tcp -j REDIRECT --to-ports $loginPort

  $ipt -t nat -A "${baseChain}" -m set --match-set $walledGargenSet dst -j ACCEPT
  $ipt -t nat -A "${baseChain}" -m set --match-set $allowedClientSet src -j ACCEPT
  # $ipt -t nat -A "${baseChain}" -m set --match-set keepcna src -j "${baseChain}_REDIRECT"
  $ipt -t nat -A "${baseChain}" -m set --match-set $authenticatedSet src -j ACCEPT
  $ipt -t nat -A "${baseChain}" -j "${baseChain}_REDIRECT"

  $ipt -A "${baseChain}_IN" -m set --match-set $walledGargenSet dst -j ACCEPT
  $ipt -A "${baseChain}_IN" -m set --match-set $restrictedSet dst -j DROP
  $ipt -A "${baseChain}_IN" -m set --match-set $allowedClientSet src -j ACCEPT
  $ipt -A "${baseChain}_IN" -m set --match-set $authenticatedSet src -j ACCEPT
  $ipt -A "${baseChain}_IN" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  $ipt -A "${baseChain}_IN" -j DROP
  # drop

  $ipt -A "${baseChain}_OUT" -j ACCEPT

  # Whitelist
  eval local freeAuth="\$SSID${ssid}_WHITELIST"
  [ -z "$freeAuth" ] || freeauth=`echo $freeAuth | tr ';' '\n'`
  for mac in $freeAuth ; do
    [ -z "$mac" ] && continue
    ipset add -! $allowedClientSet "$mac"
  done

  # Wallgarden
  wanIp=`getWanIp`
  [ -z "$wanIp" ] || ipset add -! $walledGargenSet "$wanIp"

  if [ `addressIsIp $CLOUD` ] ; then
    ipset add -! $walledGargenSet "$CLOUD"
  else
    ipset add -! $walledGargenSet "`resolveHostname $CLOUD`"
  fi
  eval local wallgarden="\$SSID${ssid}_WALLGARDEN"
  [ -z "$wallgarden" ] || wallgarden=`echo $wallgarden | tr ';' '\n'`
  for site in $wallgarden ; do
    [ -z "$site" ] && continue
    if [ `addressIsIp $site` ] ; then
      ipset add -! "$walledGargenSet" "$site"
    else
      ping -c 1 -w 1 $site &>/dev/null
    fi
  done

  # https
  eval local allowHttps="\$SSID${ssid}_ALLOW_HTTPS"
  [ "$allowHttps" == 1 ] && $ipt -I "${baseChain}_IN" -p tcp --dport 443 -j ACCEPT

  # Restricted net
  eval local restrictedNets="\$SSID${ssid}_RESTRICTED"
  [ -z "$restrictedNets" ] || restrictedNets=`echo $restrictedNets | tr ';' '\n'`
  for net in $restrictedNets ; do
    [ -z "$net" ] && continue
    ipset add -! $restrictedSet "$net" 2>/dev/null
  done

  restoreSessionDataOnSsid "$ssid"
}

stopHotspotOnSsid() {
  local ssid="$1"
  local baseChain="HOTSPOT$ssid"
  local authenticatedSet="authenticated$ssid"
  local allowedClientSet="allowed${ssid}"
  local walledGargenSet="wallgarden${ssid}"
  local restrictedSet="restricted${ssid}"
  local autologinSet="autologin${ssid}"

  $ipt -t nat -F "$baseChain"
  $ipt -t nat -X "$baseChain"
  $ipt -t nat -F "${baseChain}_REDIRECT"
  $ipt -t nat -X "${baseChain}_REDIRECT"

  $ipt -F "${baseChain}_IN"
  $ipt -X "${baseChain}_IN"
  $ipt -F "${baseChain}_OUT"
  $ipt -X "${baseChain}_OUT"

  ipset destroy -! "$authenticatedSet" 2>/dev/null
  ipset destroy -! "$allowedClientSet" 2>/dev/null
  ipset destroy -! "$walledGargenSet" 2>/dev/null
  ipset destroy -! "$restrictedSet" 2>/dev/null
  ipset destroy -! "$autologinSet" 2>/dev/null
}

startHotspot() {
  echo "Start hotspot"

  iptables -w -t nat -N HOTSPOT
  iptables -w -t nat -A PREROUTING -j HOTSPOT

  iptables -w -N HOTSPOT
  iptables -w -A FORWARD -j HOTSPOT

  local hotspots=`getHotspotInstanceList`
  for ssid in $hotspots ; do
    echo "  Setting up Hotspot $ssid"
    setupHotspotOnSsid $ssid
  done

  # ipset create -! keepcna hash:mac timeout 10
  # ipset create -! keepcnadst hash:ip

  # $ipt -t mangle -N MARK_KEEP_CNA
  # iptables -t mangle -A MARK_KEEP_CNA -j MARK --set-mark 20
  # iptables -t mangle -A MARK_KEEP_CNA -j CONNMARK --save-mark

  # $ipt -t mangle -I PREROUTING \
  #   -p tcp --dport 80 \
  #   -m conntrack --ctstate NEW \
  #   -m set --match-set keepcna src \
  #   -m set --match-set keepcnadst dst \
  #   -j MARK_KEEP_CNA

  # $ipt -t mangle -I POSTROUTING \
  #   -p tcp --sport 80 \
  #   -m conntrack --ctstate ESTABLISHED,RELATED \
  #   -m set --match-set keepcnadst src \
  #   -j CONNMARK --restore-mark

  /etc/init.d/dnsmasq restart
}

stopHotspot() {
  echo "Stop hotspot"

  $ipt -t nat -D PREROUTING -j HOTSPOT
  $ipt -t nat -F HOTSPOT
  $ipt -t nat -X HOTSPOT

  $ipt -D FORWARD -j HOTSPOT
  $ipt -F HOTSPOT
  $ipt -X HOTSPOT

  local hotspots=`getHotspotInstanceList`
  for ssid in $hotspots ; do
    echo "  Stop Hotspot $ssid"
    stopHotspotOnSsid $ssid
  done

  $ipt -t mangle -P PREROUTING ACCEPT
  $ipt -t mangle -P POSTROUTING ACCEPT
  $ipt -t mangle -F
  $ipt -t mangle -X

  # ipset destroy -! keepcna 2>/dev/null
  # ipset destroy -! keepcnadst 2>/dev/null
}

startPrivoxy() {
  echo "  Start privoxy"

  local instances=`ls -1 $CONFIG | grep privoxy | grep .conf`
  for instance in $instances ; do
    privoxy --pidfile "/var/run/${instance}.pid" "$CONFIG/$instance"
  done
}

stopPrivoxy() {
  echo "  Stop privoxy"

  local pids="`pgrep privoxy`"
  [ -z "$pids" ] || kill -9 "$pids"
}

startFirewall() {
  echo "  Initializing iptables rules and chains..."
  $ebt -t nat -A PREROUTING -p IPv4 --pkttype-type broadcast --ip-proto udp --ip-sport 67:68 --ip-dport 67:68 -j ACCEPT
  if [ $? -eq 0 ] ; then
    $ebt -t nat -A PREROUTING -p IPv4 --ip-proto udp --ip-dport 53 -j ACCEPT
    $ebt -t nat -A PREROUTING -p ARP -j ACCEPT
    $ebt -t nat -A PREROUTING --pkttype-type broadcast -j DROP

    $ebt -t nat -A POSTROUTING -p IPv4 --pkttype-type broadcast --ip-proto udp --ip-sport 67:68 --ip-dport 67:68 -j ACCEPT
    $ebt -t nat -A POSTROUTING -p ARP -j ACCEPT
    $ebt -t nat -A POSTROUTING --pkttype-type broadcast -j DROP
  fi

  $ipt -t nat -N FIREWALL
  $ipt -t nat -A PREROUTING -j FIREWALL
  $ipt -N FIREWALL
  $ipt -A FORWARD -j FIREWALL

  $ipt -A FIREWALL -p udp --dport 53 -j ACCEPT
  $ipt -A FIREWALL -p udp --sport 67:68 --dport 67:68 -j ACCEPT

  enabledSsids=`getEnabledSsidList`
  for ssid in $enabledSsids ; do
    if [ ! `isSsidInBridgeMode $ssid` ] ; then
      eval ssidIp="\$SSID${ssid}_IP"
      eval ssidNetmask="\$SSID${ssid}_NETMASK"

      wanInf=`getWanInf`
      $ipt -t nat -A POSTROUTING -s "$ssidIp/$ssidNetmask" -o $wanInf -j MASQUERADE
    fi
  done
}

stopFirewall() {
  echo -n "  Clearing ebtables rules..."
  $ebt -t nat -F; $ebt -t nat -X; $ebt -t nat -Z;
  $ebt -t broute -F; $ebt -t broute -X; $ebt -t broute -Z
  echo "done."

  echo -n "  Clearing iptables rules..."
  $ipt -t nat -P PREROUTING ACCEPT
  $ipt -t nat -P INPUT ACCEPT
  $ipt -t nat -P OUTPUT ACCEPT
  $ipt -t nat -P POSTROUTING ACCEPT
  $ipt -t nat -F
  $ipt -t nat -X

  $ipt -P INPUT ACCEPT
  $ipt -P FORWARD ACCEPT
  $ipt -P OUTPUT ACCEPT
  $ipt -F
  $ipt -X

  $ipt -t mangle -P PREROUTING ACCEPT
  $ipt -t mangle -P INPUT ACCEPT
  $ipt -t mangle -P FORWARD ACCEPT
  $ipt -t mangle -P OUTPUT ACCEPT
  $ipt -t mangle -P POSTROUTING ACCEPT
  $ipt -t mangle -F
  $ipt -t mangle -X
  echo "done."
}

startQoS() {
  ssids=`getEnabledSsidList`
  for ssid in $ssids ; do
    enableQosOnSsid $ssid
    [ "`isQosEnabledOnSsid $ssid`" ] || continue

    sessionDir="/var/stats/ssid${ssid}/sessions"
    [ -d "$sessionDir" ] && cd $sessionDir || continue

    sessions=`ls`
    for session in $sessions ; do
      ip=`cat "$sessionDir/$session/ip"`
      [ -z "$ip" ] && continue
      maxDownload=`cat "$sessionDir/$session/maxDownload" 2>/dev/null`
      maxUpload=`cat "$sessionDir/$session/maxUpload" 2>/dev/null`
      [ -z "$maxDownload" -a -z "$maxUpload" ] || enableQosOfIpOnSsid $ssid $ip "$maxDownload" "$maxUpload"
    done
  done
}

stopQoS() {
  echo "Remove QoS rules"
  ssids=`getEnabledSsidList`
  ssids=`getEnabledSsidList`
  for ssid in $ssids ; do
    disableQosOnSsid $ssid
  done
}

startAll() {
  echo "STARTING..."

  syncTime
  startPrivoxy
  startFirewall
  startHotspot
  startQoS

  touch /tmp/booted
  echo "DONE"
}

stopAll() {
  echo "STOPPING..."
  stopQoS
  stopHotspot
  stopFirewall
  stopPrivoxy

  echo "DONE"
}

stop() {
  case $1 in
  job)
    stopJobs
    ;;
  hotspot)
    stopHotspot
    ;;
  proxy)
    stopPrivoxy
    ;;
  qos)
    stopQoS
    ;;
  time)
    :
    ;;
  *)
    stopAll
    ;;
  esac
}

start() {
  case $1 in
  job)
    startJobs
    ;;
  hotspot)
    startHotspot
    ;;
  proxy)
    startPrivoxy
    ;;
  qos)
    startQoS
    ;;
  time)
    syncTime
    ;;
  *)
    startAll
    ;;
  esac
}

restart() {
  stop $1
  start $1
}
