#! /bin/bash set -e # Author: Pankaj Shelare # Email: pankaj.shelare@gmail.com # This script is created and enhanced using the thoughts of the below given link reference. # REFERENCE: https://lb.raspberrypi.org/forums/viewtopic.php?t=211542 # Although, the script is created using the thought process of the above link, # there are many enhancements made to solve BUGS (occurred during evaluation and testing phase) # and to promote many advanced features to automate and setup the single WiFi chip of # Raspberry Pi as an Access Point(AP) and Station(STA) Network both (and hence, supporting # HOTSPOT feature in Raspberry Pi using the execution of this script). # BUG FIXES: # TODO: DHCPCD created problem in new Buster OS so, while upgrating OS make sure that, DHCPCD # and other dependancies are locked so that, it will have less conflict in re-installation. # This is presently not done but, it can be done using the below command. This feature will # be release in future version of the script. # sudo apt-mark hold dhcpcd5 # Store all input options in an array: options=("$@") #echo "Input options are: ${options[@]}" OS_VERSION=`cat /etc/os-release 2>/dev/null | grep -i "VERSION_ID" | awk -F '=' '{gsub("\"", "", $2); print $2}'` echo "" echo "[INFO]: Processing network setup for OS Version: $OS_VERSION" apIpDefault="10.0.0.1" apDhcpRangeDefault="10.0.0.50,10.0.0.150,12h" apSetupIptablesMasqueradeDefault="iptables -t nat -A POSTROUTING -s 10.0.0.0/24 ! -d 10.0.0.0/24 -j MASQUERADE" apCountryCodeDefault="PA" apChannelDefault="1" apIp="$apIpDefault" apDhcpRange="$apDhcpRangeDefault" apSetupIptablesMasquerade="$apSetupIptablesMasqueradeDefault" apCountryCode="$apCountryCodeDefault" apChannel="$apChannelDefault" apSsid="" apPassphrase="" apPasswordConfig="" # REFERENCE: Country codes taken from: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 countryCodeArray=('AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT', 'JE', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SX', 'SY', 'SZ', 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'YE', 'YT', 'ZA', 'ZM', 'ZW') workDir="/opt" installDir="$workDir/network-setup" logDir="$installDir/log" execDir="$installDir/bin" downloadDir="$installDir/downloads" netStartFile="$execDir/netStart" netStopFile="$execDir/netStop.sh" netLogFile="$logDir/network.log" netStopServiceFile="/etc/systemd/system/netStop.service" netStationConfigFile="/etc/network/interfaces.d/station" netShutdownFlagFile="$logDir/netShutdownFlag" shutdownRecoveryFile="$execDir/shutdownRecovery" rcLocalLogFile="$logDir/rc.local.log" cleanup=false install=false installUpgrade=false apSsidValid=false apPassphraseValid=false apCountryCodeValid=true apIpAddrValid=true rebootFlag=true wlanInterfaceNameValid=true # Defined common WLAN and AP Interface names here as in the recent and future versions of Debian based OS # may change the Networking Interface name. wlanInterfaceNameDefault="wlan0" wlanInterfaceName="$wlanInterfaceNameDefault" apInterfaceName="uap0" hostNameDefault="raspberrypi" hostName="$hostNameDefault" # FIX: for https://github.com/idev1/rpihotspot/issues/12#issuecomment-605552834 if [ ! -z "$( hostname )" ]; then hostName="$( hostname )" fi echo "[INFO]: Hostname is: $hostName" function setWlanDetails() { # Set Country Code: wlanCountryCode="$( cat /etc/wpa_supplicant/wpa_supplicant.conf | grep -i 'country=' | awk -F '=' '{print $2}' )" # FIX: #12, trimming spaces and carriage return for WLAN Country code if there are any. wlanCountryCode="$( echo $wlanCountryCode | tr -d '\r' )" if [[ ! -z "${wlanCountryCode}" && \ ("${countryCodeArray[@]}" =~ "${wlanCountryCode}") ]]; then apCountryCode="$wlanCountryCode" apCountryCodeDefault="$wlanCountryCode" fi # Read WiFi Station(${wlanInterfaceName}) IP, Mask and Broadcast addresses: read wlanIpAddr wlanIpMask wlanIpCast <<< $( echo $( ifconfig ${wlanInterfaceName} | grep 'inet ' ) | awk -F " " '{print $2" "$4" "$6}' ) # Set AP Channel: wlanChannel="$( iwlist ${wlanInterfaceName} channel | grep 'Current Frequency:' | awk -F '(' '{gsub("\)", "", $2); print $2}' | awk -F ' ' '{print $2}' )" if [ ! -z "${wlanChannel}" ]; then apChannel="$wlanChannel" apChannelDefault="$wlanChannel" fi } setWlanDetails # REFERENCE: https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses # Visit above site to know more about Reserved Private IP Address for LAN/WLAN communication. function validIpAddress() { local ip=$1 local status=1 if [[ $ip =~ ^(10|172|192)\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then IFS='.' read ipi1 ipi2 ipi3 ipi4 <<< "$ip" IFS='.' read -r -a wlanIpMaskArr <<< "$wlanIpMask" IFS='.' read -r -a wlanIpAddrArr <<< "$wlanIpAddr" wlanIpStartWith="" wlanIpStartWithCount=0 for i in ${!wlanIpMaskArr[@]}; do mskVal=${wlanIpMaskArr[$i]} if [ $mskVal == 255 ]; then if [ -z "$wlanIpStartWith" ]; then wlanIpStartWith="${wlanIpAddrArr[$i]}" else wlanIpStartWith="$wlanIpStartWith.${wlanIpAddrArr[$i]}" fi wlanIpStartWithCount=$((wlanIpStartWithCount+1)) fi done wlanIpStartWith="$wlanIpStartWith." case $ipi1 in 10) [[ ( $ip != $wlanIpAddr && ! $ip =~ ${wlanIpStartWith}* ) && \ ((${#ipi2} -eq 1 && ${ipi2} -le 255) || (${#ipi2} -gt 1 && "${ipi2}" != 0* && ${ipi2} -le 255)) && \ ((${#ipi3} -eq 1 && ${ipi3} -le 255) || (${#ipi3} -gt 1 && "${ipi3}" != 0* && ${ipi3} -le 255)) && \ ((${#ipi4} -eq 1 && ${ipi4} -le 255) || (${#ipi4} -gt 1 && "${ipi4}" != 0* && ${ipi4} -le 255)) ]] status=$? ;; 172) [[ ( $ip != $wlanIpAddr && ! $ip =~ ${wlanIpStartWith}* ) && \ ("${ipi2}" != 0* && ${ipi2} -ge 16 && ${ipi2} -le 31) && \ ((${#ipi3} -eq 1 && ${ipi3} -le 255) || (${#ipi3} -gt 1 && "${ipi3}" != 0* && ${ipi3} -le 255)) && \ ((${#ipi4} -eq 1 && ${ipi4} -le 255) || (${#ipi4} -gt 1 && "${ipi4}" != 0* && ${ipi4} -le 255)) ]] status=$? ;; 192) [[ ( $ip != $wlanIpAddr && ! $ip =~ ${wlanIpStartWith}* ) && \ ("${ipi2}" != 0* && ${ipi2} -eq 168) && \ ((${#ipi3} -eq 1 && ${ipi3} -le 255) || (${#ipi3} -gt 1 && "${ipi3}" != 0* && ${ipi3} -le 255)) && \ ((${#ipi4} -eq 1 && ${ipi4} -le 255) || (${#ipi4} -gt 1 && "${ipi4}" != 0* && ${ipi4} -le 255)) ]] status=$? ;; esac fi return $status } # Check first if a valid --wifi-interface name option is provided or not. # If a valid --wifi-interface name option is provided then, reset the WLAN details # by calling the function: setWlanDetails. for i in ${!options[@]}; do option="${options[$i]}" if [[ "$option" == --wifi-interface=* ]]; then wlanInterfaceNameTemp="$(echo $option | awk -F '=' '{print $2}')" if [ ! -z "$wlanInterfaceNameTemp" ]; then if [ "$(iwlist $wlanInterfaceNameTemp scan 2>/dev/null)" ]; then wlanInterfaceNameValid=true wlanInterfaceName="$wlanInterfaceNameTemp" setWlanDetails else wlanInterfaceNameValid=false wlanInterfaceName="$wlanInterfaceNameDefault" fi fi fi done # Process input options other than --wifi-interface. for i in ${!options[@]}; do option="${options[$i]}" if [ "$option" = "--clean" ]; then cleanup=true fi if [ "$option" = "--install" ]; then install=true fi if [ "$option" = "--install-upgrade" ]; then installUpgrade=true fi if [[ "$option" == --ap-ssid=* ]]; then apSsid="$(echo $option | awk -F '=' '{print $2}')" if [[ "$apSsid" =~ ^[A-Za-z0-9_-]{3,}$ ]]; then apSsidValid=true fi fi if [[ "$option" == --ap-password=* ]]; then apPassphrase="$(echo $option | awk -F '=' '{print $2}')" if [[ "$apPassphrase" =~ ^[A-Za-z0-9@#$%^\&*_+-]{8,}$ ]]; then apPassphraseValid=true apPasswordConfig="wpa_passphrase=$apPassphrase" fi fi if [[ "$option" == --ap-country-code=* ]]; then apCountryCodeTemp="$(echo $option | awk -F '=' '{print $2}')" if [ ! -z "$apCountryCodeTemp" ]; then if [[ "${countryCodeArray[@]}" =~ "${apCountryCodeTemp}" ]]; then if [[ ! -z "${wlanCountryCode}" && \ (( ! "${countryCodeArray[@]}" =~ "${wlanCountryCode}") || \ ( ! "${apCountryCodeTemp}" =~ "${wlanCountryCode}")) ]]; then apCountryCodeValid=false else apCountryCodeValid=true apCountryCode="$apCountryCodeTemp" fi else apCountryCodeValid=false fi fi fi if [[ "$option" == --ap-ip-address=* ]]; then apIpAddrTemp="$(echo $option | awk -F '=' '{print $2}')" if [ ! -z "$apIpAddrTemp" ]; then if validIpAddress "$apIpAddrTemp"; then apIpAddrValid=true # Successful validation. Now set apIp, apDhcpRange and apSetupIptablesMasquerade: apIp="$apIpAddrTemp" IFS='.' read -r -a apIpArr <<< "$apIp" apIpSubnetSize=24 apIpFirstThreeDigits="${apIpArr[0]}.${apIpArr[1]}.${apIpArr[2]}" apIpLastDigit=${apIpArr[3]} div=$((apIpLastDigit/100)) minCalcDigit=1 maxCalcDigit=100 case $div in # Between (0-99) 0) minCalcDigit=$((apIpLastDigit+1)); maxCalcDigit=$((minCalcDigit+100)) ;; # Between (100-199) 1) minCalcDigit=$((200-apIpLastDigit)); maxCalcDigit=$((minCalcDigit+100)) ;; # Between (200-255) 2) minCalcDigit=$((256-apIpLastDigit)); maxCalcDigit=$((minCalcDigit+100)) ;; *) minCalcDigit=1; maxCalcDigit=100 ;; esac case ${apIpArr[0]} in 10) apIpSubnetSize=24 ;; 172) apIpSubnetSize=20 ;; 192) apIpSubnetSize=16 ;; *) apIpSubnetSize=24 ;; esac apDhcpRange="${apIpFirstThreeDigits}.${minCalcDigit},${apIpFirstThreeDigits}.${maxCalcDigit},12h" apSetupIptablesMasquerade="iptables -t nat -A POSTROUTING -s ${apIpFirstThreeDigits}.0/${apIpSubnetSize} ! -d ${apIpFirstThreeDigits}.0/${apIpSubnetSize} -j MASQUERADE" else apIpAddrValid=false fi fi fi done # Process AP Password encryption: for i in ${!options[@]}; do option="${options[$i]}" if [ "$apSsidValid" = true -a "$apPassphraseValid" = true -a "$option" = "--ap-password-encrypt" ]; then apWpaPsk="$( wpa_passphrase ${apSsid} ${apPassphrase} | awk '{$1=$1};1' | grep -P '^psk=' | awk -F '=' '{print $2}' )" apPasswordConfig="wpa_psk=$apWpaPsk" fi done doRemoveDisableIPv6Setup() { result=$(sed -n '/^#__IPv6_SETUP_START__/,/^#__IPv6_SETUP_END__/p' /etc/sysctl.conf) if [ ! -z "$result" ]; then echo "[Remove]: IPv6 config from /etc/sysctl.conf" sed '/^#__IPv6_SETUP_START__/,/^#__IPv6_SETUP_END__/d' /etc/sysctl.conf > ./tmp.conf rm -f /etc/sysctl.conf mv ./tmp.conf /etc/sysctl.conf rm -f ./tmp.conf fi } doAddDisableIPv6Setup() { doRemoveDisableIPv6Setup cat >> /etc/sysctl.conf < ./tmp.conf rm -f /etc/dhcpcd.conf mv ./tmp.conf /etc/dhcpcd.conf rm -f ./tmp.conf fi } doAddDhcpdApSetup() { doRemoveDhcpdApSetup cat >> /etc/dhcpcd.conf </dev/null | grep -c "$netStartFile") -gt 0 ]; then echo "[Remove]: entry -> '$netStartFile' from /etc/rc.local" sed '/netStart/d' /etc/rc.local > ./tmp.conf rm -f /etc/rc.local mv ./tmp.conf /etc/rc.local rm -f ./tmp.conf fi } doAddRcLocalNetStartSetup() { doRemoveRcLocalNetStartSetup sed '/exit 0/d' /etc/rc.local > ./tmp.conf echo "/bin/bash $netStartFile exit 0" >> ./tmp.conf rm -f /etc/rc.local mv ./tmp.conf /etc/rc.local rm -f ./tmp.conf } doRemoveApIpEntriesFromHostFile() { if [ `cat /etc/hosts | grep -c ^10.` -gt 0 -o \ `cat /etc/hosts | grep -c ^172.` -gt 0 -o \ `cat /etc/hosts | grep -c ^192.168.` -gt 0 ]; then sed '/^10./d;/^172./d;/^192.168./d' /etc/hosts > ./tmp.conf mv ./tmp.conf /etc/hosts rm -f ./tmp.conf echo "[Cleanup]: Cleaned all AP IP entries from /etc/hosts file." fi } doAddApIpEntriesToHostFile() { cat > /etc/hosts < /etc/iptables.ipv4.nat' bash -c 'cat /dev/null > /proc/sys/net/ipv4/ip_forward' sed -i 's/^net.ipv4.ip_forward=.*$/#net.ipv4.ip_forward=1/' /etc/sysctl.conf echo "[Cleanup]: Cleaned all NAT IP Table entries." } doRestartSysDaemon() { if [ ! `sudo systemctl status dhcpcd 2> /dev/null | grep "systemctl daemon-reload"` ]; then systemctl daemon-reload echo "[Restart]: System Daemon restarted!" fi } doAptClean() { apt-get clean apt-get autoclean -y apt-get autoremove -y echo "[Cleanup]: apt-get clean/autoremove done." } doCleanup() { echo "[Cleanup]: cleaning ..." # Do apt-get clean: doAptClean # Cleanup: /etc/dhcpcd.conf doRemoveDhcpdApSetup # Cleanup: /etc/rc.local doRemoveRcLocalNetStartSetup if [ $(dpkg-query -W -f='${Status}' hostapd 2>/dev/null | grep -c "ok installed") -eq 1 ]; then echo "[Remove]: hostapd" apt-get purge -y hostapd # FIX: broken link if purge did not remove the dirctory as the dirctory is not empty and the directory has user-data. if [ -d "/etc/hostapd" ]; then rm -rf /etc/hostapd* echo "[Remove]: Forcibly removed directory: /etc/hostapd." fi fi if [ $(dpkg-query -W -f='${Status}' dnsmasq 2>/dev/null | grep -c "ok installed") -eq 1 ]; then echo "[Remove]: dnsmasq" apt-get purge -y dnsmasq # FIX: broken link if purge did not remove the dirctory as the dirctory is not empty and the directory has user-data. if [ -d "/etc/dnsmasq.d" ]; then rm -rf /etc/dnsmasq* echo "[Remove]: Forcibly removed directory: /etc/dnsmasq.d and all related dnsmasq files." fi fi # FIX: In Buster OS, dns-root-data creating problem while installing dnsmasq and hence, purge required for dns-root-data: if [ $(dpkg-query -W -f='${Status}' dns-root-data 2>/dev/null | grep -c "ok installed") -eq 1 ]; then echo "[Remove]: dns-root-data" apt-get purge -y dns-root-data fi if [ $(dpkg-query -W -f='${Status}' iptables-persistent 2>/dev/null | grep -c "ok installed") -eq 1 ]; then echo "[Remove]: iptables-persistent" apt-get purge -y iptables-persistent fi if [ -f "$netStationConfigFile" ]; then echo "[Remove]: $netStationConfigFile" rm -f $netStationConfigFile fi if [ -f "/etc/dnsmasq.conf" ]; then echo "[Remove]: /etc/dnsmasq.conf" rm -f /etc/dnsmasq.conf fi if [ -f "/etc/dnsmasq.conf.orig" ]; then echo "[Remove]: /etc/dnsmasq.conf.orig" rm -f /etc/dnsmasq.conf fi if [ -f "/etc/hostapd/hostapd.conf" ]; then echo "[Remove]: /etc/hostapd/hostapd.conf" rm -f /etc/hostapd/hostapd.conf fi if [ -f "/etc/default/hostapd" ]; then echo "[Remove]: /etc/default/hostapd" rm -f /etc/default/hostapd fi if [ $(systemctl list-unit-files --type=service 2>/dev/null | grep -c 'netStop.service') -gt 0 ]; then systemctl stop netStop.service systemctl disable netStop.service echo "[Remove]: stop/disable service -> netStop" fi if [ -f "$netStopServiceFile" ]; then echo "[Remove]: $netStopServiceFile" rm -f $netStopServiceFile fi if [ -f "$netStartFile" ]; then echo "[Remove]: $netStartFile" rm -f $netStartFile fi if [ -f "$netStopFile" ]; then echo "[Remove]: $netStopFile" rm -f $netStopFile fi if [ -f "$netLogFile" ]; then echo "[Remove]: $netLogFile" rm -f $netLogFile fi if [ -f "$rcLocalLogFile" ]; then echo "[Remove]: $rcLocalLogFile" rm -f $rcLocalLogFile fi if [ -f "$shutdownRecoveryFile" ]; then echo "[Remove]: $shutdownRecoveryFile" rm -f $shutdownRecoveryFile fi if [ -f "$netShutdownFlagFile" ]; then echo "[Remove]: $netShutdownFlagFile" rm -f $netShutdownFlagFile fi doRemoveIpTableNatEntries # FIX: for https://github.com/idev1/rpihotspot/issues/12#issuecomment-605552834 doRemoveApIpEntriesFromHostFile # Clean and auto remove the previously install dependant component if they exists by improper purging. doAptClean #Restart DHCPCD service: # FIX: it seems daemon-reload required on Buster OS+ as the dhcpcd don't start by default # if the dhcpcd service unit is changed and then, it wait for sometime indicating that a # daemon-restart is required. doRestartSysDaemon systemctl restart dhcpcd # FIX: For Buster OS, forcibly enabling dhcpcd if its previously disabled. if [ $OS_VERSION == 10 ]; then systemctl enable dhcpcd echo "[Cleanup]: Forcibly enabled dhcpcd." fi sleep 5 echo "[Cleanup]: DONE" } downloadReqDependancies() { apt-get update --fix-missing if [ "$installUpgrade" = true ]; then apt-get upgrade -y --fix-missing apt-get dist-upgrade -y fi apt-get install -y hostapd dnsmasq iptables-persistent } isAvailableReqDependancies() { [ $(dpkg-query -W -f='${Status}' hostapd 2>/dev/null | grep -c "ok installed") -eq 1 -a \ $(dpkg-query -W -f='${Status}' dnsmasq 2>/dev/null | grep -c "ok installed") -eq 1 -a \ $(dpkg-query -W -f='${Status}' iptables-persistent 2>/dev/null | grep -c "ok installed") -eq 1 ] status=$? return $status } doInstall() { echo "" echo "[WLAN]: ${wlanInterfaceName} IP address: $wlanIpAddr" echo "[WLAN]: ${wlanInterfaceName} IP Mask address: $wlanIpMask" echo "[WLAN]: ${wlanInterfaceName} IP Broadcast address: $wlanIpCast" echo "[WLAN]: ${wlanInterfaceName} Country Code: $wlanCountryCode" echo "[WLAN]: ${wlanInterfaceName} Channel: $wlanChannel" doCleanup touch $netLogFile chmod ug+w $netLogFile #Silent install iptables: echo iptables-persistent iptables-persistent/autosave_v4 boolean true | debconf-set-selections echo iptables-persistent iptables-persistent/autosave_v6 boolean true | debconf-set-selections #If Internet is available then, install hostapd, dnsmasq, iptables-persistent from internet: if [ $(curl -Is http://www.google.com 2>/dev/null | head -n 1 | grep -c '200 OK') -gt 0 ]; then echo "[Install]: installing: hostapd dnsmasq iptables-persistent from net ..." downloadReqDependancies else if [ -f $downloadDir/1_libnl-route-3-200.deb -a \ -f $downloadDir/2_hostapd.deb -a \ -f $downloadDir/3_libnfnetlink0.deb -a \ -f $downloadDir/4_dnsmasq-base.deb -a \ -f $downloadDir/5_dnsmasq.deb -a \ -f $downloadDir/6_netfilter-persistent.deb -a \ -f $downloadDir/7_iptables-persistent.deb ]; then echo "[Install]: installing: hostapd dnsmasq iptables-persistent from local available dependencies ..." dpkg --install $downloadDir/1_libnl-route-3-200.deb dpkg --install $downloadDir/2_hostapd.deb dpkg --install $downloadDir/3_libnfnetlink0.deb dpkg --install $downloadDir/4_dnsmasq-base.deb dpkg --install $downloadDir/5_dnsmasq.deb dpkg --install $downloadDir/6_netfilter-persistent.deb dpkg --install $downloadDir/7_iptables-persistent.deb fi fi # FIX: For issue #13, Raspbian Buster OS unable to correct nameserver entry in /etc/resolv.conf hence, # need to correct this entry for downloading the files again: if ! isAvailableReqDependancies; then if [ ! `sudo cat /etc/resolv.conf 2>/dev/null | grep "8.8.8.8"` ]; then echo "nameserver 8.8.8.8" >> /etc/resolv.conf echo "[Install]: Google nameserver 8.8.8.8 added into /etc/resolv.conf." echo "[Install]: Now retrying 2nd time to download required dependancies ..." downloadReqDependancies fi fi if ! isAvailableReqDependancies; then echo "[Install]: Required dependancies: hostapd, dnsmasq and iptables-persistent are not available. Please check your internet connection!" echo "[Install]: Installation FAILED! Exiting installation now.." exit 0 fi systemctl stop hostapd systemctl stop dnsmasq doAddDhcpdApSetup if [ ! -f "/etc/dnsmasq.conf.orig" ]; then echo "[Move]: /etc/dnsmasq.conf to /etc/dnsmasq.conf.orig" mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig fi cat > /etc/dnsmasq.conf < /etc/hostapd/hostapd.conf < $netStationConfigFile < $shutdownRecoveryFile <> $netLogFile' echo "[WARNING]: Last shutdown errors may affect Access Point(AP) Network to become non-functional!" echo "[SOLUTION]: Reboot system to solve the shutdown errors." #read -n 1 -p "Reboot System [y/n]: " "rebootFlag" if [ "$rebootFlag" = "y" -o "$rebootFlag" = true ]; then sudo $netStopFile echo "Rebooting in 5 seconds ..." sleep 5 sudo reboot fi elif [ -f "$netShutdownFlagFile" ]; then sudo rm -f $netShutdownFlagFile fi EOF chmod ug+x $shutdownRecoveryFile # Create startup script cat > $netStartFile < $rcLocalLogFile exec 1>&2 # Attach script for improper shutdown recovery: source $shutdownRecoveryFile #Make sure no ${apInterfaceName} interface exists (this generates an error; we could probably use an if statement to check if it exists first) echo "Removing ${apInterfaceName} interface..." iw dev ${apInterfaceName} del #Add ${apInterfaceName} interface (this is dependent on the wireless interface being called ${wlanInterfaceName}, which it may not be in Stretch) echo "Adding ${apInterfaceName} interface..." iw dev ${wlanInterfaceName} interface add ${apInterfaceName} type __ap #Modify iptables (these can probably be saved using iptables-persistent if desired) echo "IPV4 forwarding: setting..." #sysctl net.ipv4.ip_forward=1 #echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf sed -i 's/^#net.ipv4.ip_forward=.*$/net.ipv4.ip_forward=1/' /etc/sysctl.conf echo "Editing IP tables..." echo 1 > /proc/sys/net/ipv4/ip_forward iptables -F iptables -t nat -F sleep 2 $apSetupIptablesMasquerade iptables -t nat -A POSTROUTING -o ${wlanInterfaceName} -j MASQUERADE iptables -A FORWARD -i ${wlanInterfaceName} -o ${apInterfaceName} -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i ${apInterfaceName} -o ${wlanInterfaceName} -j ACCEPT #iptables-save > /etc/iptables/rules.v4 iptables-save > /etc/iptables.ipv4.nat #iptables-restore < /etc/iptables.ipv4.nat # Bring up ${apInterfaceName} interface. Commented out line may be a possible alternative to using dhcpcd.conf to set up the IP address. #ifconfig ${apInterfaceName} 10.0.0.1 netmask 255.255.255.0 broadcast 10.0.0.255 ifconfig ${apInterfaceName} up # Start hostapd. 10-second sleep avoids some race condition, apparently. It may not need to be that long. (?) echo "Starting hostapd service..." systemctl start hostapd.service sleep 10 #Start dhcpcd. Again, a 5-second sleep echo "Starting dhcpcd service..." systemctl start dhcpcd.service sleep 20 echo "Starting dnsmasq service..." systemctl restart dnsmasq.service #systemctl start dnsmasq.service echo "Enabling netStop service..." systemctl enable netStop.service systemctl start netStop.service echo "netStart DONE" bash -c 'echo "\$(date +"%Y-%m-%d %T") - Started: hostapd, dnsmasq, dhcpcd" >> $netLogFile' EOF chmod ug+x $netStartFile doAddRcLocalNetStartSetup doAddApIpEntriesToHostFile # Disable regular network services: # The netStart script handles starting up network services in a certain order and time frame. Disabling them here makes sure things are not run at system startup. systemctl unmask hostapd cat > $netStopFile <> $netLogFile' # Handle proper shutdown by touching a empty shutdown flag file: sudo touch $netShutdownFlagFile EOF chmod ug+x $netStopFile # REFERENCE: https://raspberrypi.stackexchange.com/questions/89732/run-a-script-at-shutdown-on-raspbian cat > $netStopServiceFile <