Compare commits

..

No commits in common. "master" and "0.7.6" have entirely different histories.

2 changed files with 402 additions and 574 deletions

View File

@ -4,7 +4,7 @@ Set Linux as router in one command. Able to provide Internet, or create WiFi hot
It wraps `iptables`, `dnsmasq` etc. stuff. Use in one command, restore in one command or by `control-c` (or even by closing terminal window). It wraps `iptables`, `dnsmasq` etc. stuff. Use in one command, restore in one command or by `control-c` (or even by closing terminal window).
[More tools and projects 🛠️](https://garywill.github.io) | [🍻 Buy me a coffee ❤️](https://github.com/garywill/receiving/blob/master/receiving_methods.md) [Linux-Router News & Developer Notes 📰](https://github.com/garywill/linux-router/issues/28) | [More tools and projects 🛠️](https://garywill.github.io) | [🍻 Buy me a coffee ❤️](https://github.com/garywill/receiving/blob/master/receiving_methods.md)
## Features ## Features
@ -19,17 +19,14 @@ Basic features:
- Specify upstream DNS (kind of a plain DNS proxy) - Specify upstream DNS (kind of a plain DNS proxy)
- IPv6 (behind NATed LAN, like IPv4) - IPv6 (behind NATed LAN, like IPv4)
- Creating WiFi hotspot: - Creating WiFi hotspot:
- Wifi 3/4/5/6
- 2.4GHz, 5GHz
- Channel selecting - Channel selecting
- Choose encryptions: WPA2/WPA, WPA2, WPA, No encryption - Choose encryptions: WPA2/WPA, WPA2, WPA, No encryption
- Create AP on the same interface you are getting Internet (Need hardware support. Usually require same channel) - Create AP on the same interface you are getting Internet (usually require same channel)
- Transparent proxy (redsocks) - Transparent proxy (redsocks)
- Transparent DNS proxy (hijack port 53 packets) - Transparent DNS proxy (hijack port 53 packets)
- Detect and prevent interference from following Linux system daemons: - Detect NetworkManager and make sure it won't interfere (handle interface (un)managed status)
- NetworkManager (handle interface (un)managed status) - Detect firewalld and make sure it won't interfere our (by using `trusted` zone)
- firewalld (use temporary `trusted` zone) - You can run many instances, to create many different networks. Has instances managing feature.
- Instances managing. You can run multiple instances, to create different sub-networks.
**For many other features, see below [CLI usage](#cli-usage-and-other-features)** **For many other features, see below [CLI usage](#cli-usage-and-other-features)**
@ -85,9 +82,9 @@ I'm currently not packaging for any distro. If you do, open a PR and add the lin
- iptables (or nftables with `iptables-nft` translation linked) - iptables (or nftables with `iptables-nft` translation linked)
- WiFi hotspot dependencies - WiFi hotspot dependencies
- hostapd - hostapd
- iw (or iwconfig, when iw can not recognize adapter) - iw
- iwconfig (you only need this if 'iw' can not recognize your adapter)
- haveged (optional) - haveged (optional)
- crda and wireless-regdb (optional)
@ -384,19 +381,19 @@ Options:
(defaults to /etc/hostapd/hostapd.accept) (defaults to /etc/hostapd/hostapd.accept)
--hostapd-debug <level> 1 or 2. Passes -d or -dd to hostapd --hostapd-debug <level> 1 or 2. Passes -d or -dd to hostapd
--isolate-clients Disable wifi communication between clients --isolate-clients Disable wifi communication between clients
--sta-timeout <seconds> Timeout to disconnect a no-signal client
--no-haveged Do not run haveged automatically when needed --no-haveged Do not run haveged automatically when needed
--hs20 Enable Hotspot 2.0 --hs20 Enable Hotspot 2.0
WiFi 4 (802.11n) configs (2.4G/5GHz): (default: not enable) WiFi 4 (802.11n) configs:
--wifi4 Enable IEEE 802.11n (HT, High Throughput) --wifi4 Enable IEEE 802.11n (HT)
--ht-capab <HT caps> HT capabilities (example: '[HT40+][DSSS_CCK-40]') --req-ht Require station HT (High Throughput) mode
(default: '[HT40+]') --ht-capab <HT caps> HT capabilities (default: [HT40+])
--req-wifi4 Only support Wifi>=4 clients
WiFi 5 (802.11ac) configs:
--wifi5 Enable IEEE 802.11ac (VHT)
--req-vht Require station VHT (Very High Thoughtput) mode
--vht-capab <VHT caps> VHT capabilities
WiFi 5 (802.11ac) configs (5GHz): (default: not enable)
--wifi5 Enable IEEE 802.11ac (VHT, Very High Thoughtput)
--vht-capab <VHT caps> VHT capabilities (example: '[VHT160][RXLDPC]')
--vht-ch-width <index> Index of VHT channel width: --vht-ch-width <index> Index of VHT channel width:
0 for 20MHz or 40MHz (default) 0 for 20MHz or 40MHz (default)
1 for 80MHz 1 for 80MHz
@ -406,32 +403,9 @@ Options:
segment. Use with '--vht-ch-width' segment. Use with '--vht-ch-width'
--vht-seg1-ch <channel> Channel index of VHT center frequency for secondary --vht-seg1-ch <channel> Channel index of VHT center frequency for secondary
(second 80MHz) segment. Use with '--vht-ch-width 3' (second 80MHz) segment. Use with '--vht-ch-width 3'
--req-wifi5 Only support Wifi>=5 clients
WiFi 6 (802.11ax) configs (2.4G/5GHz): (default: not enable)
--wifi6 Enable IEEE 802.11ax (HE, High Efficiency)
--he-ch-width <index> 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> Channel index of HE center frequency for primary
segment. Use with '--he-ch-width'
--he-seg1-ch <channel> Channel index of HE center frequency for secondary
(second 80MHz) segment. Use with '--he-ch-width 3'
--he-su-bfe HE Single User Beamformee support
--he-su-bfr HE Single User Beamformer support
--he-mu-bfr HE Multi User Beamformer support
--req-wifi6 Only support Wifi>=6 clients
--p2ptwt Peer-to-Peer Target Wake Time support
Note: Some cutting-edge Wifi features strongly depends on hostapd built
with specific flags enabled and compatible hardware
Instance managing: Instance managing:
--daemon Run in background --daemon Run in background
--keep-confdir Don't delete the temporary config dir after exit
-l, --list-running Show running instances -l, --list-running Show running instances
--lc, --list-clients <id|interface> --lc, --list-clients <id|interface>
List clients of an instance. Or list neighbors of List clients of an instance. Or list neighbors of
@ -440,6 +414,11 @@ Options:
--stop <id> Stop a running instance --stop <id> Stop a running instance
For <id> you can use PID or subnet interface name. For <id> you can use PID or subnet interface name.
You can get them with '--list-running' You can get them with '--list-running'
Examples:
lnxrouter -i eth1
lnxrouter --ap wlan0 MyAccessPoint -p MyPassPhrase
lnxrouter -i eth1 --tp <transparent-proxy> --dns <dns-proxy>
``` ```
</details> </details>
@ -463,7 +442,7 @@ Visit [**my homepage** 🏡](https://garywill.github.io) to see **more tools and
> >
> 🥂 ( ^\_^) o自自o (^_^ ) 🍻 > 🥂 ( ^\_^) o自自o (^_^ ) 🍻
🤝 Bisides, thank [create_ap](https://github.com/oblique/create_ap) by [oblique](https://github.com/oblique). This script was forked from create\_ap. Now they are quite different. 🤝 Also thank those people who contributed to that project. 🤝 Bisides, thank [create_ap](https://github.com/oblique/create_ap) by [oblique](https://github.com/oblique). This script was forked from create\_ap. Now they are quite different. (See `history` branch for how I modified create_ap). 🤝 Also thank those who contributed to that project.
👨‍💻 You can be contributor, too! 👨‍💻 You can be contributor, too!

499
lnxrouter
View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
VERSION=0.8.1 VERSION=0.7.6
PROGNAME="$(basename "$0")" PROGNAME="$(basename "$0")"
export LC_ALL=C export LC_ALL=C
@ -101,19 +101,19 @@ Options:
(defaults to /etc/hostapd/hostapd.accept) (defaults to /etc/hostapd/hostapd.accept)
--hostapd-debug <level> 1 or 2. Passes -d or -dd to hostapd --hostapd-debug <level> 1 or 2. Passes -d or -dd to hostapd
--isolate-clients Disable wifi communication between clients --isolate-clients Disable wifi communication between clients
--sta-timeout <seconds> Timeout to disconnect a no-signal client
--no-haveged Do not run haveged automatically when needed --no-haveged Do not run haveged automatically when needed
--hs20 Enable Hotspot 2.0 --hs20 Enable Hotspot 2.0
WiFi 4 (802.11n) configs (2.4G/5GHz): (default: not enable) WiFi 4 (802.11n) configs:
--wifi4 Enable IEEE 802.11n (HT, High Throughput) --wifi4 Enable IEEE 802.11n (HT)
--ht-capab <HT caps> HT capabilities (example: '[HT40+][DSSS_CCK-40]') --req-ht Require station HT (High Throughput) mode
(default: '[HT40+]') --ht-capab <HT caps> HT capabilities (default: [HT40+])
--req-wifi4 Only support Wifi>=4 clients
WiFi 5 (802.11ac) configs:
--wifi5 Enable IEEE 802.11ac (VHT)
--req-vht Require station VHT (Very High Thoughtput) mode
--vht-capab <VHT caps> VHT capabilities
WiFi 5 (802.11ac) configs (5GHz): (default: not enable)
--wifi5 Enable IEEE 802.11ac (VHT, Very High Thoughtput)
--vht-capab <VHT caps> VHT capabilities (example: '[VHT160][RXLDPC]')
--vht-ch-width <index> Index of VHT channel width: --vht-ch-width <index> Index of VHT channel width:
0 for 20MHz or 40MHz (default) 0 for 20MHz or 40MHz (default)
1 for 80MHz 1 for 80MHz
@ -123,32 +123,9 @@ Options:
segment. Use with '--vht-ch-width' segment. Use with '--vht-ch-width'
--vht-seg1-ch <channel> Channel index of VHT center frequency for secondary --vht-seg1-ch <channel> Channel index of VHT center frequency for secondary
(second 80MHz) segment. Use with '--vht-ch-width 3' (second 80MHz) segment. Use with '--vht-ch-width 3'
--req-wifi5 Only support Wifi>=5 clients
WiFi 6 (802.11ax) configs (2.4G/5GHz): (default: not enable)
--wifi6 Enable IEEE 802.11ax (HE, High Efficiency)
--he-ch-width <index> 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> Channel index of HE center frequency for primary
segment. Use with '--he-ch-width'
--he-seg1-ch <channel> Channel index of HE center frequency for secondary
(second 80MHz) segment. Use with '--he-ch-width 3'
--he-su-bfe HE Single User Beamformee support
--he-su-bfr HE Single User Beamformer support
--he-mu-bfr HE Multi User Beamformer support
--req-wifi6 Only support Wifi>=6 clients
--p2ptwt Peer-to-Peer Target Wake Time support
Note: Some cutting-edge Wifi features strongly depends on hostapd built
with specific flags enabled and compatible hardware
Instance managing: Instance managing:
--daemon Run in background --daemon Run in background
--keep-confdir Don't delete the temporary config dir after exit
-l, --list-running Show running instances -l, --list-running Show running instances
--lc, --list-clients <id|interface> --lc, --list-clients <id|interface>
List clients of an instance. Or list neighbors of List clients of an instance. Or list neighbors of
@ -216,6 +193,15 @@ define_global_variables(){
WPA_VERSION=2 WPA_VERSION=2
MAC_FILTER=0 MAC_FILTER=0
MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept
IEEE80211N=0
REQUIREHT=0
IEEE80211AC=0
REQUIREVHT=0
HT_CAPAB='[HT40+]'
VHT_CAPAB=
VHTCHANNELWIDTH=0
VHTSEG0CHINDEX=0
VHTSEG1CHINDEX=0
DRIVER=nl80211 DRIVER=nl80211
NO_VIRT=0 # not use virtual interface NO_VIRT=0 # not use virtual interface
COUNTRY= COUNTRY=
@ -225,32 +211,8 @@ define_global_variables(){
USE_PSK=0 USE_PSK=0
ISOLATE_CLIENTS=0 ISOLATE_CLIENTS=0
QR=0 # show wifi qr QR=0 # show wifi qr
STATIMEOUT=
#wifi4
IEEE80211N=0
REQUIREHT=0
HT_CAPAB='[HT40+]'
#wifi5
IEEE80211AC=0
REQUIREVHT=0
VHT_CAPAB=
VHTCHANNELWIDTH=0
VHTSEG0CHINDEX=
VHTSEG1CHINDEX=
#wifi6
IEEE80211AX=0
REQUIREHE=0
HECHANNELWIDTH=0
HESEG0CHINDEX=
HESEG1CHINDEX=
HESUBFE=0
HESUBFR=0
HEMUBFR=0
P2PTWT=0
# script variables # script variables
PHY=
VWIFI_IFACE= # virtual wifi interface name, if created VWIFI_IFACE= # virtual wifi interface name, if created
VIRT_NAME= # name to use for virtual interface if --virt-name is used VIRT_NAME= # name to use for virtual interface if --virt-name is used
AP_IFACE= # can be VWIFI_IFACE or WIFI_IFACE AP_IFACE= # can be VWIFI_IFACE or WIFI_IFACE
@ -268,9 +230,7 @@ define_global_variables(){
NM_UNM_LIST= # it's called "list" but for now one interface NM_UNM_LIST= # it's called "list" but for now one interface
NM_PID= NM_PID=
FIREWALLD_PID= FIREWALLD_PID=
OLD_FIREWALLD_ZONE=
TMP_FIREWALLD_ZONE= TMP_FIREWALLD_ZONE=
KEEP_CONFDIR=
} }
parse_user_options(){ parse_user_options(){
@ -308,6 +268,8 @@ parse_user_options(){
SHARE_METHOD=redsocks SHARE_METHOD=redsocks
shift shift
;; ;;
-g) -g)
shift shift
GATEWAY4="$1" GATEWAY4="$1"
@ -336,6 +298,7 @@ parse_user_options(){
shift shift
MAC_USE_RANDOM=1 MAC_USE_RANDOM=1
;; ;;
--dns) --dns)
shift shift
DNS="$1" DNS="$1"
@ -385,11 +348,12 @@ parse_user_options(){
shift shift
DNS_NOCACHE=1 DNS_NOCACHE=1
;; ;;
--isolate-clients) --isolate-clients)
shift shift
ISOLATE_CLIENTS=1 ISOLATE_CLIENTS=1
;; ;;
# wifi ap
--ap) --ap)
shift shift
WIFI_IFACE="$1" WIFI_IFACE="$1"
@ -406,6 +370,8 @@ parse_user_options(){
shift shift
QR=1 QR=1
;; ;;
--hidden) --hidden)
shift shift
HIDDEN=1 HIDDEN=1
@ -419,6 +385,7 @@ parse_user_options(){
MAC_FILTER_ACCEPT="$1" MAC_FILTER_ACCEPT="$1"
shift shift
;; ;;
-c) -c)
shift shift
CHANNEL="$1" CHANNEL="$1"
@ -434,9 +401,46 @@ parse_user_options(){
[[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2 [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2
shift shift
;; ;;
--sta-timeout)
--wifi4|--ieee80211n)
shift shift
STATIMEOUT="$1" IEEE80211N=1
;;
--req-ht|--require-ht)
shift
REQUIREHT=1
;;
--wifi5|--ieee80211ac)
shift
IEEE80211AC=1
;;
--req-vht|--require-vht)
shift
REQUIREVHT=1
;;
--ht-capab)
shift
HT_CAPAB="$1"
shift
;;
--vht-capab)
shift
VHT_CAPAB="$1"
shift
;;
--vht-ch-width|--vht-channel-width)
shift
VHTCHANNELWIDTH="$1"
shift
;;
--vht-seg0-ch|--vht-seg0-channel)
shift
VHTSEG0CHINDEX="$1"
shift
;;
--vht-seg1-ch|--vht-seg1-channel)
shift
VHTSEG1CHINDEX="$1"
shift shift
;; ;;
--driver) --driver)
@ -453,6 +457,7 @@ parse_user_options(){
VIRT_NAME="$1" VIRT_NAME="$1"
shift shift
;; ;;
--country) --country)
shift shift
COUNTRY="$1" COUNTRY="$1"
@ -483,90 +488,7 @@ parse_user_options(){
shift shift
USE_PSK=1 USE_PSK=1
;; ;;
# wifi 4
--wifi4|--ieee80211n)
shift
IEEE80211N=1
;;
--req-wifi4|--req-ht|--require-ht)
shift
REQUIREHT=1
;;
--ht-capab)
shift
HT_CAPAB="$1"
shift
;;
# wifi 5
--wifi5|--ieee80211ac)
shift
IEEE80211AC=1
;;
--req-wifi5|--req-vht|--require-vht)
shift
REQUIREVHT=1
;;
--vht-capab)
shift
VHT_CAPAB="$1"
shift
;;
--vht-ch-width|--vht-channel-width)
shift
VHTCHANNELWIDTH="$1"
shift
;;
--vht-seg0-ch|--vht-seg0-channel)
shift
VHTSEG0CHINDEX="$1"
shift
;;
--vht-seg1-ch|--vht-seg1-channel)
shift
VHTSEG1CHINDEX="$1"
shift
;;
# wifi 6
--wifi6|--ieee80211ax)
shift
IEEE80211AX=1
;;
--req-wifi6|--req-he|--require-he)
shift
REQUIREHE=1
;;
--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
;;
--he-su-bfe)
shift
HESUBFE=1
;;
--he-su-bfr)
shift
HESUBFR=1
;;
--he-mu-bfr)
shift
HEMUBFR=1
;;
--p2ptwt)
shift
P2PTWT=1
;;
# instance managing
--daemon) --daemon)
shift shift
DAEMONIZE=1 DAEMONIZE=1
@ -585,10 +507,7 @@ parse_user_options(){
LIST_CLIENTS_ID="$1" LIST_CLIENTS_ID="$1"
shift shift
;; ;;
--keep-confdir)
shift
KEEP_CONFDIR=1
;;
*) *)
echo "Invalid parameter: $1" 1>&2 echo "Invalid parameter: $1" 1>&2
exit 1 exit 1
@ -663,6 +582,7 @@ get_interface_phy_device() { # only for wifi interface
return 0 return 0
fi fi
done done
echo "Failed to get phy interface" >&2
return 1 return 1
} }
@ -702,51 +622,38 @@ can_be_ap() {
} }
can_transmit_to_channel() { can_transmit_to_channel() {
local IFACE CHANNEL_NUM CHANNEL_INFO CHANNEL_FREQ_FILTER local IFACE CHANNEL_NUM CHANNEL_INFO
IFACE=$1 IFACE=$1
CHANNEL_NUM=$2 CHANNEL_NUM=$2
if [[ $FREQ_BAND == "2.4" ]]; then
CHANNEL_FREQ_FILTER="(24)"
elif [[ $FREQ_BAND -eq 5 ]]; then
CHANNEL_FREQ_FILTER="(5[1-8])"
elif [[ $FREQ_BAND -eq 6 ]]; then
CHANNEL_FREQ_FILTER="((59)|(6[0-9])|(7[0-1]))"
fi
if [[ $USE_IWCONFIG -eq 0 ]]; then if [[ $USE_IWCONFIG -eq 0 ]]; then
CHANNEL_INFO=$(get_adapter_info "${IFACE}" | grep -E " ${CHANNEL_FREQ_FILTER}[0-9]{2}(\.[0-9]+){0,1} MHz \[${CHANNEL_NUM}\]") CHANNEL_INFO=$(get_adapter_info "${IFACE}" | grep -E " [0-9]+(\.[0-9]+){0,1} MHz \[${CHANNEL_NUM}\]")
[[ -z "${CHANNEL_INFO}" ]] && return 1 [[ -z "${CHANNEL_INFO}" ]] && return 1
[[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 2 [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 1
[[ "${CHANNEL_INFO}" == *disabled* ]] && return 3 [[ "${CHANNEL_INFO}" == *disabled* ]] && return 1
return 0 return 0
else else
CHANNEL_NUM="$(printf '%02d' "${CHANNEL_NUM}")" 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 [[ -z "${CHANNEL_INFO}" ]] && return 1
return 0 return 0
fi fi
} }
# taken from iw/util.c
ieee80211_frequency_to_channel() { ieee80211_frequency_to_channel() {
local FREQ=$1 local FREQ=$1
if [[ $FREQ -eq 2484 ]]; then
# 2.4G
if [[ $FREQ -ge 2412 && $FREQ -le 2472 ]]; then # 2.4 GHz band: Channels 1-13 (2412~2472 MHz)
echo $(( (FREQ - 2407) / 5 ))
elif [[ $FREQ -eq 2484 ]]; then # 2.4 GHz Channel 14 (2484 MHz, Japan only)
echo 14 echo 14
elif [[ $FREQ -lt 2484 ]]; then
# 5G echo $(( ($FREQ - 2407) / 5 ))
elif [[ $FREQ -ge 5160 && $FREQ -le 5885 ]]; then # 5 GHz band: Standard Channels 36-165 (5180~5825 MHz) (extra: 32, 169-177) elif [[ $FREQ -ge 4910 && $FREQ -le 4980 ]]; then
echo $(( (FREQ - 5000) / 5 )) echo $(( ($FREQ - 4000) / 5 ))
elif [[ $FREQ -le 45000 ]]; then
# 6G echo $(( ($FREQ - 5000) / 5 ))
elif [[ $FREQ -ge 5955 && $FREQ -le 7115 ]]; then # 6 GHz band: Channels 1-233 (5955~7115 MHz), Wi-Fi 6E/7 elif [[ $FREQ -ge 58320 && $FREQ -le 64800 ]]; then
echo $(( (FREQ - 5950) / 5 )) echo $(( ($FREQ - 56160) / 2160 ))
elif [[ $FREQ -eq 5935 ]]; then # 6 GHz band: Special case for 5935 MHz (Channel 2, rare) else
echo 2
else # Frequency not in supported Wi-Fi bands (2.4/5/6 GHz)
echo 0 echo 0
fi fi
} }
@ -766,7 +673,7 @@ is_unicast_macaddr() {
local x local x
x=$(echo "$1" | cut -d: -f1) x=$(echo "$1" | cut -d: -f1)
x=$(printf '%d' "0x${x}") x=$(printf '%d' "0x${x}")
[[ $(expr "$x" % 2) -eq 0 ]] [[ $(expr $x % 2) -eq 0 ]]
} }
get_interface_mac() { get_interface_mac() {
@ -809,7 +716,7 @@ show_interface_pci_info() { # pci id / model / virtual
[[ -n "$driver" ]] && echo "System-already-loaded driver: $driver" [[ -n "$driver" ]] && echo "System-already-loaded driver: $driver"
[[ -n "$device_fullname" ]] && echo "$device_fullname" [[ -n "$device_fullname" ]] && echo "$device_fullname"
echo "" echo ""
# TODO Fix pci and usb devices # TODO usb
} }
alloc_new_vface_name() { # only for wifi alloc_new_vface_name() { # only for wifi
@ -874,15 +781,15 @@ generate_random_mac() {
is_ip4_lan_range_available() { # checks 192.168.x.x is_ip4_lan_range_available() { # checks 192.168.x.x
( ip -4 address | grep "inet 192\.168\.$1\." > /dev/null 2>&1 ) && return 1 ( ip -4 address | grep "inet 192\.168\.$1\." > /dev/null 2>&1 ) && return 1
( ip -4 route | grep "^192\.168\.$1\." > /dev/null 2>&1 ) && return 1 ( ip -4 route | grep "^192\.168\.$1\." > /dev/null 2>&1 ) && return 1
( ip -4 route get "192.168.$1.0" 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && \ ( ip -4 route get 192.168.$1.0 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && \
( ip -4 route get "192.168.$1.255" 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && return 0 ( ip -4 route get 192.168.$1.255 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && return 0
return 1 return 1
} }
is_ip6_lan_range_available() { # checks fdxx:: is_ip6_lan_range_available() { # checks fdxx::
( ip -6 address | grep -i "inet6 fd$1:$2$3:$4$5:$6$7:" > /dev/null 2>&1 ) && return 1 ( ip -6 address | grep -i "inet6 fd$1:$2$3:$4$5:$6$7:" > /dev/null 2>&1 ) && return 1
( ip -6 route | grep -i "^fd$1:$2$3:$4$5:$6$7:" > /dev/null 2>&1 ) && return 1 ( ip -6 route | grep -i "^fd$1:$2$3:$4$5:$6$7:" > /dev/null 2>&1 ) && return 1
( ip -6 route get "fd$1:$2$3:$4$5:$6$7::" 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && \ ( ip -6 route get fd$1:$2$3:$4$5:$6$7:: 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && \
( ip -6 route get "fd$1:$2$3:$4$5:$6$7:ffff:ffff:ffff:ffff" 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && return 0 ( ip -6 route get fd$1:$2$3:$4$5:$6$7:ffff:ffff:ffff:ffff 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && return 0
return 1 return 1
} }
@ -924,7 +831,7 @@ haveged_watchdog() {
elif ! pidof haveged > /dev/null 2>&1; then # TODO judge zombie ? elif ! pidof haveged > /dev/null 2>&1; then # TODO judge zombie ?
echo "Low entropy detected, starting haveged" 1>&2 echo "Low entropy detected, starting haveged" 1>&2
# boost low-entropy # boost low-entropy
haveged -w 1024 -p "$COMMON_CONFDIR/haveged.pid" haveged -w 1024 -p $COMMON_CONFDIR/haveged.pid
fi fi
fi fi
sleep 2 sleep 2
@ -963,12 +870,8 @@ get_pid_by_dbus_name() {
} }
is_same_netns() { is_same_netns() {
local pid2="$1" local pid2="$1"
local my_netns his_netns
[[ ! -f /proc/$$/ns/net ]] && return 0 # no netns feature. treat as same [[ ! -f /proc/$$/ns/net ]] && return 0 # no netns feature. treat as same
my_netns="$(readlink "/proc/$$/ns/net")" [[ "$(readlink /proc/$$/ns/net)" == "$(readlink /proc/$pid2/ns/net)" ]] && return 0
his_netns="$(readlink "/proc/$pid2/ns/net")"
[[ ! -n "$his_netns" ]] && return 1 # can't find his pid or netns (maybe different pidns), treat as not same
[[ "$my_netns" == "$his_netns" ]] && return 0
return 1 return 1
} }
#----------------- #-----------------
@ -1015,7 +918,7 @@ nm_set_managed() {
NM_UNM_LIST= NM_UNM_LIST=
} }
nm_restore_manage() { nm_restore_manage() {
if [[ -n "$NM_UNM_LIST" ]]; then if [[ $NM_UNM_LIST ]]; then
echo "Restore $NM_UNM_LIST managed by NetworkManager" echo "Restore $NM_UNM_LIST managed by NetworkManager"
nm_set_managed "$NM_UNM_LIST" nm_set_managed "$NM_UNM_LIST"
sleep 0.5 sleep 0.5
@ -1037,28 +940,18 @@ is_firewalld_running() {
FIREWALLD_PID= # cancel value if treat as not running FIREWALLD_PID= # cancel value if treat as not running
return 1 # not running return 1 # not running
} }
firewalld_addto_tmptrustedzone() { firewalld_add_tmpzone() {
OLD_FIREWALLD_ZONE="$(firewall-cmd --get-zone-of-interface=$SUBNET_IFACE 2>/dev/null)" # TMP_FIREWALLD_ZONE="lrt${$}${SUBNET_IFACE}"
[[ "$OLD_FIREWALLD_ZONE" == 'trusted' ]] && return TMP_FIREWALLD_ZONE="trusted"
# firewall-cmd --new-zone=$TMP_FIREWALLD_ZONE || die "Failed creating temporary firewalld zone"
TMP_FIREWALLD_ZONE="trusted" # need subnet interface into this zone during linux-router working
if [[ -n "$OLD_FIREWALLD_ZONE" ]]; then
echo "Getting $SUBNET_IFACE out from firewalld zone '$OLD_FIREWALLD_ZONE' ..."
firewall-cmd --zone=$OLD_FIREWALLD_ZONE --remove-interface=$SUBNET_IFACE >/dev/null || die "Failed removing $SUBNET_IFACE from firewalld '$OLD_FIREWALLD_ZONE' zone"
fi
echo "Adding $SUBNET_IFACE to firewalld '$TMP_FIREWALLD_ZONE' 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 '$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_restoreoldzone() { firewalld_del_tmpzone() {
if [[ -n "$TMP_FIREWALLD_ZONE" ]];then if [[ -n "$TMP_FIREWALLD_ZONE" ]];then
echo "Removing $SUBNET_IFACE from firewalld '$TMP_FIREWALLD_ZONE' zone" echo "Removing $SUBNET_IFACE from firewalld '$TMP_FIREWALLD_ZONE' zone"
firewall-cmd --zone=$TMP_FIREWALLD_ZONE --remove-interface=$SUBNET_IFACE >/dev/null firewall-cmd --zone=$TMP_FIREWALLD_ZONE --remove-interface=$SUBNET_IFACE >/dev/null
# firewall-cmd --delete-zone=$TMP_FIREWALLD_ZONE
if [[ -n "$OLD_FIREWALLD_ZONE" ]]; then
echo "Restoring $SUBNET_IFACE to firewalld '$OLD_FIREWALLD_ZONE' zone"
firewall-cmd --zone=$OLD_FIREWALLD_ZONE --add-interface=$SUBNET_IFACE >/dev/null
fi
fi fi
} }
@ -1185,7 +1078,7 @@ start_nat() {
# forward subnet -> internet # forward subnet -> internet
iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \
-o "$INTERNET_IFACE" \ -o $INTERNET_IFACE \
-j ACCEPT || die -j ACCEPT || die
# forward any -> subnet # forward any -> subnet
@ -1291,8 +1184,8 @@ allow_dhcp() {
echo echo
echo "iptables: allow dhcp" echo "iptables: allow dhcp"
iptb 4 v filter I INPUT -i "${SUBNET_IFACE}" -p udp -m udp --dport 67 -j ACCEPT || die 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 iptb 6 v filter I INPUT -i ${SUBNET_IFACE} -p udp -m udp --dport 547 -j ACCEPT || die
} }
# TODO: use 'DNAT' instead of '--to-ports' to support other IP # TODO: use 'DNAT' instead of '--to-ports' to support other IP
@ -1329,8 +1222,8 @@ start_redsocks() {
iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" -s "$SUBNET_NET" -j lrt${$}${SUBNET_IFACE}-TP || 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 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 iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p udp -m udp --dport ${TP_PORT} -j ACCEPT || die
done done
} }
@ -1431,13 +1324,13 @@ _cleanup() {
ip addr flush "${SUBNET_IFACE}" ip addr flush "${SUBNET_IFACE}"
[[ ! "$KEEP_CONFDIR" -eq 1 ]] && rm -rf "$CONFDIR" rm -rf "$CONFDIR"
ip link set down dev "${SUBNET_IFACE}" ip link set down dev "${SUBNET_IFACE}"
firewalld_restoreoldzone firewalld_del_tmpzone
if [[ -n "$VWIFI_IFACE" ]]; then # the subnet interface (virtual wifi interface) will be removed if [[ $VWIFI_IFACE ]]; then # the subnet interface (virtual wifi interface) will be removed
iw dev "${VWIFI_IFACE}" del iw dev "${VWIFI_IFACE}" del
dealloc_vface_name "$VWIFI_IFACE" dealloc_vface_name "$VWIFI_IFACE"
fi fi
@ -1467,7 +1360,6 @@ clean_iptables() {
cleanup() { cleanup() {
trap "" SIGINT SIGUSR1 SIGUSR2 EXIT SIGTERM trap "" SIGINT SIGUSR1 SIGUSR2 EXIT SIGTERM
touch "$CONFDIR/exit_$(date +"%Y-%m-%d_%H:%M:%S.%6N")"
echo echo
echo echo
echo "Doing cleanup.. " echo "Doing cleanup.. "
@ -1510,14 +1402,12 @@ init_conf_dirs() {
cd "$TMPDIR" || die "Couldn't change directory to linux-router's temporary path" cd "$TMPDIR" || die "Couldn't change directory to linux-router's temporary path"
CONFDIR="$(mktemp -d $TMPDIR/lnxrouter.${TARGET_IFACE}.conf.XXXXXX)" || die "Instance couldn't make config dir" # config dir for one instance CONFDIR="$(mktemp -d $TMPDIR/lnxrouter.${TARGET_IFACE}.conf.XXXXXX)" || die "Instance couldn't make config dir" # config dir for one instance
echo "Config dir: $CONFDIR" chmod 755 "$CONFDIR"
chmod 755 "$CONFDIR" || die "chmod config dir failed" #echo "Config dir: $CONFDIR"
echo $$ > "$CONFDIR/pid" echo $$ > "$CONFDIR/pid"
touch "$CONFDIR/begin_$(date +"%Y-%m-%d_%H:%M:%S.%6N")"
COMMON_CONFDIR="$TMPDIR/lnxrouter_common.conf" # config dir for all instances COMMON_CONFDIR="$TMPDIR/lnxrouter_common.conf" # config dir for all instances
mkdir -p "$COMMON_CONFDIR" || die "Failed creating common config dir" mkdir -p "$COMMON_CONFDIR"
} }
#== functions to deal with running instances #== functions to deal with running instances
@ -1767,14 +1657,9 @@ daemonizing_check(){
#============================ #============================
check_wifi_settings() { check_wifi_settings() {
PHY="$(get_interface_phy_device "$WIFI_IFACE")"
if [[ -z "$PHY" ]]; then
echo "ERROR: Can't get phy of wifi interface '$WIFI_IFACE' (Did you spell the interface name right?)" >&2
exit 1
fi
if ! ( which iw > /dev/null 2>&1 && iw dev "$WIFI_IFACE" info > /dev/null 2>&1 ); then 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 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 USE_IWCONFIG=1
fi fi
@ -1961,8 +1846,6 @@ prepare_wifi_interface() {
CHANNEL=36 CHANNEL=36
fi fi
fi fi
echo "Freq band: $FREQ_BAND GHz Channel: $CHANNEL"
} }
decide_subnet_interface() { decide_subnet_interface() {
@ -2024,6 +1907,55 @@ write_hostapd_conf() {
EOF EOF
fi fi
if [[ $HOTSPOT20 -eq 1 ]]; then
echo "hs20=1" >> "$CONFDIR/hostapd.conf"
fi
if [[ $IEEE80211N -eq 1 ]]; then
cat <<- EOF >> "$CONFDIR/hostapd.conf"
ieee80211n=1
ht_capab=${HT_CAPAB}
EOF
fi
if [[ $REQUIREHT -eq 1 ]]; then
echo "require_ht=1" >> "$CONFDIR/hostapd.conf"
fi
if [[ $IEEE80211AC -eq 1 ]]; then
echo "ieee80211ac=1" >> "$CONFDIR/hostapd.conf"
fi
if [[ $REQUIREVHT -eq 1 ]]; then
echo "require_vht=1" >> "$CONFDIR/hostapd.conf"
fi
if [[ -n "$VHT_CAPAB" ]]; then
echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf"
fi
if [[ $VHTCHANNELWIDTH -gt 0 ]]; then
cat <<- EOF >> "$CONFDIR/hostapd.conf"
vht_oper_chwidth=${VHTCHANNELWIDTH}
EOF
fi
if [[ $VHTSEG0CHINDEX -gt 0 ]]; then
cat <<- EOF >> "$CONFDIR/hostapd.conf"
vht_oper_centr_freq_seg0_idx=${VHTSEG0CHINDEX}
EOF
fi
if [[ $VHTSEG1CHINDEX -gt 0 ]]; then
cat <<- EOF >> "$CONFDIR/hostapd.conf"
vht_oper_centr_freq_seg1_idx=${VHTSEG1CHINDEX}
EOF
fi
if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then
echo "wmm_enabled=1" >> "$CONFDIR/hostapd.conf"
fi
if [[ -n "$PASSPHRASE" ]]; then if [[ -n "$PASSPHRASE" ]]; then
[[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3 [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3
if [[ $USE_PSK -eq 0 ]]; then if [[ $USE_PSK -eq 0 ]]; then
@ -2041,91 +1973,6 @@ write_hostapd_conf() {
else else
echo "WARN: WiFi is not protected by password" >&2 echo "WARN: WiFi is not protected by password" >&2
fi fi
if [[ $HOTSPOT20 -eq 1 ]]; then
echo "hs20=1" >> "$CONFDIR/hostapd.conf"
fi
if [[ -n "$STATIMEOUT" ]]; then
echo "ap_max_inactivity=${STATIMEOUT}" >> "$CONFDIR/hostapd.conf"
fi
if [[ $IEEE80211N -eq 1 ]]; then # wifi4
echo "ieee80211n=1" >> "$CONFDIR/hostapd.conf"
if [[ -n "$HT_CAPAB" ]]; then
echo "ht_capab=${HT_CAPAB}" >> "$CONFDIR/hostapd.conf"
fi
if [[ $REQUIREHT -eq 1 ]]; then
echo "require_ht=1" >> "$CONFDIR/hostapd.conf"
fi
fi
if [[ $IEEE80211AC -eq 1 ]]; then # wifi5
echo "ieee80211ac=1" >> "$CONFDIR/hostapd.conf"
if [[ -n "$VHT_CAPAB" ]]; then
echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf"
fi
if [[ -n "$VHTCHANNELWIDTH" ]]; then
echo "vht_oper_chwidth=${VHTCHANNELWIDTH}" >> "$CONFDIR/hostapd.conf"
fi
if [[ -n "$VHTSEG0CHINDEX" ]]; then
echo "vht_oper_centr_freq_seg0_idx=${VHTSEG0CHINDEX}" >> "$CONFDIR/hostapd.conf"
fi
if [[ -n "$VHTSEG1CHINDEX" ]]; then
echo "vht_oper_centr_freq_seg1_idx=${VHTSEG1CHINDEX}" >> "$CONFDIR/hostapd.conf"
fi
if [[ $REQUIREVHT -eq 1 ]]; then
echo "require_vht=1" >> "$CONFDIR/hostapd.conf"
fi
fi
if [[ $IEEE80211AX -eq 1 ]]; then # wifi6
echo "ieee80211ax=1" >> "$CONFDIR/hostapd.conf"
if [[ $REQUIREHE -eq 1 ]]; then
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 "$HECHANNELWIDTH" ]]; then
echo "he_oper_chwidth=${HECHANNELWIDTH}" >> "$CONFDIR/hostapd.conf"
fi
if [[ -n "$HESEG0CHINDEX" ]]; then
echo "he_oper_centr_freq_seg0_idx=${HESEG0CHINDEX}" >> "$CONFDIR/hostapd.conf"
fi
if [[ -n "$HESEG1CHINDEX" ]]; then
echo "he_oper_centr_freq_seg1_idx=${HESEG1CHINDEX}" >> "$CONFDIR/hostapd.conf"
fi
fi
if [[ $P2PTWT -eq 1 ]]; then
echo "peer_to_peer_twt=1" >> "$CONFDIR/hostapd.conf"
fi
if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]] || [[ $IEEE80211AX -eq 1 ]]; then
echo "wmm_enabled=1" >> "$CONFDIR/hostapd.conf"
fi
chmod 600 "$CONFDIR/hostapd.conf" chmod 600 "$CONFDIR/hostapd.conf"
} }
@ -2240,9 +2087,8 @@ run_wifi_ap_processes() {
echo echo
echo "Starting hostapd" echo "Starting hostapd"
if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then if which complain > /dev/null 2>&1; then
echo "Setting hostapd to AppArmor complain mode..." complain hostapd
"$COMPLAIN_CMD" hostapd
fi fi
# hostapd '-P' works only when use '-B' (run in background) # hostapd '-P' works only when use '-B' (run in background)
@ -2262,9 +2108,10 @@ start_dnsmasq() {
echo echo
echo "Starting dnsmasq" echo "Starting dnsmasq"
if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then if which complain > /dev/null 2>&1; then
echo "Setting dnsmasq to AppArmor complain mode..." # openSUSE's apparmor does not allow dnsmasq to read files.
"$COMPLAIN_CMD" dnsmasq # remove restriction.
complain dnsmasq
fi fi
# Using '-d'(no daemon) dnsmasq will not turn into 'nobody' # Using '-d'(no daemon) dnsmasq will not turn into 'nobody'
@ -2285,8 +2132,10 @@ start_dnsmasq() {
} }
check_rfkill_unblock_wifi() { check_rfkill_unblock_wifi() {
local PHY
if which rfkill > /dev/null 2>&1 ; then if which rfkill > /dev/null 2>&1 ; then
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 fi
} }
@ -2368,7 +2217,7 @@ fi
# judge channel availability after changing country code # judge channel availability after changing country code
if [[ $WIFI_IFACE ]] ; then 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. (Tips: 1. Check usable channels: 'iw phy $PHY info'. 2. Check country code then check again. )" can_transmit_to_channel "${AP_IFACE}" ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz."
fi fi
[[ $WIFI_IFACE ]] && write_hostapd_conf [[ $WIFI_IFACE ]] && write_hostapd_conf
@ -2473,7 +2322,7 @@ fi
echo "" echo ""
is_firewalld_running && firewalld_addto_tmptrustedzone is_firewalld_running && firewalld_add_tmpzone
echo echo