##!/bin/sh
#! /bin/sh
#
### BEGIN INIT INFO
# Provides:       netconf
# Required-Start: $remote_fs $named $syslog
# Required-Stop:  $remote_fs $named $syslog
# Default-Start:  3 5
# Default-Stop:   0 1 2 6
# Description:    Comb NS Netconfig
### END INIT INFO

# Source function library.
. /etc/init.d/functions

if [ -e /etc/default/static ];then
        source /etc/default/static
	STAT_LAN_IP="${IP}"
	PREFIX_LAN=${IPV6PREFIX}
	ADDR_LAN=${IPV6ADDR}
	LAN_IDX=${IPV6ULANET-0}
else
	STAT_LAN_IP="";
	PREFIX_WIFI=""
	ADDR_WIFI=""
	LAN_IDX="0";
fi

if [ -e /etc/default/wifi ];then
        source /etc/default/wifi
	STAT_WIFI_IP="${IP}"
	IPV6_WIFI=${IPV6}
	if [ "${IPV6_WIFI}" == "1" ];then
		PREFIX_WIFI=${IPV6PREFIX}
		ADDR_WIFI=${IPV6ADDR}
	else
		PREFIX_WIFI=""
		ADDR_WIFI=""
		IPV64WIFI=0
	fi
	if [ "${WIFI_MODE}" == "STA" ];then
		WIFI_IFACE="wlan0"
		WIFI_SUBPRE=${IPV6ULANET-1}
	else
		WIFI_IFACE="wlan1"
		WIFI_SUBPRE=${IPV6ULANET-2}
	fi
else
	PREFIX_WIFI=""
	ADDR_WIFI=""
	IPV6_WIFI=0
	STAT_WIFI_IP=""
	IPV64WIFI=0
fi

if [ -e /etc/default/vlans ];then
	source /etc/default/vlans
else
	VLANS=""
fi;

if [ -e /etc/default/ppp ];then
        source /etc/default/ppp
	IPV6_EN=${IPV6-0}
	if [ "${IPV6_EN}" == "0" ];then
  		IPV64LAN="0";
		IPV64WAN="0";
	fi
	EXT_DHCP=${DHCP}
	EXT_DHCP6=${DHCP6}
else
	IPV6_EN="0";
	ENABLE="0";
	IPV64LAN="0";
	IPV64WAN="0";
	EXT_DHCP="0";
	EXT_DHCP6="0";
fi

if [ "${VLAN}" ] && [ -e /etc/default/vlan_${VLAN} ];then
	source /etc/default/vlan_${VLAN}
	WAN_IFACE="eth0.${VLAN}"
	STAT_WAN_IP="${IP}"
	DEF_ULANET=$(printf "%x" $((${VLAN} << 4)))
	WAN_IDX=${IPV6ULANET-${DEF_ULANET}}
	EIFACE=${WAN_IFACE}
elif [ "${VLAN}" ];then
	WAN_IFACE="eth0.${VLAN}"
	STAT_WAN_IP="";
	WAN_IDX=$(printf "%x" $((${VLAN} << 4)))
	EIFACE=${WAN_IFACE}
elif [ "${IPV64LAN}" != "1" ];then
	WAN_IFACE="eth0"
	STAT_WAN_IP="${STAT_WAN_LAN}"
	WAN_IDX=${LAN_IDX}
	EIFACE=${WAN_IFACE}
else
	EIFACE="eth0"
	WAN_IFACE=""
fi

get_eui64_prefix() {
  IFACE=${1}
  ORIG_IFS=${IFS}
  IFS=:
  m=($(cat /sys/class/net/${IFACE}/address))
  IFS=${ORIG_IFS}

  printf "%s:%s:%x:%x:%x:%x\n" ${2} ${3} $((((0x${m[0]} ^ 2) << 8) + 0x${m[1]}))  0x${m[2]}ff 0xfe${m[3]} 0x${m[4]}${m[5]}
}

get_eui64_link() {
  IFACE=${1}
  ORIG_IFS=${IFS}
  IFS=:
  m=($(cat /sys/class/net/${IFACE}/address))
  IFS=${ORIG_IFS}

  printf "fe80::%x:%x:%x:%x\n" $((((0x${m[0]} ^ 2) << 8) + 0x${m[1]}))  0x${m[2]}ff 0xfe${m[3]} 0x${m[4]}${m[5]}
}

conf_radvd_64_int() {
  if [ "${3}" ];then
    iface="${1}:${2}"
    presub=${3}
   else
    iface="${1}"
    presub=${2}
  fi;
  cat <<__EOF__
	prefix 0:0:0:${presub}::/64 {
		Base6to4Interface ${iface};
		AdvAutonomous on;
		DeprecatePrefix on;
		AdvValidLifetime 3600;
		AdvPreferredLifetime 1440;
	};

__EOF__
}

conf_radvd_int() {
  ORIG_IFS=${IFS}
  IFS=:
  subnet6=(${2})
  IFS=${ORIG_IFS}

  if [ "${subnet6[0]}" == "" ];then
	subnet6[0]="0"
  fi

  cat <<__EOF__
interface ${1} {
	AdvSendAdvert on;
	AdvOtherConfigFlag on;
#	IgnoreIfMissing on;
#	MinRtrAdvInterval 30;
#	MaxRtrAdvInterval 100;
	AdvReachableTime 30000;
	AdvRetransTimer 10000;
#	AdvDefaultLifetime 0;

__EOF__

  printf "\tRDNSS %s {\n\t};\n\n" $(get_eui64_link ${1})

  if [ "${IPV6ULA}" ];then
    printf "\tprefix %s:%s::/64 {\n\t\tAdvOnLink on;\n\t\tAdvAutonomous on;\n\t\tAdvPreferredLifetime 604800;\n\t\tAdvValidLifetime 2592000;\n\t};\n\n" ${IPV6ULA} ${subnet6[0]}
  fi;

  ip -6 route show proto dhcp dev ${1} |\
    awk '{printf "\tprefix %s {\n\t\tAdvOnLink on;\n\t\tAdvAutonomous on;\n\t\tAdvPreferredLifetime 604800;\n\t\tAdvValidLifetime 2592000;\n\t};\n\n",$1}'

  if [ "${IPV64PPP}" == "1" ];then
    conf_radvd_64_int ppp0 ${subnet6[0]}
  fi;

  if [ "${IPV64LAN}" == "1" ];then
    if [ "${STAT_LAN_IP}" ];then
      conf_radvd_64_int eth0 static ${subnet6[0]}
     else
      conf_radvd_64_int eth0 dhcp ${subnet6[0]}
    fi
  fi;

  if [ "${IPV64WAN}" == "1" ] && [ "${WAN_IFACE}" ];then
    if [ "${STAT_WAN_IP}" ];then
      conf_radvd_64_int ${WAN_IFACE} static ${subnet6[0]}
     else
      conf_radvd_64_int ${WAN_IFACE} dhcp ${subnet6[0]}
    fi
  fi;

  if [ "${IPV64WIFI}" == "1" ];then
    if [ "${WIFI_MODE}" == "STA" ];then
      if [ "${STAT_WIFI_IP}" ];then
        conf_radvd_64_int ${WIFI_IFACE} static ${subnet6[0]}
       else
        conf_radvd_64_int ${WIFI_IFACE} dhcp ${subnet6[0]}
      fi
     else
      conf_radvd_64_int ${WIFI_IFACE} ${subnet6[0]}
    fi
  fi
}

fixup_prefix(){
  PREFIX=""
  eval $(ipcalc -p --minaddr ${ipaddr} 2>/dev/null);
  if [ "${PREFIX}" ] && [ ${PREFIX} -lt 65 ];then
    echo ${MINADDR}/${PREFIX}
  fi
}

conf_prefixes() {
  (for ipaddr in $@;do
    fixup_prefix ${ipaddr}
  done) |sort |uniq |awk '{printf "\tprefix %s {\n\t\tAdvOnLink on;\n\t\tAdvAutonomous on;\n\t\tAdvPreferredLifetime 604800;\n\t\tAdvValidLifetime 2592000;\n\t};\n\n",$1}'
}

conf_radvd_vlan() {
  if [ ! -e /etc/default/vlan_${1} ] || [ ! -d /sys/class/net/eth0.${1} ];then
    return 0;
  fi

  IPV6ADDR=""
  IPV6PREFIX=""
  IPV6="0"
  IPV6ULANET=$(printf "%x" $((${1} << 4)))

  source /etc/default/vlan_${1}

  if [ "${IPV6}" == "1" ] || [ "${VLAN}" == "${1}" ];then
    conf_radvd_int eth0.${1} ${IPV6ULANET}
    conf_prefixes ${IPV6PREFIX}
    printf "};\n\n";
  fi
}

build_radvd_conf() {
  if [ "${IPV6_EN}" == "1" ] && [ -d /sys/class/net/eth0 ];then
    conf_radvd_int eth0 ${LAN_IDX}
    conf_prefixes ${PREFIX_LAN}
    printf "};\n\n";
  fi;

  if [ "${IPV6_WIFI}" == "1" ] && [ -d /sys/class/net/${WIFI_IFACE} ];then
    conf_radvd_int ${WIFI_IFACE} ${WIFI_SUBPRE}
    conf_prefixes ${PREFIX_WIFI}
    printf "};\n\n";
  fi

  for vlanid in ${VLANS};do
    if [ "${vlanid}" == "${VLAN}" ];then
      continue;
    fi;
    (conf_radvd_vlan ${vlanid})
  done

  if [ "${VLAN}" ] && [ "${IPV6_EN}" == "1" ];then
    (conf_radvd_vlan ${VLAN})
  fi;
}

conf_dhcpcd_vlan() {
  if [ ! -e /etc/default/vlan_${1} ] || [ ! -d /sys/class/net/eth0.${1} ];then
    return 0;
  fi

  IPV6="0"
  SUFFIX=0;

  source /etc/default/vlan_${1}

  if [ "${IPV6}" == "1" ] || [ "${VLAN}" == "${1}" ];then
    return 0
  fi
  return 1
}

build_dhcpcd_conf() {
  if [ "${EIFACE}" != "eth0" ];then
    IFACE=${WAN_IFACE}
    IAID=$(printf "ff:00:00:%02X" ${VLAN})
   else
    IFACE=${EIFACE}
    IAID=${EIFACE}
  fi;

  cat <<__EOF__
duid
noipv6rs
ipv6only
slaac private
logfile /var/log/dhcpcd.log

background
waitip 6
timeout 15
#debug
__EOF__

  PRE=0
  SUFFIX=0;

  if [ "${IPV6_EN}" == "1" ] && [ -d /sys/class/net/eth0 ] && [ "${VLAN}" != "" ] ;then
    PDLIST=" eth0/${PRE}/64/${SUFFIX}";
    LAST="eth0"
    PRE=$((${PRE} + 1));
  fi;

  if [ "${IPV6_WIFI}" == "1" ] && [ -d /sys/class/net/${WIFI_IFACE} ];then
    PDLIST="${PDLIST} ${WIFI_IFACE}/${PRE}/64/${SUFFIX}";
    LAST="${WIFI_IFACE}"
    PRE=$((${PRE} + 1));
  fi

  for vlanid in ${VLANS};do
    if [ "${vlanid}" == "${VLAN}" ];then
      continue;
    fi;
    if (conf_dhcpcd_vlan ${vlanid});then
      PDLIST="${PDLIST} eth0.${vlanid}/${PRE}/64/${SUFFIX}";
      LAST="eth0.${vlanid}"
      PRE=$((${PRE} + 1));
    fi
  done

  cat <<__EOF__

env last_delegate=${LAST}

interface ${IFACE}
	ipv6rs
	iaid ${IAID}
	ia_pd ${IAID} ${PDLIST}

__EOF__

}

run_dhcpcd() {
  if [ -e /var/run/dhcpcd-${1}.pid ];then
    dhcpcd -k ${1}
    dhcpcd -x ${1}
    if [ -e /var/run/dhcpcd-${1}.pid ];then
      /bin/kill $(cat /var/run/dhcpcd-${1}.pid)
      sleep 2
      if [ -e /var/run/dhcpcd-${1}.pid ];then
        /bin/kill -9 $(cat /var/run/dhcpcd-${1}.pid)
        sleep 2
      fi;
    fi
  fi;

  if [ "${2}" == "1" ];then
    /etc/init.d/radvd stop
    /sbin/ip -6 addr flush scope global dynamic
    /usr/sbin/dhcpcd -f /run/netconf/dhcpcd_${1}.conf ${1} > /dev/null 2>&1
  fi;
}

update_secret() {
  if [ ! -e ${1} ];then
    printf "%s\t*\t%s\n" ${2} ${3} > ${1}
   elif ! grep -q -s -E "^${2}\s" ${1};then
    printf "%s\t*\t%s\n" ${2} ${3} >> ${1}
   elif ! grep -q -s -E "^${2}\s\*\s${3}$" ${1};then
    sed -e 's|'${2}'\s.*|'${2}'\t*\t'${3}'|' -i ${1}
 fi;
}

ppp_call_conf() {
  PPP_OPTS="noipdefault\nusepeerdns\npersist\nlcp-echo-failure 2\nlcp-echo-interval 60\nnoauth\nholdoff 30\nmaxfail 0\nplugin rp-pppoe.so\n";

  if [ "${USER}" ];then
    PPP_OPTS="${PPP_OPTS}user ${USER}\n"
  fi;

  if [ "${MRU}" ];then
    PPP_OPTS="${PPP_OPTS}mru ${MRU}\n"
   else
    PPP_OPTS="${PPP_OPTS}mru 1492\n"
  fi;

  if [ "${SERVICE}" ];then
    PPP_OPTS="${PPP_OPTS}rp_pppoe_service ${SERVICE}\n"
  fi;

  PPP_OPTS="${PPP_OPTS}nic-${EIFACE}\n"

  if [ "${IPV6PPP}" == "1" ];then
    PPP_OPTS="${PPP_OPTS}+ipv6\nipv6cp-use-persistent\n"
  fi;

  printf "${PPP_OPTS}"  > /run/netconf/ns_default

  if [ ! -L /etc/ppp/peers/ns_default ];then
     if [ -e /etc/ppp/peers/ns_default ];then
       rm /etc/ppp/peers/ns_default
     fi;
     ln -rs /run/netconf/ns_default /etc/ppp/peers/ns_default
  fi;
}

ppp_conf() {
  ppp_call_conf

  update_secret /etc/ppp/pap-secrets ${USER} ${PASS}
  update_secret /etc/ppp/chap-secrets ${USER} ${PASS}
  chown root.root /etc/ppp/pap-secrets /etc/ppp/chap-secrets
  chmod 400 /etc/ppp/pap-secrets /etc/ppp/chap-secrets
}

start_radvd() {
  build_radvd_conf > /run/netconf/radvd.conf
   if [ ! -L /etc/radvd.conf ];then
     if [ -e /etc/radvd.conf ];then
       rm /etc/radvd.conf
     fi;
     ln -rs /run/netconf/radvd.conf /etc/radvd.conf
   fi;
  /etc/init.d/radvd reload || /etc/init.d/radvd start
}

start_dhcpcd() {
  build_dhcpcd_conf > /run/netconf/dhcpcd_${EIFACE}.conf
  if [ "${IPV6_EN}" == "1" ] && [ "${EXT_DHCP6}" == "1" ];then
    run_dhcpcd ${EIFACE} 1
   else
    run_dhcpcd ${EIFACE} 0
  fi
}

start_ipv6_firewall() {
  if [ "${FWLOCAL}" == "1" ] && [ "${WWW}" == "0" ];then
    if [ "${IPV6ULA}" ];then
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p tcp --dport 80
    fi;
   elif [ "${WWW}" == "1" ];then
    /usr/sbin/ip6tables -A PPP -j ACCEPT -p tcp --dport 80
  fi;

  if [ "${FWLOCAL}" == "0" ];then
    if [ "${IPV6ULA}" ];then
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48
    fi;
   else
    if [ "${IPV6ULA}" ];then
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p icmpv6
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p tcp --sport 0:1023 --dport 2049:2052
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p udp --sport 0:1023 --dport 2049:2052
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p tcp --sport 0:1023 --dport 111
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p udp --sport 0:1023 --dport 111
    fi;
  fi;
}

start_ipv4_firewall() {
  if [ "${DHCP}" == "1" ];then
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p udp -d 255.255.255.255 --dport 67:68
   else
    /usr/sbin/iptables -A PPP -j DROP -i ${1} -p udp -d 255.255.255.255 --dport 67:68
  fi;

  if [ "${FWLOCAL}" == "1" ] && [ "${WWW}" == "0" ];then
    /sbin/ip route show dev ${1} scope link proto kernel |sort |uniq |\
	awk -v DEV=${1} \
		'{printf "/usr/sbin/iptables -A PPP -j ACCEPT -p tcp -i %s -d %s -s %s --dport 80\n", DEV, $3, $1, DEV, $3, $1}' |sh
   elif [ "${WWW}" == "1" ];then
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p tcp --dport 80
    /usr/sbin/iptables -A PPP -j ACCEPT -i ppp0 -p tcp --dport 80
  fi

  if [ "${FWLOCAL}" == "0" ];then
    /sbin/ip route show dev ${1} scope link proto kernel |sort |uniq |\
	awk -v DEV=${1} '{printf "/usr/sbin/iptables -A PPP -j ACCEPT -i %s -s %s -d %s\n\
		/usr/sbin/iptables -A PPP -j ACCEPT -p igmp -i %s -s %s -d 224.0.0.0/4\n", DEV, $1, $1, DEV, $1}' |sh
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p udp -d 255.255.255.255
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p udp -d 224.0.0.251
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -d 224.0.0.1
   else
    /sbin/ip route show dev ${1} scope link proto kernel |sort |uniq |awk -v DEV=${1} '{printf "\
	/usr/sbin/iptables -A PPP -j ACCEPT -p tcp --sport 0:1023 --dport 2049:2052 -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j ACCEPT -p udp --sport 0:1023 --dport 2049:2052 -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j ACCEPT -p tcp --sport 0:1023 --dport 111 -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j ACCEPT -p udp --sport 0:1023 --dport 111 -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j DROP -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j DROP -p igmp -i %s -s %s -d 224.0.0.0/4\n", \
		DEV, $1, $1, DEV, $1, $1, DEV, $1, $1, DEV, $1, $1, DEV, $1, $1, DEV, $1}' |sh
    /usr/sbin/iptables -A PPP -j DROP -i ${1} -p udp -d 255.255.255.255
    /usr/sbin/iptables -A PPP -j DROP -i ${1} -p udp -d 224.0.0.251
    /usr/sbin/iptables -A PPP -j DROP -i ${1} -d 224.0.0.1
  fi;

  /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p tcp --tcp-flags SYN,ACK,FIN,RST FIN,ACK
#  /usr/sbin/iptables -A PPP -j LOG -i ${1}
  /usr/sbin/iptables -A PPP -j DROP -i ${1}
}

setup_firewall() {
  /usr/sbin/iptables -F PPP
  /usr/sbin/ip6tables -F PPP

  /usr/sbin/ip6tables -F IPv6LOCAL
  if [ "${IPV6ULA}" ];then
    /usr/sbin/ip6tables -A IPv6LOCAL -j ACCEPT -s ${IPV6ULA}::/48
  fi;
  /usr/sbin/ip6tables -A IPv6LOCAL -j ACCEPT -s fd00::/7

  if [ "${ENABLE}" == "1" ] && [ "${FWALL}" == "1" ];then
    start_ipv4_firewall ${EIFACE}
    start_ipv6_firewall
    echo 1 > /proc/sys/net/ipv4/conf/${EIFACE}/rp_filter
   elif [ "${ENABLE}" == "1" ] && [ "${WWW}" == "1" ];then
    /usr/sbin/iptables -A PPP -j ACCEPT -i ppp0 -p tcp --dport 80
    /usr/sbin/ip6tables -A PPP -j ACCEPT
    echo 0 > /proc/sys/net/ipv4/conf/${EIFACE}/rp_filter
   else
    if [ "${IPV6ULA}" ];then
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p tcp --dport 80
    fi
    /usr/sbin/ip6tables -A PPP -j REJECT --reject-with icmp6-adm-prohibited -p tcp --dport 80
    /usr/sbin/ip6tables -A PPP -j ACCEPT
    echo 0 > /proc/sys/net/ipv4/conf/${EIFACE}/rp_filter
  fi;
}

if [ ! -d /run/netconf ];then
  mkdir -p /run/netconf
fi;

case "$1" in
	radvd)
		start_radvd
	;;
	dhcpcd)
		start_dhcpcd
	;;
	firewall)
		setup_firewall
	;;
	ppp)
		ppp_conf
	;;
	start)
		setup_firewall

		build_dhcpcd_conf > /run/netconf/dhcpcd_${EIFACE}.conf
		if [ "${IPV6_EN}" == "1" ] && [ "${EXT_DHCP6}" == "1" ];then
			run_dhcpcd ${EIFACE} 1
		else
			run_dhcpcd ${EIFACE} 0
			start_radvd
		fi;

		if [ "${ENABLE}" == "1" ] && [ "${USER}" ] && [ "${PASS}" ];then
			ppp_conf
		fi;
	;;
	*)
		N=/etc/init.d/$NAME
		echo "Usage: $N {start|stop|status|restart|reload|force-reload}" >&2
		exit 1
	;;
esac
