From f94e36e998081fdeaab376d1a228a025f7f92ccf Mon Sep 17 00:00:00 2001 From: Phani Pavan Kambhampati <60005847+kphanipavan@users.noreply.github.com> Date: Sat, 21 Sep 2024 16:42:40 +0530 Subject: [PATCH 01/12] add options for wifi66 --- lnxrouter | 410 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 240 insertions(+), 170 deletions(-) diff --git a/lnxrouter b/lnxrouter index 4dc7af3..2fd90e6 100755 --- a/lnxrouter +++ b/lnxrouter @@ -1,7 +1,7 @@ #!/bin/bash -VERSION=0.6.7 -PROGNAME="$(basename $0)" +VERSION=0.7.3a +PROGNAME="$(basename "$0")" export LC_ALL=C @@ -88,8 +88,7 @@ Options: Using this you can't use same wlan interface for both Internet and AP --virt-name Set name of virtual interface - -c Channel number (default: 1) - --force_channel Force the use of channel provided by -c flag + -c Specify channel (default: use current, or 1 / 36) --country Set two-letter country code for regularity (example: US) --freq-band Set frequency band: 2.4 or 5 (default: 2.4) @@ -104,29 +103,42 @@ Options: --hostapd-debug 1 or 2. Passes -d or -dd to hostapd --isolate-clients Disable wifi communication between clients --no-haveged Do not run haveged automatically when needed - --hs20 Enable Hotspot 2.0 (Make sure your hostapd build supports it) + --hs20 Enable Hotspot 2.0 - WiFi 4(802.11N) Config: - --ieee80211n Enable IEEE 802.11n (HT) - --use_ht Enable High Throughput mode - --ht_capab HT capabilities (default: [HT40+]) + WiFi 4 (802.11n) configs: + --wifi4 Enable IEEE 802.11n (HT) + --req-ht Require station HT (High Throughput) mode + --ht-capab HT capabilities (default: [HT40+]) - WiFi 5(802.11AC) Config: - --ieee80211ac Enable IEEE 802.11ac (VHT) - --use_vht Enable Very High Thoughtput mode - --vht_capab VHT capabilities - --vht_channel_width - Index of VHT Channel Width: + WiFi 5 (802.11ac) configs: + --wifi5 Enable IEEE 802.11ac (VHT) + --req-vht Require station VHT (Very High Thoughtput) mode + --vht-capab VHT capabilities + + --vht-ch-width Index of VHT channel width: 0 for 20MHz or 40MHz (default) 1 for 80MHz 2 for 160MHz 3 for 80+80MHz (Non-contigous 160MHz) - --seg0_center_freq_idx - Channel index of Center frequency for primary segment, use with --vht_channel_width - --seg1_center_freq_idx - Channel index of Center frequency for secondary (second 80MHz) segment, use with --vht_channel_width=3 - Pick above 2 values from the F0 index column from the 5GHz table in https://en.wikipedia.org/wiki/List_of_WLAN_channels#5_GHz_(802.11a/h/n/ac/ax) - + --vht-seg0-ch Channel index of VHT center frequency for primary + segment. Use with '--vht-ch-width' + --vht-seg1-ch Channel index of VHT center frequency for secondary + (second 80MHz) segment. Use with '--vht-ch-width 3' + + WiFi 6 (802.11ax) configs: + --wifi6 Enable IEEE 802.11ax (HE) + --req-he Require station HE (High Efficiency) mode + + --he-ch-width Index of HE channel width: + 0 for 20MHz or 40MHz (default) + 1 for 80MHz + 2 for 160MHz + 3 for 80+80MHz (Non-contigous 160MHz) + --he-seg0-ch Channel index of HE center frequency for primary + segment. Use with '--he-ch-width' + --he-seg1-ch Channel index of HE center frequency for secondary + (second 80MHz) segment. Use with '--he-ch-width 3' + Instance managing: --daemon Run in background -l, --list-running Show running instances @@ -196,7 +208,6 @@ define_global_variables(){ HIDDEN=0 # hidden wifi hotspot WIFI_IFACE= CHANNEL=default - FORCECHANNEL=0 # Forces channel provided by -c flag HOTSPOT20=0 # For enabling Hotspot 2.0 WPA_VERSION=2 MAC_FILTER=0 @@ -205,11 +216,16 @@ define_global_variables(){ REQUIREHT=0 IEEE80211AC=0 REQUIREVHT=0 + IEEE80211AX=0 + REQUIRE_HE=0 HT_CAPAB='[HT40+]' VHT_CAPAB= VHTCHANNELWIDTH=0 VHTSEG0CHINDEX=0 VHTSEG1CHINDEX=0 + HECHANNELWIDTH=0 + HESEG0CHINDEX=0 + HESEG1CHINDEX=0 DRIVER=nl80211 NO_VIRT=0 # not use virtual interface COUNTRY= @@ -397,10 +413,6 @@ parse_user_options(){ CHANNEL="$1" shift ;; - --force_channel) - shift - FORCECHANNEL=1 - ;; --hs20) shift HOTSPOT20=1 @@ -412,47 +424,70 @@ parse_user_options(){ shift ;; - --ieee80211n) + --wifi4|--ieee80211n) shift IEEE80211N=1 ;; - --use_ht) + --req-ht|--require-ht) shift REQUIREHT=1 ;; - --ieee80211ac) + --wifi5|--ieee80211ac) shift IEEE80211AC=1 ;; - --use_vht) + --wifi6|--ieee80211ax) + shift + IEEE80211AX=1 + ;; + --req-he|--require-he) + shift + REQUIRE_HE=1 + ;; + --req-vht|--require-vht) shift REQUIREVHT=1 ;; - --ht_capab) + --ht-capab) shift HT_CAPAB="$1" shift ;; - --vht_capab) + --vht-capab) shift VHT_CAPAB="$1" shift ;; - --vht_channel_width) + --vht-ch-width|--vht-channel-width) shift VHTCHANNELWIDTH="$1" shift ;; - --seg0_center_freq_idx) + --vht-seg0-ch|--vht-seg0-channel) shift VHTSEG0CHINDEX="$1" shift ;; - --seg1_center_freq_idx) + --vht-seg1-ch|--vht-seg1-channel) shift VHTSEG1CHINDEX="$1" shift ;; + --he-ch-width|--he-channel-width) + shift + HECHANNELWIDTH="$1" + shift + ;; + --he-seg0-ch|--he-seg0-channel) + shift + HESEG0CHINDEX="$1" + shift + ;; + --he-seg1-ch|--he-seg1-channel) + shift + HESEG1CHINDEX="$1" + shift + ;; --driver) shift DRIVER="$1" @@ -484,9 +519,9 @@ parse_user_options(){ ;; --hostapd-debug) shift - if [ "x$1" = "x1" ]; then + if [ "$1" = "1" ]; then HOSTAPD_DEBUG_ARGS="-d" - elif [ "x$1" = "x2" ]; then + elif [ "$1" = "2" ]; then HOSTAPD_DEBUG_ARGS="-dd" else printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1" @@ -543,8 +578,8 @@ sep_ip_port() { if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then if (echo "$INPUT" | grep ':' >/dev/null 2>&1) ;then # ipv4 + port - IP="$(echo $INPUT | cut -d: -f1)" - PORT="$(echo $INPUT | cut -d: -f2)" + IP="$(echo "$INPUT" | cut -d: -f1)" + PORT="$(echo "$INPUT" | cut -d: -f2)" else # ipv4 IP="$INPUT" @@ -552,11 +587,11 @@ sep_ip_port() { elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then if (echo "$INPUT" | grep '\]\:' >/dev/null 2>&1) ;then # ipv6 + port - IP="$(echo $INPUT | cut -d']' -f1 | cut -d'[' -f2)" - PORT="$(echo $INPUT | cut -d']' -f2 |cut -d: -f2)" + IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" + PORT="$(echo "$INPUT" | cut -d']' -f2 |cut -d: -f2)" else # ipv6 - IP="$(echo $INPUT | cut -d']' -f1 | cut -d'[' -f2)" + IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" fi else # port @@ -585,10 +620,10 @@ get_interface_phy_device() { # only for wifi interface echo "$1" return 0 elif [[ -e "$x/device/net/$1" ]]; then - echo ${x##*/} + echo "${x##*/}" return 0 elif [[ -e "$x/device/net:$1" ]]; then - echo ${x##*/} + echo "${x##*/}" return 0 fi done @@ -600,13 +635,13 @@ get_adapter_info() { # only for wifi interface local iPHY iPHY=$(get_interface_phy_device "$1") [[ $? -ne 0 ]] && return 1 - iw phy $iPHY info + iw phy "$iPHY" info } get_adapter_kernel_module() { local MODULE MODULE=$(readlink -f "/sys/class/net/$1/device/driver/module") - echo ${MODULE##*/} + echo "${MODULE##*/}" } can_be_sta_and_ap() { @@ -637,18 +672,14 @@ can_transmit_to_channel() { CHANNEL_NUM=$2 if [[ $USE_IWCONFIG -eq 0 ]]; then - if [[ $FREQ_BAND == 2.4 ]]; then - CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " 24[0-9][0-9] MHz \[${CHANNEL_NUM}\]") - else - CHANNEL_INFO=$(get_adapter_info ${IFACE} | grep " \(49[0-9][0-9]\|5[0-9]\{3\}\) MHz \[${CHANNEL_NUM}\]") - fi + CHANNEL_INFO=$(get_adapter_info "${IFACE}" | grep -E " [0-9]+(\.[0-9]+){0,1} MHz \[${CHANNEL_NUM}\]") [[ -z "${CHANNEL_INFO}" ]] && return 1 [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1 [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1 return 0 else CHANNEL_NUM=$(printf '%02d' ${CHANNEL_NUM}) - CHANNEL_INFO=$(iwlist ${IFACE} channel | grep -E "Channel[[:blank:]]${CHANNEL_NUM}[[:blank:]]?:") + CHANNEL_INFO=$(iwlist "${IFACE}" channel | grep -E "Channel[[:blank:]]${CHANNEL_NUM}[[:blank:]]?:") [[ -z "${CHANNEL_INFO}" ]] && return 1 return 0 fi @@ -672,9 +703,6 @@ ieee80211_frequency_to_channel() { fi } -is_5ghz_frequency() { - [[ $1 =~ ^(49[0-9]{2})|(5[0-9]{3})$ ]] -} is_interface_wifi_connected() { if [[ $USE_IWCONFIG -eq 0 ]]; then @@ -698,29 +726,42 @@ get_interface_mac() { cat "/sys/class/net/${1}/address" } -get_interface_pci_info() { # pci id / model / virtual +show_interface_pci_info() { # pci id / model / virtual is_interface "$1" || return local device_path - local pci_id - local pci_full + local bus_id="" + local device_type_and_bus_id="unknown" + local driver="" + local device_fullname="" device_path="$(readlink -f /sys/class/net/$1)" if [[ "$device_path" == "/sys/devices/pci"* ]]; then - pci_id="$(echo $device_path | sed 's/\//\n/g' | tail -n 3 |sed -n 1p)" + local pci_path + + pci_path=$device_path/../.. + + if [[ -d "$pci_path/driver" ]] ; then + driver=$(readlink -f "$pci_path/driver" | sed 's/\//\n/g' | tail -n 1) + fi + + bus_id="$(echo "$device_path" | sed 's/\//\n/g' | tail -n 3 |sed -n 1p)" + device_type_and_bus_id="PCI: $bus_id" if which lspci >/dev/null 2>&1 ; then - pci_full="$( lspci -D -nn | grep -E "^$pci_id " )" - echo " PCI: $pci_full" - else - echo " PCI: $pci_id" + device_fullname="$( lspci -D -nn -s "$bus_id" | awk '{$1="" ; print $0}' )" fi + elif [[ "$device_path" == *"/virtual/"* ]]; then - echo " virtual interface" + device_type_and_bus_id="virtual interface" fi + + echo "$device_type_and_bus_id" + [[ -n "$driver" ]] && echo "System-already-loaded driver: $driver" + [[ -n "$device_fullname" ]] && echo "$device_fullname" + echo "" # TODO usb - # TODO current driver } alloc_new_vface_name() { # only for wifi @@ -730,16 +771,16 @@ alloc_new_vface_name() { # only for wifi while :; do v_iface_name="x$i${WIFI_IFACE}" i=$((i + 1)) - is_vface_name_allocated ${v_iface_name} || break + is_vface_name_allocated "${v_iface_name}" || break done fi - mkdir -p $COMMON_CONFDIR/vfaces - touch $COMMON_CONFDIR/vfaces/${v_iface_name} + mkdir -p "$COMMON_CONFDIR/vfaces" + touch "$COMMON_CONFDIR/vfaces/${v_iface_name}" echo "${v_iface_name}" } dealloc_vface_name() { - rm -f $COMMON_CONFDIR/vfaces/$1 + rm -f "$COMMON_CONFDIR/vfaces/$1" } #====== @@ -772,10 +813,10 @@ generate_random_mac() { r5=$( printf "%02x" $(($RANDOM%256)) ) r6=$( printf "%02x" $(($RANDOM%256)) ) RAND_MAC="$r1:$r2:$r3:$r4:$r5:$r6" - ( ! ip link | grep "link" | grep $RAND_MAC > /dev/null 2>&1 ) && \ - ( ! ip maddress | grep "link" | grep $RAND_MAC > /dev/null 2>&1 ) && \ + ( ! ip link | grep "link" | grep "$RAND_MAC" > /dev/null 2>&1 ) && \ + ( ! ip maddress | grep "link" | grep "$RAND_MAC" > /dev/null 2>&1 ) && \ ( ! ip neigh | grep "lladdr $RAND_MAC" > /dev/null 2>&1 ) && \ - ( ! get_all_mac_in_system | grep $RAND_MAC ) && \ + ( ! get_all_mac_in_system | grep "$RAND_MAC" ) && \ break done echo "$RAND_MAC" @@ -815,7 +856,7 @@ generate_random_lan_ip6_prefix() { r5=$( printf "%x" $(($RANDOM%240+16)) ) r6=$( printf "%x" $(($RANDOM%240+16)) ) r7=$( printf "%x" $(($RANDOM%240+16)) ) - is_ip6_lan_range_available $r1 $r2 $r3 $r4 $r5 $r6 $r7 && break + is_ip6_lan_range_available "$r1" "$r2" "$r3" "$r4" "$r5" "$r6" "$r7" && break done echo "fd$r1:$r2$r3:$r4$r5:$r6$r7::" } @@ -851,7 +892,7 @@ pid_watchdog() { if [[ -e "/proc/$PID" ]]; then ST="$(cat "/proc/$PID/status" | grep "^State:" | awk '{print $2}')" if [[ "$ST" != 'Z' ]]; then - sleep $SLEEP + sleep "$SLEEP" continue fi fi @@ -872,35 +913,35 @@ is_nm_running() { } nm_knows() { - (nmcli dev show $1 | grep -E "^GENERAL.STATE:" >/dev/null 2>&1 ) && return 0 # nm sees + (nmcli dev show "$1" | grep -E "^GENERAL.STATE:" >/dev/null 2>&1 ) && return 0 # nm sees return 1 # nm doesn't see this interface } nm_get_manage() { # get an interface's managed state local s - s=$(nmcli dev show $1 | grep -E "^GENERAL.STATE:") || return 2 # no such interface - (echo $s | grep "unmanaged" >/dev/null 2>&1) && return 1 # unmanaged + s=$(nmcli dev show "$1" | grep -E "^GENERAL.STATE:") || return 2 # no such interface + (echo "$s" | grep "unmanaged" >/dev/null 2>&1) && return 1 # unmanaged return 0 # managed } nm_set_unmanaged() { - while ! nm_knows $1 ; do # wait for virtual wifi interface seen by NM + while ! nm_knows "$1" ; do # wait for virtual wifi interface seen by NM sleep 0.5 done - if nm_get_manage $1 ;then + if nm_get_manage "$1" ;then echo "Set $1 unmanaged by NetworkManager" - nmcli dev set $1 managed no || die "Failed to set $1 unmanaged by NetworkManager" + nmcli dev set "$1" managed no || die "Failed to set $1 unmanaged by NetworkManager" NM_UNM_LIST=$1 sleep 1 fi } nm_set_managed() { - nmcli dev set $1 managed yes + nmcli dev set "$1" managed yes NM_UNM_LIST= } nm_restore_manage() { if [[ $NM_UNM_LIST ]]; then echo "Restore $NM_UNM_LIST managed by NetworkManager" - nm_set_managed $NM_UNM_LIST + nm_set_managed "$NM_UNM_LIST" sleep 0.5 fi } @@ -1168,18 +1209,18 @@ set_interface_mac() { INTERFACE=$1 MAC=$2 - ip link set dev ${INTERFACE} address ${MAC} + ip link set dev "${INTERFACE}" address "${MAC}" } backup_interface_status() { # virtual wifi interface will be destroyed, so no need to save status # backup interface up or down status - (ip link show ${SUBNET_IFACE} |grep -q "state UP") && SUBNET_IFACE_ORIGINAL_UP_STATUS=1 + (ip link show "${SUBNET_IFACE}" |grep -q "state UP") && SUBNET_IFACE_ORIGINAL_UP_STATUS=1 # save interface old mac #if [[ -n "$NEW_MACADDR" ]]; then - OLD_MACADDR=$(get_interface_mac $SUBNET_IFACE) + OLD_MACADDR=$(get_interface_mac "$SUBNET_IFACE") #echo "Saved ${SUBNET_IFACE} old MAC address ${OLD_MACADDR} into RAM" #fi @@ -1196,14 +1237,14 @@ restore_interface_status() { restore_ipv6_bits - if [[ -n "$OLD_MACADDR" && "$(get_interface_mac $SUBNET_IFACE)" != "$OLD_MACADDR" ]] ; then + if [[ -n "$OLD_MACADDR" && "$(get_interface_mac "$SUBNET_IFACE")" != "$OLD_MACADDR" ]] ; then echo "Restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR} ..." - set_interface_mac ${SUBNET_IFACE} ${OLD_MACADDR} || echo "Failed restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR}" >&2 + set_interface_mac "${SUBNET_IFACE}" "${OLD_MACADDR}" || echo "Failed restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR}" >&2 fi nm_restore_manage - [[ $SUBNET_IFACE_ORIGINAL_UP_STATUS -eq 1 ]] && ip link set up dev ${SUBNET_IFACE} && echo "Restore ${SUBNET_IFACE} to link up" + [[ $SUBNET_IFACE_ORIGINAL_UP_STATUS -eq 1 ]] && ip link set up dev "${SUBNET_IFACE}" && echo "Restore ${SUBNET_IFACE} to link up" } #--------------------------------------- @@ -1214,11 +1255,11 @@ kill_processes() { # for this instance # even if the $CONFDIR is empty, the for loop will assign # a value in $x. so we need to check if the value is a file if [[ -f $x ]] && sleep 0.3 && [[ -f $x ]]; then - pid=$(cat $x) - pn=$( ps -p $pid -o comm= ) + pid=$(cat "$x") + pn=$( ps -p "$pid" -o comm= ) #echo "Killing $pid $pn ... " - pkill -P $pid - kill $pid 2>/dev/null && ( echo "Killed $(basename $x) $pid $pn" && rm $x ) || echo "Failed to kill $(basename $x) $pid $pn, it may have exited" + pkill -P "$pid" + kill "$pid" 2>/dev/null && ( echo "Killed $(basename "$x") $pid $pn" && rm "$x" ) || echo "Failed to kill $(basename "$x") $pid $pn, it may have exited" fi done } @@ -1226,15 +1267,15 @@ kill_processes() { # for this instance _cleanup() { local x - ip addr flush ${SUBNET_IFACE} + ip addr flush "${SUBNET_IFACE}" - rm -rf $CONFDIR + rm -rf "$CONFDIR" - ip link set down dev ${SUBNET_IFACE} + ip link set down dev "${SUBNET_IFACE}" if [[ $VWIFI_IFACE ]]; then # the subnet interface (virtual wifi interface) will be removed - iw dev ${VWIFI_IFACE} del - dealloc_vface_name $VWIFI_IFACE + iw dev "${VWIFI_IFACE}" del + dealloc_vface_name "$VWIFI_IFACE" fi restore_interface_status @@ -1243,12 +1284,12 @@ _cleanup() { echo "Exiting: This is the only running instance" # kill common processes for x in $COMMON_CONFDIR/*.pid; do - [[ -f $x ]] && kill -9 $(cat $x) && rm $x + [[ -f $x ]] && kill -9 $(cat "$x") && rm "$x" done - rm -d $COMMON_CONFDIR/vfaces - rm -d $COMMON_CONFDIR - rm -d $TMPDIR + rm -d "$COMMON_CONFDIR/vfaces" + rm -d "$COMMON_CONFDIR" + rm -d "$TMPDIR" else echo "Exiting: This is NOT the only running instance" fi @@ -1330,7 +1371,7 @@ list_running() { IFACE=${IFACE%%.*} subn_iface=$(cat $x/subn_iface) - if [[ $IFACE == $subn_iface ]]; then + if [[ "$IFACE" == "$subn_iface" ]]; then echo $(cat $x/pid) $IFACE else echo $(cat $x/pid) $IFACE '('$(cat $x/subn_iface)')' @@ -1367,7 +1408,7 @@ print_clients_from_leases() { # MAC|IP|HOST|lease FILEC="$(cat "$LEASE_FILE" | grep -v -E "^duid\b" | sed -r '/^\s*$/d' )" # TODO: duid is somewhat related to ipv6. I don't know about it. Not sure excluding it miss some info or not - echo "$FILEC" | while read line + echo "$FILEC" | while read -r line do #echo aa$line LEASEstamp="$(echo "$line" | awk '{print $1}')" @@ -1388,20 +1429,20 @@ print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS local line - ip n | grep -E "\bdev $IFACE\b" | sed 's/ /|/g' | while read line + ip n | grep -E "\bdev $IFACE\b" | sed 's/ /|/g' | while read -r line do local MAC IP STATUS - IP="$(echo $line | awk -F'|' '{print $1}')" + IP="$(echo "$line" | awk -F'|' '{print $1}')" - if [[ "$(echo $line | awk -F'|' '{print $4}')" == "lladdr" ]]; then # has mac + if [[ "$(echo "$line" | awk -F'|' '{print $4}')" == "lladdr" ]]; then # has mac # if has mac, $4="lladdr" and $5=macaddress and $6+=status - MAC="$(echo $line | awk -F'|' '{print $5}')" - STATUS="$(echo $line | awk -F'|' '$1="";$2="";$3="";$4="";$5="";{print}' | awk '{$1=$1;print}'| sed 's/ /,/g')" + MAC="$(echo "$line" | awk -F'|' '{print $5}')" + STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";$5="";{print}' | awk '{$1=$1;print}'| sed 's/ /,/g')" else # no mac # if no mac, $4="" and $5+=status MAC="?" - STATUS="$(echo $line | awk -F'|' '$1="";$2="";$3="";$4="";{print}' | awk '{$1=$1;print}' | sed 's/ /,/g')" + STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";{print}' | awk '{$1=$1;print}' | sed 's/ /,/g')" fi if [[ -n "$IP" && ( "$MAC" != "?" || "$STATUS" != "FAILED" ) ]]; then echo "$MAC|$IP|?|$STATUS" @@ -1411,10 +1452,10 @@ print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS print_interface_neighbors_via_iw() { # MAC|_|_|signal local IFACE=$1 local MAC SIGNAL - iw dev $IFACE station dump | awk '($1 ~ /Station$/) {print $2}' | while read MAC + iw dev "$IFACE" station dump | awk '($1 ~ /Station$/) {print $2}' | while read -r MAC do if [[ -n "$MAC" ]]; then - SIGNAL="$(iw dev $IFACE station get $MAC | grep "signal:" | awk '{print $2}')" + SIGNAL="$(iw dev "$IFACE" station get "$MAC" | grep "signal:" | awk '{print $2}')" echo "${MAC}|?|?|${SIGNAL}_dBm" fi done @@ -1435,7 +1476,7 @@ list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active fi else # non-number given IFACE="$1" - if ( ! is_interface $IFACE ) ; then + if ( ! is_interface "$IFACE" ) ; then echo "'$IFACE' is not an interface or PID" >&2 exit 1 fi @@ -1447,18 +1488,18 @@ list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active echo "Tip: '$IFACE' is not an interface hosted by $PROGNAME" >&2 fi fi - output="$(echo "$output" ; print_interface_neighbors_via_iw $IFACE) " - output="$(echo "$output" ; print_interface_neighbors_via_iproute $IFACE)" + output="$(echo "$output" ; print_interface_neighbors_via_iw "$IFACE") " + output="$(echo "$output" ; print_interface_neighbors_via_iproute "$IFACE")" output="$(echo "$output" | sort -k 1 -k 2 -t '|' | uniq | sed -r '/^\s*$/d')" - echo "$IFACE ($(get_interface_mac $IFACE)) neighbors:" + echo "$IFACE ($(get_interface_mac "$IFACE")) neighbors:" local fmt="%-19s%-41s%-20s%s" # string length: MAC 17, ipv4 15, ipv6 39, hostname ? printf "$fmt\n" "MAC" "IP" "HOSTNAME" "INFO" local line - echo "$output"| while read line + echo "$output"| while read -r line do if [[ -n "$line" ]]; then echo "$line" | awk -F'|' "{printf \"$fmt\n\",\$1,\$2,\$3,\$4}" @@ -1490,14 +1531,14 @@ send_stop() { local x # send stop signal to specific pid - if is_running_pid $1; then - kill -USR1 $1 + if is_running_pid "$1"; then + kill -USR1 "$1" return fi # send stop signal to specific interface for x in $(list_running | grep -E " \(?${1}( |\)?\$)" | cut -f1 -d' '); do - kill -USR1 $x + kill -USR1 "$x" done } @@ -1560,13 +1601,13 @@ daemonizing_check(){ #============================ check_wifi_settings() { - if ! ( which iw > /dev/null 2>&1 && iw dev $WIFI_IFACE info > /dev/null 2>&1 ); then - echo "WARN: Can't use 'iw' to operate interfce '$WIFI_IFACE', trying 'iwconfig' (not as good as 'iw') ..." >&2 + if ! ( which iw > /dev/null 2>&1 && iw dev "$WIFI_IFACE" info > /dev/null 2>&1 ); then + echo "WARN: Can't use 'iw' to operate interfce '$WIFI_IFACE', trying 'iwconfig' (not as good as 'iw') ... (Did you spell the interface name right?)" >&2 USE_IWCONFIG=1 fi if [[ $USE_IWCONFIG -eq 1 ]]; then - if ! (which iwconfig > /dev/null 2>&1 && iwconfig $WIFI_IFACE > /dev/null 2>&1); then + if ! (which iwconfig > /dev/null 2>&1 && iwconfig "$WIFI_IFACE" > /dev/null 2>&1); then echo "ERROR: Can't use 'iwconfig' to operate interfce '$WIFI_IFACE'" >&2 exit 1 fi @@ -1577,26 +1618,18 @@ check_wifi_settings() { 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 + 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_interface_wifi_connected ${WIFI_IFACE}; then + if ! can_be_sta_and_ap "${WIFI_IFACE}"; then + if is_interface_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 @@ -1607,7 +1640,7 @@ check_wifi_settings() { HOSTAPD=$(which hostapd) - if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then + 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 @@ -1634,7 +1667,7 @@ check_wifi_settings() { exit 1 fi - if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^rtl[0-9].*$ ]]; then + 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 @@ -1649,7 +1682,7 @@ check_wifi_settings() { echo "WARN: option --virt-name $VIRT_NAME has ${#VIRT_NAME} characters which might be too long, consider making it shorter in case of errors" >&2 fi - if [[ ! -z $VIRT_NAME ]] && is_vface_name_allocated $VIRT_NAME; then + if [[ ! -z $VIRT_NAME ]] && is_vface_name_allocated "$VIRT_NAME"; then echo "WARN: interface $VIRT_NAME aleady exists, this will cause an error" fi } @@ -1660,7 +1693,7 @@ check_if_new_mac_valid() { exit 1 fi - if [[ $(get_all_mac_in_system | grep -c ${NEW_MACADDR}) -ne 0 ]]; then + if [[ $(get_all_mac_in_system | grep -c "${NEW_MACADDR}") -ne 0 ]]; then echo "WARN: MAC address '${NEW_MACADDR}' already exists" >&2 fi } @@ -1698,31 +1731,32 @@ decide_ip_addresses() { prepare_wifi_interface() { if [[ $USE_IWCONFIG -eq 0 ]]; then - iw dev ${WIFI_IFACE} set power_save off + iw dev "${WIFI_IFACE}" set power_save off fi if [[ $NO_VIRT -eq 0 ]]; then ## Will generate virtual wifi interface - if is_interface_wifi_connected ${WIFI_IFACE} && [[ FORCECHANNEL -eq 0 ]]; 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}" + + # TODO move this to check_wifi_settings() ? + if is_interface_wifi_connected "${WIFI_IFACE}"; then + WIFI_IFACE_FREQ=$(iw dev "${WIFI_IFACE}" link | grep -i freq | awk '{print $2}' | sed 's/\.00*$//g') # NOTE we assume integer currently, which can be right, or wrong in the future + WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel "${WIFI_IFACE_FREQ}") + + echo "${WIFI_IFACE} already working in channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" + + if [[ $CHANNEL == default ]]; then + echo "Use wifi adapter current channel $WIFI_IFACE_CHANNEL as target channel" CHANNEL=$WIFI_IFACE_CHANNEL - else - echo + fi + + if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then + echo "WARN: Wifi adapter already working in channel ${WIFI_IFACE_CHANNEL}, which is different than target channel $CHANNEL" >&2 fi fi echo "Creating a virtual WiFi interface... " VWIFI_IFACE=$(alloc_new_vface_name) - if iw dev ${WIFI_IFACE} interface add ${VWIFI_IFACE} type __ap; then + if iw dev "${WIFI_IFACE}" interface add "${VWIFI_IFACE}" type __ap; then # Successfully created virtual wifi interface # if NM running, it will give the new virtual interface a random MAC. MAC will go back after setting NM unmanaged sleep 2 @@ -1742,6 +1776,15 @@ prepare_wifi_interface() { else # no virtual wifi interface, use wifi device interface itself AP_IFACE=${WIFI_IFACE} fi + + if [[ $CHANNEL == default ]]; then + echo "Channel not specified, use default" + if [[ $FREQ_BAND == 2.4 ]]; then + CHANNEL=1 + else + CHANNEL=36 + fi + fi } decide_subnet_interface() { @@ -1758,14 +1801,14 @@ dealwith_mac() { if [[ -n "$NEW_MACADDR" ]] ; then # user choose to set subnet mac echo "Setting ${SUBNET_IFACE} new MAC address ${NEW_MACADDR} ..." - set_interface_mac ${SUBNET_IFACE} ${NEW_MACADDR} || die "Failed setting new MAC address" + set_interface_mac "${SUBNET_IFACE}" "${NEW_MACADDR}" || die "Failed setting new MAC address" elif [[ $VWIFI_IFACE ]]; then # user didn't choose to set mac, but using virtual wifi interface - VMAC=$(get_new_macaddr_according_to_existing ${WIFI_IFACE}) + VMAC=$(get_new_macaddr_according_to_existing "${WIFI_IFACE}") if [[ "$VMAC" ]]; then echo "Assigning MAC address $VMAC to virtual interface $VWIFI_IFACE according to $WIFI_IFACE ..." - set_interface_mac $VWIFI_IFACE $VMAC + set_interface_mac "$VWIFI_IFACE" "$VMAC" fi fi } @@ -1826,6 +1869,15 @@ write_hostapd_conf() { echo "require_vht=1" >> "$CONFDIR/hostapd.conf" fi + if [[ $IEEE80211AX -eq 1 ]]; then + echo "ieee80211ax=1" >> "$CONFDIR/hostapd.conf" + fi + + if [[ $REQUIRE_HE -eq 1 ]]; then + echo "require_he=1" >> "$CONFDIR/hostapd.conf" + fi + + if [[ -n "$VHT_CAPAB" ]]; then echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf" fi @@ -1848,6 +1900,24 @@ write_hostapd_conf() { EOF fi + if [[ $HECHANNELWIDTH -gt 0 ]]; then + cat <<- EOF >> "$CONFDIR/hostapd.conf" + he_oper_chwidth=${HECHANNELWIDTH} + EOF + fi + + if [[ $HESEG0CHINDEX -gt 0 ]]; then + cat <<- EOF >> "$CONFDIR/hostapd.conf" + he_oper_centr_freq_seg0_idx=${HESEG0CHINDEX} + EOF + fi + + if [[ $HESEG1CHINDEX -gt 0 ]]; then + cat <<- EOF >> "$CONFDIR/hostapd.conf" + he_oper_centr_freq_seg1_idx=${HESEG1CHINDEX} + EOF + fi + if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then echo "wmm_enabled=1" >> "$CONFDIR/hostapd.conf" fi @@ -1869,7 +1939,6 @@ write_hostapd_conf() { else echo "WARN: WiFi is not protected by password" >&2 fi - echo "Config for current session is $CONFDIR/hostapd.conf" # Useful for sharing with other hostapd users. chmod 600 "$CONFDIR/hostapd.conf" } @@ -1932,7 +2001,7 @@ write_dnsmasq_conf() { 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 + 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 @@ -1976,7 +2045,7 @@ run_wifi_ap_processes() { # 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` + STDBUF_PATH=$(which stdbuf) if [ $? -eq 0 ]; then STDBUF_PATH=$STDBUF_PATH" -oL" fi @@ -1996,7 +2065,7 @@ run_wifi_ap_processes() { # sleep 1 #done #echo -n "hostapd PID: " ; cat $CONFDIR/hostapd.pid - pid_watchdog $HOSTAPD_PID 10 "hostapd failed" & + pid_watchdog "$HOSTAPD_PID" 10 "hostapd failed. (tip: try '--hostapd-debug' to get some debug info)" & sleep 3 } @@ -2023,15 +2092,15 @@ start_dnsmasq() { DNSMASQ_PID="$(cat "$CONFDIR/dnsmasq.pid" )" echo "dnsmasq PID: $DNSMASQ_PID" ######(wait $DNSMASQ_PID ; die "dnsmasq failed") & # wait can't deal with non-child - pid_watchdog $DNSMASQ_PID 9 "dnsmasq failed" & + pid_watchdog "$DNSMASQ_PID" 9 "dnsmasq failed" & sleep 2 } check_rfkill_unblock_wifi() { local PHY if which rfkill > /dev/null 2>&1 ; then - PHY=$(get_interface_phy_device ${SUBNET_IFACE}) - [[ -n $PHY ]] && rfkill unblock $(rfkill | grep $PHY | awk '{print $1}') >/dev/null 2>&1 + PHY=$(get_interface_phy_device "${SUBNET_IFACE}") + [[ -n $PHY ]] && rfkill unblock $(rfkill | grep "$PHY" | awk '{print $1}') >/dev/null 2>&1 fi } @@ -2078,7 +2147,8 @@ echo echo "PID: $$" TARGET_IFACE="$(decide_target_interface)" || exit 1 # judge wired (-i CONN_IFACE) or wireless hotspot (--ap $WIFI_IFACE) -echo "Target interface is ${TARGET_IFACE} ($(get_interface_mac $TARGET_IFACE)) $(get_interface_pci_info $TARGET_IFACE)" +echo "Target interface is ${TARGET_IFACE} ($(get_interface_mac "$TARGET_IFACE")) " +show_interface_pci_info "$TARGET_IFACE" if [[ "$MAC_USE_RANDOM" -eq 1 ]] ; then NEW_MACADDR="$(generate_random_mac)" @@ -2114,7 +2184,7 @@ fi # judge channel availability after changing country code if [[ $WIFI_IFACE ]] ; then - can_transmit_to_channel ${AP_IFACE} ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz." + can_transmit_to_channel "${AP_IFACE}" ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz." fi [[ $WIFI_IFACE ]] && write_hostapd_conf @@ -2122,8 +2192,8 @@ fi #=================================================== # set interface unmanaged by networkManager -if [[ $NM_RUNNING -eq 1 ]] && nm_knows $TARGET_IFACE; then # if nm knows target iface, should know subnet iface too. but need to wait until nm finds subnet iface (waiting code is in nm_set_unmanaged() - nm_set_unmanaged ${SUBNET_IFACE} # will write NM_UNM_LIST +if [[ $NM_RUNNING -eq 1 ]] && nm_knows "$TARGET_IFACE"; then # if nm knows target iface, should know subnet iface too. but need to wait until nm finds subnet iface (waiting code is in nm_set_unmanaged() + nm_set_unmanaged "${SUBNET_IFACE}" # will write NM_UNM_LIST fi [[ $NO_DNSMASQ -eq 0 ]] && write_dnsmasq_conf @@ -2131,16 +2201,16 @@ fi # initialize subnet interface # take subnet interface down first -ip link set down dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} down" +ip link set down dev "${SUBNET_IFACE}" || die "Failed setting ${SUBNET_IFACE} down" # flush old IPs of subnet interface -ip addr flush ${SUBNET_IFACE} || die "Failed flush ${SUBNET_IFACE} IP" +ip addr flush "${SUBNET_IFACE}" || die "Failed flush ${SUBNET_IFACE} IP" dealwith_mac # setting MAC should be after setting NM unmanaged [[ $WIFI_IFACE ]] && check_rfkill_unblock_wifi # bring subnet interface up -ip link set up dev ${SUBNET_IFACE} || die "Failed bringing ${SUBNET_IFACE} up" +ip link set up dev "${SUBNET_IFACE}" || die "Failed bringing ${SUBNET_IFACE} up" # hostapd , haveged [[ $WIFI_IFACE ]] && run_wifi_ap_processes @@ -2243,6 +2313,6 @@ show_qr() { bash -c "while :; do sleep 8000 ; done " & KEEP_RUNNING_PID=$! echo "$KEEP_RUNNING_PID" > "$CONFDIR/keep_running.pid" -wait $KEEP_RUNNING_PID +wait "$KEEP_RUNNING_PID" clean_exit From 3d9e205773d530fce67a9c74f97f287d3186a09c Mon Sep 17 00:00:00 2001 From: Phani Pavan Kambhampati <60005847+kphanipavan@users.noreply.github.com> Date: Sat, 14 Jun 2025 09:55:34 +0530 Subject: [PATCH 02/12] rebase to 0.7.6 and upgrade version to 0.8.0-unstable0 --- lnxrouter | 417 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 264 insertions(+), 153 deletions(-) diff --git a/lnxrouter b/lnxrouter index 2fd90e6..a71e0a6 100755 --- a/lnxrouter +++ b/lnxrouter @@ -1,6 +1,6 @@ #!/bin/bash -VERSION=0.7.3a +VERSION=0.8.0-unstable0 PROGNAME="$(basename "$0")" export LC_ALL=C @@ -29,17 +29,16 @@ Options: and to provide Internet to (To create WiFi hotspot use '--ap' instead) -o Specify an inteface to provide Internet from. - (See Notice 1) (Note using this with default DNS option may leak queries to other interfaces) - -n Do not provide Internet (See Notice 1) + -n Do not provide Internet --ban-priv Disallow clients to access my private network -g This host's IPv4 address in subnet (mask is /24) (example: '192.168.5.1' or '5' shortly) -6 Enable IPv6 (NAT) - --no4 Disable IPv4 Internet (not forwarding IPv4) - (See Notice 1). Usually used with '-6' + --no4 Disable IPv4 Internet (not forwarding IPv4). + Usually used with '-6' --p6 Set IPv6 LAN address prefix (length 64) (example: 'fd00:0:0:5::' or '5' shortly) @@ -48,7 +47,7 @@ Options: --dns || DNS server's upstream DNS. Use ',' to seperate multiple servers - (default: use /etc/resolve.conf) + (default: use /etc/resolv.conf) (Note IPv6 addresses need '[]' around) --no-dns Do not serve DNS --no-dnsmasq Disable dnsmasq server (DHCP, DNS, RA) @@ -149,12 +148,6 @@ Options: --stop Stop a running instance For you can use PID or subnet interface name. You can get them with '--list-running' - - Notice 1: This script assume your host's default policy won't forward - packets, so the script won't explictly ban forwarding in any - mode. In some unexpected case (eg. mistaken configurations) may - cause unwanted packets leakage between 2 networks, which you - should be aware of if you want isolated network Examples: $PROGNAME -i eth1 @@ -173,7 +166,7 @@ check_empty_option(){ define_global_variables(){ # user options - GATEWAY= # IPv4 address for this host + GATEWAY4= # 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 @@ -201,6 +194,8 @@ define_global_variables(){ SUBNET_IFACE= # which interface to create network SHARE_METHOD=nat OLD_MACADDR= + SUBNET_NET4= + SUBNET_NET6= ##### wifi hotspot @@ -217,7 +212,7 @@ define_global_variables(){ IEEE80211AC=0 REQUIREVHT=0 IEEE80211AX=0 - REQUIRE_HE=0 + REQUIREHE=0 HT_CAPAB='[HT40+]' VHT_CAPAB= VHTCHANNELWIDTH=0 @@ -241,7 +236,6 @@ define_global_variables(){ VIRT_NAME= # name to use for virtual interface if --virt-name is used AP_IFACE= # can be VWIFI_IFACE or WIFI_IFACE USE_IWCONFIG=0 # some device can't use iw - ####### #-- to deal with info of a running instance. then will exit @@ -251,8 +245,11 @@ define_global_variables(){ # -- variables for running CONFDIR= - NM_RUNNING=0 + IP_VERs= NM_UNM_LIST= # it's called "list" but for now one interface + NM_PID= + FIREWALLD_PID= + TMP_FIREWALLD_ZONE= } parse_user_options(){ @@ -294,7 +291,7 @@ parse_user_options(){ -g) shift - GATEWAY="$1" + GATEWAY4="$1" shift ;; -6) @@ -442,7 +439,7 @@ parse_user_options(){ ;; --req-he|--require-he) shift - REQUIRE_HE=1 + REQUIREHE=1 ;; --req-vht|--require-vht) shift @@ -901,15 +898,39 @@ pid_watchdog() { } #======== - - +get_pid_by_dbus_name() { + local DBUS_NAME="$1" + local pid r + + which dbus-send >/dev/null 2>&1 || return 1 + + pid="$( dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetConnectionUnixProcessID string:$DBUS_NAME 2>/dev/null | grep " uint32 " | awk '{print $2}' )" + r=$? + + echo "$pid" + return $r +} +is_same_netns() { + local pid2="$1" + [[ ! -f /proc/$$/ns/net ]] && return 0 # no netns feature. treat as same + [[ "$(readlink /proc/$$/ns/net)" == "$(readlink /proc/$pid2/ns/net)" ]] && return 0 + return 1 +} +#----------------- # only support NetworkManager >= 0.9.9 is_nm_running() { + NM_PID="$(get_pid_by_dbus_name "org.freedesktop.NetworkManager")" + + [[ ! -n "$NM_PID" ]] && return 1 # not running + if (which nmcli >/dev/null 2>&1 ) && (nmcli -t -f RUNNING g 2>&1 | grep -E '^running$' >/dev/null 2>&1 ) ; then - echo 1 - else - echo 0 + if is_same_netns "$NM_PID"; then + return 0 + fi fi + + NM_PID= # cancel value if treat as not running + return 1 # not running } nm_knows() { @@ -945,21 +966,38 @@ nm_restore_manage() { sleep 0.5 fi } -#========= -check_iptables() -{ - echo - iptables --version +#------- +is_firewalld_running() { + FIREWALLD_PID="$(get_pid_by_dbus_name "org.fedoraproject.FirewallD1")" - if which firewall-cmd > /dev/null 2>&1; then - if [[ "$(firewall-cmd --state 2>&1)" == "running" ]]; then + [[ ! -n "$FIREWALLD_PID" ]] && return 1 # not running + + if (which firewall-cmd >/dev/null 2>&1 ) && [[ "$(firewall-cmd --state 2>&1)" == "running" ]] ; then + if is_same_netns "$FIREWALLD_PID"; then echo "firewalld is running ($(firewall-cmd --version))" - echo -e "\nWARN: We haven't completed the compatibility with firewalld.\nWARN: If you see any trouble, try:\nWARN: 1) 'firewall-cmd --zone=trusted --add-interface='\nWARN: 2) disable firewalld\n" >&2 - # TODO + return 0 fi fi + + FIREWALLD_PID= # cancel value if treat as not running + return 1 # not running +} +firewalld_add_tmpzone() { +# TMP_FIREWALLD_ZONE="lrt${$}${SUBNET_IFACE}" + TMP_FIREWALLD_ZONE="trusted" +# firewall-cmd --new-zone=$TMP_FIREWALLD_ZONE || die "Failed creating temporary firewalld zone" + echo "Adding $SUBNET_IFACE to firewalld '$TMP_FIREWALLD_ZONE' zone" + firewall-cmd --zone=$TMP_FIREWALLD_ZONE --add-interface=$SUBNET_IFACE >/dev/null || die "Failed adding interface to firewalld temporary zone" +} +firewalld_del_tmpzone() { + if [[ -n "$TMP_FIREWALLD_ZONE" ]];then + echo "Removing $SUBNET_IFACE from firewalld '$TMP_FIREWALLD_ZONE' zone" + firewall-cmd --zone=$TMP_FIREWALLD_ZONE --remove-interface=$SUBNET_IFACE >/dev/null +# firewall-cmd --delete-zone=$TMP_FIREWALLD_ZONE + fi } +#========= CUSTOM_CHAINS_4_filter= CUSTOM_CHAINS_4_nat= CUSTOM_CHAINS_6_filter= @@ -988,6 +1026,8 @@ iptb() local FULL="" local ADD_TO_UNDO=1 + local arr_name w + for arr_name in CUSTOM_CHAINS_4_filter CUSTOM_CHAINS_4_nat CUSTOM_CHAINS_6_filter CUSTOM_CHAINS_6_nat do local arr_content @@ -1039,86 +1079,146 @@ iptb() return $? } +disable_unwanted_forwarding() { + for iv in "${IP_VERs[@]}"; do + if [[ "$INTERNET_IFACE" ]]; then + iptb "$iv" n filter I FORWARD \ + -i "$SUBNET_IFACE" ! -o "$INTERNET_IFACE" \ + -j REJECT || die + iptb "$iv" n filter I FORWARD \ + ! -i "$INTERNET_IFACE" -o "$SUBNET_IFACE" \ + -j REJECT || die + fi + + if [[ "$SHARE_METHOD" == 'redsocks' || "$SHARE_METHOD" == 'none' \ + || ( "$iv" -eq "4" && "$NO4" -eq 1 ) ]];then + iptb "$iv" n filter I FORWARD -i "$SUBNET_IFACE" -j REJECT || die + iptb "$iv" n filter I FORWARD -o "$SUBNET_IFACE" -j REJECT || die + fi + done + +} start_nat() { - if [[ $INTERNET_IFACE ]]; then - IPTABLES_NAT_OUT="-o ${INTERNET_IFACE}" - IPTABLES_NAT_IN="-i ${INTERNET_IFACE}" - MASQUERADE_NOTOUT="" - else - MASQUERADE_NOTOUT="! -o ${SUBNET_IFACE}" - fi + local SUBNET_NET + + local iv + echo echo "iptables: NAT " - if [[ $NO4 -eq 0 ]]; then - iptb 4 v nat I POSTROUTING -s ${GATEWAY%.*}.0/24 $IPTABLES_NAT_OUT $MASQUERADE_NOTOUT ! -d ${GATEWAY%.*}.0/24 -j MASQUERADE || die - iptb 4 v filter I FORWARD -i ${SUBNET_IFACE} $IPTABLES_NAT_OUT -s ${GATEWAY%.*}.0/24 -j ACCEPT || die - iptb 4 v filter I FORWARD -o ${SUBNET_IFACE} $IPTABLES_NAT_IN -d ${GATEWAY%.*}.0/24 -j ACCEPT || die - fi - - iptb 6 v nat I POSTROUTING -s ${PREFIX6}/64 $IPTABLES_NAT_OUT $MASQUERADE_NOTOUT ! -d ${PREFIX6}/64 -j MASQUERADE || die - iptb 6 v filter I FORWARD -i ${SUBNET_IFACE} $IPTABLES_NAT_OUT -s ${PREFIX6}/64 -j ACCEPT || die - iptb 6 v filter I FORWARD -o ${SUBNET_IFACE} $IPTABLES_NAT_IN -d ${PREFIX6}/64 -j ACCEPT || die + + for iv in "${IP_VERs[@]}"; do + [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue + + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" + [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" + + if [[ -n "$INTERNET_IFACE" ]]; then # only one Internet interface + # masquerade subnet -> internet + iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ + -o "$INTERNET_IFACE" \ + -j MASQUERADE || die + + # forward subnet -> internet + iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ + -o $INTERNET_IFACE \ + -j ACCEPT || die + + # forward any -> subnet + iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ + -i "$INTERNET_IFACE" \ + -j ACCEPT || die + else # any interface can be Internet + # masquerade subnet -> any(!subnet) + iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ + ! -o "$SUBNET_IFACE" \ + -j MASQUERADE || die + + # forward subnet -> any + iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ + -j ACCEPT || die + + # forward any -> subnet + iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ + -j ACCEPT || die + fi + done } start_ban_lan() { + local arr_nets_to_protect + local ICMP_NAME + local iv s + echo echo "iptables: Disallow clients to access LAN" - iptb 4 n filter N lrt${$}${SUBNET_IFACE}-BLF || die - # TODO: allow '--dhcp-dns(6)' address port 53, which can be something needed, e.g. a VPN's internal private IP - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 0.0.0.0/8 -j REJECT || die # TODO: use array - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 10.0.0.0/8 -j REJECT || die - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 100.64.0.0/10 -j REJECT || die - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 127.0.0.0/8 -j REJECT || die - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 169.254.0.0/16 -j REJECT || die - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 172.16.0.0/12 -j REJECT || die - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 192.168.0.0/16 -j REJECT || die - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 224.0.0.0/4 -j REJECT || die - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLF -d 255.255.255.255 -j REJECT || die - iptb 4 n filter I FORWARD -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLF || die - - iptb 4 n filter N lrt${$}${SUBNET_IFACE}-BLI || die - iptb 4 v filter I lrt${$}${SUBNET_IFACE}-BLI -i ${SUBNET_IFACE} ! -p icmp -j REJECT || die # ipv6 need icmp to function. TODO: maybe we can block some unneeded icmp to improve security - - iptb 4 n filter I INPUT -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLI || die - - - iptb 6 n filter N lrt${$}${SUBNET_IFACE}-BLF || die - iptb 6 v filter I lrt${$}${SUBNET_IFACE}-BLF -d fc00::/7 -j REJECT || die - iptb 6 v filter I lrt${$}${SUBNET_IFACE}-BLF -d fe80::/10 -j REJECT || die - iptb 6 v filter I lrt${$}${SUBNET_IFACE}-BLF -d ff00::/8 -j REJECT || die - iptb 6 v filter I lrt${$}${SUBNET_IFACE}-BLF -d ::1 -j REJECT || die - iptb 6 v filter I lrt${$}${SUBNET_IFACE}-BLF -d ::/128 -j REJECT || die - iptb 6 v filter I lrt${$}${SUBNET_IFACE}-BLF -d ::ffff:0:0/96 -j REJECT || die - iptb 6 v filter I lrt${$}${SUBNET_IFACE}-BLF -d ::ffff:0:0:0/96 -j REJECT || die - - iptb 6 n filter I FORWARD -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLF || die - - iptb 6 n filter N lrt${$}${SUBNET_IFACE}-BLI || die - iptb 6 v filter I lrt${$}${SUBNET_IFACE}-BLI -i ${SUBNET_IFACE} ! -p icmpv6 -j REJECT || die - - iptb 6 n filter I INPUT -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLI || die + for iv in "${IP_VERs[@]}"; do + # ban forwarding for subnet + iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLF || die + # TODO: allow '--dhcp-dns(6)' address port 53, which can be something needed, e.g. a VPN's internal private IP + if [[ "$iv" -eq "4" ]]; then + arr_nets_to_protect=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") + ICMP_NAME="icmp" + elif [[ "$iv" -eq "6" ]]; then + arr_nets_to_protect=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::/128" "::ffff:0:0/96" "::ffff:0:0:0/96") + ICMP_NAME="icmpv6" + fi + for s in "${arr_nets_to_protect[@]}"; do + iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLF -d "$s" -j REJECT || die + done + iptb "$iv" n filter I FORWARD -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLF || die + + # ban input from subnet + iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLI || die + iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLI -i ${SUBNET_IFACE} ! -p "$ICMP_NAME" -j REJECT || die # ipv6 need icmp to function. TODO: maybe we can block some unneeded icmp to improve security + iptb "$iv" n filter I INPUT -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLI || die + done } allow_dns_port() { + local SUBNET_NET + local GATEWAY + local PROTs + local iv pt + + echo echo "iptables: allow DNS" - iptb 4 v filter I INPUT -i ${SUBNET_IFACE} -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} -p tcp -m tcp --dport 53 -j ACCEPT || die - iptb 4 v filter I INPUT -i ${SUBNET_IFACE} -s ${GATEWAY%.*}.0/24 -d ${GATEWAY} -p udp -m udp --dport 53 -j ACCEPT || die - iptb 6 v filter I INPUT -i ${SUBNET_IFACE} -s ${PREFIX6}/64 -d ${GATEWAY6} -p tcp -m tcp --dport 53 -j ACCEPT || die - iptb 6 v filter I INPUT -i ${SUBNET_IFACE} -s ${PREFIX6}/64 -d ${GATEWAY6} -p udp -m udp --dport 53 -j ACCEPT || die + + for iv in "${IP_VERs[@]}"; do + [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" + [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" + + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" + [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" + + + PROTs=("tcp" "udp") + for pt in "${PROTs[@]}"; do + iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j ACCEPT || die + done + done } start_catch_dns() { + local GATEWAY + local PROTs + local iv pt + echo echo "iptables: redirect DNS queries to this host" - iptb 4 v nat I PREROUTING -i ${SUBNET_IFACE} ! -d ${GATEWAY} -p udp -m udp --dport 53 -j REDIRECT --to-ports 53 || die - iptb 4 v nat I PREROUTING -i ${SUBNET_IFACE} ! -d ${GATEWAY} -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 53 || die - - iptb 6 v nat I PREROUTING -i ${SUBNET_IFACE} ! -d ${GATEWAY6} -p udp -m udp --dport 53 -j REDIRECT --to-ports 53 || die - iptb 6 v nat I PREROUTING -i ${SUBNET_IFACE} ! -d ${GATEWAY6} -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 53 || die + + for iv in "${IP_VERs[@]}"; do + [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" + [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" + + PROTs=("tcp" "udp") + for pt in "${PROTs[@]}"; do + iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" ! -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j REDIRECT --to-ports 53 || die + done + done } @@ -1132,44 +1232,41 @@ allow_dhcp() { # TODO: use 'DNAT' instead of '--to-ports' to support other IP start_redsocks() { + local SUBNET_NET + local arr_nets_to_ignore + local s iv + echo echo "iptables: transparent proxy non-LAN TCP and UDP(not tested) traffic to port ${TP_PORT}" - if [[ $NO4 -eq 0 ]]; then - iptb 4 n nat N lrt${$}${SUBNET_IFACE}-TP || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 0.0.0.0/8 -j RETURN || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 10.0.0.0/8 -j RETURN || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 100.64.0.0/10 -j RETURN || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 127.0.0.0/8 -j RETURN || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 169.254.0.0/16 -j RETURN || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 172.16.0.0/12 -j RETURN || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 192.168.0.0/16 -j RETURN || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 224.0.0.0/4 -j RETURN || die - iptb 4 n nat A lrt${$}${SUBNET_IFACE}-TP -d 255.255.255.255 -j RETURN || die + + for iv in "${IP_VERs[@]}"; do + [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue - iptb 4 v nat A lrt${$}${SUBNET_IFACE}-TP -p tcp -j REDIRECT --to-ports ${TP_PORT} || die - iptb 4 v nat A lrt${$}${SUBNET_IFACE}-TP -p udp -j REDIRECT --to-ports ${TP_PORT} || die + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" + [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" + + + iptb "$iv" n nat N lrt${$}${SUBNET_IFACE}-TP || die + + if [[ "$iv" -eq "4" ]]; then + arr_nets_to_ignore=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") + elif [[ "$iv" -eq "6" ]];then + arr_nets_to_ignore=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::") + fi + + for s in "${arr_nets_to_ignore[@]}"; do + iptb "$iv" n nat A lrt${$}${SUBNET_IFACE}-TP -d "$s" -j RETURN || die + done - iptb 4 v nat I PREROUTING -i ${SUBNET_IFACE} -s ${GATEWAY%.*}.0/24 -j lrt${$}${SUBNET_IFACE}-TP || die + iptb "$iv" v nat A lrt${$}${SUBNET_IFACE}-TP -p tcp -j REDIRECT --to-ports ${TP_PORT} || die + iptb "$iv" v nat A lrt${$}${SUBNET_IFACE}-TP -p udp -j REDIRECT --to-ports ${TP_PORT} || die - iptb 4 v filter I INPUT -i ${SUBNET_IFACE} -s ${GATEWAY%.*}.0/24 -p tcp -m tcp --dport ${TP_PORT} -j ACCEPT || die - iptb 4 v filter I INPUT -i ${SUBNET_IFACE} -s ${GATEWAY%.*}.0/24 -p udp -m udp --dport ${TP_PORT} -j ACCEPT || die - fi - - iptb 6 n nat N lrt${$}${SUBNET_IFACE}-TP || die - iptb 6 n nat A lrt${$}${SUBNET_IFACE}-TP -d fc00::/7 -j RETURN || die - iptb 6 n nat A lrt${$}${SUBNET_IFACE}-TP -d fe80::/10 -j RETURN || die - iptb 6 n nat A lrt${$}${SUBNET_IFACE}-TP -d ff00::/8 -j RETURN || die - iptb 6 n nat A lrt${$}${SUBNET_IFACE}-TP -d ::1 -j RETURN || die - iptb 6 n nat A lrt${$}${SUBNET_IFACE}-TP -d :: -j RETURN || die - - iptb 6 v nat A lrt${$}${SUBNET_IFACE}-TP -p tcp -j REDIRECT --to-ports ${TP_PORT} || die - iptb 6 v nat A lrt${$}${SUBNET_IFACE}-TP -p udp -j REDIRECT --to-ports ${TP_PORT} || die - - iptb 6 v nat I PREROUTING -i ${SUBNET_IFACE} -s ${PREFIX6}/64 -j lrt${$}${SUBNET_IFACE}-TP || die - - iptb 6 v filter I INPUT -i ${SUBNET_IFACE} -s ${PREFIX6}/64 -p tcp -m tcp --dport ${TP_PORT} -j ACCEPT || die - iptb 6 v filter I INPUT -i ${SUBNET_IFACE} -s ${PREFIX6}/64 -p udp -m udp --dport ${TP_PORT} -j ACCEPT || die + iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" -s "$SUBNET_NET" -j lrt${$}${SUBNET_IFACE}-TP || die + + iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p tcp -m tcp --dport ${TP_PORT} -j ACCEPT || die + iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p udp -m udp --dport ${TP_PORT} -j ACCEPT || die + done } #--------------------------------------- @@ -1273,6 +1370,8 @@ _cleanup() { ip link set down dev "${SUBNET_IFACE}" + firewalld_del_tmpzone + if [[ $VWIFI_IFACE ]]; then # the subnet interface (virtual wifi interface) will be removed iw dev "${VWIFI_IFACE}" del dealloc_vface_name "$VWIFI_IFACE" @@ -1711,11 +1810,11 @@ decide_target_interface() { } decide_ip_addresses() { - if [[ ! -n $GATEWAY ]]; then - GATEWAY="$(generate_random_ip4)" - echo "Use random LAN IPv4 address $GATEWAY" - elif [[ ! "$GATEWAY" =~ "." ]]; then - GATEWAY="192.168.${GATEWAY}.1" + if [[ ! -n $GATEWAY4 ]]; then + GATEWAY4="$(generate_random_ip4)" + echo "Use random LAN IPv4 address $GATEWAY4" + elif [[ ! "$GATEWAY4" =~ "." ]]; then + GATEWAY4="192.168.${GATEWAY4}.1" fi if [[ $IPV6 -eq 1 && ! -n $PREFIX6 ]]; then @@ -1727,6 +1826,10 @@ decide_ip_addresses() { if [[ $IPV6 -eq 1 ]]; then GATEWAY6="${PREFIX6}${IID6}" fi + + SUBNET_NET4="${GATEWAY4%.*}.0/24" + [[ $IPV6 -eq 1 ]] && SUBNET_NET6="${PREFIX6}/64" + } prepare_wifi_interface() { @@ -1873,7 +1976,7 @@ write_hostapd_conf() { echo "ieee80211ax=1" >> "$CONFDIR/hostapd.conf" fi - if [[ $REQUIRE_HE -eq 1 ]]; then + if [[ $REQUIREHE -eq 1 ]]; then echo "require_he=1" >> "$CONFDIR/hostapd.conf" fi @@ -1943,6 +2046,7 @@ write_hostapd_conf() { } write_dnsmasq_conf() { + local i if grep "^nobody:" /etc/group >/dev/null 2>&1 ; then NOBODY_GROUP="nobody" else @@ -1957,12 +2061,12 @@ write_dnsmasq_conf() { user=nobody group=$NOBODY_GROUP bind-dynamic - listen-address=${GATEWAY} + listen-address=${GATEWAY4} 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} + dhcp-range=${GATEWAY4%.*}.10,${GATEWAY4%.*}.250,255.255.255.0 + dhcp-option-force=option:router,${GATEWAY4} #log-dhcp log-facility=$CONFDIR/dnsmasq.log bogus-priv @@ -1976,7 +2080,7 @@ write_dnsmasq_conf() { fi if [[ "$DHCP_DNS" != "no" ]]; then if [[ "$DHCP_DNS" == "gateway" ]]; then - dns_offer="$GATEWAY" + dns_offer="$GATEWAY4" else dns_offer="$DHCP_DNS" fi @@ -2052,8 +2156,9 @@ run_wifi_ap_processes() { echo echo "Starting hostapd" - if which complain > /dev/null 2>&1; then - complain hostapd + if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then + echo "Setting hostapd to AppArmor complain mode..." + "$COMPLAIN_CMD" hostapd fi # hostapd '-P' works only when use '-B' (run in background) @@ -2073,10 +2178,9 @@ start_dnsmasq() { echo echo "Starting dnsmasq" - if which complain > /dev/null 2>&1; then - # openSUSE's apparmor does not allow dnsmasq to read files. - # remove restriction. - complain dnsmasq + if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then + echo "Setting dnsmasq to AppArmor complain mode..." + "$COMPLAIN_CMD" dnsmasq fi # Using '-d'(no daemon) dnsmasq will not turn into 'nobody' @@ -2118,8 +2222,6 @@ ARGS=( "$@" ) parse_user_options "$@" # TODO: detect user option conflict -# check if networkManager running -NM_RUNNING="$(is_nm_running)" TMPDIR="$(decide_tmpdir)" @@ -2192,7 +2294,7 @@ fi #=================================================== # set interface unmanaged by networkManager -if [[ $NM_RUNNING -eq 1 ]] && nm_knows "$TARGET_IFACE"; then # if nm knows target iface, should know subnet iface too. but need to wait until nm finds subnet iface (waiting code is in nm_set_unmanaged() +if is_nm_running && nm_knows "$TARGET_IFACE"; then # if nm knows target iface, should know subnet iface too. but need to wait until nm finds subnet iface (waiting code is in nm_set_unmanaged() nm_set_unmanaged "${SUBNET_IFACE}" # will write NM_UNM_LIST fi @@ -2209,6 +2311,20 @@ dealwith_mac # setting MAC should be after setting NM unmanaged [[ $WIFI_IFACE ]] && check_rfkill_unblock_wifi + +echo +iptables --version +echo "Notice: Not showing all operations done to iptables rules" + +if [[ "$IPV6" -eq 0 ]]; then + IP_VERs=("4") +else + IP_VERs=("4" "6") +fi + +disable_unwanted_forwarding + + # bring subnet interface up ip link set up dev "${SUBNET_IFACE}" || die "Failed bringing ${SUBNET_IFACE} up" @@ -2216,7 +2332,7 @@ ip link set up dev "${SUBNET_IFACE}" || die "Failed bringing ${SUBNET_IFACE} up" [[ $WIFI_IFACE ]] && run_wifi_ap_processes # add ipv4 address to subnet interface -ip -4 addr add ${GATEWAY}/24 broadcast ${GATEWAY%.*}.255 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv4 address" +ip -4 addr add ${GATEWAY4}/24 broadcast ${GATEWAY4%.*}.255 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv4 address" set_ipv6_bits @@ -2225,25 +2341,15 @@ if [[ $IPV6 -eq 1 ]] ; then ip -6 addr add ${GATEWAY6}/64 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv6 address" fi -check_iptables - -echo "NOTICE: Not showing all operations done to iptables rules" - -[[ "$NO4" -eq 1 ]] && echo -e "\nWARN: Since you're using in this mode (no IPv4 Internet), make sure you've read Notice 1\n" >&2 # enable Internet sharing if [[ "$SHARE_METHOD" == "none" ]]; then echo "No Internet sharing" - echo -e "\nWARN: Since you're using in this mode (no Internet share), make sure you've read Notice 1\n" >&2 - [[ "$BANLAN" -eq 1 ]] && start_ban_lan elif [[ "$SHARE_METHOD" == "nat" ]]; then - - [[ "$INTERNET_IFACE" ]] && echo -e "\nWARN: Since you're using in this mode (specify Internet interface), make sure you've read Notice 1\n" >&2 - [[ "$INTERNET_IFACE" && "$dnsmasq_NO_DNS" -eq 0 ]] && echo -e "\nWARN: You specified Internet interface but this host is providing local DNS. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 start_nat @@ -2283,6 +2389,11 @@ fi [[ $NO_DNSMASQ -eq 0 ]] && ( allow_dhcp ; start_dnsmasq ) + +echo "" +is_firewalld_running && firewalld_add_tmpzone + + echo echo "== Setting up completed, now linux-router should be working ==" From 78934b8128c66a8fa65750dc2f8194e927b50494 Mon Sep 17 00:00:00 2001 From: Phani Pavan Kambhampati <60005847+kphanipavan@users.noreply.github.com> Date: Sat, 14 Jun 2025 12:06:58 +0530 Subject: [PATCH 03/12] fix channel detection --- lnxrouter | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lnxrouter b/lnxrouter index a71e0a6..a9d64a7 100755 --- a/lnxrouter +++ b/lnxrouter @@ -1,6 +1,6 @@ #!/bin/bash -VERSION=0.8.0-unstable0 +VERSION=0.8.0-unstable1 PROGNAME="$(basename "$0")" export LC_ALL=C @@ -664,15 +664,22 @@ can_be_ap() { } can_transmit_to_channel() { - local IFACE CHANNEL_NUM CHANNEL_INFO + local IFACE CHANNEL_NUM CHANNEL_INFO CHANNEL_FREQ_FILTER IFACE=$1 CHANNEL_NUM=$2 + if [[ $FREQ_BAND == "2.4" ]]; then + CHANNEL_FREQ_FILTER="(24)" + elif [[ $FREQ_BAND -eq 5 ]]; then + CHANNEL_FREQ_FILTER="(5[0-8])" + elif [[ $FREQ_BAND -eq 6 ]]; then + CHANNEL_FREQ_FILTER="((59)|(6[0-9])|(70))" + fi if [[ $USE_IWCONFIG -eq 0 ]]; then - CHANNEL_INFO=$(get_adapter_info "${IFACE}" | grep -E " [0-9]+(\.[0-9]+){0,1} MHz \[${CHANNEL_NUM}\]") + CHANNEL_INFO=$(get_adapter_info "${IFACE}" | grep -E " ${CHANNEL_FREQ_FILTER}[0-9]+(\.[0-9]+){0,1} MHz \[${CHANNEL_NUM}\]") [[ -z "${CHANNEL_INFO}" ]] && return 1 - [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1 - [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1 + [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 2 + [[ "${CHANNEL_INFO}" == *disabled* ]] && return 3 return 0 else CHANNEL_NUM=$(printf '%02d' ${CHANNEL_NUM}) From 60ce7d7e2e83eb40bb356227a74d5fdf68e251c3 Mon Sep 17 00:00:00 2001 From: garywill Date: Sun, 27 Jul 2025 14:06:05 +0800 Subject: [PATCH 04/12] can_transmit_to_channel: fix 5GHz and 6GHz freq range --- lnxrouter | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnxrouter b/lnxrouter index 68e23a3..7f3001e 100755 --- a/lnxrouter +++ b/lnxrouter @@ -670,9 +670,9 @@ can_transmit_to_channel() { if [[ $FREQ_BAND == "2.4" ]]; then CHANNEL_FREQ_FILTER="(24)" elif [[ $FREQ_BAND -eq 5 ]]; then - CHANNEL_FREQ_FILTER="(5[0-8])" + CHANNEL_FREQ_FILTER="(5[1-8])" elif [[ $FREQ_BAND -eq 6 ]]; then - CHANNEL_FREQ_FILTER="((59)|(6[0-9])|(70))" + CHANNEL_FREQ_FILTER="((59)|(6[0-9])|(7[0-1]))" fi if [[ $USE_IWCONFIG -eq 0 ]]; then From e34c91ba188b946208dc1ec332987d674a45624e Mon Sep 17 00:00:00 2001 From: garywill Date: Sun, 27 Jul 2025 14:06:39 +0800 Subject: [PATCH 05/12] can_transmit_to_channel: limit freq integer part to 4 digits --- lnxrouter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnxrouter b/lnxrouter index 7f3001e..1126d34 100755 --- a/lnxrouter +++ b/lnxrouter @@ -676,7 +676,7 @@ can_transmit_to_channel() { fi if [[ $USE_IWCONFIG -eq 0 ]]; then - CHANNEL_INFO=$(get_adapter_info "${IFACE}" | grep -E " ${CHANNEL_FREQ_FILTER}[0-9]+(\.[0-9]+){0,1} MHz \[${CHANNEL_NUM}\]") + CHANNEL_INFO=$(get_adapter_info "${IFACE}" | grep -E " ${CHANNEL_FREQ_FILTER}[0-9]{2}(\.[0-9]+){0,1} MHz \[${CHANNEL_NUM}\]") [[ -z "${CHANNEL_INFO}" ]] && return 1 [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 2 [[ "${CHANNEL_INFO}" == *disabled* ]] && return 3 From 57b07bb10e06c6e4e4c498113b32681d998b79c2 Mon Sep 17 00:00:00 2001 From: Phani Pavan Kambhampati <60005847+kphanipavan@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:04:42 +0530 Subject: [PATCH 06/12] enable wmm when wifi 6 is enabled --- lnxrouter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnxrouter b/lnxrouter index 4272219..3d974da 100755 --- a/lnxrouter +++ b/lnxrouter @@ -2051,7 +2051,7 @@ write_hostapd_conf() { EOF fi - if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then + if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]] || [[ $IEEE80211AX -eq 1 ]]; then echo "wmm_enabled=1" >> "$CONFDIR/hostapd.conf" fi From 8830b95cffc460cb19769630581e029c2be56f05 Mon Sep 17 00:00:00 2001 From: Phani Pavan K Date: Mon, 28 Jul 2025 11:35:11 +0530 Subject: [PATCH 07/12] lint remove stray spaces --- lnxrouter | 405 +++++++++++++++++++++++++++--------------------------- 1 file changed, 203 insertions(+), 202 deletions(-) diff --git a/lnxrouter b/lnxrouter index 3d974da..828622f 100755 --- a/lnxrouter +++ b/lnxrouter @@ -1,6 +1,6 @@ #!/bin/bash -VERSION=0.8.0-unstable1 +VERSION=0.8.0-unstable2 PROGNAME="$(basename "$0")" export LC_ALL=C @@ -33,17 +33,17 @@ Options: queries to other interfaces) -n Do not provide Internet --ban-priv Disallow clients to access my private network - + -g This host's IPv4 address in subnet (mask is /24) (example: '192.168.5.1' or '5' shortly) -6 Enable IPv6 (NAT) --no4 Disable IPv4 Internet (not forwarding IPv4). Usually used with '-6' - - --p6 Set IPv6 LAN address prefix (length 64) - (example: 'fd00:0:0:5::' or '5' shortly) + + --p6 Set IPv6 LAN address prefix (length 64) + (example: 'fd00:0:0:5::' or '5' shortly) Using this enables '-6' - + --dns || DNS server's upstream DNS. Use ',' to seperate multiple servers @@ -51,37 +51,37 @@ Options: (Note IPv6 addresses need '[]' around) --no-dns Do not serve DNS --no-dnsmasq Disable dnsmasq server (DHCP, DNS, RA) - --catch-dns Transparent DNS proxy, redirect packets(TCP/UDP) + --catch-dns Transparent DNS proxy, redirect packets(TCP/UDP) whose destination port is 53 to this host --log-dns Show DNS query log (dnsmasq) --dhcp-dns |no Set IPv4 DNS offered by DHCP (default: this host). --dhcp-dns6 |no - Set IPv6 DNS offered by DHCP (RA) + Set IPv6 DNS offered by DHCP (RA) (default: this host) (Note IPv6 addresses need '[]' around) - Using both above two will enable '--no-dns' + Using both above two will enable '--no-dns' --hostname DNS server associate this name with this host. Use '-' to read name from /etc/hostname -d DNS server will take into account /etc/hosts - -e DNS server will take into account additional + -e DNS server will take into account additional hosts file --dns-nocache DNS server no cache - + --mac Set MAC address --random-mac Use random MAC address - + --tp Transparent proxy, redirect non-LAN TCP and UDP(not tested) traffic to port. (usually used with '--dns') - + WiFi hotspot options: --ap Create WiFi access point - -p, --password + -p, --password WiFi password --qr Show WiFi QR code in terminal (need qrencode) - + --hidden Hide access point (not broadcast SSID) --no-virt Do not create virtual interface Using this you can't use same wlan interface @@ -113,44 +113,44 @@ Options: --wifi5 Enable IEEE 802.11ac (VHT) --req-vht Require station VHT (Very High Thoughtput) mode --vht-capab VHT capabilities - + --vht-ch-width Index of VHT channel width: 0 for 20MHz or 40MHz (default) 1 for 80MHz 2 for 160MHz - 3 for 80+80MHz (Non-contigous 160MHz) - --vht-seg0-ch Channel index of VHT center frequency for primary + 3 for 80+80MHz (Non-contigous 160MHz) + --vht-seg0-ch Channel index of VHT center frequency for primary segment. Use with '--vht-ch-width' --vht-seg1-ch Channel index of VHT center frequency for secondary (second 80MHz) segment. Use with '--vht-ch-width 3' - + WiFi 6 (802.11ax) configs: --wifi6 Enable IEEE 802.11ax (HE) --req-he Require station HE (High Efficiency) mode - + --he-ch-width Index of HE channel width: 0 for 20MHz or 40MHz (default) 1 for 80MHz 2 for 160MHz - 3 for 80+80MHz (Non-contigous 160MHz) + 3 for 80+80MHz (Non-contigous 160MHz) --he-seg0-ch Channel index of HE center frequency for primary segment. Use with '--he-ch-width' --he-seg1-ch Channel index of HE center frequency for secondary (second 80MHz) segment. Use with '--he-ch-width 3' - + Instance managing: --daemon Run in background --keep-confdir Don't delete the temporary config dir after exit -l, --list-running Show running instances - --lc, --list-clients + --lc, --list-clients List clients of an instance. Or list neighbors of an interface, even if it isn't handled by us. (passive mode) --stop Stop a running instance For you can use PID or subnet interface name. You can get them with '--list-running' - + Examples: $PROGNAME -i eth1 $PROGNAME --ap wlan0 MyAccessPoint -p MyPassPhrase @@ -185,26 +185,26 @@ define_global_variables(){ DNS_NOCACHE= 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 + THISHOSTNAME= # this host's name the DNS tells clients TP_PORT= # transparent proxy port DNS= # upstream DNS MAC_USE_RANDOM=0 NEW_MACADDR= DAEMONIZE=0 - + # script variables SUBNET_IFACE= # which interface to create network - SHARE_METHOD=nat + SHARE_METHOD=nat OLD_MACADDR= SUBNET_NET4= SUBNET_NET6= - + ##### wifi hotspot # user options HIDDEN=0 # hidden wifi hotspot WIFI_IFACE= - CHANNEL=default + CHANNEL=default HOTSPOT20=0 # For enabling Hotspot 2.0 WPA_VERSION=2 MAC_FILTER=0 @@ -232,7 +232,7 @@ define_global_variables(){ USE_PSK=0 ISOLATE_CLIENTS=0 QR=0 # show wifi qr - + # script variables PHY= VWIFI_IFACE= # virtual wifi interface name, if created @@ -240,7 +240,7 @@ define_global_variables(){ AP_IFACE= # can be VWIFI_IFACE or WIFI_IFACE USE_IWCONFIG=0 # some device can't use iw ####### - + #-- to deal with info of a running instance. then will exit LIST_RUNNING=0 STOP_ID= @@ -291,8 +291,8 @@ parse_user_options(){ SHARE_METHOD=redsocks shift ;; - - + + -g) shift GATEWAY4="$1" @@ -321,7 +321,7 @@ parse_user_options(){ shift MAC_USE_RANDOM=1 ;; - + --dns) shift DNS="$1" @@ -348,7 +348,7 @@ parse_user_options(){ --catch-dns) shift CATCH_DNS=1 - ;; + ;; --log-dns) shift SHOW_DNS_QUERY=1 @@ -371,12 +371,12 @@ parse_user_options(){ shift DNS_NOCACHE=1 ;; - + --isolate-clients) shift ISOLATE_CLIENTS=1 ;; - + --ap) shift WIFI_IFACE="$1" @@ -393,8 +393,8 @@ parse_user_options(){ shift QR=1 ;; - - + + --hidden) shift HIDDEN=1 @@ -580,7 +580,7 @@ sep_ip_port() { local PORT local INPUT INPUT="$1" - if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then + if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then if (echo "$INPUT" | grep ':' >/dev/null 2>&1) ;then # ipv4 + port IP="$(echo "$INPUT" | cut -d: -f1)" @@ -589,7 +589,7 @@ sep_ip_port() { # ipv4 IP="$INPUT" fi - elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then + elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then if (echo "$INPUT" | grep '\]\:' >/dev/null 2>&1) ;then # ipv6 + port IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" @@ -598,7 +598,7 @@ sep_ip_port() { # ipv6 IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" fi - else + else # port IP='127.0.0.1' PORT="$INPUT" @@ -745,35 +745,35 @@ get_interface_mac() { show_interface_pci_info() { # pci id / model / virtual is_interface "$1" || return - + local device_path local bus_id="" local device_type_and_bus_id="unknown" local driver="" local device_fullname="" - + device_path="$(readlink -f /sys/class/net/$1)" - + if [[ "$device_path" == "/sys/devices/pci"* ]]; then local pci_path pci_path=$device_path/../.. - + if [[ -d "$pci_path/driver" ]] ; then driver=$(readlink -f "$pci_path/driver" | sed 's/\//\n/g' | tail -n 1) fi - + bus_id="$(echo "$device_path" | sed 's/\//\n/g' | tail -n 3 |sed -n 1p)" device_type_and_bus_id="PCI: $bus_id" - + if which lspci >/dev/null 2>&1 ; then device_fullname="$( lspci -D -nn -s "$bus_id" | awk '{$1="" ; print $0}' )" fi - + elif [[ "$device_path" == *"/virtual/"* ]]; then device_type_and_bus_id="virtual interface" fi - + echo "$device_type_and_bus_id" [[ -n "$driver" ]] && echo "System-already-loaded driver: $driver" [[ -n "$device_fullname" ]] && echo "$device_fullname" @@ -820,7 +820,7 @@ get_new_macaddr_according_to_existing() { } generate_random_mac() { - local r1 r2 r3 r4 r5 r6 + local r1 r2 r3 r4 r5 r6 local RAND_MAC while :; do r1=$( printf "%02x" $(($RANDOM%256/4*4)) ) @@ -905,7 +905,7 @@ pid_watchdog() { local ERR_MSG="$3" local ST while true - do + do if [[ -e "/proc/$PID" ]]; then ST="$(cat "/proc/$PID/status" | grep "^State:" | awk '{print $2}')" if [[ "$ST" != 'Z' ]]; then @@ -915,18 +915,18 @@ pid_watchdog() { fi die "$ERR_MSG" done - + } #======== get_pid_by_dbus_name() { local DBUS_NAME="$1" local pid r - + which dbus-send >/dev/null 2>&1 || return 1 - + pid="$( dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetConnectionUnixProcessID string:$DBUS_NAME 2>/dev/null | grep " uint32 " | awk '{print $2}' )" r=$? - + echo "$pid" return $r } @@ -940,15 +940,15 @@ is_same_netns() { # only support NetworkManager >= 0.9.9 is_nm_running() { NM_PID="$(get_pid_by_dbus_name "org.freedesktop.NetworkManager")" - + [[ ! -n "$NM_PID" ]] && return 1 # not running - + if (which nmcli >/dev/null 2>&1 ) && (nmcli -t -f RUNNING g 2>&1 | grep -E '^running$' >/dev/null 2>&1 ) ; then if is_same_netns "$NM_PID"; then return 0 fi fi - + NM_PID= # cancel value if treat as not running return 1 # not running } @@ -989,9 +989,9 @@ nm_restore_manage() { #------- is_firewalld_running() { FIREWALLD_PID="$(get_pid_by_dbus_name "org.fedoraproject.FirewallD1")" - + [[ ! -n "$FIREWALLD_PID" ]] && return 1 # not running - + if (which firewall-cmd >/dev/null 2>&1 ) && [[ "$(firewall-cmd --state 2>&1)" == "running" ]] ; then if is_same_netns "$FIREWALLD_PID"; then echo "firewalld is running ($(firewall-cmd --version))" @@ -1022,7 +1022,7 @@ CUSTOM_CHAINS_4_filter= CUSTOM_CHAINS_4_nat= CUSTOM_CHAINS_6_filter= CUSTOM_CHAINS_6_nat= -iptb() +iptb() { local FoS=$1 # 4 | 6 shift @@ -1034,26 +1034,26 @@ iptb() shift local CH=$1 # chain shift - + [[ "$IPV6" -ne 1 && "$FoS" == "6" ]] && return - + local CMD_HEAD="" local MOUTH="" local NECK="" local HAND_UN_NC=0 local TAIL="" - + local FULL="" local ADD_TO_UNDO=1 - + local arr_name w - + for arr_name in CUSTOM_CHAINS_4_filter CUSTOM_CHAINS_4_nat CUSTOM_CHAINS_6_filter CUSTOM_CHAINS_6_nat do local arr_content eval arr_content=\"\${$arr_name}\" #echo $arr_content - + for w in $arr_content do if [[ "$arr_name" =~ "$FoS" && "$arr_name" =~ "$T" && "$w" == "$CH" ]]; then @@ -1061,37 +1061,37 @@ iptb() fi done done - + [[ "$FoS" == "4" ]] && CMD_HEAD="iptables -w " [[ "$FoS" == "6" ]] && CMD_HEAD="ip6tables -w " - + [[ "$Vis" == 'v' ]] && MOUTH="-v" - + NECK="-t ${T}" - + if [[ "$ACT" == "N" ]]; then eval CUSTOM_CHAINS_${FoS}_${T}=\"\${CUSTOM_CHAINS_${FoS}_${T}} ${CH}\" HAND_UN_NC=1 fi - - - + + + [[ ! "$NETFILTER_XT_MATCH_COMMENT" == "0" ]] && TAIL="-m comment --comment lrt${$}${SUBNET_IFACE}" - + if [[ "$ADD_TO_UNDO" -eq 1 ]]; then if [[ "$ACT" == "I" || "$ACT" == "A" ]]; then - echo "$CMD_HEAD $NECK -D ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables.sh + echo "$CMD_HEAD $NECK -D ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables.sh fi - + if [[ "$HAND_UN_NC" -eq 1 ]]; then echo "$CMD_HEAD $NECK -F ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables_2.sh echo "$CMD_HEAD $NECK -X ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables_2.sh fi fi - - - + + + FULL="$CMD_HEAD $MOUTH $NECK -${ACT} ${CH} $@ $TAIL" #echo $FULL @@ -1109,40 +1109,40 @@ disable_unwanted_forwarding() { ! -i "$INTERNET_IFACE" -o "$SUBNET_IFACE" \ -j REJECT || die fi - + if [[ "$SHARE_METHOD" == 'redsocks' || "$SHARE_METHOD" == 'none' \ || ( "$iv" -eq "4" && "$NO4" -eq 1 ) ]];then iptb "$iv" n filter I FORWARD -i "$SUBNET_IFACE" -j REJECT || die iptb "$iv" n filter I FORWARD -o "$SUBNET_IFACE" -j REJECT || die fi done - + } start_nat() { local SUBNET_NET - + local iv echo echo "iptables: NAT " - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" - + if [[ -n "$INTERNET_IFACE" ]]; then # only one Internet interface # masquerade subnet -> internet iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ -o "$INTERNET_IFACE" \ -j MASQUERADE || die - + # forward subnet -> internet iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ -o $INTERNET_IFACE \ -j ACCEPT || die - + # forward any -> subnet iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ -i "$INTERNET_IFACE" \ @@ -1152,32 +1152,32 @@ start_nat() { iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ ! -o "$SUBNET_IFACE" \ -j MASQUERADE || die - + # forward subnet -> any iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ -j ACCEPT || die - + # forward any -> subnet iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ -j ACCEPT || die fi - done + done } start_ban_lan() { local arr_nets_to_protect local ICMP_NAME local iv s - + echo echo "iptables: Disallow clients to access LAN" - + for iv in "${IP_VERs[@]}"; do # ban forwarding for subnet iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLF || die # TODO: allow '--dhcp-dns(6)' address port 53, which can be something needed, e.g. a VPN's internal private IP if [[ "$iv" -eq "4" ]]; then - arr_nets_to_protect=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") + arr_nets_to_protect=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") ICMP_NAME="icmp" elif [[ "$iv" -eq "6" ]]; then arr_nets_to_protect=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::/128" "::ffff:0:0/96" "::ffff:0:0:0/96") @@ -1187,7 +1187,7 @@ start_ban_lan() { iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLF -d "$s" -j REJECT || die done iptb "$iv" n filter I FORWARD -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLF || die - + # ban input from subnet iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLI || die iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLI -i ${SUBNET_IFACE} ! -p "$ICMP_NAME" -j REJECT || die # ipv6 need icmp to function. TODO: maybe we can block some unneeded icmp to improve security @@ -1202,14 +1202,14 @@ allow_dns_port() { local PROTs local iv pt - + echo echo "iptables: allow DNS" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" @@ -1218,7 +1218,7 @@ allow_dns_port() { for pt in "${PROTs[@]}"; do iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j ACCEPT || die done - done + done } @@ -1229,11 +1229,11 @@ start_catch_dns() { echo echo "iptables: redirect DNS queries to this host" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" - + PROTs=("tcp" "udp") for pt in "${PROTs[@]}"; do iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" ! -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j REDIRECT --to-ports 53 || die @@ -1243,9 +1243,9 @@ start_catch_dns() { allow_dhcp() { - echo + echo echo "iptables: allow dhcp" - + iptb 4 v filter I INPUT -i ${SUBNET_IFACE} -p udp -m udp --dport 67 -j ACCEPT || die iptb 6 v filter I INPUT -i ${SUBNET_IFACE} -p udp -m udp --dport 547 -j ACCEPT || die } @@ -1255,25 +1255,25 @@ start_redsocks() { local SUBNET_NET local arr_nets_to_ignore local s iv - + echo echo "iptables: transparent proxy non-LAN TCP and UDP(not tested) traffic to port ${TP_PORT}" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" - - + + iptb "$iv" n nat N lrt${$}${SUBNET_IFACE}-TP || die - + if [[ "$iv" -eq "4" ]]; then arr_nets_to_ignore=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") elif [[ "$iv" -eq "6" ]];then arr_nets_to_ignore=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::") fi - + for s in "${arr_nets_to_ignore[@]}"; do iptb "$iv" n nat A lrt${$}${SUBNET_IFACE}-TP -d "$s" -j RETURN || die done @@ -1283,7 +1283,7 @@ start_redsocks() { iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" -s "$SUBNET_NET" -j lrt${$}${SUBNET_IFACE}-TP || die - + iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p tcp -m tcp --dport ${TP_PORT} -j ACCEPT || die iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p udp -m udp --dport ${TP_PORT} -j ACCEPT || die done @@ -1297,7 +1297,7 @@ backup_ipv6_bits() { "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr" \ "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode" \ "$CONFDIR/sys_6_conf_iface/" || die "Failed backing up interface ipv6 bits" - + if [[ "$SHARE_METHOD" == 'redsocks' ]] ; then cp "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/forwarding" \ "$CONFDIR/sys_6_conf_iface/" || die "Failed backking up interface ipv6 bits" @@ -1322,45 +1322,45 @@ restore_ipv6_bits() { set_interface_mac() { local INTERFACE local MAC - + INTERFACE=$1 MAC=$2 - - ip link set dev "${INTERFACE}" address "${MAC}" + + ip link set dev "${INTERFACE}" address "${MAC}" } backup_interface_status() { # virtual wifi interface will be destroyed, so no need to save status - + # backup interface up or down status (ip link show "${SUBNET_IFACE}" |grep -q "state UP") && SUBNET_IFACE_ORIGINAL_UP_STATUS=1 - - # save interface old mac - #if [[ -n "$NEW_MACADDR" ]]; then + + # save interface old mac + #if [[ -n "$NEW_MACADDR" ]]; then OLD_MACADDR=$(get_interface_mac "$SUBNET_IFACE") #echo "Saved ${SUBNET_IFACE} old MAC address ${OLD_MACADDR} into RAM" #fi - + backup_ipv6_bits - + # TODO : ? backup ip and others??? - + # nm managing status is saved when nm_set_unmanaged() } restore_interface_status() { # virtual wifi interface will be destroyed, so no need to restore status # don't use [[ $VWIFI_IFACE ]] to judge, if creating virtual wifi failed, VWIFI_IFACE is empty [[ "$WIFI_IFACE" && "$NO_VIRT" -eq 0 ]] && return - + restore_ipv6_bits if [[ -n "$OLD_MACADDR" && "$(get_interface_mac "$SUBNET_IFACE")" != "$OLD_MACADDR" ]] ; then echo "Restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR} ..." set_interface_mac "${SUBNET_IFACE}" "${OLD_MACADDR}" || echo "Failed restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR}" >&2 fi - + nm_restore_manage - + [[ $SUBNET_IFACE_ORIGINAL_UP_STATUS -eq 1 ]] && ip link set up dev "${SUBNET_IFACE}" && echo "Restore ${SUBNET_IFACE} to link up" } #--------------------------------------- @@ -1373,7 +1373,7 @@ kill_processes() { # for this instance # a value in $x. so we need to check if the value is a file if [[ -f $x ]] && sleep 0.3 && [[ -f $x ]]; then pid=$(cat "$x") - pn=$( ps -p "$pid" -o comm= ) + pn=$( ps -p "$pid" -o comm= ) #echo "Killing $pid $pn ... " pkill -P "$pid" kill "$pid" 2>/dev/null && ( echo "Killed $(basename "$x") $pid $pn" && rm "$x" ) || echo "Failed to kill $(basename "$x") $pid $pn, it may have exited" @@ -1385,27 +1385,27 @@ _cleanup() { local x ip addr flush "${SUBNET_IFACE}" - + [[ ! "$KEEP_CONFDIR" -eq 1 ]] && rm -rf "$CONFDIR" - + ip link set down dev "${SUBNET_IFACE}" - + firewalld_del_tmpzone - + if [[ $VWIFI_IFACE ]]; then # the subnet interface (virtual wifi interface) will be removed iw dev "${VWIFI_IFACE}" del dealloc_vface_name "$VWIFI_IFACE" fi - + restore_interface_status - + if ! has_running_instance; then echo "Exiting: This is the only running instance" # kill common processes for x in $COMMON_CONFDIR/*.pid; do [[ -f $x ]] && kill -9 $(cat "$x") && rm "$x" done - + rm -d "$COMMON_CONFDIR/vfaces" rm -d "$COMMON_CONFDIR" rm -d "$TMPDIR" @@ -1416,7 +1416,7 @@ _cleanup() { clean_iptables() { [[ -f $CONFDIR/undo_iptables.sh ]] && bash $CONFDIR/undo_iptables.sh - + [[ -f $CONFDIR/undo_iptables_2.sh ]] && bash $CONFDIR/undo_iptables_2.sh } @@ -1430,11 +1430,11 @@ cleanup() { echo "Undoing iptables changes .." clean_iptables > /dev/null _cleanup 2> /dev/null - + #pgid=$(ps opgid= $$ |awk '{print $1}' ) #echo "Killing PGID $pgid ..." #kill -15 -$pgid - #sleep 1 + #sleep 1 echo "Cleaning up done" #kill -9 -$pgid } @@ -1526,7 +1526,7 @@ print_clients_from_leases() { # MAC|IP|HOST|lease local FILEC local line local LEASEstr LEASEstamp - + FILEC="$(cat "$LEASE_FILE" | grep -v -E "^duid\b" | sed -r '/^\s*$/d' )" # TODO: duid is somewhat related to ipv6. I don't know about it. Not sure excluding it miss some info or not @@ -1537,31 +1537,31 @@ print_clients_from_leases() { # MAC|IP|HOST|lease MAC="$(echo "$line" | awk '{print $2}')" IP="$(echo "$line" | awk '{print $3}' | sed 's/\[//g' | sed 's/\]//g')" HOST="$(echo "$line" | awk '{print $4}' | sed 's/*/?/g' | sed 's/|/_/g' | sed 's/ /_/g' )" - + if [[ -n "$MAC" ]]; then LEASEstr="$(date -d @${LEASEstamp} +%m-%d_%X)" - + echo "$MAC|$IP|$HOST|lease_$LEASEstr" fi done - + } -print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS +print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS local IFACE=$1 - + local line - + ip n | grep -E "\bdev $IFACE\b" | sed 's/ /|/g' | while read -r line do local MAC IP STATUS - + IP="$(echo "$line" | awk -F'|' '{print $1}')" - + if [[ "$(echo "$line" | awk -F'|' '{print $4}')" == "lladdr" ]]; then # has mac # if has mac, $4="lladdr" and $5=macaddress and $6+=status MAC="$(echo "$line" | awk -F'|' '{print $5}')" STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";$5="";{print}' | awk '{$1=$1;print}'| sed 's/ /,/g')" - else # no mac + else # no mac # if no mac, $4="" and $5+=status MAC="?" STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";{print}' | awk '{$1=$1;print}' | sed 's/ /,/g')" @@ -1571,7 +1571,7 @@ print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS fi done } -print_interface_neighbors_via_iw() { # MAC|_|_|signal +print_interface_neighbors_via_iw() { # MAC|_|_|signal local IFACE=$1 local MAC SIGNAL iw dev "$IFACE" station dump | awk '($1 ~ /Station$/) {print $2}' | while read -r MAC @@ -1586,14 +1586,14 @@ print_interface_neighbors_via_iw() { # MAC|_|_|signal list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active mode) local IFACE pid local CONFDIR - + local output="" # If number (PID) is given, get the associated wifi iface if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then pid="$1" IFACE=$(get_subn_iface_from_pid "$pid") if [[ -z "$IFACE" ]] ; then - echo "'$pid' is not the pid of a running $PROGNAME instance." >&2 + echo "'$pid' is not the pid of a running $PROGNAME instance." >&2 exit 1 fi else # non-number given @@ -1612,14 +1612,14 @@ list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active fi output="$(echo "$output" ; print_interface_neighbors_via_iw "$IFACE") " output="$(echo "$output" ; print_interface_neighbors_via_iproute "$IFACE")" - + output="$(echo "$output" | sort -k 1 -k 2 -t '|' | uniq | sed -r '/^\s*$/d')" echo "$IFACE ($(get_interface_mac "$IFACE")) neighbors:" - + local fmt="%-19s%-41s%-20s%s" # string length: MAC 17, ipv4 15, ipv6 39, hostname ? printf "$fmt\n" "MAC" "IP" "HOSTNAME" "INFO" - + local line echo "$output"| while read -r line do @@ -1732,14 +1732,14 @@ check_wifi_settings() { echo "WARN: Can't use 'iw' to operate interfce '$WIFI_IFACE', trying 'iwconfig' (not as good as 'iw') ..." >&2 USE_IWCONFIG=1 fi - + if [[ $USE_IWCONFIG -eq 1 ]]; then if ! (which iwconfig > /dev/null 2>&1 && iwconfig "$WIFI_IFACE" > /dev/null 2>&1); then echo "ERROR: Can't use 'iwconfig' to operate interfce '$WIFI_IFACE'" >&2 exit 1 fi fi - + if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then echo "ERROR: Invalid frequency band" >&2 exit 1 @@ -1778,7 +1778,7 @@ check_wifi_settings() { DRIVER=rtl871xdrv fi fi - + if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2 exit 1 @@ -1854,32 +1854,32 @@ decide_ip_addresses() { if [[ $IPV6 -eq 1 ]]; then GATEWAY6="${PREFIX6}${IID6}" fi - + SUBNET_NET4="${GATEWAY4%.*}.0/24" [[ $IPV6 -eq 1 ]] && SUBNET_NET6="${PREFIX6}/64" - + } prepare_wifi_interface() { if [[ $USE_IWCONFIG -eq 0 ]]; then iw dev "${WIFI_IFACE}" set power_save off fi - + if [[ $NO_VIRT -eq 0 ]]; then ## Will generate virtual wifi interface - + # TODO move this to check_wifi_settings() ? if is_interface_wifi_connected "${WIFI_IFACE}"; then WIFI_IFACE_FREQ=$(iw dev "${WIFI_IFACE}" link | grep -i freq | awk '{print $2}' | sed 's/\.00*$//g') # NOTE we assume integer currently, which can be right, or wrong in the future WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel "${WIFI_IFACE_FREQ}") - + echo "${WIFI_IFACE} already working in channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" - + if [[ $CHANNEL == default ]]; then echo "Use wifi adapter current channel $WIFI_IFACE_CHANNEL as target channel" CHANNEL=$WIFI_IFACE_CHANNEL fi - + if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then echo "WARN: Wifi adapter already working in channel ${WIFI_IFACE_CHANNEL}, which is different than target channel $CHANNEL" >&2 fi @@ -1890,7 +1890,7 @@ prepare_wifi_interface() { if iw dev "${WIFI_IFACE}" interface add "${VWIFI_IFACE}" type __ap; then # Successfully created virtual wifi interface # if NM running, it will give the new virtual interface a random MAC. MAC will go back after setting NM unmanaged - sleep 2 + sleep 2 echo "${VWIFI_IFACE} created" else VWIFI_IFACE= @@ -1902,12 +1902,12 @@ prepare_wifi_interface() { die "Failed creating virtual WiFi interface. Maybe your WiFi adapter does not fully support virtual interfaces. Try again with '--no-virt'" fi fi - + AP_IFACE=${VWIFI_IFACE} else # no virtual wifi interface, use wifi device interface itself AP_IFACE=${WIFI_IFACE} fi - + if [[ $CHANNEL == default ]]; then echo "Channel not specified, use default" if [[ $FREQ_BAND == 2.4 ]]; then @@ -1930,12 +1930,12 @@ decide_subnet_interface() { dealwith_mac() { local VMAC - - if [[ -n "$NEW_MACADDR" ]] ; then # user choose to set subnet mac + + if [[ -n "$NEW_MACADDR" ]] ; then # user choose to set subnet mac echo "Setting ${SUBNET_IFACE} new MAC address ${NEW_MACADDR} ..." set_interface_mac "${SUBNET_IFACE}" "${NEW_MACADDR}" || die "Failed setting new MAC address" - + elif [[ $VWIFI_IFACE ]]; then # user didn't choose to set mac, but using virtual wifi interface VMAC=$(get_new_macaddr_according_to_existing "${WIFI_IFACE}") @@ -1946,7 +1946,7 @@ dealwith_mac() { fi } -write_hostapd_conf() { +write_hostapd_conf() { cat <<- EOF > "$CONFDIR/hostapd.conf" beacon_int=100 ssid=${SSID} @@ -2011,6 +2011,7 @@ write_hostapd_conf() { fi + if [[ -n "$VHT_CAPAB" ]]; then echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf" fi @@ -2082,11 +2083,11 @@ write_dnsmasq_conf() { else NOBODY_GROUP="nogroup" fi - + mkfifo "$CONFDIR/dnsmasq.log" || die "Failed creating pipe file for dnsmasq" chown nobody "$CONFDIR/dnsmasq.log" || die "Failed changing dnsmasq log file owner" - cat "$CONFDIR/dnsmasq.log" & - + cat "$CONFDIR/dnsmasq.log" & + cat <<- EOF > "$CONFDIR/dnsmasq.conf" user=nobody group=$NOBODY_GROUP @@ -2104,7 +2105,7 @@ write_dnsmasq_conf() { EOF # 'log-dhcp'(Extra logging for DHCP) shows too much logs. # if use '-d', 'log-facility' should = /dev/null - if [[ $SHARE_METHOD == "none" ]]; then + if [[ $SHARE_METHOD == "none" ]]; then echo "no-resolv" >> "$CONFDIR/dnsmasq.conf" echo "no-poll" >> "$CONFDIR/dnsmasq.conf" fi @@ -2116,7 +2117,7 @@ write_dnsmasq_conf() { 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 @@ -2131,7 +2132,7 @@ write_dnsmasq_conf() { 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 @@ -2139,7 +2140,7 @@ write_dnsmasq_conf() { [[ "$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 @@ -2173,7 +2174,7 @@ run_wifi_ap_processes() { HAVEGED_WATCHDOG_PID=$! echo "$HAVEGED_WATCHDOG_PID" > "$CONFDIR/haveged_watchdog.pid" echo - echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" + echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" fi # start access point @@ -2183,14 +2184,14 @@ run_wifi_ap_processes() { if [ $? -eq 0 ]; then STDBUF_PATH=$STDBUF_PATH" -oL" fi - echo + echo echo "Starting hostapd" - + if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then echo "Setting hostapd to AppArmor complain mode..." "$COMPLAIN_CMD" hostapd fi - + # 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=$! @@ -2205,17 +2206,17 @@ run_wifi_ap_processes() { } start_dnsmasq() { - echo + echo echo "Starting dnsmasq" - + if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then echo "Setting dnsmasq to AppArmor complain mode..." "$COMPLAIN_CMD" dnsmasq fi - + # 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 -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 @@ -2224,7 +2225,7 @@ start_dnsmasq() { if [[ $i -gt 10 ]]; then die "Couldn't get dnsmasq PID" ; fi done DNSMASQ_PID="$(cat "$CONFDIR/dnsmasq.pid" )" - echo "dnsmasq PID: $DNSMASQ_PID" + echo "dnsmasq PID: $DNSMASQ_PID" ######(wait $DNSMASQ_PID ; die "dnsmasq failed") & # wait can't deal with non-child pid_watchdog "$DNSMASQ_PID" 9 "dnsmasq failed" & sleep 2 @@ -2239,7 +2240,7 @@ check_rfkill_unblock_wifi() { #=========== Above are functions ====================== #=========== Executing begin ============================== -# if empty option, show usage and exit +# if empty option, show usage and exit check_empty_option "$@" # TODO: are some global variables are still defined in those following code? @@ -2253,12 +2254,12 @@ parse_user_options "$@" TMPDIR="$(decide_tmpdir)" -# if user choose to deal with running instances, will output some info then exit after this +# if user choose to deal with running instances, will output some info then exit after this # NOTE above don't require root -check_other_functions +check_other_functions # NOTE below require root -# if user choose to daemonize, will start new background process and exit this +# if user choose to daemonize, will start new background process and exit this daemonizing_check # check if wifi will work on this system and user settings @@ -2350,7 +2351,7 @@ else IP_VERs=("4" "6") fi -disable_unwanted_forwarding +disable_unwanted_forwarding # bring subnet interface up @@ -2374,36 +2375,36 @@ fi if [[ "$SHARE_METHOD" == "none" ]]; then echo "No Internet sharing" - + [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + 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. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 - + start_nat - + [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + echo 1 > "/proc/sys/net/ipv4/ip_forward" || die "Failed enabling system ipv4 forwarding" # TODO maybe uneeded in '--no4' mode - + if [[ $IPV6 -eq 1 ]]; then echo 1 > "/proc/sys/net/ipv6/conf/all/forwarding" || die "Failed enabling system ipv6 forwarding" # TODO if '-o' used, set only 2 interfaces' bits fi - + # to enable clients to establish PPTP connections we must # load nf_nat_pptp module modprobe nf_nat_pptp > /dev/null 2>&1 && echo "Loaded kernel module nf_nat_pptp" - + 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" # to set NA router bit fi - + [[ "$dnsmasq_NO_DNS" -eq 0 && ! $DNS ]] && echo -e "\nWARN: You are using in transparent proxy mode but this host is providing local DNS. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + start_redsocks fi @@ -2422,7 +2423,7 @@ echo "" is_firewalld_running && firewalld_add_tmpzone -echo +echo echo "== Setting up completed, now linux-router should be working ==" #============================================================ From 77feb7e3bac540ba258fdf07dfb3cde2d19f2c7e Mon Sep 17 00:00:00 2001 From: garywill Date: Mon, 28 Jul 2025 14:15:18 +0800 Subject: [PATCH 08/12] Revert "lint remove stray spaces" This reverts commit 8830b95cffc460cb19769630581e029c2be56f05. --- lnxrouter | 405 +++++++++++++++++++++++++++--------------------------- 1 file changed, 202 insertions(+), 203 deletions(-) diff --git a/lnxrouter b/lnxrouter index 828622f..3d974da 100755 --- a/lnxrouter +++ b/lnxrouter @@ -1,6 +1,6 @@ #!/bin/bash -VERSION=0.8.0-unstable2 +VERSION=0.8.0-unstable1 PROGNAME="$(basename "$0")" export LC_ALL=C @@ -33,17 +33,17 @@ Options: queries to other interfaces) -n Do not provide Internet --ban-priv Disallow clients to access my private network - + -g This host's IPv4 address in subnet (mask is /24) (example: '192.168.5.1' or '5' shortly) -6 Enable IPv6 (NAT) --no4 Disable IPv4 Internet (not forwarding IPv4). Usually used with '-6' - - --p6 Set IPv6 LAN address prefix (length 64) - (example: 'fd00:0:0:5::' or '5' shortly) + + --p6 Set IPv6 LAN address prefix (length 64) + (example: 'fd00:0:0:5::' or '5' shortly) Using this enables '-6' - + --dns || DNS server's upstream DNS. Use ',' to seperate multiple servers @@ -51,37 +51,37 @@ Options: (Note IPv6 addresses need '[]' around) --no-dns Do not serve DNS --no-dnsmasq Disable dnsmasq server (DHCP, DNS, RA) - --catch-dns Transparent DNS proxy, redirect packets(TCP/UDP) + --catch-dns Transparent DNS proxy, redirect packets(TCP/UDP) whose destination port is 53 to this host --log-dns Show DNS query log (dnsmasq) --dhcp-dns |no Set IPv4 DNS offered by DHCP (default: this host). --dhcp-dns6 |no - Set IPv6 DNS offered by DHCP (RA) + Set IPv6 DNS offered by DHCP (RA) (default: this host) (Note IPv6 addresses need '[]' around) - Using both above two will enable '--no-dns' + Using both above two will enable '--no-dns' --hostname DNS server associate this name with this host. Use '-' to read name from /etc/hostname -d DNS server will take into account /etc/hosts - -e DNS server will take into account additional + -e DNS server will take into account additional hosts file --dns-nocache DNS server no cache - + --mac Set MAC address --random-mac Use random MAC address - + --tp Transparent proxy, redirect non-LAN TCP and UDP(not tested) traffic to port. (usually used with '--dns') - + WiFi hotspot options: --ap Create WiFi access point - -p, --password + -p, --password WiFi password --qr Show WiFi QR code in terminal (need qrencode) - + --hidden Hide access point (not broadcast SSID) --no-virt Do not create virtual interface Using this you can't use same wlan interface @@ -113,44 +113,44 @@ Options: --wifi5 Enable IEEE 802.11ac (VHT) --req-vht Require station VHT (Very High Thoughtput) mode --vht-capab VHT capabilities - + --vht-ch-width Index of VHT channel width: 0 for 20MHz or 40MHz (default) 1 for 80MHz 2 for 160MHz - 3 for 80+80MHz (Non-contigous 160MHz) - --vht-seg0-ch Channel index of VHT center frequency for primary + 3 for 80+80MHz (Non-contigous 160MHz) + --vht-seg0-ch Channel index of VHT center frequency for primary segment. Use with '--vht-ch-width' --vht-seg1-ch Channel index of VHT center frequency for secondary (second 80MHz) segment. Use with '--vht-ch-width 3' - + WiFi 6 (802.11ax) configs: --wifi6 Enable IEEE 802.11ax (HE) --req-he Require station HE (High Efficiency) mode - + --he-ch-width Index of HE channel width: 0 for 20MHz or 40MHz (default) 1 for 80MHz 2 for 160MHz - 3 for 80+80MHz (Non-contigous 160MHz) + 3 for 80+80MHz (Non-contigous 160MHz) --he-seg0-ch Channel index of HE center frequency for primary segment. Use with '--he-ch-width' --he-seg1-ch Channel index of HE center frequency for secondary (second 80MHz) segment. Use with '--he-ch-width 3' - + Instance managing: --daemon Run in background --keep-confdir Don't delete the temporary config dir after exit -l, --list-running Show running instances - --lc, --list-clients + --lc, --list-clients List clients of an instance. Or list neighbors of an interface, even if it isn't handled by us. (passive mode) --stop Stop a running instance For you can use PID or subnet interface name. You can get them with '--list-running' - + Examples: $PROGNAME -i eth1 $PROGNAME --ap wlan0 MyAccessPoint -p MyPassPhrase @@ -185,26 +185,26 @@ define_global_variables(){ DNS_NOCACHE= 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 + THISHOSTNAME= # this host's name the DNS tells clients TP_PORT= # transparent proxy port DNS= # upstream DNS MAC_USE_RANDOM=0 NEW_MACADDR= DAEMONIZE=0 - + # script variables SUBNET_IFACE= # which interface to create network - SHARE_METHOD=nat + SHARE_METHOD=nat OLD_MACADDR= SUBNET_NET4= SUBNET_NET6= - + ##### wifi hotspot # user options HIDDEN=0 # hidden wifi hotspot WIFI_IFACE= - CHANNEL=default + CHANNEL=default HOTSPOT20=0 # For enabling Hotspot 2.0 WPA_VERSION=2 MAC_FILTER=0 @@ -232,7 +232,7 @@ define_global_variables(){ USE_PSK=0 ISOLATE_CLIENTS=0 QR=0 # show wifi qr - + # script variables PHY= VWIFI_IFACE= # virtual wifi interface name, if created @@ -240,7 +240,7 @@ define_global_variables(){ AP_IFACE= # can be VWIFI_IFACE or WIFI_IFACE USE_IWCONFIG=0 # some device can't use iw ####### - + #-- to deal with info of a running instance. then will exit LIST_RUNNING=0 STOP_ID= @@ -291,8 +291,8 @@ parse_user_options(){ SHARE_METHOD=redsocks shift ;; - - + + -g) shift GATEWAY4="$1" @@ -321,7 +321,7 @@ parse_user_options(){ shift MAC_USE_RANDOM=1 ;; - + --dns) shift DNS="$1" @@ -348,7 +348,7 @@ parse_user_options(){ --catch-dns) shift CATCH_DNS=1 - ;; + ;; --log-dns) shift SHOW_DNS_QUERY=1 @@ -371,12 +371,12 @@ parse_user_options(){ shift DNS_NOCACHE=1 ;; - + --isolate-clients) shift ISOLATE_CLIENTS=1 ;; - + --ap) shift WIFI_IFACE="$1" @@ -393,8 +393,8 @@ parse_user_options(){ shift QR=1 ;; - - + + --hidden) shift HIDDEN=1 @@ -580,7 +580,7 @@ sep_ip_port() { local PORT local INPUT INPUT="$1" - if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then + if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then if (echo "$INPUT" | grep ':' >/dev/null 2>&1) ;then # ipv4 + port IP="$(echo "$INPUT" | cut -d: -f1)" @@ -589,7 +589,7 @@ sep_ip_port() { # ipv4 IP="$INPUT" fi - elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then + elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then if (echo "$INPUT" | grep '\]\:' >/dev/null 2>&1) ;then # ipv6 + port IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" @@ -598,7 +598,7 @@ sep_ip_port() { # ipv6 IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" fi - else + else # port IP='127.0.0.1' PORT="$INPUT" @@ -745,35 +745,35 @@ get_interface_mac() { show_interface_pci_info() { # pci id / model / virtual is_interface "$1" || return - + local device_path local bus_id="" local device_type_and_bus_id="unknown" local driver="" local device_fullname="" - + device_path="$(readlink -f /sys/class/net/$1)" - + if [[ "$device_path" == "/sys/devices/pci"* ]]; then local pci_path pci_path=$device_path/../.. - + if [[ -d "$pci_path/driver" ]] ; then driver=$(readlink -f "$pci_path/driver" | sed 's/\//\n/g' | tail -n 1) fi - + bus_id="$(echo "$device_path" | sed 's/\//\n/g' | tail -n 3 |sed -n 1p)" device_type_and_bus_id="PCI: $bus_id" - + if which lspci >/dev/null 2>&1 ; then device_fullname="$( lspci -D -nn -s "$bus_id" | awk '{$1="" ; print $0}' )" fi - + elif [[ "$device_path" == *"/virtual/"* ]]; then device_type_and_bus_id="virtual interface" fi - + echo "$device_type_and_bus_id" [[ -n "$driver" ]] && echo "System-already-loaded driver: $driver" [[ -n "$device_fullname" ]] && echo "$device_fullname" @@ -820,7 +820,7 @@ get_new_macaddr_according_to_existing() { } generate_random_mac() { - local r1 r2 r3 r4 r5 r6 + local r1 r2 r3 r4 r5 r6 local RAND_MAC while :; do r1=$( printf "%02x" $(($RANDOM%256/4*4)) ) @@ -905,7 +905,7 @@ pid_watchdog() { local ERR_MSG="$3" local ST while true - do + do if [[ -e "/proc/$PID" ]]; then ST="$(cat "/proc/$PID/status" | grep "^State:" | awk '{print $2}')" if [[ "$ST" != 'Z' ]]; then @@ -915,18 +915,18 @@ pid_watchdog() { fi die "$ERR_MSG" done - + } #======== get_pid_by_dbus_name() { local DBUS_NAME="$1" local pid r - + which dbus-send >/dev/null 2>&1 || return 1 - + pid="$( dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetConnectionUnixProcessID string:$DBUS_NAME 2>/dev/null | grep " uint32 " | awk '{print $2}' )" r=$? - + echo "$pid" return $r } @@ -940,15 +940,15 @@ is_same_netns() { # only support NetworkManager >= 0.9.9 is_nm_running() { NM_PID="$(get_pid_by_dbus_name "org.freedesktop.NetworkManager")" - + [[ ! -n "$NM_PID" ]] && return 1 # not running - + if (which nmcli >/dev/null 2>&1 ) && (nmcli -t -f RUNNING g 2>&1 | grep -E '^running$' >/dev/null 2>&1 ) ; then if is_same_netns "$NM_PID"; then return 0 fi fi - + NM_PID= # cancel value if treat as not running return 1 # not running } @@ -989,9 +989,9 @@ nm_restore_manage() { #------- is_firewalld_running() { FIREWALLD_PID="$(get_pid_by_dbus_name "org.fedoraproject.FirewallD1")" - + [[ ! -n "$FIREWALLD_PID" ]] && return 1 # not running - + if (which firewall-cmd >/dev/null 2>&1 ) && [[ "$(firewall-cmd --state 2>&1)" == "running" ]] ; then if is_same_netns "$FIREWALLD_PID"; then echo "firewalld is running ($(firewall-cmd --version))" @@ -1022,7 +1022,7 @@ CUSTOM_CHAINS_4_filter= CUSTOM_CHAINS_4_nat= CUSTOM_CHAINS_6_filter= CUSTOM_CHAINS_6_nat= -iptb() +iptb() { local FoS=$1 # 4 | 6 shift @@ -1034,26 +1034,26 @@ iptb() shift local CH=$1 # chain shift - + [[ "$IPV6" -ne 1 && "$FoS" == "6" ]] && return - + local CMD_HEAD="" local MOUTH="" local NECK="" local HAND_UN_NC=0 local TAIL="" - + local FULL="" local ADD_TO_UNDO=1 - + local arr_name w - + for arr_name in CUSTOM_CHAINS_4_filter CUSTOM_CHAINS_4_nat CUSTOM_CHAINS_6_filter CUSTOM_CHAINS_6_nat do local arr_content eval arr_content=\"\${$arr_name}\" #echo $arr_content - + for w in $arr_content do if [[ "$arr_name" =~ "$FoS" && "$arr_name" =~ "$T" && "$w" == "$CH" ]]; then @@ -1061,37 +1061,37 @@ iptb() fi done done - + [[ "$FoS" == "4" ]] && CMD_HEAD="iptables -w " [[ "$FoS" == "6" ]] && CMD_HEAD="ip6tables -w " - + [[ "$Vis" == 'v' ]] && MOUTH="-v" - + NECK="-t ${T}" - + if [[ "$ACT" == "N" ]]; then eval CUSTOM_CHAINS_${FoS}_${T}=\"\${CUSTOM_CHAINS_${FoS}_${T}} ${CH}\" HAND_UN_NC=1 fi - - - + + + [[ ! "$NETFILTER_XT_MATCH_COMMENT" == "0" ]] && TAIL="-m comment --comment lrt${$}${SUBNET_IFACE}" - + if [[ "$ADD_TO_UNDO" -eq 1 ]]; then if [[ "$ACT" == "I" || "$ACT" == "A" ]]; then - echo "$CMD_HEAD $NECK -D ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables.sh + echo "$CMD_HEAD $NECK -D ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables.sh fi - + if [[ "$HAND_UN_NC" -eq 1 ]]; then echo "$CMD_HEAD $NECK -F ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables_2.sh echo "$CMD_HEAD $NECK -X ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables_2.sh fi fi - - - + + + FULL="$CMD_HEAD $MOUTH $NECK -${ACT} ${CH} $@ $TAIL" #echo $FULL @@ -1109,40 +1109,40 @@ disable_unwanted_forwarding() { ! -i "$INTERNET_IFACE" -o "$SUBNET_IFACE" \ -j REJECT || die fi - + if [[ "$SHARE_METHOD" == 'redsocks' || "$SHARE_METHOD" == 'none' \ || ( "$iv" -eq "4" && "$NO4" -eq 1 ) ]];then iptb "$iv" n filter I FORWARD -i "$SUBNET_IFACE" -j REJECT || die iptb "$iv" n filter I FORWARD -o "$SUBNET_IFACE" -j REJECT || die fi done - + } start_nat() { local SUBNET_NET - + local iv echo echo "iptables: NAT " - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" - + if [[ -n "$INTERNET_IFACE" ]]; then # only one Internet interface # masquerade subnet -> internet iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ -o "$INTERNET_IFACE" \ -j MASQUERADE || die - + # forward subnet -> internet iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ -o $INTERNET_IFACE \ -j ACCEPT || die - + # forward any -> subnet iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ -i "$INTERNET_IFACE" \ @@ -1152,32 +1152,32 @@ start_nat() { iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ ! -o "$SUBNET_IFACE" \ -j MASQUERADE || die - + # forward subnet -> any iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ -j ACCEPT || die - + # forward any -> subnet iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ -j ACCEPT || die fi - done + done } start_ban_lan() { local arr_nets_to_protect local ICMP_NAME local iv s - + echo echo "iptables: Disallow clients to access LAN" - + for iv in "${IP_VERs[@]}"; do # ban forwarding for subnet iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLF || die # TODO: allow '--dhcp-dns(6)' address port 53, which can be something needed, e.g. a VPN's internal private IP if [[ "$iv" -eq "4" ]]; then - arr_nets_to_protect=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") + arr_nets_to_protect=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") ICMP_NAME="icmp" elif [[ "$iv" -eq "6" ]]; then arr_nets_to_protect=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::/128" "::ffff:0:0/96" "::ffff:0:0:0/96") @@ -1187,7 +1187,7 @@ start_ban_lan() { iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLF -d "$s" -j REJECT || die done iptb "$iv" n filter I FORWARD -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLF || die - + # ban input from subnet iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLI || die iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLI -i ${SUBNET_IFACE} ! -p "$ICMP_NAME" -j REJECT || die # ipv6 need icmp to function. TODO: maybe we can block some unneeded icmp to improve security @@ -1202,14 +1202,14 @@ allow_dns_port() { local PROTs local iv pt - + echo echo "iptables: allow DNS" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" @@ -1218,7 +1218,7 @@ allow_dns_port() { for pt in "${PROTs[@]}"; do iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j ACCEPT || die done - done + done } @@ -1229,11 +1229,11 @@ start_catch_dns() { echo echo "iptables: redirect DNS queries to this host" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" - + PROTs=("tcp" "udp") for pt in "${PROTs[@]}"; do iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" ! -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j REDIRECT --to-ports 53 || die @@ -1243,9 +1243,9 @@ start_catch_dns() { allow_dhcp() { - echo + echo echo "iptables: allow dhcp" - + iptb 4 v filter I INPUT -i ${SUBNET_IFACE} -p udp -m udp --dport 67 -j ACCEPT || die iptb 6 v filter I INPUT -i ${SUBNET_IFACE} -p udp -m udp --dport 547 -j ACCEPT || die } @@ -1255,25 +1255,25 @@ start_redsocks() { local SUBNET_NET local arr_nets_to_ignore local s iv - + echo echo "iptables: transparent proxy non-LAN TCP and UDP(not tested) traffic to port ${TP_PORT}" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" - - + + iptb "$iv" n nat N lrt${$}${SUBNET_IFACE}-TP || die - + if [[ "$iv" -eq "4" ]]; then arr_nets_to_ignore=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") elif [[ "$iv" -eq "6" ]];then arr_nets_to_ignore=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::") fi - + for s in "${arr_nets_to_ignore[@]}"; do iptb "$iv" n nat A lrt${$}${SUBNET_IFACE}-TP -d "$s" -j RETURN || die done @@ -1283,7 +1283,7 @@ start_redsocks() { iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" -s "$SUBNET_NET" -j lrt${$}${SUBNET_IFACE}-TP || die - + iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p tcp -m tcp --dport ${TP_PORT} -j ACCEPT || die iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p udp -m udp --dport ${TP_PORT} -j ACCEPT || die done @@ -1297,7 +1297,7 @@ backup_ipv6_bits() { "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr" \ "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode" \ "$CONFDIR/sys_6_conf_iface/" || die "Failed backing up interface ipv6 bits" - + if [[ "$SHARE_METHOD" == 'redsocks' ]] ; then cp "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/forwarding" \ "$CONFDIR/sys_6_conf_iface/" || die "Failed backking up interface ipv6 bits" @@ -1322,45 +1322,45 @@ restore_ipv6_bits() { set_interface_mac() { local INTERFACE local MAC - + INTERFACE=$1 MAC=$2 - - ip link set dev "${INTERFACE}" address "${MAC}" + + ip link set dev "${INTERFACE}" address "${MAC}" } backup_interface_status() { # virtual wifi interface will be destroyed, so no need to save status - + # backup interface up or down status (ip link show "${SUBNET_IFACE}" |grep -q "state UP") && SUBNET_IFACE_ORIGINAL_UP_STATUS=1 - - # save interface old mac - #if [[ -n "$NEW_MACADDR" ]]; then + + # save interface old mac + #if [[ -n "$NEW_MACADDR" ]]; then OLD_MACADDR=$(get_interface_mac "$SUBNET_IFACE") #echo "Saved ${SUBNET_IFACE} old MAC address ${OLD_MACADDR} into RAM" #fi - + backup_ipv6_bits - + # TODO : ? backup ip and others??? - + # nm managing status is saved when nm_set_unmanaged() } restore_interface_status() { # virtual wifi interface will be destroyed, so no need to restore status # don't use [[ $VWIFI_IFACE ]] to judge, if creating virtual wifi failed, VWIFI_IFACE is empty [[ "$WIFI_IFACE" && "$NO_VIRT" -eq 0 ]] && return - + restore_ipv6_bits if [[ -n "$OLD_MACADDR" && "$(get_interface_mac "$SUBNET_IFACE")" != "$OLD_MACADDR" ]] ; then echo "Restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR} ..." set_interface_mac "${SUBNET_IFACE}" "${OLD_MACADDR}" || echo "Failed restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR}" >&2 fi - + nm_restore_manage - + [[ $SUBNET_IFACE_ORIGINAL_UP_STATUS -eq 1 ]] && ip link set up dev "${SUBNET_IFACE}" && echo "Restore ${SUBNET_IFACE} to link up" } #--------------------------------------- @@ -1373,7 +1373,7 @@ kill_processes() { # for this instance # a value in $x. so we need to check if the value is a file if [[ -f $x ]] && sleep 0.3 && [[ -f $x ]]; then pid=$(cat "$x") - pn=$( ps -p "$pid" -o comm= ) + pn=$( ps -p "$pid" -o comm= ) #echo "Killing $pid $pn ... " pkill -P "$pid" kill "$pid" 2>/dev/null && ( echo "Killed $(basename "$x") $pid $pn" && rm "$x" ) || echo "Failed to kill $(basename "$x") $pid $pn, it may have exited" @@ -1385,27 +1385,27 @@ _cleanup() { local x ip addr flush "${SUBNET_IFACE}" - + [[ ! "$KEEP_CONFDIR" -eq 1 ]] && rm -rf "$CONFDIR" - + ip link set down dev "${SUBNET_IFACE}" - + firewalld_del_tmpzone - + if [[ $VWIFI_IFACE ]]; then # the subnet interface (virtual wifi interface) will be removed iw dev "${VWIFI_IFACE}" del dealloc_vface_name "$VWIFI_IFACE" fi - + restore_interface_status - + if ! has_running_instance; then echo "Exiting: This is the only running instance" # kill common processes for x in $COMMON_CONFDIR/*.pid; do [[ -f $x ]] && kill -9 $(cat "$x") && rm "$x" done - + rm -d "$COMMON_CONFDIR/vfaces" rm -d "$COMMON_CONFDIR" rm -d "$TMPDIR" @@ -1416,7 +1416,7 @@ _cleanup() { clean_iptables() { [[ -f $CONFDIR/undo_iptables.sh ]] && bash $CONFDIR/undo_iptables.sh - + [[ -f $CONFDIR/undo_iptables_2.sh ]] && bash $CONFDIR/undo_iptables_2.sh } @@ -1430,11 +1430,11 @@ cleanup() { echo "Undoing iptables changes .." clean_iptables > /dev/null _cleanup 2> /dev/null - + #pgid=$(ps opgid= $$ |awk '{print $1}' ) #echo "Killing PGID $pgid ..." #kill -15 -$pgid - #sleep 1 + #sleep 1 echo "Cleaning up done" #kill -9 -$pgid } @@ -1526,7 +1526,7 @@ print_clients_from_leases() { # MAC|IP|HOST|lease local FILEC local line local LEASEstr LEASEstamp - + FILEC="$(cat "$LEASE_FILE" | grep -v -E "^duid\b" | sed -r '/^\s*$/d' )" # TODO: duid is somewhat related to ipv6. I don't know about it. Not sure excluding it miss some info or not @@ -1537,31 +1537,31 @@ print_clients_from_leases() { # MAC|IP|HOST|lease MAC="$(echo "$line" | awk '{print $2}')" IP="$(echo "$line" | awk '{print $3}' | sed 's/\[//g' | sed 's/\]//g')" HOST="$(echo "$line" | awk '{print $4}' | sed 's/*/?/g' | sed 's/|/_/g' | sed 's/ /_/g' )" - + if [[ -n "$MAC" ]]; then LEASEstr="$(date -d @${LEASEstamp} +%m-%d_%X)" - + echo "$MAC|$IP|$HOST|lease_$LEASEstr" fi done - + } -print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS +print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS local IFACE=$1 - + local line - + ip n | grep -E "\bdev $IFACE\b" | sed 's/ /|/g' | while read -r line do local MAC IP STATUS - + IP="$(echo "$line" | awk -F'|' '{print $1}')" - + if [[ "$(echo "$line" | awk -F'|' '{print $4}')" == "lladdr" ]]; then # has mac # if has mac, $4="lladdr" and $5=macaddress and $6+=status MAC="$(echo "$line" | awk -F'|' '{print $5}')" STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";$5="";{print}' | awk '{$1=$1;print}'| sed 's/ /,/g')" - else # no mac + else # no mac # if no mac, $4="" and $5+=status MAC="?" STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";{print}' | awk '{$1=$1;print}' | sed 's/ /,/g')" @@ -1571,7 +1571,7 @@ print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS fi done } -print_interface_neighbors_via_iw() { # MAC|_|_|signal +print_interface_neighbors_via_iw() { # MAC|_|_|signal local IFACE=$1 local MAC SIGNAL iw dev "$IFACE" station dump | awk '($1 ~ /Station$/) {print $2}' | while read -r MAC @@ -1586,14 +1586,14 @@ print_interface_neighbors_via_iw() { # MAC|_|_|signal list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active mode) local IFACE pid local CONFDIR - + local output="" # If number (PID) is given, get the associated wifi iface if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then pid="$1" IFACE=$(get_subn_iface_from_pid "$pid") if [[ -z "$IFACE" ]] ; then - echo "'$pid' is not the pid of a running $PROGNAME instance." >&2 + echo "'$pid' is not the pid of a running $PROGNAME instance." >&2 exit 1 fi else # non-number given @@ -1612,14 +1612,14 @@ list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active fi output="$(echo "$output" ; print_interface_neighbors_via_iw "$IFACE") " output="$(echo "$output" ; print_interface_neighbors_via_iproute "$IFACE")" - + output="$(echo "$output" | sort -k 1 -k 2 -t '|' | uniq | sed -r '/^\s*$/d')" echo "$IFACE ($(get_interface_mac "$IFACE")) neighbors:" - + local fmt="%-19s%-41s%-20s%s" # string length: MAC 17, ipv4 15, ipv6 39, hostname ? printf "$fmt\n" "MAC" "IP" "HOSTNAME" "INFO" - + local line echo "$output"| while read -r line do @@ -1732,14 +1732,14 @@ check_wifi_settings() { echo "WARN: Can't use 'iw' to operate interfce '$WIFI_IFACE', trying 'iwconfig' (not as good as 'iw') ..." >&2 USE_IWCONFIG=1 fi - + if [[ $USE_IWCONFIG -eq 1 ]]; then if ! (which iwconfig > /dev/null 2>&1 && iwconfig "$WIFI_IFACE" > /dev/null 2>&1); then echo "ERROR: Can't use 'iwconfig' to operate interfce '$WIFI_IFACE'" >&2 exit 1 fi fi - + if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then echo "ERROR: Invalid frequency band" >&2 exit 1 @@ -1778,7 +1778,7 @@ check_wifi_settings() { DRIVER=rtl871xdrv fi fi - + if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2 exit 1 @@ -1854,32 +1854,32 @@ decide_ip_addresses() { if [[ $IPV6 -eq 1 ]]; then GATEWAY6="${PREFIX6}${IID6}" fi - + SUBNET_NET4="${GATEWAY4%.*}.0/24" [[ $IPV6 -eq 1 ]] && SUBNET_NET6="${PREFIX6}/64" - + } prepare_wifi_interface() { if [[ $USE_IWCONFIG -eq 0 ]]; then iw dev "${WIFI_IFACE}" set power_save off fi - + if [[ $NO_VIRT -eq 0 ]]; then ## Will generate virtual wifi interface - + # TODO move this to check_wifi_settings() ? if is_interface_wifi_connected "${WIFI_IFACE}"; then WIFI_IFACE_FREQ=$(iw dev "${WIFI_IFACE}" link | grep -i freq | awk '{print $2}' | sed 's/\.00*$//g') # NOTE we assume integer currently, which can be right, or wrong in the future WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel "${WIFI_IFACE_FREQ}") - + echo "${WIFI_IFACE} already working in channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" - + if [[ $CHANNEL == default ]]; then echo "Use wifi adapter current channel $WIFI_IFACE_CHANNEL as target channel" CHANNEL=$WIFI_IFACE_CHANNEL fi - + if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then echo "WARN: Wifi adapter already working in channel ${WIFI_IFACE_CHANNEL}, which is different than target channel $CHANNEL" >&2 fi @@ -1890,7 +1890,7 @@ prepare_wifi_interface() { if iw dev "${WIFI_IFACE}" interface add "${VWIFI_IFACE}" type __ap; then # Successfully created virtual wifi interface # if NM running, it will give the new virtual interface a random MAC. MAC will go back after setting NM unmanaged - sleep 2 + sleep 2 echo "${VWIFI_IFACE} created" else VWIFI_IFACE= @@ -1902,12 +1902,12 @@ prepare_wifi_interface() { die "Failed creating virtual WiFi interface. Maybe your WiFi adapter does not fully support virtual interfaces. Try again with '--no-virt'" fi fi - + AP_IFACE=${VWIFI_IFACE} else # no virtual wifi interface, use wifi device interface itself AP_IFACE=${WIFI_IFACE} fi - + if [[ $CHANNEL == default ]]; then echo "Channel not specified, use default" if [[ $FREQ_BAND == 2.4 ]]; then @@ -1930,12 +1930,12 @@ decide_subnet_interface() { dealwith_mac() { local VMAC - - if [[ -n "$NEW_MACADDR" ]] ; then # user choose to set subnet mac + + if [[ -n "$NEW_MACADDR" ]] ; then # user choose to set subnet mac echo "Setting ${SUBNET_IFACE} new MAC address ${NEW_MACADDR} ..." set_interface_mac "${SUBNET_IFACE}" "${NEW_MACADDR}" || die "Failed setting new MAC address" - + elif [[ $VWIFI_IFACE ]]; then # user didn't choose to set mac, but using virtual wifi interface VMAC=$(get_new_macaddr_according_to_existing "${WIFI_IFACE}") @@ -1946,7 +1946,7 @@ dealwith_mac() { fi } -write_hostapd_conf() { +write_hostapd_conf() { cat <<- EOF > "$CONFDIR/hostapd.conf" beacon_int=100 ssid=${SSID} @@ -2011,7 +2011,6 @@ write_hostapd_conf() { fi - if [[ -n "$VHT_CAPAB" ]]; then echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf" fi @@ -2083,11 +2082,11 @@ write_dnsmasq_conf() { else NOBODY_GROUP="nogroup" fi - + mkfifo "$CONFDIR/dnsmasq.log" || die "Failed creating pipe file for dnsmasq" chown nobody "$CONFDIR/dnsmasq.log" || die "Failed changing dnsmasq log file owner" - cat "$CONFDIR/dnsmasq.log" & - + cat "$CONFDIR/dnsmasq.log" & + cat <<- EOF > "$CONFDIR/dnsmasq.conf" user=nobody group=$NOBODY_GROUP @@ -2105,7 +2104,7 @@ write_dnsmasq_conf() { EOF # 'log-dhcp'(Extra logging for DHCP) shows too much logs. # if use '-d', 'log-facility' should = /dev/null - if [[ $SHARE_METHOD == "none" ]]; then + if [[ $SHARE_METHOD == "none" ]]; then echo "no-resolv" >> "$CONFDIR/dnsmasq.conf" echo "no-poll" >> "$CONFDIR/dnsmasq.conf" fi @@ -2117,7 +2116,7 @@ write_dnsmasq_conf() { 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 @@ -2132,7 +2131,7 @@ write_dnsmasq_conf() { 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 @@ -2140,7 +2139,7 @@ write_dnsmasq_conf() { [[ "$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 @@ -2174,7 +2173,7 @@ run_wifi_ap_processes() { HAVEGED_WATCHDOG_PID=$! echo "$HAVEGED_WATCHDOG_PID" > "$CONFDIR/haveged_watchdog.pid" echo - echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" + echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" fi # start access point @@ -2184,14 +2183,14 @@ run_wifi_ap_processes() { if [ $? -eq 0 ]; then STDBUF_PATH=$STDBUF_PATH" -oL" fi - echo + echo echo "Starting hostapd" - + if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then echo "Setting hostapd to AppArmor complain mode..." "$COMPLAIN_CMD" hostapd fi - + # 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=$! @@ -2206,17 +2205,17 @@ run_wifi_ap_processes() { } start_dnsmasq() { - echo + echo echo "Starting dnsmasq" - + if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then echo "Setting dnsmasq to AppArmor complain mode..." "$COMPLAIN_CMD" dnsmasq fi - + # 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 -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 @@ -2225,7 +2224,7 @@ start_dnsmasq() { if [[ $i -gt 10 ]]; then die "Couldn't get dnsmasq PID" ; fi done DNSMASQ_PID="$(cat "$CONFDIR/dnsmasq.pid" )" - echo "dnsmasq PID: $DNSMASQ_PID" + echo "dnsmasq PID: $DNSMASQ_PID" ######(wait $DNSMASQ_PID ; die "dnsmasq failed") & # wait can't deal with non-child pid_watchdog "$DNSMASQ_PID" 9 "dnsmasq failed" & sleep 2 @@ -2240,7 +2239,7 @@ check_rfkill_unblock_wifi() { #=========== Above are functions ====================== #=========== Executing begin ============================== -# if empty option, show usage and exit +# if empty option, show usage and exit check_empty_option "$@" # TODO: are some global variables are still defined in those following code? @@ -2254,12 +2253,12 @@ parse_user_options "$@" TMPDIR="$(decide_tmpdir)" -# if user choose to deal with running instances, will output some info then exit after this +# if user choose to deal with running instances, will output some info then exit after this # NOTE above don't require root -check_other_functions +check_other_functions # NOTE below require root -# if user choose to daemonize, will start new background process and exit this +# if user choose to daemonize, will start new background process and exit this daemonizing_check # check if wifi will work on this system and user settings @@ -2351,7 +2350,7 @@ else IP_VERs=("4" "6") fi -disable_unwanted_forwarding +disable_unwanted_forwarding # bring subnet interface up @@ -2375,36 +2374,36 @@ fi if [[ "$SHARE_METHOD" == "none" ]]; then echo "No Internet sharing" - + [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + 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. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 - + start_nat - + [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + echo 1 > "/proc/sys/net/ipv4/ip_forward" || die "Failed enabling system ipv4 forwarding" # TODO maybe uneeded in '--no4' mode - + if [[ $IPV6 -eq 1 ]]; then echo 1 > "/proc/sys/net/ipv6/conf/all/forwarding" || die "Failed enabling system ipv6 forwarding" # TODO if '-o' used, set only 2 interfaces' bits fi - + # to enable clients to establish PPTP connections we must # load nf_nat_pptp module modprobe nf_nat_pptp > /dev/null 2>&1 && echo "Loaded kernel module nf_nat_pptp" - + 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" # to set NA router bit fi - + [[ "$dnsmasq_NO_DNS" -eq 0 && ! $DNS ]] && echo -e "\nWARN: You are using in transparent proxy mode but this host is providing local DNS. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + start_redsocks fi @@ -2423,7 +2422,7 @@ echo "" is_firewalld_running && firewalld_add_tmpzone -echo +echo echo "== Setting up completed, now linux-router should be working ==" #============================================================ From 4ea93a1fa2faaf89d6c7ba634dde15370e6532ad Mon Sep 17 00:00:00 2001 From: Phani Pavan K Date: Mon, 28 Jul 2025 12:26:14 +0530 Subject: [PATCH 09/12] to resolve merge conflicts --- lnxrouter | 405 +++++++++++++++++++++++++++--------------------------- 1 file changed, 203 insertions(+), 202 deletions(-) diff --git a/lnxrouter b/lnxrouter index 3d974da..828622f 100755 --- a/lnxrouter +++ b/lnxrouter @@ -1,6 +1,6 @@ #!/bin/bash -VERSION=0.8.0-unstable1 +VERSION=0.8.0-unstable2 PROGNAME="$(basename "$0")" export LC_ALL=C @@ -33,17 +33,17 @@ Options: queries to other interfaces) -n Do not provide Internet --ban-priv Disallow clients to access my private network - + -g This host's IPv4 address in subnet (mask is /24) (example: '192.168.5.1' or '5' shortly) -6 Enable IPv6 (NAT) --no4 Disable IPv4 Internet (not forwarding IPv4). Usually used with '-6' - - --p6 Set IPv6 LAN address prefix (length 64) - (example: 'fd00:0:0:5::' or '5' shortly) + + --p6 Set IPv6 LAN address prefix (length 64) + (example: 'fd00:0:0:5::' or '5' shortly) Using this enables '-6' - + --dns || DNS server's upstream DNS. Use ',' to seperate multiple servers @@ -51,37 +51,37 @@ Options: (Note IPv6 addresses need '[]' around) --no-dns Do not serve DNS --no-dnsmasq Disable dnsmasq server (DHCP, DNS, RA) - --catch-dns Transparent DNS proxy, redirect packets(TCP/UDP) + --catch-dns Transparent DNS proxy, redirect packets(TCP/UDP) whose destination port is 53 to this host --log-dns Show DNS query log (dnsmasq) --dhcp-dns |no Set IPv4 DNS offered by DHCP (default: this host). --dhcp-dns6 |no - Set IPv6 DNS offered by DHCP (RA) + Set IPv6 DNS offered by DHCP (RA) (default: this host) (Note IPv6 addresses need '[]' around) - Using both above two will enable '--no-dns' + Using both above two will enable '--no-dns' --hostname DNS server associate this name with this host. Use '-' to read name from /etc/hostname -d DNS server will take into account /etc/hosts - -e DNS server will take into account additional + -e DNS server will take into account additional hosts file --dns-nocache DNS server no cache - + --mac Set MAC address --random-mac Use random MAC address - + --tp Transparent proxy, redirect non-LAN TCP and UDP(not tested) traffic to port. (usually used with '--dns') - + WiFi hotspot options: --ap Create WiFi access point - -p, --password + -p, --password WiFi password --qr Show WiFi QR code in terminal (need qrencode) - + --hidden Hide access point (not broadcast SSID) --no-virt Do not create virtual interface Using this you can't use same wlan interface @@ -113,44 +113,44 @@ Options: --wifi5 Enable IEEE 802.11ac (VHT) --req-vht Require station VHT (Very High Thoughtput) mode --vht-capab VHT capabilities - + --vht-ch-width Index of VHT channel width: 0 for 20MHz or 40MHz (default) 1 for 80MHz 2 for 160MHz - 3 for 80+80MHz (Non-contigous 160MHz) - --vht-seg0-ch Channel index of VHT center frequency for primary + 3 for 80+80MHz (Non-contigous 160MHz) + --vht-seg0-ch Channel index of VHT center frequency for primary segment. Use with '--vht-ch-width' --vht-seg1-ch Channel index of VHT center frequency for secondary (second 80MHz) segment. Use with '--vht-ch-width 3' - + WiFi 6 (802.11ax) configs: --wifi6 Enable IEEE 802.11ax (HE) --req-he Require station HE (High Efficiency) mode - + --he-ch-width Index of HE channel width: 0 for 20MHz or 40MHz (default) 1 for 80MHz 2 for 160MHz - 3 for 80+80MHz (Non-contigous 160MHz) + 3 for 80+80MHz (Non-contigous 160MHz) --he-seg0-ch Channel index of HE center frequency for primary segment. Use with '--he-ch-width' --he-seg1-ch Channel index of HE center frequency for secondary (second 80MHz) segment. Use with '--he-ch-width 3' - + Instance managing: --daemon Run in background --keep-confdir Don't delete the temporary config dir after exit -l, --list-running Show running instances - --lc, --list-clients + --lc, --list-clients List clients of an instance. Or list neighbors of an interface, even if it isn't handled by us. (passive mode) --stop Stop a running instance For you can use PID or subnet interface name. You can get them with '--list-running' - + Examples: $PROGNAME -i eth1 $PROGNAME --ap wlan0 MyAccessPoint -p MyPassPhrase @@ -185,26 +185,26 @@ define_global_variables(){ DNS_NOCACHE= 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 + THISHOSTNAME= # this host's name the DNS tells clients TP_PORT= # transparent proxy port DNS= # upstream DNS MAC_USE_RANDOM=0 NEW_MACADDR= DAEMONIZE=0 - + # script variables SUBNET_IFACE= # which interface to create network - SHARE_METHOD=nat + SHARE_METHOD=nat OLD_MACADDR= SUBNET_NET4= SUBNET_NET6= - + ##### wifi hotspot # user options HIDDEN=0 # hidden wifi hotspot WIFI_IFACE= - CHANNEL=default + CHANNEL=default HOTSPOT20=0 # For enabling Hotspot 2.0 WPA_VERSION=2 MAC_FILTER=0 @@ -232,7 +232,7 @@ define_global_variables(){ USE_PSK=0 ISOLATE_CLIENTS=0 QR=0 # show wifi qr - + # script variables PHY= VWIFI_IFACE= # virtual wifi interface name, if created @@ -240,7 +240,7 @@ define_global_variables(){ AP_IFACE= # can be VWIFI_IFACE or WIFI_IFACE USE_IWCONFIG=0 # some device can't use iw ####### - + #-- to deal with info of a running instance. then will exit LIST_RUNNING=0 STOP_ID= @@ -291,8 +291,8 @@ parse_user_options(){ SHARE_METHOD=redsocks shift ;; - - + + -g) shift GATEWAY4="$1" @@ -321,7 +321,7 @@ parse_user_options(){ shift MAC_USE_RANDOM=1 ;; - + --dns) shift DNS="$1" @@ -348,7 +348,7 @@ parse_user_options(){ --catch-dns) shift CATCH_DNS=1 - ;; + ;; --log-dns) shift SHOW_DNS_QUERY=1 @@ -371,12 +371,12 @@ parse_user_options(){ shift DNS_NOCACHE=1 ;; - + --isolate-clients) shift ISOLATE_CLIENTS=1 ;; - + --ap) shift WIFI_IFACE="$1" @@ -393,8 +393,8 @@ parse_user_options(){ shift QR=1 ;; - - + + --hidden) shift HIDDEN=1 @@ -580,7 +580,7 @@ sep_ip_port() { local PORT local INPUT INPUT="$1" - if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then + if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then if (echo "$INPUT" | grep ':' >/dev/null 2>&1) ;then # ipv4 + port IP="$(echo "$INPUT" | cut -d: -f1)" @@ -589,7 +589,7 @@ sep_ip_port() { # ipv4 IP="$INPUT" fi - elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then + elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then if (echo "$INPUT" | grep '\]\:' >/dev/null 2>&1) ;then # ipv6 + port IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" @@ -598,7 +598,7 @@ sep_ip_port() { # ipv6 IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" fi - else + else # port IP='127.0.0.1' PORT="$INPUT" @@ -745,35 +745,35 @@ get_interface_mac() { show_interface_pci_info() { # pci id / model / virtual is_interface "$1" || return - + local device_path local bus_id="" local device_type_and_bus_id="unknown" local driver="" local device_fullname="" - + device_path="$(readlink -f /sys/class/net/$1)" - + if [[ "$device_path" == "/sys/devices/pci"* ]]; then local pci_path pci_path=$device_path/../.. - + if [[ -d "$pci_path/driver" ]] ; then driver=$(readlink -f "$pci_path/driver" | sed 's/\//\n/g' | tail -n 1) fi - + bus_id="$(echo "$device_path" | sed 's/\//\n/g' | tail -n 3 |sed -n 1p)" device_type_and_bus_id="PCI: $bus_id" - + if which lspci >/dev/null 2>&1 ; then device_fullname="$( lspci -D -nn -s "$bus_id" | awk '{$1="" ; print $0}' )" fi - + elif [[ "$device_path" == *"/virtual/"* ]]; then device_type_and_bus_id="virtual interface" fi - + echo "$device_type_and_bus_id" [[ -n "$driver" ]] && echo "System-already-loaded driver: $driver" [[ -n "$device_fullname" ]] && echo "$device_fullname" @@ -820,7 +820,7 @@ get_new_macaddr_according_to_existing() { } generate_random_mac() { - local r1 r2 r3 r4 r5 r6 + local r1 r2 r3 r4 r5 r6 local RAND_MAC while :; do r1=$( printf "%02x" $(($RANDOM%256/4*4)) ) @@ -905,7 +905,7 @@ pid_watchdog() { local ERR_MSG="$3" local ST while true - do + do if [[ -e "/proc/$PID" ]]; then ST="$(cat "/proc/$PID/status" | grep "^State:" | awk '{print $2}')" if [[ "$ST" != 'Z' ]]; then @@ -915,18 +915,18 @@ pid_watchdog() { fi die "$ERR_MSG" done - + } #======== get_pid_by_dbus_name() { local DBUS_NAME="$1" local pid r - + which dbus-send >/dev/null 2>&1 || return 1 - + pid="$( dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetConnectionUnixProcessID string:$DBUS_NAME 2>/dev/null | grep " uint32 " | awk '{print $2}' )" r=$? - + echo "$pid" return $r } @@ -940,15 +940,15 @@ is_same_netns() { # only support NetworkManager >= 0.9.9 is_nm_running() { NM_PID="$(get_pid_by_dbus_name "org.freedesktop.NetworkManager")" - + [[ ! -n "$NM_PID" ]] && return 1 # not running - + if (which nmcli >/dev/null 2>&1 ) && (nmcli -t -f RUNNING g 2>&1 | grep -E '^running$' >/dev/null 2>&1 ) ; then if is_same_netns "$NM_PID"; then return 0 fi fi - + NM_PID= # cancel value if treat as not running return 1 # not running } @@ -989,9 +989,9 @@ nm_restore_manage() { #------- is_firewalld_running() { FIREWALLD_PID="$(get_pid_by_dbus_name "org.fedoraproject.FirewallD1")" - + [[ ! -n "$FIREWALLD_PID" ]] && return 1 # not running - + if (which firewall-cmd >/dev/null 2>&1 ) && [[ "$(firewall-cmd --state 2>&1)" == "running" ]] ; then if is_same_netns "$FIREWALLD_PID"; then echo "firewalld is running ($(firewall-cmd --version))" @@ -1022,7 +1022,7 @@ CUSTOM_CHAINS_4_filter= CUSTOM_CHAINS_4_nat= CUSTOM_CHAINS_6_filter= CUSTOM_CHAINS_6_nat= -iptb() +iptb() { local FoS=$1 # 4 | 6 shift @@ -1034,26 +1034,26 @@ iptb() shift local CH=$1 # chain shift - + [[ "$IPV6" -ne 1 && "$FoS" == "6" ]] && return - + local CMD_HEAD="" local MOUTH="" local NECK="" local HAND_UN_NC=0 local TAIL="" - + local FULL="" local ADD_TO_UNDO=1 - + local arr_name w - + for arr_name in CUSTOM_CHAINS_4_filter CUSTOM_CHAINS_4_nat CUSTOM_CHAINS_6_filter CUSTOM_CHAINS_6_nat do local arr_content eval arr_content=\"\${$arr_name}\" #echo $arr_content - + for w in $arr_content do if [[ "$arr_name" =~ "$FoS" && "$arr_name" =~ "$T" && "$w" == "$CH" ]]; then @@ -1061,37 +1061,37 @@ iptb() fi done done - + [[ "$FoS" == "4" ]] && CMD_HEAD="iptables -w " [[ "$FoS" == "6" ]] && CMD_HEAD="ip6tables -w " - + [[ "$Vis" == 'v' ]] && MOUTH="-v" - + NECK="-t ${T}" - + if [[ "$ACT" == "N" ]]; then eval CUSTOM_CHAINS_${FoS}_${T}=\"\${CUSTOM_CHAINS_${FoS}_${T}} ${CH}\" HAND_UN_NC=1 fi - - - + + + [[ ! "$NETFILTER_XT_MATCH_COMMENT" == "0" ]] && TAIL="-m comment --comment lrt${$}${SUBNET_IFACE}" - + if [[ "$ADD_TO_UNDO" -eq 1 ]]; then if [[ "$ACT" == "I" || "$ACT" == "A" ]]; then - echo "$CMD_HEAD $NECK -D ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables.sh + echo "$CMD_HEAD $NECK -D ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables.sh fi - + if [[ "$HAND_UN_NC" -eq 1 ]]; then echo "$CMD_HEAD $NECK -F ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables_2.sh echo "$CMD_HEAD $NECK -X ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables_2.sh fi fi - - - + + + FULL="$CMD_HEAD $MOUTH $NECK -${ACT} ${CH} $@ $TAIL" #echo $FULL @@ -1109,40 +1109,40 @@ disable_unwanted_forwarding() { ! -i "$INTERNET_IFACE" -o "$SUBNET_IFACE" \ -j REJECT || die fi - + if [[ "$SHARE_METHOD" == 'redsocks' || "$SHARE_METHOD" == 'none' \ || ( "$iv" -eq "4" && "$NO4" -eq 1 ) ]];then iptb "$iv" n filter I FORWARD -i "$SUBNET_IFACE" -j REJECT || die iptb "$iv" n filter I FORWARD -o "$SUBNET_IFACE" -j REJECT || die fi done - + } start_nat() { local SUBNET_NET - + local iv echo echo "iptables: NAT " - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" - + if [[ -n "$INTERNET_IFACE" ]]; then # only one Internet interface # masquerade subnet -> internet iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ -o "$INTERNET_IFACE" \ -j MASQUERADE || die - + # forward subnet -> internet iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ -o $INTERNET_IFACE \ -j ACCEPT || die - + # forward any -> subnet iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ -i "$INTERNET_IFACE" \ @@ -1152,32 +1152,32 @@ start_nat() { iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ ! -o "$SUBNET_IFACE" \ -j MASQUERADE || die - + # forward subnet -> any iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ -j ACCEPT || die - + # forward any -> subnet iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ -j ACCEPT || die fi - done + done } start_ban_lan() { local arr_nets_to_protect local ICMP_NAME local iv s - + echo echo "iptables: Disallow clients to access LAN" - + for iv in "${IP_VERs[@]}"; do # ban forwarding for subnet iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLF || die # TODO: allow '--dhcp-dns(6)' address port 53, which can be something needed, e.g. a VPN's internal private IP if [[ "$iv" -eq "4" ]]; then - arr_nets_to_protect=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") + arr_nets_to_protect=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") ICMP_NAME="icmp" elif [[ "$iv" -eq "6" ]]; then arr_nets_to_protect=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::/128" "::ffff:0:0/96" "::ffff:0:0:0/96") @@ -1187,7 +1187,7 @@ start_ban_lan() { iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLF -d "$s" -j REJECT || die done iptb "$iv" n filter I FORWARD -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLF || die - + # ban input from subnet iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLI || die iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLI -i ${SUBNET_IFACE} ! -p "$ICMP_NAME" -j REJECT || die # ipv6 need icmp to function. TODO: maybe we can block some unneeded icmp to improve security @@ -1202,14 +1202,14 @@ allow_dns_port() { local PROTs local iv pt - + echo echo "iptables: allow DNS" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" @@ -1218,7 +1218,7 @@ allow_dns_port() { for pt in "${PROTs[@]}"; do iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j ACCEPT || die done - done + done } @@ -1229,11 +1229,11 @@ start_catch_dns() { echo echo "iptables: redirect DNS queries to this host" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" - + PROTs=("tcp" "udp") for pt in "${PROTs[@]}"; do iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" ! -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j REDIRECT --to-ports 53 || die @@ -1243,9 +1243,9 @@ start_catch_dns() { allow_dhcp() { - echo + echo echo "iptables: allow dhcp" - + iptb 4 v filter I INPUT -i ${SUBNET_IFACE} -p udp -m udp --dport 67 -j ACCEPT || die iptb 6 v filter I INPUT -i ${SUBNET_IFACE} -p udp -m udp --dport 547 -j ACCEPT || die } @@ -1255,25 +1255,25 @@ start_redsocks() { local SUBNET_NET local arr_nets_to_ignore local s iv - + echo echo "iptables: transparent proxy non-LAN TCP and UDP(not tested) traffic to port ${TP_PORT}" - + for iv in "${IP_VERs[@]}"; do [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue - + [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" - - + + iptb "$iv" n nat N lrt${$}${SUBNET_IFACE}-TP || die - + if [[ "$iv" -eq "4" ]]; then arr_nets_to_ignore=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") elif [[ "$iv" -eq "6" ]];then arr_nets_to_ignore=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::") fi - + for s in "${arr_nets_to_ignore[@]}"; do iptb "$iv" n nat A lrt${$}${SUBNET_IFACE}-TP -d "$s" -j RETURN || die done @@ -1283,7 +1283,7 @@ start_redsocks() { iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" -s "$SUBNET_NET" -j lrt${$}${SUBNET_IFACE}-TP || die - + iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p tcp -m tcp --dport ${TP_PORT} -j ACCEPT || die iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p udp -m udp --dport ${TP_PORT} -j ACCEPT || die done @@ -1297,7 +1297,7 @@ backup_ipv6_bits() { "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr" \ "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode" \ "$CONFDIR/sys_6_conf_iface/" || die "Failed backing up interface ipv6 bits" - + if [[ "$SHARE_METHOD" == 'redsocks' ]] ; then cp "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/forwarding" \ "$CONFDIR/sys_6_conf_iface/" || die "Failed backking up interface ipv6 bits" @@ -1322,45 +1322,45 @@ restore_ipv6_bits() { set_interface_mac() { local INTERFACE local MAC - + INTERFACE=$1 MAC=$2 - - ip link set dev "${INTERFACE}" address "${MAC}" + + ip link set dev "${INTERFACE}" address "${MAC}" } backup_interface_status() { # virtual wifi interface will be destroyed, so no need to save status - + # backup interface up or down status (ip link show "${SUBNET_IFACE}" |grep -q "state UP") && SUBNET_IFACE_ORIGINAL_UP_STATUS=1 - - # save interface old mac - #if [[ -n "$NEW_MACADDR" ]]; then + + # save interface old mac + #if [[ -n "$NEW_MACADDR" ]]; then OLD_MACADDR=$(get_interface_mac "$SUBNET_IFACE") #echo "Saved ${SUBNET_IFACE} old MAC address ${OLD_MACADDR} into RAM" #fi - + backup_ipv6_bits - + # TODO : ? backup ip and others??? - + # nm managing status is saved when nm_set_unmanaged() } restore_interface_status() { # virtual wifi interface will be destroyed, so no need to restore status # don't use [[ $VWIFI_IFACE ]] to judge, if creating virtual wifi failed, VWIFI_IFACE is empty [[ "$WIFI_IFACE" && "$NO_VIRT" -eq 0 ]] && return - + restore_ipv6_bits if [[ -n "$OLD_MACADDR" && "$(get_interface_mac "$SUBNET_IFACE")" != "$OLD_MACADDR" ]] ; then echo "Restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR} ..." set_interface_mac "${SUBNET_IFACE}" "${OLD_MACADDR}" || echo "Failed restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR}" >&2 fi - + nm_restore_manage - + [[ $SUBNET_IFACE_ORIGINAL_UP_STATUS -eq 1 ]] && ip link set up dev "${SUBNET_IFACE}" && echo "Restore ${SUBNET_IFACE} to link up" } #--------------------------------------- @@ -1373,7 +1373,7 @@ kill_processes() { # for this instance # a value in $x. so we need to check if the value is a file if [[ -f $x ]] && sleep 0.3 && [[ -f $x ]]; then pid=$(cat "$x") - pn=$( ps -p "$pid" -o comm= ) + pn=$( ps -p "$pid" -o comm= ) #echo "Killing $pid $pn ... " pkill -P "$pid" kill "$pid" 2>/dev/null && ( echo "Killed $(basename "$x") $pid $pn" && rm "$x" ) || echo "Failed to kill $(basename "$x") $pid $pn, it may have exited" @@ -1385,27 +1385,27 @@ _cleanup() { local x ip addr flush "${SUBNET_IFACE}" - + [[ ! "$KEEP_CONFDIR" -eq 1 ]] && rm -rf "$CONFDIR" - + ip link set down dev "${SUBNET_IFACE}" - + firewalld_del_tmpzone - + if [[ $VWIFI_IFACE ]]; then # the subnet interface (virtual wifi interface) will be removed iw dev "${VWIFI_IFACE}" del dealloc_vface_name "$VWIFI_IFACE" fi - + restore_interface_status - + if ! has_running_instance; then echo "Exiting: This is the only running instance" # kill common processes for x in $COMMON_CONFDIR/*.pid; do [[ -f $x ]] && kill -9 $(cat "$x") && rm "$x" done - + rm -d "$COMMON_CONFDIR/vfaces" rm -d "$COMMON_CONFDIR" rm -d "$TMPDIR" @@ -1416,7 +1416,7 @@ _cleanup() { clean_iptables() { [[ -f $CONFDIR/undo_iptables.sh ]] && bash $CONFDIR/undo_iptables.sh - + [[ -f $CONFDIR/undo_iptables_2.sh ]] && bash $CONFDIR/undo_iptables_2.sh } @@ -1430,11 +1430,11 @@ cleanup() { echo "Undoing iptables changes .." clean_iptables > /dev/null _cleanup 2> /dev/null - + #pgid=$(ps opgid= $$ |awk '{print $1}' ) #echo "Killing PGID $pgid ..." #kill -15 -$pgid - #sleep 1 + #sleep 1 echo "Cleaning up done" #kill -9 -$pgid } @@ -1526,7 +1526,7 @@ print_clients_from_leases() { # MAC|IP|HOST|lease local FILEC local line local LEASEstr LEASEstamp - + FILEC="$(cat "$LEASE_FILE" | grep -v -E "^duid\b" | sed -r '/^\s*$/d' )" # TODO: duid is somewhat related to ipv6. I don't know about it. Not sure excluding it miss some info or not @@ -1537,31 +1537,31 @@ print_clients_from_leases() { # MAC|IP|HOST|lease MAC="$(echo "$line" | awk '{print $2}')" IP="$(echo "$line" | awk '{print $3}' | sed 's/\[//g' | sed 's/\]//g')" HOST="$(echo "$line" | awk '{print $4}' | sed 's/*/?/g' | sed 's/|/_/g' | sed 's/ /_/g' )" - + if [[ -n "$MAC" ]]; then LEASEstr="$(date -d @${LEASEstamp} +%m-%d_%X)" - + echo "$MAC|$IP|$HOST|lease_$LEASEstr" fi done - + } -print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS +print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS local IFACE=$1 - + local line - + ip n | grep -E "\bdev $IFACE\b" | sed 's/ /|/g' | while read -r line do local MAC IP STATUS - + IP="$(echo "$line" | awk -F'|' '{print $1}')" - + if [[ "$(echo "$line" | awk -F'|' '{print $4}')" == "lladdr" ]]; then # has mac # if has mac, $4="lladdr" and $5=macaddress and $6+=status MAC="$(echo "$line" | awk -F'|' '{print $5}')" STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";$5="";{print}' | awk '{$1=$1;print}'| sed 's/ /,/g')" - else # no mac + else # no mac # if no mac, $4="" and $5+=status MAC="?" STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";{print}' | awk '{$1=$1;print}' | sed 's/ /,/g')" @@ -1571,7 +1571,7 @@ print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS fi done } -print_interface_neighbors_via_iw() { # MAC|_|_|signal +print_interface_neighbors_via_iw() { # MAC|_|_|signal local IFACE=$1 local MAC SIGNAL iw dev "$IFACE" station dump | awk '($1 ~ /Station$/) {print $2}' | while read -r MAC @@ -1586,14 +1586,14 @@ print_interface_neighbors_via_iw() { # MAC|_|_|signal list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active mode) local IFACE pid local CONFDIR - + local output="" # If number (PID) is given, get the associated wifi iface if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then pid="$1" IFACE=$(get_subn_iface_from_pid "$pid") if [[ -z "$IFACE" ]] ; then - echo "'$pid' is not the pid of a running $PROGNAME instance." >&2 + echo "'$pid' is not the pid of a running $PROGNAME instance." >&2 exit 1 fi else # non-number given @@ -1612,14 +1612,14 @@ list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active fi output="$(echo "$output" ; print_interface_neighbors_via_iw "$IFACE") " output="$(echo "$output" ; print_interface_neighbors_via_iproute "$IFACE")" - + output="$(echo "$output" | sort -k 1 -k 2 -t '|' | uniq | sed -r '/^\s*$/d')" echo "$IFACE ($(get_interface_mac "$IFACE")) neighbors:" - + local fmt="%-19s%-41s%-20s%s" # string length: MAC 17, ipv4 15, ipv6 39, hostname ? printf "$fmt\n" "MAC" "IP" "HOSTNAME" "INFO" - + local line echo "$output"| while read -r line do @@ -1732,14 +1732,14 @@ check_wifi_settings() { echo "WARN: Can't use 'iw' to operate interfce '$WIFI_IFACE', trying 'iwconfig' (not as good as 'iw') ..." >&2 USE_IWCONFIG=1 fi - + if [[ $USE_IWCONFIG -eq 1 ]]; then if ! (which iwconfig > /dev/null 2>&1 && iwconfig "$WIFI_IFACE" > /dev/null 2>&1); then echo "ERROR: Can't use 'iwconfig' to operate interfce '$WIFI_IFACE'" >&2 exit 1 fi fi - + if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then echo "ERROR: Invalid frequency band" >&2 exit 1 @@ -1778,7 +1778,7 @@ check_wifi_settings() { DRIVER=rtl871xdrv fi fi - + if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2 exit 1 @@ -1854,32 +1854,32 @@ decide_ip_addresses() { if [[ $IPV6 -eq 1 ]]; then GATEWAY6="${PREFIX6}${IID6}" fi - + SUBNET_NET4="${GATEWAY4%.*}.0/24" [[ $IPV6 -eq 1 ]] && SUBNET_NET6="${PREFIX6}/64" - + } prepare_wifi_interface() { if [[ $USE_IWCONFIG -eq 0 ]]; then iw dev "${WIFI_IFACE}" set power_save off fi - + if [[ $NO_VIRT -eq 0 ]]; then ## Will generate virtual wifi interface - + # TODO move this to check_wifi_settings() ? if is_interface_wifi_connected "${WIFI_IFACE}"; then WIFI_IFACE_FREQ=$(iw dev "${WIFI_IFACE}" link | grep -i freq | awk '{print $2}' | sed 's/\.00*$//g') # NOTE we assume integer currently, which can be right, or wrong in the future WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel "${WIFI_IFACE_FREQ}") - + echo "${WIFI_IFACE} already working in channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" - + if [[ $CHANNEL == default ]]; then echo "Use wifi adapter current channel $WIFI_IFACE_CHANNEL as target channel" CHANNEL=$WIFI_IFACE_CHANNEL fi - + if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then echo "WARN: Wifi adapter already working in channel ${WIFI_IFACE_CHANNEL}, which is different than target channel $CHANNEL" >&2 fi @@ -1890,7 +1890,7 @@ prepare_wifi_interface() { if iw dev "${WIFI_IFACE}" interface add "${VWIFI_IFACE}" type __ap; then # Successfully created virtual wifi interface # if NM running, it will give the new virtual interface a random MAC. MAC will go back after setting NM unmanaged - sleep 2 + sleep 2 echo "${VWIFI_IFACE} created" else VWIFI_IFACE= @@ -1902,12 +1902,12 @@ prepare_wifi_interface() { die "Failed creating virtual WiFi interface. Maybe your WiFi adapter does not fully support virtual interfaces. Try again with '--no-virt'" fi fi - + AP_IFACE=${VWIFI_IFACE} else # no virtual wifi interface, use wifi device interface itself AP_IFACE=${WIFI_IFACE} fi - + if [[ $CHANNEL == default ]]; then echo "Channel not specified, use default" if [[ $FREQ_BAND == 2.4 ]]; then @@ -1930,12 +1930,12 @@ decide_subnet_interface() { dealwith_mac() { local VMAC - - if [[ -n "$NEW_MACADDR" ]] ; then # user choose to set subnet mac + + if [[ -n "$NEW_MACADDR" ]] ; then # user choose to set subnet mac echo "Setting ${SUBNET_IFACE} new MAC address ${NEW_MACADDR} ..." set_interface_mac "${SUBNET_IFACE}" "${NEW_MACADDR}" || die "Failed setting new MAC address" - + elif [[ $VWIFI_IFACE ]]; then # user didn't choose to set mac, but using virtual wifi interface VMAC=$(get_new_macaddr_according_to_existing "${WIFI_IFACE}") @@ -1946,7 +1946,7 @@ dealwith_mac() { fi } -write_hostapd_conf() { +write_hostapd_conf() { cat <<- EOF > "$CONFDIR/hostapd.conf" beacon_int=100 ssid=${SSID} @@ -2011,6 +2011,7 @@ write_hostapd_conf() { fi + if [[ -n "$VHT_CAPAB" ]]; then echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf" fi @@ -2082,11 +2083,11 @@ write_dnsmasq_conf() { else NOBODY_GROUP="nogroup" fi - + mkfifo "$CONFDIR/dnsmasq.log" || die "Failed creating pipe file for dnsmasq" chown nobody "$CONFDIR/dnsmasq.log" || die "Failed changing dnsmasq log file owner" - cat "$CONFDIR/dnsmasq.log" & - + cat "$CONFDIR/dnsmasq.log" & + cat <<- EOF > "$CONFDIR/dnsmasq.conf" user=nobody group=$NOBODY_GROUP @@ -2104,7 +2105,7 @@ write_dnsmasq_conf() { EOF # 'log-dhcp'(Extra logging for DHCP) shows too much logs. # if use '-d', 'log-facility' should = /dev/null - if [[ $SHARE_METHOD == "none" ]]; then + if [[ $SHARE_METHOD == "none" ]]; then echo "no-resolv" >> "$CONFDIR/dnsmasq.conf" echo "no-poll" >> "$CONFDIR/dnsmasq.conf" fi @@ -2116,7 +2117,7 @@ write_dnsmasq_conf() { 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 @@ -2131,7 +2132,7 @@ write_dnsmasq_conf() { 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 @@ -2139,7 +2140,7 @@ write_dnsmasq_conf() { [[ "$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 @@ -2173,7 +2174,7 @@ run_wifi_ap_processes() { HAVEGED_WATCHDOG_PID=$! echo "$HAVEGED_WATCHDOG_PID" > "$CONFDIR/haveged_watchdog.pid" echo - echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" + echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" fi # start access point @@ -2183,14 +2184,14 @@ run_wifi_ap_processes() { if [ $? -eq 0 ]; then STDBUF_PATH=$STDBUF_PATH" -oL" fi - echo + echo echo "Starting hostapd" - + if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then echo "Setting hostapd to AppArmor complain mode..." "$COMPLAIN_CMD" hostapd fi - + # 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=$! @@ -2205,17 +2206,17 @@ run_wifi_ap_processes() { } start_dnsmasq() { - echo + echo echo "Starting dnsmasq" - + if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then echo "Setting dnsmasq to AppArmor complain mode..." "$COMPLAIN_CMD" dnsmasq fi - + # 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 -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 @@ -2224,7 +2225,7 @@ start_dnsmasq() { if [[ $i -gt 10 ]]; then die "Couldn't get dnsmasq PID" ; fi done DNSMASQ_PID="$(cat "$CONFDIR/dnsmasq.pid" )" - echo "dnsmasq PID: $DNSMASQ_PID" + echo "dnsmasq PID: $DNSMASQ_PID" ######(wait $DNSMASQ_PID ; die "dnsmasq failed") & # wait can't deal with non-child pid_watchdog "$DNSMASQ_PID" 9 "dnsmasq failed" & sleep 2 @@ -2239,7 +2240,7 @@ check_rfkill_unblock_wifi() { #=========== Above are functions ====================== #=========== Executing begin ============================== -# if empty option, show usage and exit +# if empty option, show usage and exit check_empty_option "$@" # TODO: are some global variables are still defined in those following code? @@ -2253,12 +2254,12 @@ parse_user_options "$@" TMPDIR="$(decide_tmpdir)" -# if user choose to deal with running instances, will output some info then exit after this +# if user choose to deal with running instances, will output some info then exit after this # NOTE above don't require root -check_other_functions +check_other_functions # NOTE below require root -# if user choose to daemonize, will start new background process and exit this +# if user choose to daemonize, will start new background process and exit this daemonizing_check # check if wifi will work on this system and user settings @@ -2350,7 +2351,7 @@ else IP_VERs=("4" "6") fi -disable_unwanted_forwarding +disable_unwanted_forwarding # bring subnet interface up @@ -2374,36 +2375,36 @@ fi if [[ "$SHARE_METHOD" == "none" ]]; then echo "No Internet sharing" - + [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + 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. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 - + start_nat - + [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + echo 1 > "/proc/sys/net/ipv4/ip_forward" || die "Failed enabling system ipv4 forwarding" # TODO maybe uneeded in '--no4' mode - + if [[ $IPV6 -eq 1 ]]; then echo 1 > "/proc/sys/net/ipv6/conf/all/forwarding" || die "Failed enabling system ipv6 forwarding" # TODO if '-o' used, set only 2 interfaces' bits fi - + # to enable clients to establish PPTP connections we must # load nf_nat_pptp module modprobe nf_nat_pptp > /dev/null 2>&1 && echo "Loaded kernel module nf_nat_pptp" - + 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" # to set NA router bit fi - + [[ "$dnsmasq_NO_DNS" -eq 0 && ! $DNS ]] && echo -e "\nWARN: You are using in transparent proxy mode but this host is providing local DNS. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 [[ "$BANLAN" -eq 1 ]] && start_ban_lan - + start_redsocks fi @@ -2422,7 +2423,7 @@ echo "" is_firewalld_running && firewalld_add_tmpzone -echo +echo echo "== Setting up completed, now linux-router should be working ==" #============================================================ From cc0643f4462b0c80c8d10e62b00fd809841257f8 Mon Sep 17 00:00:00 2001 From: Phani Pavan K Date: Mon, 28 Jul 2025 12:34:55 +0530 Subject: [PATCH 10/12] add he beamform(er/ee) options --- lnxrouter | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lnxrouter b/lnxrouter index 828622f..b8aa698 100755 --- a/lnxrouter +++ b/lnxrouter @@ -137,6 +137,9 @@ Options: segment. Use with '--he-ch-width' --he-seg1-ch Channel index of HE center frequency for secondary (second 80MHz) segment. Use with '--he-ch-width 3' + --he-su-bfe Enable HE Single User Beamformee support + --he-su-bfr Enable HE Single User Beamformer support + --he-mu-bfr Enable HE Multi User Beamformer support Instance managing: --daemon Run in background @@ -223,6 +226,9 @@ define_global_variables(){ HECHANNELWIDTH=0 HESEG0CHINDEX=0 HESEG1CHINDEX=0 + HESUBFE=0 + HESUBFR=0 + HEMUBFR=0 DRIVER=nl80211 NO_VIRT=0 # not use virtual interface COUNTRY= @@ -489,6 +495,21 @@ parse_user_options(){ HESEG1CHINDEX="$1" shift ;; + --he-su-bfe) + shift + HESUBFE=1 + shift + ;; + --he-su-bfr) + shift + HESUBFR=1 + shift + ;; + --he-mu-bfr) + shift + HEMUBFR=1 + shift + ;; --driver) shift DRIVER="$1" @@ -2010,7 +2031,17 @@ write_hostapd_conf() { echo "require_he=1" >> "$CONFDIR/hostapd.conf" fi + if [[ $HESUBFE -eq 1 ]]; then + echo "he_su_beamformee=1" >> "$CONFDIR/hostapd.conf" + fi + if [[ $HESUBFR -eq 1 ]]; then + echo "he_su_beamformer=1" >> "$CONFDIR/hostapd.conf" + fi + + if [[ $HEMUBFR -eq 1 ]]; then + echo "he_mu_beamformer=1" >> "$CONFDIR/hostapd.conf" + fi if [[ -n "$VHT_CAPAB" ]]; then echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf" From f5ab6861f8bd7ddb562e32cff4a46ea8711f203c Mon Sep 17 00:00:00 2001 From: Phani Pavan K Date: Mon, 28 Jul 2025 15:52:30 +0530 Subject: [PATCH 11/12] added p2p twt and idle timeout, remove random spaces --- lnxrouter | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/lnxrouter b/lnxrouter index b8aa698..093e4f3 100755 --- a/lnxrouter +++ b/lnxrouter @@ -101,15 +101,16 @@ Options: (defaults to /etc/hostapd/hostapd.accept) --hostapd-debug 1 or 2. Passes -d or -dd to hostapd --isolate-clients Disable wifi communication between clients + --idle-timeout