From 51b69cb5e5385e89e6e74f426ebbbe21e15817bf Mon Sep 17 00:00:00 2001 From: garywill Date: Wed, 20 Jan 2021 13:10:02 +0800 Subject: [PATCH] put a bunch of codes into functions --- README.md | 4 +- lnxrouter | 1639 ++++++++++++++++++++++++++++------------------------- 2 files changed, 868 insertions(+), 775 deletions(-) mode change 100644 => 100755 lnxrouter diff --git a/README.md b/README.md index 20f303e..bec8347 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Set Linux as router in one command. Able to Provide Internet, or create Wifi hot It wraps `iptables`, `dnsmasq` etc. stuff. Use in one command, restore in one command or by `control-c`. -[Buy me a coffee](https://github.com/garywill/receiving/blob/master/receiving_methods.md) +[Buy me a coffee](https://github.com/garywill/receiving/blob/master/receiving_methods.md) :) ## Features @@ -339,7 +339,7 @@ Options: - WPA3 - Global IPv6 -- Refactor clients(neighbors) listing +- Refactor clients(neighbors) listing function - Explictly ban forwarding if not needed ## Donate diff --git a/lnxrouter b/lnxrouter old mode 100644 new mode 100755 index e6ed7b5..d4772d1 --- a/lnxrouter +++ b/lnxrouter @@ -121,325 +121,342 @@ Examples: EOF } -if [[ "$1" == "" ]]; then - usage - exit 0 -fi +check_empty_option(){ + if [[ "$1" == "" ]]; then + usage + exit 0 + fi +} -GATEWAY= -PREFIX6= -IID6=1 -IPV6=0 -NO4=0 -BANLAN=0 -DHCP_DNS=gateway -DHCP_DNS6=gateway -dnsmasq_NO_DNS=0 -NO_DNSMASQ=0 -CATCH_DNS=0 -SHOW_DNS_QUERY=0 -ETC_HOSTS=0 -ADDN_HOSTS= -SUBNET_IFACE= -CONN_IFACE= -INTERNET_IFACE= -THISHOSTNAME= -SHARE_METHOD=nat -TP_PORT= -DNS= -USE_RANDOM_MAC=0 -NEW_MACADDR= -OLD_MACADDR= -DAEMONIZE=0 +define_global_variables(){ + #======== Global variables for user options ===== + GATEWAY= # IPv4 address for this host + PREFIX6= # IPv6 LAN address prefix for this host + IID6=1 # IPv6 LAN ID for this host + IPV6=0 # enable ipv6 + NO4=0 # no IPv4 Internet + BANLAN=0 # ban clients from accessing private addresses + DHCP_DNS=gateway # which ipv4 DNS the DHCP gives clients + DHCP_DNS6=gateway # which ipv6 DNS the DHCP gives clients + dnsmasq_NO_DNS=0 # disable dns server + NO_DNSMASQ=0 # disable dnsmasq (dns and dhcp) + CATCH_DNS=0 # catch clients 53 port packets + SHOW_DNS_QUERY=0 # log dns + ETC_HOSTS=0 + ADDN_HOSTS= -HIDDEN=0 -WIFI_IFACE= -VWIFI_IFACE= -AP_IFACE= -CHANNEL=default -WPA_VERSION=2 -MAC_FILTER=0 -MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept -IEEE80211N=0 -IEEE80211AC=0 -HT_CAPAB='[HT40+]' -VHT_CAPAB= -DRIVER=nl80211 -NO_VIRT=0 -COUNTRY= -FREQ_BAND=2.4 -NO_HAVEGED=0 -HOSTAPD_DEBUG_ARGS= -USE_PSK=0 -ISOLATE_CLIENTS=0 -QR=0 + SUBNET_IFACE= # which interface to create network + CONN_IFACE= # which interface user choose to use to create network + INTERNET_IFACE= # which interface to get Internet from + THISHOSTNAME= # this host's name the DNS tells clients -LIST_RUNNING=0 -STOP_ID= -LIST_CLIENTS_ID= -CONFDIR= + SHARE_METHOD=nat + TP_PORT= # transparent proxy port + DNS= # upstream DNS -ARGS=( "$@" ) + USE_RANDOM_MAC=0 + NEW_MACADDR= + OLD_MACADDR= + DAEMONIZE=0 -while [[ -n "$1" ]]; do - case "$1" in - -h|--help) - usage - exit 0 - ;; - --version) - echo "$VERSION" - exit 0 - ;; - -i) - shift - CONN_IFACE="$1" - shift - ;; - -o) - shift - INTERNET_IFACE="$1" - shift - echo "" - echo "WARN: Since you're using in this mode, make sure you've read Notice 1" >&2 - echo "" - ;; - -n) - shift - SHARE_METHOD=none - echo "" - echo "WARN: Since you're using in this mode, make sure you've read Notice 1" >&2 - echo "" - ;; - --ban-priv) - shift - BANLAN=1 - ;; - --tp) - shift - TP_PORT="$1" - shift - ;; + # wifi hotspot + HIDDEN=0 # hidden wifi hotspot + WIFI_IFACE= + VWIFI_IFACE= + AP_IFACE= + CHANNEL=default + WPA_VERSION=2 + MAC_FILTER=0 + MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept + IEEE80211N=0 + IEEE80211AC=0 + HT_CAPAB='[HT40+]' + VHT_CAPAB= + DRIVER=nl80211 + NO_VIRT=0 # not use virtual interface + COUNTRY= + FREQ_BAND=2.4 + NO_HAVEGED=0 + HOSTAPD_DEBUG_ARGS= + USE_PSK=0 + ISOLATE_CLIENTS=0 + USE_IWCONFIG=0 # automatically decided + QR=0 # show wifi qr + + #-- to deal with a running instance + LIST_RUNNING=0 + STOP_ID= + LIST_CLIENTS_ID= + + # -- variables for running + CONFDIR= +} + + + +parse_user_options(){ + while [[ -n "$1" ]]; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + --version) + echo "$VERSION" + exit 0 + ;; + -i) + shift + CONN_IFACE="$1" + shift + ;; + -o) + shift + INTERNET_IFACE="$1" + shift + echo "" + echo "WARN: Since you're using in this mode, make sure you've read Notice 1" >&2 + echo "" + ;; + -n) + shift + SHARE_METHOD=none + echo "" + echo "WARN: Since you're using in this mode, make sure you've read Notice 1" >&2 + echo "" + ;; + --ban-priv) + shift + BANLAN=1 + ;; + --tp) + shift + TP_PORT="$1" + shift + ;; + + + -g) + shift + GATEWAY="$1" + shift + ;; + -6) + shift + IPV6=1 + ;; + --no4) + shift + NO4=1 + echo "" + echo "WARN: Since you're using in this mode, make sure you've read Notice 1" >&2 + echo "" + ;; + --p6) + shift + PREFIX6="$1" + IPV6=1 + shift + ;; + --mac) + shift + NEW_MACADDR="$1" + shift + ;; + --random-mac) + shift + USE_RANDOM_MAC=1 + ;; + + --dns) + shift + DNS="$1" + shift + ;; + --no-dns) + shift + dnsmasq_NO_DNS=1 + ;; + --no-dnsmasq) + shift + NO_DNSMASQ=1 + ;; + --dhcp-dns) + shift + DHCP_DNS="$1" + shift + ;; + --dhcp-dns6) + shift + DHCP_DNS6="$1" + shift + ;; + --catch-dns) + shift + CATCH_DNS=1 + ;; + --log-dns) + shift + SHOW_DNS_QUERY=1 + ;; + --hostname) + shift + THISHOSTNAME="$1" + shift + ;; + -d) + shift + ETC_HOSTS=1 + ;; + -e) + shift + ADDN_HOSTS="$1" + shift + ;; - - -g) - shift - GATEWAY="$1" - shift - ;; - -6) - shift - IPV6=1 - ;; - --no4) - shift - NO4=1 - echo "" - echo "WARN: Since you're using in this mode, make sure you've read Notice 1" >&2 - echo "" - ;; - --p6) - shift - PREFIX6="$1" - IPV6=1 - shift - ;; - --mac) - shift - NEW_MACADDR="$1" - shift - ;; - --random-mac) - shift - USE_RANDOM_MAC=1 - ;; - - --dns) - shift - DNS="$1" - shift - ;; - --no-dns) - shift - dnsmasq_NO_DNS=1 - ;; - --no-dnsmasq) - shift - NO_DNSMASQ=1 - ;; - --dhcp-dns) - shift - DHCP_DNS="$1" - shift - ;; - --dhcp-dns6) - shift - DHCP_DNS6="$1" - shift - ;; - --catch-dns) - shift - CATCH_DNS=1 - ;; - --log-dns) - shift - SHOW_DNS_QUERY=1 - ;; - --hostname) - shift - THISHOSTNAME="$1" - shift - ;; - -d) - shift - ETC_HOSTS=1 - ;; - -e) - shift - ADDN_HOSTS="$1" - shift - ;; - - --isolate-clients) - shift - ISOLATE_CLIENTS=1 - ;; - - --ap) - shift - WIFI_IFACE="$1" - shift - SSID="$1" - shift - ;; - -p|--password) - shift - PASSPHRASE="$1" - shift - ;; - --qr) - shift - QR=1 - ;; - - - --hidden) - shift - HIDDEN=1 - ;; - --mac-filter) - shift - MAC_FILTER=1 - ;; - --mac-filter-accept) - shift - MAC_FILTER_ACCEPT="$1" - shift - ;; + --isolate-clients) + shift + ISOLATE_CLIENTS=1 + ;; + + --ap) + shift + WIFI_IFACE="$1" + shift + SSID="$1" + shift + ;; + -p|--password) + shift + PASSPHRASE="$1" + shift + ;; + --qr) + shift + QR=1 + ;; + + + --hidden) + shift + HIDDEN=1 + ;; + --mac-filter) + shift + MAC_FILTER=1 + ;; + --mac-filter-accept) + shift + MAC_FILTER_ACCEPT="$1" + shift + ;; - -c) - shift - CHANNEL="$1" - shift - ;; - -w) - shift - WPA_VERSION="$1" - [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2 - shift - ;; + -c) + shift + CHANNEL="$1" + shift + ;; + -w) + shift + WPA_VERSION="$1" + [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2 + shift + ;; - --ieee80211n) - shift - IEEE80211N=1 - ;; - --ieee80211ac) - shift - IEEE80211AC=1 - ;; - --ht_capab) - shift - HT_CAPAB="$1" - shift - ;; - --vht_capab) - shift - VHT_CAPAB="$1" - shift - ;; - --driver) - shift - DRIVER="$1" - shift - ;; - --no-virt) - shift - NO_VIRT=1 - ;; + --ieee80211n) + shift + IEEE80211N=1 + ;; + --ieee80211ac) + shift + IEEE80211AC=1 + ;; + --ht_capab) + shift + HT_CAPAB="$1" + shift + ;; + --vht_capab) + shift + VHT_CAPAB="$1" + shift + ;; + --driver) + shift + DRIVER="$1" + shift + ;; + --no-virt) + shift + NO_VIRT=1 + ;; - --country) - shift - COUNTRY="$1" - shift - ;; - --freq-band) - shift - FREQ_BAND="$1" - shift - ;; - --no-haveged) - shift - NO_HAVEGED=1 - ;; - --hostapd-debug) - shift - if [ "x$1" = "x1" ]; then - HOSTAPD_DEBUG_ARGS="-d" - elif [ "x$1" = "x2" ]; then - HOSTAPD_DEBUG_ARGS="-dd" - else - printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1" + --country) + shift + COUNTRY="$1" + shift + ;; + --freq-band) + shift + FREQ_BAND="$1" + shift + ;; + --no-haveged) + shift + NO_HAVEGED=1 + ;; + --hostapd-debug) + shift + if [ "x$1" = "x1" ]; then + HOSTAPD_DEBUG_ARGS="-d" + elif [ "x$1" = "x2" ]; then + HOSTAPD_DEBUG_ARGS="-dd" + else + printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1" + exit 1 + fi + shift + ;; + --psk) + shift + USE_PSK=1 + ;; + + --daemon) + shift + DAEMONIZE=1 + ;; + --stop) + shift + STOP_ID="$1" + shift + ;; + --list-running) + shift + LIST_RUNNING=1 + ;; + --list-clients) + shift + LIST_CLIENTS_ID="$1" + shift + ;; + + + + *) + echo "Invalid parameter: $1" 1>&2 exit 1 - fi - shift - ;; - --psk) - shift - USE_PSK=1 - ;; - - --daemon) - shift - DAEMONIZE=1 - ;; - --stop) - shift - STOP_ID="$1" - shift - ;; - --list-running) - shift - LIST_RUNNING=1 - ;; - --list-clients) - shift - LIST_CLIENTS_ID="$1" - shift - ;; + ;; + esac + done +} - - *) - echo "Invalid parameter: $1" 1>&2 - exit 1 - ;; - esac -done - +# seperate ip and port sep_ip_port() { local IP local PORT @@ -472,8 +489,6 @@ sep_ip_port() { printf -v "$3" %s "$PORT" } -USE_IWCONFIG=0 - is_interface() { [[ -z "$1" ]] && return 1 [[ -d "/sys/class/net/${1}" ]] @@ -695,6 +710,8 @@ generate_random_ip6() { PREFIX6="fd$r1:$r2$r3:$r4$r5:$r6$r7::" } + + # start haveged when needed haveged_watchdog() { local show_warn=1 @@ -719,11 +736,14 @@ haveged_watchdog() { # only support NetworkManager >= 0.9.9 -NM_RUNNING=0 -NM_UNM_LIST= -if (which nmcli >/dev/null 2>&1 ) && (nmcli -t -f RUNNING g 2>&1 | grep -E '^running$' >/dev/null 2>&1 ) ; then - NM_RUNNING=1 -fi +nm_initcheck() { + NM_RUNNING=0 + NM_UNM_LIST= + if (which nmcli >/dev/null 2>&1 ) && (nmcli -t -f RUNNING g 2>&1 | grep -E '^running$' >/dev/null 2>&1 ) ; then + NM_RUNNING=1 + fi +} + nm_knows() { (nmcli dev show $1 | grep -E "^GENERAL.STATE:" >/dev/null 2>&1 ) && return 0 # nm sees @@ -1011,12 +1031,12 @@ _cleanup() { ip addr flush ${SUBNET_IFACE} - if [[ -d $CONFDIR/sys_6_conf_iface ]]; then - cp -f $CONFDIR/sys_6_conf_iface/* /proc/sys/net/ipv6/conf/$SUBNET_IFACE/ + if [[ -d "$CONFDIR/sys_6_conf_iface" ]]; then + cp -f "$CONFDIR/sys_6_conf_iface/*" "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/" fi rm -rf $CONFDIR - if [[ $WIFI_IFACE && $NO_VIRT -eq 0 ]]; then + if [[ "$WIFI_IFACE" && "$NO_VIRT" -eq 0 ]]; then ip link set down dev ${AP_IFACE} iw dev ${VWIFI_IFACE} del dealloc_iface $VWIFI_IFACE @@ -1096,7 +1116,7 @@ clean_exit() { # SIGUSR1 exit 0 } -#======== +#== functions to deal with running instances list_running_conf() { local x @@ -1144,8 +1164,8 @@ print_client_by_mac() { local line ipaddr hostname local mac="$1" - if [[ -f $CONFDIR/dnsmasq.leases ]]; then - line=$(grep " $mac " $CONFDIR/dnsmasq.leases | tail -n 1) + if [[ -f "$CONFDIR/dnsmasq.leases" ]]; then + line=$(grep " $mac " "$CONFDIR/dnsmasq.leases" | tail -n 1) ipaddr=$(echo "$line" | cut -d' ' -f3) hostname=$(echo "$line" | cut -d' ' -f4) fi @@ -1160,7 +1180,7 @@ print_clients_in_leases() { local line ipaddr hostname local mac - if [[ -f $CONFDIR/dnsmasq.leases ]]; then + if [[ -f "$CONFDIR/dnsmasq.leases" ]]; then while read line do mac=$(echo "$line" | cut -d' ' -f2) @@ -1169,7 +1189,7 @@ print_clients_in_leases() { printf "%-20s %-18s %s\n" "MAC" "IP" "Hostname" printf "%-20s %-18s %s\n" "$mac" "$ipaddr" "$hostname" - done < $CONFDIR/dnsmasq.leases + done < "$CONFDIR/dnsmasq.leases" fi } @@ -1191,7 +1211,7 @@ list_clients() { Use --list-running to find it out." [[ -z "$CONFDIR" ]] && CONFDIR=$(get_confdir_from_pid "$pid") - if [[ -f $CONFDIR/hostapd.conf && $USE_IWCONFIG -eq 0 ]]; then + if [[ -f "$CONFDIR/hostapd.conf" && $USE_IWCONFIG -eq 0 ]]; then local awk_cmd='($1 ~ /Station$/) {print $2}' local client_list=$(iw dev "$subn_iface" station dump | awk "$awk_cmd") @@ -1249,166 +1269,537 @@ send_stop() { ## ======================================================== ## ======================================================== - -if [[ -d /dev/shm ]]; then - TMPD=/dev/shm -elif [[ -d /run/shm ]]; then - TMPD=/run/shm -else - TMPD=/tmp -fi -TMPDIR=$TMPD/lnxrouter_tmp +init_tmpdir(){ + if [[ -d /dev/shm ]]; then + TMPD=/dev/shm + elif [[ -d /run/shm ]]; then + TMPD=/run/shm + else + TMPD=/tmp + fi + TMPDIR=$TMPD/lnxrouter_tmp +} #====== -if [[ $LIST_RUNNING -eq 1 ]]; then - echo -e "List of running $PROGNAME instances:\n" - list_running - exit 0 -fi +check_other_functions(){ + if [[ $LIST_RUNNING -eq 1 ]]; then + echo -e "List of running $PROGNAME instances:\n" + list_running + exit 0 + fi -if [[ -n "$LIST_CLIENTS_ID" ]]; then - list_clients "$LIST_CLIENTS_ID" - exit 0 -fi + if [[ -n "$LIST_CLIENTS_ID" ]]; then + list_clients "$LIST_CLIENTS_ID" + exit 0 + fi -if [[ $(id -u) -ne 0 ]]; then - echo "You must run it as root." >&2 - exit 1 -fi - -if [[ -n "$STOP_ID" ]]; then - echo "Trying to kill $PROGNAME instance associated with $STOP_ID..." - send_stop "$STOP_ID" - exit 0 -fi - -#============================================= -#============================================= - -if [[ $DAEMONIZE -eq 1 && $RUNNING_AS_DAEMON -eq 0 ]]; then - echo "Running as Daemon..." - # run a detached lnxrouter - RUNNING_AS_DAEMON=1 setsid "$0" "${ARGS[@]}" & - exit 0 -fi - -if [[ $WIFI_IFACE ]]; then - - if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then - echo "ERROR: Invalid frequency band" >&2 + if [[ $(id -u) -ne 0 ]]; then + echo "You must run it as root." >&2 exit 1 fi - if [[ $CHANNEL == default ]]; then - if [[ $FREQ_BAND == 2.4 ]]; then - CHANNEL=1 + if [[ -n "$STOP_ID" ]]; then + echo "Trying to kill $PROGNAME instance associated with $STOP_ID..." + send_stop "$STOP_ID" + exit 0 + fi +} + + +daemonizing_check(){ + if [[ $DAEMONIZE -eq 1 && $RUNNING_AS_DAEMON -eq 0 ]]; then + echo "Running as Daemon..." + # run a detached lnxrouter + RUNNING_AS_DAEMON=1 setsid "$0" "${ARGS[@]}" & + exit 0 + fi +} + +#============================ +prepare_wifi() { + if [[ $WIFI_IFACE ]]; then + + if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then + echo "ERROR: Invalid frequency band" >&2 + exit 1 + fi + + if [[ $CHANNEL == default ]]; then + if [[ $FREQ_BAND == 2.4 ]]; then + CHANNEL=1 + else + CHANNEL=36 + fi + fi + + if [[ $FREQ_BAND != 5 && $CHANNEL -gt 14 ]]; then + echo "Channel number is greater than 14, assuming 5GHz frequency band" + FREQ_BAND=5 + fi + + if ! can_be_ap ${WIFI_IFACE}; then + echo "ERROR: Your adapter does not support AP (master) mode" >&2 + exit 1 + fi + + if ! can_be_sta_and_ap ${WIFI_IFACE}; then + if is_wifi_connected ${WIFI_IFACE}; then + echo "ERROR: Your adapter can not be a station (i.e. be connected) and an AP at the same time" >&2 + exit 1 + elif [[ $NO_VIRT -eq 0 ]]; then + echo "WARN: Your adapter does not fully support AP virtual interface, enabling --no-virt" >&2 + NO_VIRT=1 + fi + fi + + HOSTAPD=$(which hostapd) + + if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then + if ! strings "$HOSTAPD" | grep -m1 rtl871xdrv > /dev/null 2>&1; then + echo "ERROR: You need to patch your hostapd with rtl871xdrv patches." >&2 + exit 1 + fi + + if [[ $DRIVER != "rtl871xdrv" ]]; then + echo "WARN: Your adapter needs rtl871xdrv, enabling --driver=rtl871xdrv" >&2 + DRIVER=rtl871xdrv + fi + fi + + if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then + echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2 + exit 1 + fi + + if [[ $USE_PSK -eq 0 ]]; then + if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then + echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2 + exit 1 + fi + elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then + echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2 + exit 1 + fi + + if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^rtl[0-9].*$ ]]; then + if [[ $WPA_VERSION == '1' || $WPA_VERSION == '1+2' ]]; then + echo "WARN: Realtek drivers usually have problems with WPA1, WPA2 is recommended" >&2 + fi + echo "WARN: If AP doesn't work, read https://github.com/oblique/create_ap/blob/master/howto/realtek.md" >&2 + fi + + fi +} + +check_if_new_mac_valid() { + if [[ -n "$NEW_MACADDR" ]]; then + if ! is_unicast_macaddr "$NEW_MACADDR"; then + echo "ERROR: The first byte of MAC address (${NEW_MACADDR}) must be even" >&2 + exit 1 + fi + + if [[ $(get_all_macaddrs | grep -c ${NEW_MACADDR}) -ne 0 ]]; then + echo "WARN: MAC address '${NEW_MACADDR}' already exists" >&2 + fi + fi +} + +decide_target_interface() { + TARGET_IFACE= # This is the existing physical interface to use + if [[ $CONN_IFACE ]]; then + TARGET_IFACE=$CONN_IFACE + elif [[ $WIFI_IFACE ]]; then + TARGET_IFACE=$WIFI_IFACE + else + echo "No target interface specified" 1>&2 + exit 1 + fi + echo "Target interface is ${TARGET_IFACE}" +} + +decide_ip_addresses() { + if [[ ! -n $GATEWAY ]]; then + generate_random_ip4 + echo "Use random IPv4 address $GATEWAY" + fi + + if [[ $IPV6 -eq 1 && ! -n $PREFIX6 ]]; then + generate_random_ip6 + echo "Use random IPv6 address ${PREFIX6}${IID6}" + fi + if [[ $IPV6 -eq 1 ]]; then + GATEWAY6=${PREFIX6}${IID6} + fi +} + +prepare_wifi_interface() { + if [[ $WIFI_IFACE ]]; then + + if [[ $USE_IWCONFIG -eq 0 ]]; then + iw dev ${WIFI_IFACE} set power_save off + fi + + if [[ $NO_VIRT -eq 0 ]]; then + ## Generate virtual wifi interface + + VWIFI_IFACE=$(alloc_new_iface) + + if is_wifi_connected ${WIFI_IFACE}; then + WIFI_IFACE_FREQ=$(iw dev ${WIFI_IFACE} link | grep -i freq | awk '{print $2}') + WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel ${WIFI_IFACE_FREQ}) + echo "${WIFI_IFACE} already in channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" + if is_5ghz_frequency $WIFI_IFACE_FREQ; then + FREQ_BAND=5 + else + FREQ_BAND=2.4 + fi + if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then + echo "Channel fallback to ${WIFI_IFACE_CHANNEL}" + CHANNEL=$WIFI_IFACE_CHANNEL + else + echo + fi + fi + + VIRTDIEMSG="Maybe your WiFi adapter does not fully support virtual interfaces. + Try again with --no-virt." + echo "Creating a virtual WiFi interface... " + + if iw dev ${WIFI_IFACE} interface add ${VWIFI_IFACE} type __ap; then + echo "${VWIFI_IFACE} created." + sleep 2 + else + VWIFI_IFACE= + die "$VIRTDIEMSG" + fi + OLD_MACADDR=$(get_macaddr ${VWIFI_IFACE}) + if [[ -z "$NEW_MACADDR" && $(get_all_macaddrs | grep -c ${OLD_MACADDR}) -ne 1 ]]; then + NEW_MACADDR=$(get_new_macaddr ${VWIFI_IFACE}) + fi + AP_IFACE=${VWIFI_IFACE} else - CHANNEL=36 - fi - fi - - if [[ $FREQ_BAND != 5 && $CHANNEL -gt 14 ]]; then - echo "Channel number is greater than 14, assuming 5GHz frequency band" - FREQ_BAND=5 - fi - - if ! can_be_ap ${WIFI_IFACE}; then - echo "ERROR: Your adapter does not support AP (master) mode" >&2 - exit 1 - fi - - if ! can_be_sta_and_ap ${WIFI_IFACE}; then - if is_wifi_connected ${WIFI_IFACE}; then - echo "ERROR: Your adapter can not be a station (i.e. be connected) and an AP at the same time" >&2 - exit 1 - elif [[ $NO_VIRT -eq 0 ]]; then - echo "WARN: Your adapter does not fully support AP virtual interface, enabling --no-virt" >&2 - NO_VIRT=1 - fi - fi - - HOSTAPD=$(which hostapd) - - if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then - if ! strings "$HOSTAPD" | grep -m1 rtl871xdrv > /dev/null 2>&1; then - echo "ERROR: You need to patch your hostapd with rtl871xdrv patches." >&2 - exit 1 + OLD_MACADDR=$(get_macaddr ${WIFI_IFACE}) + AP_IFACE=${WIFI_IFACE} fi - if [[ $DRIVER != "rtl871xdrv" ]]; then - echo "WARN: Your adapter needs rtl871xdrv, enabling --driver=rtl871xdrv" >&2 - DRIVER=rtl871xdrv + fi +} + +decide_subnet_interface() { + if [[ $WIFI_IFACE ]]; then + SUBNET_IFACE=${AP_IFACE} + else + SUBNET_IFACE=${TARGET_IFACE} + fi +} + +write_hostapd_conf() { + if [[ $WIFI_IFACE ]]; then + + if [[ -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then + iw reg set "$COUNTRY" + fi + + can_transmit_to_channel ${AP_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz." + + + [[ $HIDDEN -eq 1 ]] && echo "Access Point's SSID is hidden!" + + [[ $MAC_FILTER -eq 1 ]] && echo "MAC address filtering is enabled!" + + [[ $ISOLATE_CLIENTS -eq 1 ]] && echo "Access Point's clients will be isolated!" + + # hostapd config + cat <<- EOF > "$CONFDIR/hostapd.conf" + beacon_int=100 + ssid=${SSID} + interface=${AP_IFACE} + driver=${DRIVER} + channel=${CHANNEL} + ctrl_interface=$CONFDIR/hostapd_ctrl + ctrl_interface_group=0 + ignore_broadcast_ssid=$HIDDEN + ap_isolate=$ISOLATE_CLIENTS + EOF + + if [[ -n "$COUNTRY" ]]; then + cat <<- EOF >> "$CONFDIR/hostapd.conf" + country_code=${COUNTRY} + ieee80211d=1 + EOF + fi + + if [[ $FREQ_BAND == 2.4 ]]; then + echo "hw_mode=g" >> "$CONFDIR/hostapd.conf" + else + echo "hw_mode=a" >> "$CONFDIR/hostapd.conf" + fi + + if [[ $MAC_FILTER -eq 1 ]]; then + cat <<- EOF >> "$CONFDIR/hostapd.conf" + macaddr_acl=${MAC_FILTER} + accept_mac_file=${MAC_FILTER_ACCEPT} + EOF + fi + + if [[ $IEEE80211N -eq 1 ]]; then + cat <<- EOF >> "$CONFDIR/hostapd.conf" + ieee80211n=1 + ht_capab=${HT_CAPAB} + EOF + fi + + if [[ $IEEE80211AC -eq 1 ]]; then + echo "ieee80211ac=1" >> "$CONFDIR/hostapd.conf" + fi + + if [[ -n "$VHT_CAPAB" ]]; then + echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf" + fi + + if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then + echo "wmm_enabled=1" >> "$CONFDIR/hostapd.conf" + fi + + if [[ -n "$PASSPHRASE" ]]; then + [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3 + if [[ $USE_PSK -eq 0 ]]; then + WPA_KEY_TYPE=passphrase + else + WPA_KEY_TYPE=psk + fi + cat <<- EOF >> "$CONFDIR/hostapd.conf" + wpa=${WPA_VERSION} + wpa_${WPA_KEY_TYPE}=${PASSPHRASE} + wpa_key_mgmt=WPA-PSK + wpa_pairwise=CCMP + rsn_pairwise=CCMP + EOF + else + echo "WARN: Wifi is not protected by password" >&2 + fi + chmod 600 "$CONFDIR/hostapd.conf" + fi +} + +write_dnsmasq_conf() { + if [[ $NO_DNSMASQ -eq 0 ]]; then + if grep "^nobody:" /etc/group >/dev/null 2>&1 ; then + NOBODY_GROUP="nobody" + else + NOBODY_GROUP="nogroup" + fi + cat <<- EOF > "$CONFDIR/dnsmasq.conf" + user=nobody + group=$NOBODY_GROUP + bind-dynamic + listen-address=${GATEWAY} + interface=$SUBNET_IFACE + except-interface=lo + no-dhcp-interface=lo + dhcp-range=${GATEWAY%.*}.10,${GATEWAY%.*}.250,255.255.255.0 + dhcp-option-force=option:router,${GATEWAY} + #log-dhcp + log-facility=/dev/stdout + bogus-priv + domain-needed + EOF + # 'log-dhcp'(Extra logging for DHCP) shows too much logs. + # if use '-d', 'log-facility' should = /dev/null + if [[ $SHARE_METHOD == "none" ]]; then + echo "no-resolv" >> "$CONFDIR/dnsmasq.conf" + echo "no-poll" >> "$CONFDIR/dnsmasq.conf" + fi + if [[ "$DHCP_DNS" != "no" ]]; then + if [[ "$DHCP_DNS" == "gateway" ]]; then + dns_offer="$GATEWAY" + else + dns_offer="$DHCP_DNS" + fi + echo "dhcp-option-force=option:dns-server,${dns_offer}" >> "$CONFDIR/dnsmasq.conf" + fi + + if [[ ! "$dnsmasq_NO_DNS" -eq 0 ]]; then + echo "port=0" >> "$CONFDIR/dnsmasq.conf" + fi + + [[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> "$CONFDIR/dnsmasq.conf" + [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> "$CONFDIR/dnsmasq.conf" + [[ -n "$ADDN_HOSTS" ]] && echo "addn-hosts=${ADDN_HOSTS}" >> "$CONFDIR/dnsmasq.conf" + if [[ "$THISHOSTNAME" ]]; then + [[ "$THISHOSTNAME" == "-" ]] && THISHOSTNAME="$(cat /etc/hostname)" + echo "interface-name=$THISHOSTNAME,$SUBNET_IFACE" >> "$CONFDIR/dnsmasq.conf" + fi + if [[ ! "$SHOW_DNS_QUERY" -eq 0 ]]; then + echo log-queries=extra >> "$CONFDIR/dnsmasq.conf" + fi + + if [[ $DNS ]]; then + DNS_count=$(echo "$DNS" | awk -F, '{print NF}') + for (( i=1;i<=DNS_count;i++ )); do + sep_ip_port "$(echo $DNS | cut -d, -f$i)" DNS_IP DNS_PORT + [[ "$DNS_PORT" ]] && DNS_PORT_D="#$DNS_PORT" + echo "server=${DNS_IP}${DNS_PORT_D}" >> "$CONFDIR/dnsmasq.conf" + done + + cat <<- EOF >> "$CONFDIR/dnsmasq.conf" + no-resolv + no-poll + EOF + fi + if [[ $IPV6 -eq 1 ]];then + cat <<- EOF >> "$CONFDIR/dnsmasq.conf" + listen-address=${GATEWAY6} + enable-ra + #quiet-ra + dhcp-range=interface:${SUBNET_IFACE},::,::ffff:ffff:ffff:ffff,constructor:${SUBNET_IFACE},ra-stateless,64 + EOF + if [[ "$DHCP_DNS6" != "no" ]]; then + if [[ "$DHCP_DNS6" == "gateway" ]]; then + dns_offer6="[$GATEWAY6]" + else + dns_offer6="$DHCP_DNS6" + fi + echo "dhcp-option=option6:dns-server,${dns_offer6}" >> "$CONFDIR/dnsmasq.conf" + fi fi fi - - if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then - echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2 - exit 1 - fi +} - if [[ $USE_PSK -eq 0 ]]; then - if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then - echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2 - exit 1 +run_wifi_ap_processes() { + if [[ $WIFI_IFACE ]]; then + + if [[ $NO_HAVEGED -eq 0 ]]; then + haveged_watchdog & + HAVEGED_WATCHDOG_PID=$! + echo "$HAVEGED_WATCHDOG_PID" > "$CONFDIR/haveged_watchdog.pid" + echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" fi - elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then - echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2 - exit 1 - fi - if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^rtl[0-9].*$ ]]; then - if [[ $WPA_VERSION == '1' || $WPA_VERSION == '1+2' ]]; then - echo "WARN: Realtek drivers usually have problems with WPA1, WPA2 is recommended" >&2 + # start access point + #echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl" + # start hostapd (use stdbuf when available for no delayed output in programs that redirect stdout) + STDBUF_PATH=`which stdbuf` + if [ $? -eq 0 ]; then + STDBUF_PATH=$STDBUF_PATH" -oL" fi - echo "WARN: If AP doesn't work, read https://github.com/oblique/create_ap/blob/master/howto/realtek.md" >&2 - fi + echo + echo "Starting hostapd" + # hostapd '-P' works only when use '-B' (run in background) + $STDBUF_PATH hostapd $HOSTAPD_DEBUG_ARGS -P "$CONFDIR/hostapd.pid" "$CONFDIR/hostapd.conf" & + HOSTAPD_PID=$! + echo "$HOSTAPD_PID" > "$CONFDIR/hostapd.pid" + echo "hostapd PID: $HOSTAPD_PID" + #while [[ ! -f $CONFDIR/hostapd.pid ]]; do + # sleep 1 + #done + #echo -n "hostapd PID: " ; cat $CONFDIR/hostapd.pid + ( while [ -e /proc/$HOSTAPD_PID ]; do sleep 10; done ; die "hostapd exited" ) & -fi + sleep 3 + fi +} + +backup_interface_ipv6_status() { + mkdir "$CONFDIR/sys_6_conf_iface" + if [[ $IPV6 -eq 1 ]]; then + cp "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/accept_ra" \ + "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr" \ + "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode" \ + "$CONFDIR/sys_6_conf_iface/" + + echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/accept_ra" + echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr" + echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode" + + ip -6 addr add ${GATEWAY6}/64 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv6" + else + cp "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6" "$CONFDIR/sys_6_conf_iface/" + echo 1 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6" + fi +} + + +start_dnsmasq() { + if [[ $NO_DNSMASQ -eq 0 ]]; then + start_dhcp + + if which complain > /dev/null 2>&1; then + # openSUSE's apparmor does not allow dnsmasq to read files. + # remove restriction. + complain dnsmasq + fi + + echo + echo "Starting dnsmasq" + # Using '-d'(no daemon) dnsmasq will not turn into 'nobody' + # '-x' works only when no '-d' + dnsmasq -k -C "$CONFDIR/dnsmasq.conf" -x "$CONFDIR/dnsmasq.pid" -l "$CONFDIR/dnsmasq.leases" & + #####DNSMASQ_PID=$! # only when with '-d' + ######echo "dnsmasq PID: $DNSMASQ_PID" # only when with '-d' + i=0; while [[ ! -f "$CONFDIR/dnsmasq.pid" ]]; do + sleep 1 + i=$((i + 1)) + if [[ $i -gt 10 ]]; then die "Couldn't get dnsmasq PID" ; fi + done + echo -n "dnsmasq PID: " ; cat "$CONFDIR/dnsmasq.pid" + ######(wait $DNSMASQ_PID ; die "dnsmasq failed") & # wait can't deal with non-child + ( while [ -e "/proc/$DNSMASQ_PID" ]; do sleep 10; done ; die "dnsmasq exited" ) & + sleep 2 + + fi +} + +check_if_need_rfkill_unblock_wifi() { + if [[ $WIFI_IFACE ]]; then + if which rfkill > /dev/null 2>&1 ; then + PHY=$(get_phy_device ${SUBNET_IFACE}) + [[ -n $PHY ]] && rfkill unblock $(rfkill | grep $PHY | awk '{print $1}') >/dev/null 2>&1 + fi + fi +} + +#=========== Above are functions ====================== +#=========== Executing begin ============================== + +# show usage and exit if empty option +check_empty_option "$@" + +# TODO: some global variables are still defined in those following code +define_global_variables + +ARGS=( "$@" ) + +parse_user_options "$@" + +nm_initcheck + +init_tmpdir + +# will exit after this if user choose to deal with running instances +check_other_functions + +# will start new background process and exit this if user choose to daemonize +daemonizing_check + +prepare_wifi [[ "$USE_RANDOM_MAC" -eq 1 ]] && generate_random_mac -if [[ -n "$NEW_MACADDR" ]]; then - if ! is_unicast_macaddr "$NEW_MACADDR"; then - echo "ERROR: The first byte of MAC address (${NEW_MACADDR}) must be even" >&2 - exit 1 - fi - - if [[ $(get_all_macaddrs | grep -c ${NEW_MACADDR}) -ne 0 ]]; then - echo "WARN: MAC address '${NEW_MACADDR}' already exists" >&2 - fi -fi +check_if_new_mac_valid # checks finished -## ======================================================== +## ===== Above don't echo anything if no warning or error==================== ## ======================================================== echo "PID: $$" -TARGET_IFACE= # This is the existing physical interface to use -if [[ $CONN_IFACE ]]; then - TARGET_IFACE=$CONN_IFACE -elif [[ $WIFI_IFACE ]]; then - TARGET_IFACE=$WIFI_IFACE -else - echo "No target interface specified" 1>&2 - exit 1 -fi -echo "Target interface is ${TARGET_IFACE}" +decide_target_interface [[ "$USE_RANDOM_MAC" -eq 1 ]] && echo "Use random MAC address $NEW_MACADDR" -if [[ ! -n $GATEWAY ]]; then - generate_random_ip4 - echo "Use random IPv4 address $GATEWAY" -fi -if [[ $IPV6 -eq 1 && ! -n $PREFIX6 ]]; then - generate_random_ip6 - echo "Use random IPv6 address ${PREFIX6}${IID6}" -fi -if [[ $IPV6 -eq 1 ]]; then - GATEWAY6=${PREFIX6}${IID6} -fi +decide_ip_addresses if [[ $TP_PORT ]]; then SHARE_METHOD=redsocks @@ -1425,167 +1816,26 @@ trap "cleanup" EXIT trap "clean_exit" SIGINT SIGUSR1 SIGTERM trap "die" SIGUSR2 -mkdir -p $TMPDIR -chmod 755 $TMPDIR 2>/dev/null -cd $TMPDIR || die "Couldn't change directory to linux-router's temporary path" +mkdir -p "$TMPDIR" +chmod 755 "$TMPDIR" 2>/dev/null +cd "$TMPDIR" || die "Couldn't change directory to linux-router's temporary path" -CONFDIR=$(mktemp -d $TMPDIR/lnxrouter.${TARGET_IFACE}.conf.XXX) -chmod 755 $CONFDIR +CONFDIR="$(mktemp -d $TMPDIR/lnxrouter.${TARGET_IFACE}.conf.XXX)" +chmod 755 "$CONFDIR" #echo "Config dir: $CONFDIR" -echo $$ > $CONFDIR/pid +echo $$ > "$CONFDIR/pid" -COMMON_CONFDIR=$TMPDIR/lnxrouter_common.conf -mkdir -p $COMMON_CONFDIR +COMMON_CONFDIR="$TMPDIR/lnxrouter_common.conf" +mkdir -p "$COMMON_CONFDIR" +prepare_wifi_interface +decide_subnet_interface -if [[ $WIFI_IFACE ]]; then - - if [[ $USE_IWCONFIG -eq 0 ]]; then - iw dev ${WIFI_IFACE} set power_save off - fi - - if [[ $NO_VIRT -eq 0 ]]; then - ## Generate virtual wifi interface - - VWIFI_IFACE=$(alloc_new_iface) - - if is_wifi_connected ${WIFI_IFACE}; then - WIFI_IFACE_FREQ=$(iw dev ${WIFI_IFACE} link | grep -i freq | awk '{print $2}') - WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel ${WIFI_IFACE_FREQ}) - echo "${WIFI_IFACE} already in channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" - if is_5ghz_frequency $WIFI_IFACE_FREQ; then - FREQ_BAND=5 - else - FREQ_BAND=2.4 - fi - if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then - echo "Channel fallback to ${WIFI_IFACE_CHANNEL}" - CHANNEL=$WIFI_IFACE_CHANNEL - else - echo - fi - fi - - VIRTDIEMSG="Maybe your WiFi adapter does not fully support virtual interfaces. - Try again with --no-virt." - echo "Creating a virtual WiFi interface... " - - if iw dev ${WIFI_IFACE} interface add ${VWIFI_IFACE} type __ap; then - echo "${VWIFI_IFACE} created." - sleep 2 - else - VWIFI_IFACE= - die "$VIRTDIEMSG" - fi - OLD_MACADDR=$(get_macaddr ${VWIFI_IFACE}) - if [[ -z "$NEW_MACADDR" && $(get_all_macaddrs | grep -c ${OLD_MACADDR}) -ne 1 ]]; then - NEW_MACADDR=$(get_new_macaddr ${VWIFI_IFACE}) - fi - AP_IFACE=${VWIFI_IFACE} - else - OLD_MACADDR=$(get_macaddr ${WIFI_IFACE}) - AP_IFACE=${WIFI_IFACE} - fi - -fi - -if [[ $WIFI_IFACE ]]; then - SUBNET_IFACE=${AP_IFACE} -else - SUBNET_IFACE=${TARGET_IFACE} -fi - -echo "$SUBNET_IFACE" > $CONFDIR/subn_iface - -if [[ $WIFI_IFACE ]]; then - - if [[ -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then - iw reg set "$COUNTRY" - fi - - can_transmit_to_channel ${AP_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz." - - - [[ $HIDDEN -eq 1 ]] && echo "Access Point's SSID is hidden!" - - [[ $MAC_FILTER -eq 1 ]] && echo "MAC address filtering is enabled!" - - [[ $ISOLATE_CLIENTS -eq 1 ]] && echo "Access Point's clients will be isolated!" - - # hostapd config - cat <<- EOF > $CONFDIR/hostapd.conf - beacon_int=100 - ssid=${SSID} - interface=${AP_IFACE} - driver=${DRIVER} - channel=${CHANNEL} - ctrl_interface=$CONFDIR/hostapd_ctrl - ctrl_interface_group=0 - ignore_broadcast_ssid=$HIDDEN - ap_isolate=$ISOLATE_CLIENTS - EOF - - if [[ -n "$COUNTRY" ]]; then - cat <<- EOF >> $CONFDIR/hostapd.conf - country_code=${COUNTRY} - ieee80211d=1 - EOF - fi - - if [[ $FREQ_BAND == 2.4 ]]; then - echo "hw_mode=g" >> $CONFDIR/hostapd.conf - else - echo "hw_mode=a" >> $CONFDIR/hostapd.conf - fi - - if [[ $MAC_FILTER -eq 1 ]]; then - cat <<- EOF >> $CONFDIR/hostapd.conf - macaddr_acl=${MAC_FILTER} - accept_mac_file=${MAC_FILTER_ACCEPT} - EOF - fi - - if [[ $IEEE80211N -eq 1 ]]; then - cat <<- EOF >> $CONFDIR/hostapd.conf - ieee80211n=1 - ht_capab=${HT_CAPAB} - EOF - fi - - if [[ $IEEE80211AC -eq 1 ]]; then - echo "ieee80211ac=1" >> $CONFDIR/hostapd.conf - fi - - if [[ -n "$VHT_CAPAB" ]]; then - echo "vht_capab=${VHT_CAPAB}" >> $CONFDIR/hostapd.conf - fi - - if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then - echo "wmm_enabled=1" >> $CONFDIR/hostapd.conf - fi - - if [[ -n "$PASSPHRASE" ]]; then - [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3 - if [[ $USE_PSK -eq 0 ]]; then - WPA_KEY_TYPE=passphrase - else - WPA_KEY_TYPE=psk - fi - cat <<- EOF >> $CONFDIR/hostapd.conf - wpa=${WPA_VERSION} - wpa_${WPA_KEY_TYPE}=${PASSPHRASE} - wpa_key_mgmt=WPA-PSK - wpa_pairwise=CCMP - rsn_pairwise=CCMP - EOF - else - echo "WARN: Wifi is not protected by password" >&2 - fi - chmod 600 $CONFDIR/hostapd.conf -fi +echo "$SUBNET_IFACE" > "$CONFDIR/subn_iface" +write_hostapd_conf #=================================================== #=================================================== @@ -1593,88 +1843,7 @@ if [[ $NM_RUNNING -eq 1 ]] && nm_knows $TARGET_IFACE ; then nm_set_unmanaged ${SUBNET_IFACE} fi -if [[ $NO_DNSMASQ -eq 0 ]]; then - if grep "^nobody:" /etc/group >/dev/null 2>&1 ; then - NOBODY_GROUP="nobody" - else - NOBODY_GROUP="nogroup" - fi - cat <<- EOF > $CONFDIR/dnsmasq.conf - user=nobody - group=$NOBODY_GROUP - bind-dynamic - listen-address=${GATEWAY} - interface=$SUBNET_IFACE - except-interface=lo - no-dhcp-interface=lo - dhcp-range=${GATEWAY%.*}.10,${GATEWAY%.*}.250,255.255.255.0 - dhcp-option-force=option:router,${GATEWAY} - #log-dhcp - log-facility=/dev/stdout - bogus-priv - domain-needed - EOF - # 'log-dhcp'(Extra logging for DHCP) shows too much logs. - # if use '-d', 'log-facility' should = /dev/null - if [[ $SHARE_METHOD == "none" ]]; then - echo "no-resolv" >> $CONFDIR/dnsmasq.conf - echo "no-poll" >> $CONFDIR/dnsmasq.conf - fi - if [[ "$DHCP_DNS" != "no" ]]; then - if [[ "$DHCP_DNS" == "gateway" ]]; then - dns_offer="$GATEWAY" - else - dns_offer="$DHCP_DNS" - fi - echo "dhcp-option-force=option:dns-server,${dns_offer}" >> $CONFDIR/dnsmasq.conf - fi - - if [[ ! "$dnsmasq_NO_DNS" -eq 0 ]]; then - echo "port=0" >> $CONFDIR/dnsmasq.conf - fi - - [[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> $CONFDIR/dnsmasq.conf - [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> $CONFDIR/dnsmasq.conf - [[ -n "$ADDN_HOSTS" ]] && echo "addn-hosts=${ADDN_HOSTS}" >> $CONFDIR/dnsmasq.conf - if [[ "$THISHOSTNAME" ]]; then - [[ "$THISHOSTNAME" == "-" ]] && THISHOSTNAME="$(cat /etc/hostname)" - echo "interface-name=$THISHOSTNAME,$SUBNET_IFACE" >> $CONFDIR/dnsmasq.conf - fi - if [[ ! "$SHOW_DNS_QUERY" -eq 0 ]]; then - echo log-queries=extra >> $CONFDIR/dnsmasq.conf - fi - - if [[ $DNS ]]; then - DNS_count=$(echo "$DNS" | awk -F, '{print NF}') - for (( i=1;i<=DNS_count;i++ )); do - sep_ip_port "$(echo $DNS | cut -d, -f$i)" DNS_IP DNS_PORT - [[ "$DNS_PORT" ]] && DNS_PORT_D="#$DNS_PORT" - echo "server=${DNS_IP}${DNS_PORT_D}" >> $CONFDIR/dnsmasq.conf - done - - cat <<- EOF >> $CONFDIR/dnsmasq.conf - no-resolv - no-poll - EOF - fi - if [[ $IPV6 -eq 1 ]];then - cat <<- EOF >> $CONFDIR/dnsmasq.conf - listen-address=${GATEWAY6} - enable-ra - #quiet-ra - dhcp-range=interface:${SUBNET_IFACE},::,::ffff:ffff:ffff:ffff,constructor:${SUBNET_IFACE},ra-stateless,64 - EOF - if [[ "$DHCP_DNS6" != "no" ]]; then - if [[ "$DHCP_DNS6" == "gateway" ]]; then - dns_offer6="[$GATEWAY6]" - else - dns_offer6="$DHCP_DNS6" - fi - echo "dhcp-option=option6:dns-server,${dns_offer6}" >> $CONFDIR/dnsmasq.conf - fi - fi -fi - +write_dnsmasq_conf #=========================== # initialize subnet interface @@ -1685,68 +1854,15 @@ if [[ -n "$NEW_MACADDR" ]]; then ip link set dev ${SUBNET_IFACE} address ${NEW_MACADDR} || die "Failed setting new MAC address" fi - -if [[ $WIFI_IFACE ]]; then - if which rfkill > /dev/null 2>&1 ; then - PHY=$(get_phy_device ${SUBNET_IFACE}) - [[ -n $PHY ]] && rfkill unblock $(rfkill | grep $PHY | awk '{print $1}') >/dev/null 2>&1 - fi -fi +check_if_need_rfkill_unblock_wifi ip link set up dev ${SUBNET_IFACE} || die "Failed bringing ${SUBNET_IFACE} up" -if [[ $WIFI_IFACE ]]; then - - if [[ $NO_HAVEGED -eq 0 ]]; then - haveged_watchdog & - HAVEGED_WATCHDOG_PID=$! - echo "$HAVEGED_WATCHDOG_PID" > $CONFDIR/haveged_watchdog.pid - echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" - fi - - # start access point - #echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl" - # start hostapd (use stdbuf when available for no delayed output in programs that redirect stdout) - STDBUF_PATH=`which stdbuf` - if [ $? -eq 0 ]; then - STDBUF_PATH=$STDBUF_PATH" -oL" - fi - echo - echo "Starting hostapd" - # hostapd '-P' works only when use '-B' (run in background) - $STDBUF_PATH hostapd $HOSTAPD_DEBUG_ARGS -P $CONFDIR/hostapd.pid $CONFDIR/hostapd.conf & - HOSTAPD_PID=$! - echo "$HOSTAPD_PID" > $CONFDIR/hostapd.pid - echo "hostapd PID: $HOSTAPD_PID" - #while [[ ! -f $CONFDIR/hostapd.pid ]]; do - # sleep 1 - #done - #echo -n "hostapd PID: " ; cat $CONFDIR/hostapd.pid - ( while [ -e /proc/$HOSTAPD_PID ]; do sleep 10; done ; die "hostapd exited" ) & - - sleep 3 -fi +run_wifi_ap_processes ip addr add ${GATEWAY}/24 broadcast ${GATEWAY%.*}.255 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IP" -mkdir $CONFDIR/sys_6_conf_iface -if [[ $IPV6 -eq 1 ]]; then - cp /proc/sys/net/ipv6/conf/$SUBNET_IFACE/accept_ra \ - /proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr \ - /proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode \ - $CONFDIR/sys_6_conf_iface/ - - echo 0 > /proc/sys/net/ipv6/conf/$SUBNET_IFACE/accept_ra - echo 0 > /proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr - echo 0 > /proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode - - ip -6 addr add ${GATEWAY6}/64 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv6" -else - cp /proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6 $CONFDIR/sys_6_conf_iface/ - echo 1 > /proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6 -fi - - +backup_interface_ipv6_status # enable Internet sharing if [[ "$SHARE_METHOD" == "none" ]]; then @@ -1756,16 +1872,16 @@ elif [[ "$SHARE_METHOD" == "nat" ]]; then [[ "$INTERNET_IFACE" && "$dnsmasq_NO_DNS" -eq 0 ]] && echo -e "\nWARN: You specified Internet interface but this host is providing local DNS, queries may leak to other interfaces!!!\n" >&2 start_nat [[ "$BANLAN" -eq 1 ]] && start_ban_lan - echo 1 > /proc/sys/net/ipv4/ip_forward || die "Failed enabling system ipv4 forwarding" + echo 1 > "/proc/sys/net/ipv4/ip_forward" || die "Failed enabling system ipv4 forwarding" if [[ $IPV6 -eq 1 ]]; then - echo 1 > /proc/sys/net/ipv6/conf/all/forwarding || die "Failed enabling system ipv6 forwarding" + echo 1 > "/proc/sys/net/ipv6/conf/all/forwarding" || die "Failed enabling system ipv6 forwarding" fi # to enable clients to establish PPTP connections we must # load nf_nat_pptp module modprobe nf_nat_pptp > /dev/null 2>&1 elif [[ "$SHARE_METHOD" == "redsocks" ]]; then if [[ $IPV6 -eq 1 ]]; then - echo 1 > /proc/sys/net/ipv6/conf/$SUBNET_IFACE/forwarding || die "Failed enabling $SUBNET_IFACE ipv6 forwarding" + echo 1 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/forwarding" || die "Failed enabling $SUBNET_IFACE ipv6 forwarding" fi [[ "$dnsmasq_NO_DNS" -eq 0 && ! $DNS ]] && echo -e "\nWARN: You are using transparent proxy but this host is providing local DNS, this may cause privacy leak !!!\n" >&2 @@ -1781,34 +1897,14 @@ fi [[ "$CATCH_DNS" -eq 1 ]] && start_catch_dns +start_dnsmasq -if [[ $NO_DNSMASQ -eq 0 ]]; then - start_dhcp +echo +echo "== Setting up completed, now linux-router is working ==" - if which complain > /dev/null 2>&1; then - # openSUSE's apparmor does not allow dnsmasq to read files. - # remove restriction. - complain dnsmasq - fi - - echo - echo "Starting dnsmasq" - # Using '-d'(no daemon) dnsmasq will not turn into 'nobody' - # '-x' works only when no '-d' - dnsmasq -k -C $CONFDIR/dnsmasq.conf -x $CONFDIR/dnsmasq.pid -l $CONFDIR/dnsmasq.leases & - #####DNSMASQ_PID=$! # only when with '-d' - ######echo "dnsmasq PID: $DNSMASQ_PID" # only when with '-d' - i=0; while [[ ! -f $CONFDIR/dnsmasq.pid ]]; do - sleep 1 - i=$((i + 1)) - if [[ $i -gt 10 ]]; then die "Couldn't get dnsmasq PID" ; fi - done - echo -n "dnsmasq PID: " ; cat $CONFDIR/dnsmasq.pid - ######(wait $DNSMASQ_PID ; die "dnsmasq failed") & # wait can't deal with non-child - ( while [ -e /proc/$DNSMASQ_PID ]; do sleep 10; done ; die "dnsmasq exited" ) & - sleep 2 - -fi +#============================================================ +#============================================================ +#============================================================ show_qr() { local T S P H @@ -1826,15 +1922,12 @@ show_qr() { echo " qrencode -m 2 -o \"WIFI:T:${T};S:${S};P:${P};H:${H};\"" } -echo -echo "== Setting up completed, now linux-router is working ==" - [[ "$QR" -eq 1 ]] && show_qr # need loop to keep this script running bash -c "while :; do sleep 8000 ; done " & KEEP_RUNNING_PID=$! -echo "$KEEP_RUNNING_PID" > $CONFDIR/keep_running.pid +echo "$KEEP_RUNNING_PID" > "$CONFDIR/keep_running.pid" wait $KEEP_RUNNING_PID clean_exit