2018-08-31 05:41:06 -05:00
#!/bin/bash
2021-11-06 21:31:15 -05:00
VERSION=0.6.6
2018-08-31 05:41:06 -05:00
PROGNAME="$(basename $0)"
export LC_ALL=C
SCRIPT_UMASK=0122
umask $SCRIPT_UMASK
2021-08-28 21:24:50 -05:00
phead() {
echo "linux-router $VERSION (https://github.com/garywill/linux-router)"
}
2021-11-06 21:28:36 -05:00
phead2() {
echo "Released under LGPL, with no warranty. Use on your own risk."
}
2018-08-31 05:41:06 -05:00
usage() {
2021-08-28 21:24:50 -05:00
phead
2021-11-06 21:28:36 -05:00
phead2
2018-08-31 05:41:06 -05:00
cat << EOF
Usage: $PROGNAME <options>
Options:
-h, --help Show this help
--version Print version number
-i <interface> Interface to make NATed sub-network,
and to provide Internet to
2021-11-06 21:31:15 -05:00
(To create WiFi hotspot use '--ap' instead)
2018-08-31 05:41:06 -05:00
-o <interface> Specify an inteface to provide Internet from.
2021-11-06 21:28:36 -05:00
(See Notice 1)
2018-08-31 05:41:06 -05:00
(Note using this with default DNS option may leak
queries to other interfaces)
2020-12-24 06:36:09 -06:00
-n Do not provide Internet (See Notice 1)
2020-12-24 06:36:09 -06:00
--ban-priv Disallow clients to access my private network
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
-g <ip> This host's IPv4 address in subnet (mask is /24)
2021-04-16 23:29:53 -05:00
(example: '192.168.5.1' or '5' shortly)
2018-08-31 05:41:06 -05:00
-6 Enable IPv6 (NAT)
2020-12-24 06:36:09 -06:00
--no4 Disable IPv4 Internet (not forwarding IPv4)
(See Notice 1). Usually used with '-6'
2020-12-24 06:36:09 -06:00
--p6 <prefix> Set IPv6 LAN address prefix (length 64)
2021-04-16 23:29:53 -05:00
(example: 'fd00:0:0:5::' or '5' shortly)
Using this enables '-6'
2018-08-31 05:41:06 -05:00
--dns <ip>|<port>|<ip:port>
DNS server's upstream DNS.
Use ',' to seperate multiple servers
(default: use /etc/resolve.conf)
(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)
2020-12-24 06:36:09 -06:00
whose destination port is 53 to this host
2021-11-06 21:28:36 -05:00
--log-dns Show DNS query log (dnsmasq)
2018-08-31 05:41:06 -05:00
--dhcp-dns <IP1[,IP2]>|no
2021-10-22 21:56:51 -05:00
Set IPv4 DNS offered by DHCP (default: this host).
2018-08-31 05:41:06 -05:00
--dhcp-dns6 <IP1[,IP2]>|no
Set IPv6 DNS offered by DHCP (RA)
(default: this host)
(Note IPv6 addresses need '[]' around)
2021-11-06 21:28:36 -05:00
Using both above two will enable '--no-dns'
2018-08-31 05:41:06 -05:00
--hostname <name> 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 <hosts_file> DNS server will take into account additional
hosts file
2022-04-03 05:03:51 -05:00
--dns-nocache DNS server no cache
2018-08-31 05:41:06 -05:00
--mac <MAC> Set MAC address
2020-12-24 06:36:09 -06:00
--random-mac Use random MAC address
2018-08-31 05:41:06 -05:00
--tp <port> Transparent proxy,
redirect non-LAN TCP and UDP traffic to port.
2021-01-19 23:10:02 -06:00
(usually used with '--dns')
2018-08-31 05:41:06 -05:00
2021-11-06 21:31:15 -05:00
WiFi hotspot options:
2018-08-31 05:41:06 -05:00
--ap <wifi interface> <SSID>
2021-11-06 21:31:15 -05:00
Create WiFi access point
2020-12-24 06:36:09 -06:00
-p, --password <password>
2021-11-06 21:31:15 -05:00
WiFi password
--qr Show WiFi QR code in terminal
2018-08-31 05:41:06 -05:00
--hidden Hide access point (not broadcast SSID)
--no-virt Do not create virtual interface
Using this you can't use same wlan interface
for both Internet and AP
-c <channel> Channel number (default: 1)
--country <code> Set two-letter country code for regularity
(example: US)
--freq-band <GHz> Set frequency band: 2.4 or 5 (default: 2.4)
--driver Choose your WiFi adapter driver (default: nl80211)
2021-01-19 23:10:02 -06:00
-w <WPA version> '2' for WPA2, '1' for WPA, '1+2' for both
(default: 2)
2018-08-31 05:41:06 -05:00
--psk Use 64 hex digits pre-shared-key instead of
passphrase
2021-11-06 21:31:15 -05:00
--mac-filter Enable WiFi hotspot MAC address filtering
--mac-filter-accept Location of WiFi hotspot MAC address filter list
2018-08-31 05:41:06 -05:00
(defaults to /etc/hostapd/hostapd.accept)
--hostapd-debug <level> 1 or 2. Passes -d or -dd to hostapd
--isolate-clients Disable wifi communication between clients
--ieee80211n Enable IEEE 802.11n (HT)
--ieee80211ac Enable IEEE 802.11ac (VHT)
--ht_capab <HT> HT capabilities (default: [HT40+])
--vht_capab <VHT> VHT capabilities
--no-haveged Do not run haveged automatically when needed
Instance managing:
--daemon Run in background
2021-02-21 19:20:41 -06:00
-l, --list-running Show running instances
--lc, --list-clients <id|interface>
2021-01-19 23:10:02 -06:00
List clients of an instance. Or list neighbors of
2021-02-21 19:20:41 -06:00
an interface, even if it isn't handled by us.
(passive mode)
2018-08-31 05:41:06 -05:00
--stop <id> Stop a running instance
For <id> you can use PID or subnet interface name.
You can get them with '--list-running'
2020-12-24 06:36:09 -06:00
Notice 1: This script assume your host's default policy won't forward
packets, so the script won't explictly ban forwarding in any
2021-11-06 21:31:15 -05:00
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
2020-12-24 06:36:09 -06:00
2018-08-31 05:41:06 -05:00
Examples:
$PROGNAME -i eth1
2020-12-24 06:36:09 -06:00
$PROGNAME --ap wlan0 MyAccessPoint -p MyPassPhrase
2018-08-31 05:41:06 -05:00
$PROGNAME -i eth1 --tp <transparent-proxy> --dns <dns-proxy>
EOF
}
2021-01-19 23:10:02 -06:00
check_empty_option(){
if [[ "$1" == "" ]]; then
usage
exit 0
fi
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
define_global_variables(){
2021-01-19 23:10:02 -06:00
# user options
2021-01-19 23:10:02 -06:00
GATEWAY= # IPv4 address for this host
PREFIX6= # IPv6 LAN address prefix for this host
IID6=1 # IPv6 LAN ID for this host
IPV6=0 # enable ipv6
NO4=0 # no IPv4 Internet
BANLAN=0 # ban clients from accessing private addresses
DHCP_DNS=gateway # which ipv4 DNS the DHCP gives clients
DHCP_DNS6=gateway # which ipv6 DNS the DHCP gives clients
dnsmasq_NO_DNS=0 # disable dns server
NO_DNSMASQ=0 # disable dnsmasq (dns and dhcp)
CATCH_DNS=0 # catch clients 53 port packets
SHOW_DNS_QUERY=0 # log dns
ETC_HOSTS=0
ADDN_HOSTS=
2022-04-03 05:03:51 -05:00
DNS_NOCACHE=
2021-01-19 23:10:02 -06:00
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
TP_PORT= # transparent proxy port
DNS= # upstream DNS
2021-01-19 23:10:02 -06:00
MAC_USE_RANDOM=0
2021-01-19 23:10:02 -06:00
NEW_MACADDR=
DAEMONIZE=0
2021-01-19 23:10:02 -06:00
# script variables
SUBNET_IFACE= # which interface to create network
SHARE_METHOD=nat
OLD_MACADDR=
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
##### wifi hotspot
# user options
2021-01-19 23:10:02 -06:00
HIDDEN=0 # hidden wifi hotspot
WIFI_IFACE=
CHANNEL=default
WPA_VERSION=2
MAC_FILTER=0
MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept
IEEE80211N=0
IEEE80211AC=0
HT_CAPAB='[HT40+]'
VHT_CAPAB=
DRIVER=nl80211
NO_VIRT=0 # not use virtual interface
COUNTRY=
FREQ_BAND=2.4
NO_HAVEGED=0
HOSTAPD_DEBUG_ARGS=
USE_PSK=0
ISOLATE_CLIENTS=0
QR=0 # show wifi qr
2021-01-19 23:10:02 -06:00
# script variables
VWIFI_IFACE= # virtual wifi interface name, if created
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
2021-01-19 23:10:02 -06:00
LIST_RUNNING=0
STOP_ID=
LIST_CLIENTS_ID=
# -- variables for running
CONFDIR=
2021-01-19 23:10:02 -06:00
NM_RUNNING=0
NM_UNM_LIST= # it's called "list" but for now one interface
2021-01-19 23:10:02 -06:00
}
parse_user_options(){
while [[ -n "$1" ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--version)
echo "$VERSION"
exit 0
;;
-i)
shift
CONN_IFACE="$1"
shift
;;
-o)
shift
INTERNET_IFACE="$1"
shift
;;
-n)
shift
SHARE_METHOD=none
;;
--ban-priv)
shift
BANLAN=1
;;
--tp)
shift
TP_PORT="$1"
2021-01-19 23:10:02 -06:00
SHARE_METHOD=redsocks
2021-01-19 23:10:02 -06:00
shift
;;
-g)
shift
GATEWAY="$1"
shift
;;
-6)
shift
IPV6=1
;;
--no4)
shift
NO4=1
;;
--p6)
shift
PREFIX6="$1"
IPV6=1
shift
;;
--mac)
shift
NEW_MACADDR="$1"
shift
;;
--random-mac)
shift
2021-01-19 23:10:02 -06:00
MAC_USE_RANDOM=1
2021-01-19 23:10:02 -06:00
;;
--dns)
shift
DNS="$1"
shift
;;
--no-dns)
shift
dnsmasq_NO_DNS=1
;;
--no-dnsmasq)
shift
NO_DNSMASQ=1
;;
--dhcp-dns)
shift
DHCP_DNS="$1"
shift
;;
--dhcp-dns6)
shift
DHCP_DNS6="$1"
shift
;;
--catch-dns)
shift
CATCH_DNS=1
;;
--log-dns)
shift
SHOW_DNS_QUERY=1
;;
--hostname)
shift
THISHOSTNAME="$1"
shift
;;
-d)
shift
ETC_HOSTS=1
;;
-e)
shift
ADDN_HOSTS="$1"
shift
;;
2022-04-03 05:03:51 -05:00
--dns-nocache)
shift
DNS_NOCACHE=1
;;
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
--isolate-clients)
shift
ISOLATE_CLIENTS=1
;;
--ap)
shift
WIFI_IFACE="$1"
shift
SSID="$1"
shift
;;
-p|--password)
shift
PASSPHRASE="$1"
shift
;;
--qr)
shift
QR=1
;;
--hidden)
shift
HIDDEN=1
;;
--mac-filter)
shift
MAC_FILTER=1
;;
--mac-filter-accept)
shift
MAC_FILTER_ACCEPT="$1"
shift
;;
-c)
shift
CHANNEL="$1"
shift
;;
-w)
shift
WPA_VERSION="$1"
[[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2
shift
;;
--ieee80211n)
shift
IEEE80211N=1
;;
--ieee80211ac)
shift
IEEE80211AC=1
;;
--ht_capab)
shift
HT_CAPAB="$1"
shift
;;
--vht_capab)
shift
VHT_CAPAB="$1"
shift
;;
--driver)
shift
DRIVER="$1"
shift
;;
--no-virt)
shift
NO_VIRT=1
;;
--country)
shift
COUNTRY="$1"
shift
;;
--freq-band)
shift
FREQ_BAND="$1"
shift
;;
--no-haveged)
shift
NO_HAVEGED=1
;;
--hostapd-debug)
shift
if [ "x$1" = "x1" ]; then
HOSTAPD_DEBUG_ARGS="-d"
elif [ "x$1" = "x2" ]; then
HOSTAPD_DEBUG_ARGS="-dd"
else
printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1"
exit 1
fi
shift
;;
--psk)
shift
USE_PSK=1
;;
--daemon)
shift
DAEMONIZE=1
;;
--stop)
shift
STOP_ID="$1"
shift
;;
2021-02-21 19:20:41 -06:00
-l|--list-running)
2021-01-19 23:10:02 -06:00
shift
LIST_RUNNING=1
;;
2021-01-19 23:10:02 -06:00
--lc|--list-clients)
2021-01-19 23:10:02 -06:00
shift
LIST_CLIENTS_ID="$1"
shift
;;
*)
echo "Invalid parameter: $1" 1>&2
2018-08-31 05:41:06 -05:00
exit 1
2021-01-19 23:10:02 -06:00
;;
esac
done
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# seperate ip and port
2018-08-31 05:41:06 -05:00
sep_ip_port() {
2021-01-19 23:10:02 -06:00
# usage: sep_ip_port <ip:port> <var for ip> <var for port>
# input <ip:port> can be:
# port (ip is 127.0.0.1)
# ipv4
# [ipv6]
# ipv4:port
# [ipv6]:port
2018-08-31 05:41:06 -05:00
local IP
local PORT
local INPUT
INPUT="$1"
2020-12-24 06:36:09 -06:00
if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then
if (echo "$INPUT" | grep ':' >/dev/null 2>&1) ;then
2018-08-31 05:41:06 -05:00
# ipv4 + port
IP="$(echo $INPUT | cut -d: -f1)"
PORT="$(echo $INPUT | cut -d: -f2)"
else
# ipv4
IP="$INPUT"
fi
2020-12-24 06:36:09 -06:00
elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then
if (echo "$INPUT" | grep '\]\:' >/dev/null 2>&1) ;then
2018-08-31 05:41:06 -05:00
# ipv6 + port
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)"
fi
else
# port
IP='127.0.0.1'
PORT="$INPUT"
fi
printf -v "$2" %s "$IP"
printf -v "$3" %s "$PORT"
}
2021-01-19 23:10:02 -06:00
#=========================
2018-08-31 05:41:06 -05:00
is_interface() {
[[ -z "$1" ]] && return 1
[[ -d "/sys/class/net/${1}" ]]
}
2021-01-19 23:10:02 -06:00
get_interface_phy_device() { # only for wifi interface
2018-08-31 05:41:06 -05:00
local x
for x in /sys/class/ieee80211/*; do
[[ ! -e "$x" ]] && continue
if [[ "${x##*/}" = "$1" ]]; then
2020-12-24 06:36:09 -06:00
echo "$1"
2018-08-31 05:41:06 -05:00
return 0
elif [[ -e "$x/device/net/$1" ]]; then
echo ${x##*/}
return 0
elif [[ -e "$x/device/net:$1" ]]; then
echo ${x##*/}
return 0
fi
done
echo "Failed to get phy interface" >&2
return 1
}
get_adapter_info() { # only for wifi interface
2021-01-19 23:10:02 -06:00
local iPHY
iPHY=$(get_interface_phy_device "$1")
2018-08-31 05:41:06 -05:00
[[ $? -ne 0 ]] && return 1
2021-01-19 23:10:02 -06:00
iw phy $iPHY info
2018-08-31 05:41:06 -05:00
}
get_adapter_kernel_module() {
local MODULE
MODULE=$(readlink -f "/sys/class/net/$1/device/driver/module")
echo ${MODULE##*/}
}
can_be_sta_and_ap() {
# iwconfig does not provide this information, assume false
[[ $USE_IWCONFIG -eq 1 ]] && return 1
if [[ "$(get_adapter_kernel_module "$1")" == "brcmfmac" ]]; then
echo "WARN: brmfmac driver doesn't work properly with virtual interfaces and" >&2
echo " it can cause kernel panic. For this reason we disallow virtual" >&2
echo " interfaces for your adapter." >&2
echo " For more info: https://github.com/oblique/create_ap/issues/203" >&2
return 1
fi
get_adapter_info "$1" | grep -E '{.* managed.* AP.*}' > /dev/null 2>&1 && return 0
get_adapter_info "$1" | grep -E '{.* AP.* managed.*}' > /dev/null 2>&1 && return 0
return 1
}
can_be_ap() {
# iwconfig does not provide this information, assume true
[[ $USE_IWCONFIG -eq 1 ]] && return 0
get_adapter_info "$1" | grep -E '\* AP$' > /dev/null 2>&1 && return 0
return 1
}
can_transmit_to_channel() {
local IFACE CHANNEL_NUM CHANNEL_INFO
IFACE=$1
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
[[ -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:]]?:")
[[ -z "${CHANNEL_INFO}" ]] && return 1
return 0
fi
}
# taken from iw/util.c
ieee80211_frequency_to_channel() {
local FREQ=$1
if [[ $FREQ -eq 2484 ]]; then
echo 14
elif [[ $FREQ -lt 2484 ]]; then
echo $(( ($FREQ - 2407) / 5 ))
elif [[ $FREQ -ge 4910 && $FREQ -le 4980 ]]; then
echo $(( ($FREQ - 4000) / 5 ))
elif [[ $FREQ -le 45000 ]]; then
echo $(( ($FREQ - 5000) / 5 ))
elif [[ $FREQ -ge 58320 && $FREQ -le 64800 ]]; then
echo $(( ($FREQ - 56160) / 2160 ))
else
echo 0
fi
}
is_5ghz_frequency() {
[[ $1 =~ ^(49[0-9]{2})|(5[0-9]{3})$ ]]
}
2021-01-19 23:10:02 -06:00
is_interface_wifi_connected() {
2018-08-31 05:41:06 -05:00
if [[ $USE_IWCONFIG -eq 0 ]]; then
iw dev "$1" link 2>&1 | grep -E '^Connected to' > /dev/null 2>&1 && return 0
else
iwconfig "$1" 2>&1 | grep -E 'Access Point: [0-9a-fA-F]{2}:' > /dev/null 2>&1 && return 0
fi
return 1
}
is_unicast_macaddr() {
local x
x=$(echo "$1" | cut -d: -f1)
x=$(printf '%d' "0x${x}")
[[ $(expr $x % 2) -eq 0 ]]
}
2021-01-19 23:10:02 -06:00
get_interface_mac() {
2018-08-31 05:41:06 -05:00
is_interface "$1" || return
cat "/sys/class/net/${1}/address"
}
2022-01-05 06:01:38 -06:00
get_interface_pci_info() { # pci id / model / virtual
is_interface "$1" || return
local device_path
local pci_id
local pci_full
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)"
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"
fi
elif [[ "$device_path" == *"/virtual/"* ]]; then
echo " virtual interface"
fi
# TODO usb
# TODO current driver
}
2021-01-19 23:10:02 -06:00
alloc_new_vface_name() { # only for wifi
2018-08-31 05:41:06 -05:00
local i=0
local v_iface_name=
while :; do
v_iface_name="x$i${WIFI_IFACE}"
2021-01-19 23:10:02 -06:00
if ! is_interface ${v_iface_name} && [[ ! -f $COMMON_CONFDIR/vfaces/${v_iface_name} ]]; then
mkdir -p $COMMON_CONFDIR/vfaces
touch $COMMON_CONFDIR/vfaces/${v_iface_name}
2020-12-24 06:36:09 -06:00
echo "${v_iface_name}"
2018-08-31 05:41:06 -05:00
return
fi
i=$((i + 1))
done
}
2021-01-19 23:10:02 -06:00
dealloc_vface_name() {
2021-01-19 23:10:02 -06:00
rm -f $COMMON_CONFDIR/vfaces/$1
2018-08-31 05:41:06 -05:00
}
#======
2021-01-19 23:10:02 -06:00
get_all_mac_in_system() {
2018-08-31 05:41:06 -05:00
cat /sys/class/net/*/address
}
2021-01-19 23:10:02 -06:00
get_new_macaddr_according_to_existing() {
local REALDEV OLDMAC NEWMAC LAST_BYTE i
REALDEV=$1
2021-01-19 23:10:02 -06:00
OLDMAC=$(get_interface_mac "$REALDEV")
2021-01-19 23:10:02 -06:00
NEWMAC=""
2018-08-31 05:41:06 -05:00
LAST_BYTE=$(printf %d 0x${OLDMAC##*:})
for i in {10..240}; do
NEWMAC="${OLDMAC%:*}:$(printf %02x $(( ($LAST_BYTE + $i) % 256 )))"
2021-01-19 23:10:02 -06:00
(get_all_mac_in_system | grep "$NEWMAC" > /dev/null 2>&1) || break
2018-08-31 05:41:06 -05:00
done
2020-12-24 06:36:09 -06:00
echo "$NEWMAC"
2018-08-31 05:41:06 -05:00
}
2020-12-24 06:36:09 -06:00
generate_random_mac() {
local r1 r2 r3 r4 r5 r6
2021-01-19 23:10:02 -06:00
local RAND_MAC
2020-12-24 06:36:09 -06:00
while :; do
r1=$( printf "%02x" $(($RANDOM%256/4*4)) )
r2=$( printf "%02x" $(($RANDOM%256)) )
r3=$( printf "%02x" $(($RANDOM%256)) )
r4=$( printf "%02x" $(($RANDOM%256)) )
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 neigh | grep "lladdr $RAND_MAC" > /dev/null 2>&1 ) && \
2021-01-19 23:10:02 -06:00
( ! get_all_mac_in_system | grep $RAND_MAC ) && \
2020-12-24 06:36:09 -06:00
break
done
2021-01-19 23:10:02 -06:00
echo "$RAND_MAC"
2020-12-24 06:36:09 -06:00
}
2021-01-19 23:10:02 -06:00
is_ip4_lan_range_available() { # checks 192.168.x.x
2018-08-31 05:41:06 -05:00
( 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
2020-12-24 06:36:09 -06:00
( 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
2018-08-31 05:41:06 -05:00
return 1
}
2021-01-19 23:10:02 -06:00
is_ip6_lan_range_available() { # checks fdxx::
2018-08-31 05:41:06 -05:00
( 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
2020-12-24 06:36:09 -06:00
( 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
2018-08-31 05:41:06 -05:00
return 1
}
generate_random_ip4() {
local random_ip4
while :; do
random_ip4=$(($RANDOM%256))
2021-01-19 23:10:02 -06:00
is_ip4_lan_range_available $random_ip4 && break
2018-08-31 05:41:06 -05:00
done
2021-01-19 23:10:02 -06:00
echo "192.168.$random_ip4.1"
2018-08-31 05:41:06 -05:00
}
2021-01-19 23:10:02 -06:00
generate_random_lan_ip6_prefix() {
2018-08-31 05:41:06 -05:00
local r1 r2 r3 r4 r5 r6 r7
while :; do
r1=$( printf "%x" $(($RANDOM%240+16)) )
r2=$( printf "%x" $(($RANDOM%240+16)) )
r3=$( printf "%x" $(($RANDOM%240+16)) )
r4=$( printf "%x" $(($RANDOM%240+16)) )
r5=$( printf "%x" $(($RANDOM%240+16)) )
r6=$( printf "%x" $(($RANDOM%240+16)) )
r7=$( printf "%x" $(($RANDOM%240+16)) )
2021-01-19 23:10:02 -06:00
is_ip6_lan_range_available $r1 $r2 $r3 $r4 $r5 $r6 $r7 && break
2018-08-31 05:41:06 -05:00
done
2021-01-19 23:10:02 -06:00
echo "fd$r1:$r2$r3:$r4$r5:$r6$r7::"
2018-08-31 05:41:06 -05:00
}
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
# start haveged when needed
haveged_watchdog() {
local show_warn=1
while :; do
if [[ $(cat /proc/sys/kernel/random/entropy_avail) -lt 1000 ]]; then
if ! which haveged > /dev/null 2>&1; then
if [[ $show_warn -eq 1 ]]; then
echo "WARN: Low entropy detected. We recommend you to install \`haveged'" 1>&2
show_warn=0
fi
2021-04-16 23:29:53 -05:00
elif ! pidof haveged > /dev/null 2>&1; then # TODO judge zombie ?
2018-08-31 05:41:06 -05:00
echo "Low entropy detected, starting haveged" 1>&2
# boost low-entropy
haveged -w 1024 -p $COMMON_CONFDIR/haveged.pid
fi
fi
sleep 2
done
}
2021-04-16 23:29:53 -05:00
pid_watchdog() {
local PID="$1"
local SLEEP="$2"
local ERR_MSG="$3"
local ST
while true
do
if [[ -e "/proc/$PID" ]]; then
ST="$(cat "/proc/$PID/status" | grep "^State:" | awk '{print $2}')"
if [[ "$ST" != 'Z' ]]; then
sleep $SLEEP
continue
fi
fi
die "$ERR_MSG"
done
}
2018-08-31 05:41:06 -05:00
#========
# only support NetworkManager >= 0.9.9
2021-01-19 23:10:02 -06:00
is_nm_running() {
2021-01-19 23:10:02 -06:00
if (which nmcli >/dev/null 2>&1 ) && (nmcli -t -f RUNNING g 2>&1 | grep -E '^running$' >/dev/null 2>&1 ) ; then
2021-01-19 23:10:02 -06:00
echo 1
else
echo 0
2021-01-19 23:10:02 -06:00
fi
}
2018-08-31 05:41:06 -05:00
nm_knows() {
(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
return 0 # managed
}
nm_set_unmanaged() {
while ! nm_knows $1 ; do # wait for virtual wifi interface seen by NM
sleep 0.5
done
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"
NM_UNM_LIST=$1
sleep 1
fi
}
nm_set_managed() {
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
sleep 0.5
fi
}
#=========
2021-08-28 21:27:17 -05:00
check_iptables()
{
echo
iptables --version
if which firewall-cmd > /dev/null 2>&1; then
2021-11-06 21:28:36 -05:00
if [[ "$(firewall-cmd --state 2>&1)" == "running" ]]; then
2021-08-28 21:27:17 -05:00
echo "firewalld is running ($(firewall-cmd --version))"
2021-10-22 21:16:12 -05:00
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=<SUBN_IFACE>'\nWARN: 2) disable firewalld\n" >&2
# TODO
2021-08-28 21:27:17 -05:00
fi
fi
}
2021-11-06 21:30:56 -05:00
CUSTOM_CHAINS_4_filter=
CUSTOM_CHAINS_4_nat=
CUSTOM_CHAINS_6_filter=
CUSTOM_CHAINS_6_nat=
iptb()
2018-08-31 05:41:06 -05:00
{
2021-11-06 21:30:56 -05:00
local FoS=$1 # 4 | 6
shift
local Vis=$1 # 'v' | 'n'
shift
local T=$1 # table
shift
local ACT=$1 # action: I | A | N . On undo: I or A -> D , N -> F+X
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
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
ADD_TO_UNDO=0
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
2021-04-16 23:29:53 -05:00
fi
2021-11-06 21:30:56 -05:00
[[ ! "$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
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
2021-04-16 23:29:53 -05:00
fi
2021-11-06 21:30:56 -05:00
FULL="$CMD_HEAD $MOUTH $NECK -${ACT} ${CH} $@ $TAIL"
#echo $FULL
$FULL
2018-08-31 05:41:06 -05:00
return $?
}
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
echo
echo "iptables: NAT "
2020-12-24 06:36:09 -06:00
if [[ $NO4 -eq 0 ]]; then
2021-11-06 21:30:56 -05:00
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
2018-08-31 05:41:06 -05:00
fi
2021-11-06 21:30:56 -05:00
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
2018-08-31 05:41:06 -05:00
}
2020-12-24 06:36:09 -06:00
start_ban_lan() {
echo
echo "iptables: Disallow clients to access LAN"
2021-11-06 21:30:56 -05:00
iptb 4 n filter N lrt${$}${SUBNET_IFACE}-BLF || die
2021-11-06 21:28:36 -05:00
# TODO: allow '--dhcp-dns(6)' address port 53, which can be something needed, e.g. a VPN's internal private IP
2021-11-06 21:30:56 -05:00
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
2020-12-24 06:36:09 -06:00
2021-11-06 21:30:56 -05:00
iptb 4 n filter I FORWARD -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLF || die
2020-12-24 06:36:09 -06:00
2021-11-06 21:30:56 -05:00
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
2020-12-24 06:36:09 -06:00
2021-11-06 21:30:56 -05:00
iptb 4 n filter I INPUT -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLI || die
2020-12-24 06:36:09 -06:00
2021-11-06 21:30:56 -05:00
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
2020-12-24 06:36:09 -06:00
2021-11-06 21:30:56 -05:00
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
2020-12-24 06:36:09 -06:00
}
2018-08-31 05:41:06 -05:00
allow_dns_port() {
echo
2021-01-19 23:10:02 -06:00
echo "iptables: allow DNS"
2021-11-06 21:30:56 -05:00
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
2018-08-31 05:41:06 -05:00
}
2021-11-06 21:30:56 -05:00
2018-08-31 05:41:06 -05:00
start_catch_dns() {
echo
2021-11-06 21:30:56 -05:00
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
2018-08-31 05:41:06 -05:00
}
2021-11-06 21:30:56 -05:00
2021-01-19 23:10:02 -06:00
allow_dhcp() {
2018-08-31 05:41:06 -05:00
echo
2021-01-19 23:10:02 -06:00
echo "iptables: allow dhcp"
2021-11-06 21:30:56 -05:00
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
2018-08-31 05:41:06 -05:00
}
2021-02-21 19:20:41 -06:00
# TODO: use 'DNAT' instead of '--to-ports' to support other IP
2018-08-31 05:41:06 -05:00
start_redsocks() {
echo
echo "iptables: transparent proxy non-LAN TCP/UDP traffic to port ${TP_PORT}"
2020-12-24 06:36:09 -06:00
if [[ $NO4 -eq 0 ]]; then
2021-11-06 21:30:56 -05:00
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
2020-12-24 06:36:09 -06:00
2021-11-06 21:30:56 -05:00
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
2018-08-31 05:41:06 -05:00
2021-11-06 21:30:56 -05:00
iptb 4 v nat I PREROUTING -i ${SUBNET_IFACE} -s ${GATEWAY%.*}.0/24 -j lrt${$}${SUBNET_IFACE}-TP || die
2018-08-31 05:41:06 -05:00
2021-11-06 21:30:56 -05:00
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
2020-12-24 06:36:09 -06:00
fi
2018-08-31 05:41:06 -05:00
2021-11-06 21:30:56 -05:00
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
2018-08-31 05:41:06 -05:00
2021-11-06 21:30:56 -05:00
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
2018-08-31 05:41:06 -05:00
}
2021-11-06 21:30:56 -05:00
2021-01-19 23:10:02 -06:00
#---------------------------------------
2021-01-19 23:10:02 -06:00
backup_ipv6_bits() {
2021-01-19 23:10:02 -06:00
mkdir "$CONFDIR/sys_6_conf_iface" || die "Failed making dir to save interface IPv6 status"
cp "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6" \
"/proc/sys/net/ipv6/conf/$SUBNET_IFACE/accept_ra" \
"/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr" \
"/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode" \
2021-02-21 19:20:41 -06:00
"$CONFDIR/sys_6_conf_iface/" || die "Failed backing up interface ipv6 bits"
2021-01-19 23:10:02 -06:00
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"
fi
2021-01-19 23:10:02 -06:00
}
2021-01-19 23:10:02 -06:00
set_ipv6_bits() {
2021-01-19 23:10:02 -06:00
if [[ $IPV6 -eq 1 ]]; then
echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6"
echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/accept_ra"
echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr"
echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode"
else
echo 1 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6"
fi
}
2021-01-19 23:10:02 -06:00
restore_ipv6_bits() {
2021-01-19 23:10:02 -06:00
if [[ -d "$CONFDIR/sys_6_conf_iface" ]]; then
cp -f "$CONFDIR/sys_6_conf_iface/*" "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/"
fi
}
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
set_interface_mac() {
local INTERFACE
local MAC
INTERFACE=$1
MAC=$2
ip link set dev ${INTERFACE} address ${MAC}
}
2021-01-19 23:10:02 -06:00
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
2021-02-21 19:20:41 -06:00
#if [[ -n "$NEW_MACADDR" ]]; then
2021-01-19 23:10:02 -06:00
OLD_MACADDR=$(get_interface_mac $SUBNET_IFACE)
2021-02-21 19:20:41 -06:00
#echo "Saved ${SUBNET_IFACE} old MAC address ${OLD_MACADDR} into RAM"
#fi
2021-01-19 23:10:02 -06:00
backup_ipv6_bits
2021-11-06 21:31:15 -05:00
# TODO : ? backup ip and others???
2021-01-19 23:10:02 -06:00
# 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
2021-02-21 19:20:41 -06:00
if [[ -n "$OLD_MACADDR" && "$(get_interface_mac $SUBNET_IFACE)" != "$OLD_MACADDR" ]] ; then
2021-01-19 23:10:02 -06:00
echo "Restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR} ..."
2021-02-21 19:20:41 -06:00
set_interface_mac ${SUBNET_IFACE} ${OLD_MACADDR} || echo "Failed restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR}" >&2
2021-01-19 23:10:02 -06:00
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"
}
2021-01-19 23:10:02 -06:00
#---------------------------------------
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
kill_processes() { # for this instance
2018-08-31 05:41:06 -05:00
#echo "Killing processes"
local x pid
for x in $CONFDIR/*.pid; do
# 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= )
#echo "Killing $pid $pn ... "
2020-12-24 06:36:09 -06:00
pkill -P $pid
2021-11-06 21:28:36 -05:00
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"
2018-08-31 05:41:06 -05:00
fi
done
}
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
_cleanup() {
local x
ip addr flush ${SUBNET_IFACE}
rm -rf $CONFDIR
2021-01-19 23:10:02 -06:00
ip link set down dev ${SUBNET_IFACE}
if [[ $VWIFI_IFACE ]]; then # the subnet interface (virtual wifi interface) will be removed
2018-08-31 05:41:06 -05:00
iw dev ${VWIFI_IFACE} del
2021-01-19 23:10:02 -06:00
dealloc_vface_name $VWIFI_IFACE
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
restore_interface_status
2018-08-31 05:41:06 -05:00
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
2021-01-19 23:10:02 -06:00
rm -d $COMMON_CONFDIR/vfaces
2018-08-31 05:41:06 -05:00
rm -d $COMMON_CONFDIR
rm -d $TMPDIR
else
echo "Exiting: This is NOT the only running instance"
fi
}
clean_iptables() {
2021-11-20 06:32:38 -06:00
[[ -f $CONFDIR/undo_iptables.sh ]] && bash $CONFDIR/undo_iptables.sh
2020-12-24 06:36:09 -06:00
2021-11-06 21:30:56 -05:00
[[ -f $CONFDIR/undo_iptables_2.sh ]] && bash $CONFDIR/undo_iptables_2.sh
2018-08-31 05:41:06 -05:00
}
cleanup() {
trap "" SIGINT SIGUSR1 SIGUSR2 EXIT SIGTERM
echo
echo
echo "Doing cleanup.. "
kill_processes
2021-11-06 21:31:15 -05:00
echo "Undoing iptables changes .."
2021-11-06 21:30:56 -05:00
clean_iptables > /dev/null
2018-08-31 05:41:06 -05:00
_cleanup 2> /dev/null
2021-11-20 06:32:38 -06:00
#pgid=$(ps opgid= $$ |awk '{print $1}' )
#echo "Killing PGID $pgid ..."
#kill -15 -$pgid
#sleep 1
2018-08-31 05:41:06 -05:00
echo "Cleaning up done"
2020-12-24 06:36:09 -06:00
#kill -9 -$pgid
2018-08-31 05:41:06 -05:00
}
2021-02-21 19:20:41 -06:00
# NOTE function die() is designed not to be used before init_trap() executed
2018-08-31 05:41:06 -05:00
die() { # SIGUSR2
echo "Error occured"
[[ -n "$1" ]] && echo -e "\nERROR: $1\n" >&2
# send die signal to the main process
[[ $BASHPID -ne $$ ]] && kill -USR2 $$ || cleanup
exit 1
}
clean_exit() { # SIGUSR1
# send clean_exit signal to the main process
[[ $BASHPID -ne $$ ]] && kill -USR1 $$ || cleanup
exit 0
}
2021-01-19 23:10:02 -06:00
init_trap(){
trap "cleanup" EXIT
trap "clean_exit" SIGINT SIGUSR1 SIGTERM
trap "die" SIGUSR2
}
init_conf_dirs() {
mkdir -p "$TMPDIR" || die "Couldn't make linux-router's temporary dir"
chmod 755 "$TMPDIR" 2>/dev/null
cd "$TMPDIR" || die "Couldn't change directory to linux-router's temporary path"
2021-08-21 20:27:49 -05:00
CONFDIR="$(mktemp -d $TMPDIR/lnxrouter.${TARGET_IFACE}.conf.XXXXXX)" || die "Instance couldn't make config dir" # config dir for one instance
2021-01-19 23:10:02 -06:00
chmod 755 "$CONFDIR"
#echo "Config dir: $CONFDIR"
echo $$ > "$CONFDIR/pid"
COMMON_CONFDIR="$TMPDIR/lnxrouter_common.conf" # config dir for all instances
mkdir -p "$COMMON_CONFDIR"
}
2021-01-19 23:10:02 -06:00
#== functions to deal with running instances
2018-08-31 05:41:06 -05:00
list_running_conf() {
local x
for x in $TMPDIR/lnxrouter.*; do
if [[ -f $x/pid && -f $x/subn_iface && -d /proc/$(cat $x/pid) ]]; then
2020-12-24 06:36:09 -06:00
echo "$x"
2018-08-31 05:41:06 -05:00
fi
done
}
list_running() {
local IFACE subn_iface x
for x in $(list_running_conf); do
IFACE=${x#*.}
IFACE=${IFACE%%.*}
subn_iface=$(cat $x/subn_iface)
if [[ $IFACE == $subn_iface ]]; then
echo $(cat $x/pid) $IFACE
else
echo $(cat $x/pid) $IFACE '('$(cat $x/subn_iface)')'
fi
done
}
get_subn_iface_from_pid() {
list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E "^${1} " | cut -d' ' -f2
}
get_pid_from_subn_iface() {
list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E " ${1}$" | cut -d' ' -f1
}
get_confdir_from_pid() {
local IFACE x
for x in $(list_running_conf); do
if [[ $(cat $x/pid) == "$1" ]]; then
2020-12-24 06:36:09 -06:00
echo "$x"
2018-08-31 05:41:06 -05:00
break
fi
done
}
2021-01-19 23:10:02 -06:00
#======================================================
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
print_clients_from_leases() { # MAC|IP|HOST|lease
local LEASE_FILE="$1"
local FILEC
local line
local LEASEstr LEASEstamp
FILEC="$(cat "$LEASE_FILE" | grep -v -E "^duid\b" | sed -r '/^\s*$/d' )"
2021-02-21 19:20:41 -06:00
# TODO: duid is somewhat related to ipv6. I don't know about it. Not sure excluding it miss some info or not
2021-01-19 23:10:02 -06:00
echo "$FILEC" | while read line
do
#echo aa$line
LEASEstamp="$(echo "$line" | awk '{print $1}')"
MAC="$(echo "$line" | awk '{print $2}')"
IP="$(echo "$line" | awk '{print $3}' | sed 's/\[//g' | sed 's/\]//g')"
2021-02-21 19:20:41 -06:00
HOST="$(echo "$line" | awk '{print $4}' | sed 's/*/?/g' | sed 's/|/_/g' | sed 's/ /_/g' )"
2021-01-19 23:10:02 -06:00
if [[ -n "$MAC" ]]; then
LEASEstr="$(date -d @${LEASEstamp} +%m-%d_%X)"
2018-08-31 05:41:06 -05:00
2021-02-21 19:20:41 -06:00
echo "$MAC|$IP|$HOST|lease_$LEASEstr"
2021-01-19 23:10:02 -06:00
fi
done
}
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 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
# 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')"
fi
2021-02-21 19:20:41 -06:00
if [[ -n "$IP" && ( "$MAC" != "?" || "$STATUS" != "FAILED" ) ]]; then
2021-01-19 23:10:02 -06:00
echo "$MAC|$IP|?|$STATUS"
fi
done
}
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
do
if [[ -n "$MAC" ]]; then
SIGNAL="$(iw dev $IFACE station get $MAC | grep "signal:" | awk '{print $2}')"
2021-02-21 19:20:41 -06:00
echo "${MAC}|?|?|${SIGNAL}_dBm"
2021-01-19 23:10:02 -06:00
fi
done
2018-08-31 05:41:06 -05:00
}
2021-02-21 19:20:41 -06:00
list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active mode)
2021-01-19 23:10:02 -06:00
local IFACE pid
local CONFDIR
local output=""
# If number (PID) is given, get the associated wifi iface
2018-08-31 05:41:06 -05:00
if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then
pid="$1"
2021-01-19 23:10:02 -06:00
IFACE=$(get_subn_iface_from_pid "$pid")
if [[ -z "$IFACE" ]] ; then
echo "'$pid' is not the pid of a running $PROGNAME instance." >&2
exit 1
fi
else # non-number given
IFACE="$1"
if ( ! is_interface $IFACE ) ; then
2021-02-21 19:20:41 -06:00
echo "'$IFACE' is not an interface or PID" >&2
2021-01-19 23:10:02 -06:00
exit 1
fi
pid=$(get_pid_from_subn_iface "$IFACE")
if [[ -n "$pid" ]] ; then # if this interface is hosted by us
CONFDIR=$(get_confdir_from_pid "$pid")
output="$(print_clients_from_leases "$CONFDIR/dnsmasq.leases" )"
else # this interface NOT hosted by us
echo "Tip: '$IFACE' is not an interface hosted by $PROGNAME" >&2
fi
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
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')"
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
echo "$IFACE ($(get_interface_mac $IFACE)) neighbors:"
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
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
do
if [[ -n "$line" ]]; then
echo "$line" | awk -F'|' "{printf \"$fmt\n\",\$1,\$2,\$3,\$4}"
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
done
# TODO : merge same mac and same ip line
2018-08-31 05:41:06 -05:00
}
has_running_instance() {
local PID x
for x in $TMPDIR/lnxrouter.*; do
if [[ -f $x/pid ]]; then
PID=$(cat $x/pid)
if [[ -d /proc/$PID ]]; then
return 0
fi
fi
done
return 1
}
is_running_pid() {
list_running | grep -E "^${1} " > /dev/null 2>&1
}
send_stop() {
local x
# send stop signal to specific pid
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
done
}
## ========================================================
## ========================================================
2021-01-19 23:10:02 -06:00
# decide linux-router's global temporary path for all instances
# this is different and should be before config-saving dir. The latter is for one instance
2021-01-19 23:10:02 -06:00
decide_tmpdir(){
local TMPD
2021-01-19 23:10:02 -06:00
if [[ -d /dev/shm ]]; then
TMPD=/dev/shm
elif [[ -d /run/shm ]]; then
TMPD=/run/shm
else
TMPD=/tmp
fi
2021-01-19 23:10:02 -06:00
#TMPDIR=$TMPD/lnxrouter_tmp
echo "$TMPD/lnxrouter_tmp"
2021-01-19 23:10:02 -06:00
}
2018-08-31 05:41:06 -05:00
#======
2021-01-19 23:10:02 -06:00
check_other_functions(){
if [[ $LIST_RUNNING -eq 1 ]]; then
echo -e "List of running $PROGNAME instances:\n"
list_running
exit 0
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ -n "$LIST_CLIENTS_ID" ]]; then
list_clients "$LIST_CLIENTS_ID"
exit 0
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
##### root test ##### NOTE above don't require root ##########
2021-01-19 23:10:02 -06:00
if [[ $(id -u) -ne 0 ]]; then
2021-11-06 21:31:15 -05:00
echo "ERROR: Need root to continue" >&2
2021-01-19 23:10:02 -06:00
exit 1
fi
2021-01-19 23:10:02 -06:00
###### NOTE below require root ##########
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ -n "$STOP_ID" ]]; then
echo "Trying to kill $PROGNAME instance associated with $STOP_ID..."
send_stop "$STOP_ID"
exit 0
fi
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
daemonizing_check(){
if [[ $DAEMONIZE -eq 1 && $RUNNING_AS_DAEMON -eq 0 ]]; then
echo "Running as Daemon..."
# run a detached lnxrouter
RUNNING_AS_DAEMON=1 setsid "$0" "${ARGS[@]}" &
exit 0
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
#============================
2021-01-19 23:10:02 -06:00
check_wifi_settings() {
2021-02-21 19:20:41 -06:00
if ! ( which iw > /dev/null 2>&1 && iw dev $WIFI_IFACE info > /dev/null 2>&1 ); then
2021-04-16 23:29:53 -05:00
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
2021-02-21 19:20:41 -06:00
exit 1
fi
fi
2021-01-19 23:10:02 -06:00
if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then
echo "ERROR: Invalid frequency band" >&2
exit 1
fi
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
if [[ $CHANNEL == default ]]; then
if [[ $FREQ_BAND == 2.4 ]]; then
CHANNEL=1
else
CHANNEL=36
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ $FREQ_BAND != 5 && $CHANNEL -gt 14 ]]; then
echo "Channel number is greater than 14, assuming 5GHz frequency band"
FREQ_BAND=5
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if ! can_be_ap ${WIFI_IFACE}; then
echo "ERROR: Your adapter does not support AP (master) mode" >&2
exit 1
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if ! can_be_sta_and_ap ${WIFI_IFACE}; then
2021-01-19 23:10:02 -06:00
if is_interface_wifi_connected ${WIFI_IFACE}; then
2021-01-19 23:10:02 -06:00
echo "ERROR: Your adapter can not be a station (i.e. be connected) and an AP at the same time" >&2
2018-08-31 05:41:06 -05:00
exit 1
2021-01-19 23:10:02 -06:00
elif [[ $NO_VIRT -eq 0 ]]; then
echo "WARN: Your adapter does not fully support AP virtual interface, enabling --no-virt" >&2
NO_VIRT=1
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
HOSTAPD=$(which hostapd)
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
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
2021-01-19 23:10:02 -06:00
exit 1
fi
2021-01-19 23:10:02 -06:00
if [[ $DRIVER != "rtl871xdrv" ]]; then
echo "WARN: Your adapter needs rtl871xdrv, enabling --driver=rtl871xdrv" >&2
DRIVER=rtl871xdrv
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
fi
if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then
echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2
exit 1
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ $USE_PSK -eq 0 ]]; then
if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then
echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2
exit 1
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then
echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2
exit 1
fi
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
if [[ $(get_adapter_kernel_module ${WIFI_IFACE}) =~ ^rtl[0-9].*$ ]]; then
if [[ $WPA_VERSION == '1' || $WPA_VERSION == '1+2' ]]; then
echo "WARN: Realtek drivers usually have problems with WPA1, WPA2 is recommended" >&2
fi
echo "WARN: If AP doesn't work, read https://github.com/oblique/create_ap/blob/master/howto/realtek.md" >&2
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
check_if_new_mac_valid() {
2021-01-19 23:10:02 -06:00
if ! is_unicast_macaddr "$NEW_MACADDR"; then
echo "ERROR: The first byte of MAC address (${NEW_MACADDR}) must be even" >&2
exit 1
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ $(get_all_mac_in_system | grep -c ${NEW_MACADDR}) -ne 0 ]]; then
2021-01-19 23:10:02 -06:00
echo "WARN: MAC address '${NEW_MACADDR}' already exists" >&2
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
decide_target_interface() {
2021-01-19 23:10:02 -06:00
# TARGET_IFACE is a existing physical interface
if [[ "$CONN_IFACE" ]]; then
echo "$CONN_IFACE"
elif [[ "$WIFI_IFACE" ]]; then
echo "$WIFI_IFACE"
2021-01-19 23:10:02 -06:00
else
2021-02-21 19:20:41 -06:00
echo "No target interface specified" >&2
return 1
2021-01-19 23:10:02 -06:00
fi
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
decide_ip_addresses() {
if [[ ! -n $GATEWAY ]]; then
2021-01-19 23:10:02 -06:00
GATEWAY="$(generate_random_ip4)"
echo "Use random LAN IPv4 address $GATEWAY"
2021-04-16 23:29:53 -05:00
elif [[ ! "$GATEWAY" =~ "." ]]; then
GATEWAY="192.168.${GATEWAY}.1"
2021-01-19 23:10:02 -06:00
fi
2020-12-24 06:36:09 -06:00
2021-01-19 23:10:02 -06:00
if [[ $IPV6 -eq 1 && ! -n $PREFIX6 ]]; then
2021-01-19 23:10:02 -06:00
PREFIX6="$(generate_random_lan_ip6_prefix)"
echo "Use random LAN IPv6 address ${PREFIX6}${IID6}"
2021-04-16 23:29:53 -05:00
elif [[ ! "$PREFIX6" =~ ":" ]]; then
PREFIX6="fd00:0:0:${PREFIX6}::"
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
if [[ $IPV6 -eq 1 ]]; then
2021-01-19 23:10:02 -06:00
GATEWAY6="${PREFIX6}${IID6}"
2021-01-19 23:10:02 -06:00
fi
}
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
prepare_wifi_interface() {
2021-01-19 23:10:02 -06:00
if [[ $USE_IWCONFIG -eq 0 ]]; then
iw dev ${WIFI_IFACE} set power_save off
fi
if [[ $NO_VIRT -eq 0 ]]; then
2021-01-19 23:10:02 -06:00
## Will generate virtual wifi interface
2021-01-19 23:10:02 -06:00
if is_interface_wifi_connected ${WIFI_IFACE}; then
2021-01-19 23:10:02 -06:00
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
2021-01-19 23:10:02 -06:00
else
2021-01-19 23:10:02 -06:00
FREQ_BAND=2.4
2021-01-19 23:10:02 -06:00
fi
2021-01-19 23:10:02 -06:00
if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then
echo "Channel fallback to ${WIFI_IFACE_CHANNEL}"
CHANNEL=$WIFI_IFACE_CHANNEL
else
echo
2021-01-19 23:10:02 -06:00
fi
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
echo "Creating a virtual WiFi interface... "
2021-01-19 23:10:02 -06:00
VWIFI_IFACE=$(alloc_new_vface_name)
2021-01-19 23:10:02 -06:00
if iw dev ${WIFI_IFACE} interface add ${VWIFI_IFACE} type __ap; then
2021-01-19 23:10:02 -06:00
# Successfully created virtual wifi interface
2021-02-21 19:20:41 -06:00
# if NM running, it will give the new virtual interface a random MAC. MAC will go back after setting NM unmanaged
sleep 2
echo "${VWIFI_IFACE} created"
2021-01-19 23:10:02 -06:00
else
VWIFI_IFACE=
2021-01-19 23:10:02 -06:00
die "Failed creating virtual WiFi interface. Maybe your WiFi adapter does not fully support virtual interfaces. Try again with '--no-virt'"
2021-01-19 23:10:02 -06:00
fi
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
AP_IFACE=${VWIFI_IFACE}
2021-01-19 23:10:02 -06:00
else # no virtual wifi interface, use wifi device interface itself
2021-01-19 23:10:02 -06:00
AP_IFACE=${WIFI_IFACE}
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
decide_subnet_interface() {
if [[ $WIFI_IFACE ]]; then
2021-01-19 23:10:02 -06:00
echo "${AP_IFACE}"
2021-01-19 23:10:02 -06:00
else
2021-01-19 23:10:02 -06:00
echo "${TARGET_IFACE}"
fi
}
dealwith_mac() {
local VMAC
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})
if [[ "$VMAC" ]]; then
echo "Assigning MAC address $VMAC to virtual interface $VWIFI_IFACE according to $WIFI_IFACE ..."
set_interface_mac $VWIFI_IFACE $VMAC
fi
2021-01-19 23:10:02 -06:00
fi
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
write_hostapd_conf() {
2021-01-19 23:10:02 -06:00
cat <<- EOF > "$CONFDIR/hostapd.conf"
beacon_int=100
ssid=${SSID}
interface=${AP_IFACE}
driver=${DRIVER}
channel=${CHANNEL}
ctrl_interface=$CONFDIR/hostapd_ctrl
ctrl_interface_group=0
ignore_broadcast_ssid=$HIDDEN
ap_isolate=$ISOLATE_CLIENTS
EOF
if [[ -n "$COUNTRY" ]]; then
cat <<- EOF >> "$CONFDIR/hostapd.conf"
country_code=${COUNTRY}
ieee80211d=1
2021-01-19 23:10:02 -06:00
EOF
2021-01-19 23:10:02 -06:00
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ $FREQ_BAND == 2.4 ]]; then
echo "hw_mode=g" >> "$CONFDIR/hostapd.conf"
else
echo "hw_mode=a" >> "$CONFDIR/hostapd.conf"
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ $MAC_FILTER -eq 1 ]]; then
cat <<- EOF >> "$CONFDIR/hostapd.conf"
macaddr_acl=${MAC_FILTER}
accept_mac_file=${MAC_FILTER_ACCEPT}
EOF
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ $IEEE80211N -eq 1 ]]; then
cat <<- EOF >> "$CONFDIR/hostapd.conf"
ieee80211n=1
ht_capab=${HT_CAPAB}
EOF
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ $IEEE80211AC -eq 1 ]]; then
echo "ieee80211ac=1" >> "$CONFDIR/hostapd.conf"
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ -n "$VHT_CAPAB" ]]; then
echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf"
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]]; then
echo "wmm_enabled=1" >> "$CONFDIR/hostapd.conf"
fi
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
if [[ -n "$PASSPHRASE" ]]; then
[[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3
if [[ $USE_PSK -eq 0 ]]; then
WPA_KEY_TYPE=passphrase
2021-01-19 23:10:02 -06:00
else
2021-01-19 23:10:02 -06:00
WPA_KEY_TYPE=psk
2021-01-19 23:10:02 -06:00
fi
2021-01-19 23:10:02 -06:00
cat <<- EOF >> "$CONFDIR/hostapd.conf"
wpa=${WPA_VERSION}
wpa_${WPA_KEY_TYPE}=${PASSPHRASE}
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
rsn_pairwise=CCMP
EOF
else
2021-11-06 21:31:15 -05:00
echo "WARN: WiFi is not protected by password" >&2
2021-01-19 23:10:02 -06:00
fi
2021-01-19 23:10:02 -06:00
chmod 600 "$CONFDIR/hostapd.conf"
2021-01-19 23:10:02 -06:00
}
write_dnsmasq_conf() {
2021-01-19 23:10:02 -06:00
if grep "^nobody:" /etc/group >/dev/null 2>&1 ; then
NOBODY_GROUP="nobody"
else
NOBODY_GROUP="nogroup"
fi
2021-04-16 23:29:53 -05:00
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" &
2021-01-19 23:10:02 -06:00
cat <<- EOF > "$CONFDIR/dnsmasq.conf"
user=nobody
group=$NOBODY_GROUP
bind-dynamic
listen-address=${GATEWAY}
interface=$SUBNET_IFACE
except-interface=lo
no-dhcp-interface=lo
dhcp-range=${GATEWAY%.*}.10,${GATEWAY%.*}.250,255.255.255.0
dhcp-option-force=option:router,${GATEWAY}
#log-dhcp
2021-04-16 23:29:53 -05:00
log-facility=$CONFDIR/dnsmasq.log
2021-01-19 23:10:02 -06:00
bogus-priv
domain-needed
EOF
# 'log-dhcp'(Extra logging for DHCP) shows too much logs.
# if use '-d', 'log-facility' should = /dev/null
if [[ $SHARE_METHOD == "none" ]]; then
echo "no-resolv" >> "$CONFDIR/dnsmasq.conf"
echo "no-poll" >> "$CONFDIR/dnsmasq.conf"
fi
if [[ "$DHCP_DNS" != "no" ]]; then
if [[ "$DHCP_DNS" == "gateway" ]]; then
dns_offer="$GATEWAY"
2021-01-19 23:10:02 -06:00
else
2021-01-19 23:10:02 -06:00
dns_offer="$DHCP_DNS"
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
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
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
[[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> "$CONFDIR/dnsmasq.conf"
[[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> "$CONFDIR/dnsmasq.conf"
[[ -n "$ADDN_HOSTS" ]] && echo "addn-hosts=${ADDN_HOSTS}" >> "$CONFDIR/dnsmasq.conf"
if [[ "$THISHOSTNAME" ]]; then
[[ "$THISHOSTNAME" == "-" ]] && THISHOSTNAME="$(cat /etc/hostname)"
echo "interface-name=$THISHOSTNAME,$SUBNET_IFACE" >> "$CONFDIR/dnsmasq.conf"
fi
if [[ ! "$SHOW_DNS_QUERY" -eq 0 ]]; then
echo log-queries=extra >> "$CONFDIR/dnsmasq.conf"
fi
if [[ $DNS ]]; then
DNS_count=$(echo "$DNS" | awk -F, '{print NF}')
for (( i=1;i<=DNS_count;i++ )); do
sep_ip_port "$(echo $DNS | cut -d, -f$i)" DNS_IP DNS_PORT
[[ "$DNS_PORT" ]] && DNS_PORT_D="#$DNS_PORT"
echo "server=${DNS_IP}${DNS_PORT_D}" >> "$CONFDIR/dnsmasq.conf"
done
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
cat <<- EOF >> "$CONFDIR/dnsmasq.conf"
no-resolv
no-poll
EOF
fi
2022-04-03 05:03:51 -05:00
if [[ $DNS_NOCACHE -eq 1 ]]; then
echo "cache-size=0" >> "$CONFDIR/dnsmasq.conf"
echo "no-negcache" >> "$CONFDIR/dnsmasq.conf"
fi
2021-01-19 23:10:02 -06:00
if [[ $IPV6 -eq 1 ]];then
cat <<- EOF >> "$CONFDIR/dnsmasq.conf"
listen-address=${GATEWAY6}
enable-ra
#quiet-ra
dhcp-range=interface:${SUBNET_IFACE},::,::ffff:ffff:ffff:ffff,constructor:${SUBNET_IFACE},ra-stateless,64
EOF
if [[ "$DHCP_DNS6" != "no" ]]; then
if [[ "$DHCP_DNS6" == "gateway" ]]; then
dns_offer6="[$GATEWAY6]"
else
dns_offer6="$DHCP_DNS6"
2021-01-19 23:10:02 -06:00
fi
2021-01-19 23:10:02 -06:00
echo "dhcp-option=option6:dns-server,${dns_offer6}" >> "$CONFDIR/dnsmasq.conf"
2021-01-19 23:10:02 -06:00
fi
fi
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
run_wifi_ap_processes() {
2021-01-19 23:10:02 -06:00
if [[ $NO_HAVEGED -eq 0 ]]; then
haveged_watchdog &
HAVEGED_WATCHDOG_PID=$!
echo "$HAVEGED_WATCHDOG_PID" > "$CONFDIR/haveged_watchdog.pid"
2021-08-28 21:24:50 -05:00
echo
2021-01-19 23:10:02 -06:00
echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID"
fi
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
# start access point
#echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl"
# start hostapd (use stdbuf when available for no delayed output in programs that redirect stdout)
STDBUF_PATH=`which stdbuf`
if [ $? -eq 0 ]; then
STDBUF_PATH=$STDBUF_PATH" -oL"
2021-01-19 23:10:02 -06:00
fi
2021-01-19 23:10:02 -06:00
echo
echo "Starting hostapd"
2021-08-28 21:24:50 -05:00
if which complain > /dev/null 2>&1; then
complain hostapd
fi
2021-01-19 23:10:02 -06:00
# hostapd '-P' works only when use '-B' (run in background)
$STDBUF_PATH hostapd $HOSTAPD_DEBUG_ARGS -P "$CONFDIR/hostapd.pid" "$CONFDIR/hostapd.conf" &
HOSTAPD_PID=$!
echo "$HOSTAPD_PID" > "$CONFDIR/hostapd.pid"
echo "hostapd PID: $HOSTAPD_PID"
#while [[ ! -f $CONFDIR/hostapd.pid ]]; do
# sleep 1
#done
#echo -n "hostapd PID: " ; cat $CONFDIR/hostapd.pid
2021-04-16 23:29:53 -05:00
pid_watchdog $HOSTAPD_PID 10 "hostapd failed" &
2021-01-19 23:10:02 -06:00
sleep 3
2021-01-19 23:10:02 -06:00
}
start_dnsmasq() {
2021-08-28 21:24:50 -05:00
echo
echo "Starting dnsmasq"
2021-01-19 23:10:02 -06:00
if which complain > /dev/null 2>&1; then
# openSUSE's apparmor does not allow dnsmasq to read files.
# remove restriction.
complain dnsmasq
2018-08-31 05:41:06 -05:00
fi
2021-08-28 21:24:50 -05:00
2021-01-19 23:10:02 -06:00
# Using '-d'(no daemon) dnsmasq will not turn into 'nobody'
# '-x' works only when no '-d'
dnsmasq -k -C "$CONFDIR/dnsmasq.conf" -x "$CONFDIR/dnsmasq.pid" -l "$CONFDIR/dnsmasq.leases" &
#####DNSMASQ_PID=$! # only when with '-d'
######echo "dnsmasq PID: $DNSMASQ_PID" # only when with '-d'
i=0; while [[ ! -f "$CONFDIR/dnsmasq.pid" ]]; do
sleep 1
i=$((i + 1))
if [[ $i -gt 10 ]]; then die "Couldn't get dnsmasq PID" ; fi
done
2021-04-16 23:29:53 -05:00
DNSMASQ_PID="$(cat "$CONFDIR/dnsmasq.pid" )"
echo "dnsmasq PID: $DNSMASQ_PID"
2021-01-19 23:10:02 -06:00
######(wait $DNSMASQ_PID ; die "dnsmasq failed") & # wait can't deal with non-child
2021-04-16 23:29:53 -05:00
pid_watchdog $DNSMASQ_PID 9 "dnsmasq failed" &
2021-01-19 23:10:02 -06:00
sleep 2
2021-01-19 23:10:02 -06:00
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
check_rfkill_unblock_wifi() {
local PHY
2021-01-19 23:10:02 -06:00
if which rfkill > /dev/null 2>&1 ; then
2021-01-19 23:10:02 -06:00
PHY=$(get_interface_phy_device ${SUBNET_IFACE})
2021-01-19 23:10:02 -06:00
[[ -n $PHY ]] && rfkill unblock $(rfkill | grep $PHY | awk '{print $1}') >/dev/null 2>&1
2021-01-19 23:10:02 -06:00
fi
}
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
#=========== Above are functions ======================
#=========== Executing begin ==============================
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# if empty option, show usage and exit
2021-01-19 23:10:02 -06:00
check_empty_option "$@"
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# TODO: are some global variables are still defined in those following code?
2021-01-19 23:10:02 -06:00
define_global_variables
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
ARGS=( "$@" )
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
parse_user_options "$@"
2021-01-19 23:10:02 -06:00
# TODO: detect user option conflict
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# check if networkManager running
2021-01-19 23:10:02 -06:00
NM_RUNNING="$(is_nm_running)"
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
TMPDIR="$(decide_tmpdir)"
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# if user choose to deal with running instances, will output some info then exit after this
# NOTE above don't require root
2021-01-19 23:10:02 -06:00
check_other_functions
2021-01-19 23:10:02 -06:00
# NOTE below require root
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# if user choose to daemonize, will start new background process and exit this
2021-01-19 23:10:02 -06:00
daemonizing_check
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# check if wifi will work on this system and user settings
2021-01-19 23:10:02 -06:00
[[ $WIFI_IFACE ]] && check_wifi_settings
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
[[ -n "$NEW_MACADDR" ]] && check_if_new_mac_valid # check NEW_MACADDR. will exit if not valid
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# checks finished
## ===== Above don't echo anything if no warning or error====================
## ========================================================
2021-08-28 21:24:50 -05:00
phead
2021-11-06 21:28:36 -05:00
phead2
echo
2021-01-19 23:10:02 -06:00
echo "PID: $$"
2021-02-21 19:20:41 -06:00
TARGET_IFACE="$(decide_target_interface)" || exit 1 # judge wired (-i CONN_IFACE) or wireless hotspot (--ap $WIFI_IFACE)
2022-01-05 06:01:38 -06:00
echo "Target interface is ${TARGET_IFACE} ($(get_interface_mac $TARGET_IFACE)) $(get_interface_pci_info $TARGET_IFACE)"
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
if [[ "$MAC_USE_RANDOM" -eq 1 ]] ; then
NEW_MACADDR="$(generate_random_mac)"
echo "Use random MAC address $NEW_MACADDR"
fi
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
decide_ip_addresses # ip 4 & 6 lan addresses
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
# if user choose to make DHCP to tell clients to use other DNS, we don't have to serve DNS
[[ $DHCP_DNS != 'gateway' && $DHCP_DNS6 != 'gateway' ]] && dnsmasq_NO_DNS=1
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
#===========================================================
#==== begin to do some change on config files and system===
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
init_trap
2021-02-21 19:20:41 -06:00
# NOTE function die() is designed not to be used before init_trap() executed
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
init_conf_dirs # CONFDIR , COMMON_CONFDIR . make dir
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
[[ $WIFI_IFACE ]] && prepare_wifi_interface # this will create virtual ap interface (if needed) and set VWIFI_IFACE and AP_IFACE (if success)
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
SUBNET_IFACE="$(decide_subnet_interface)" # SUBNET_IFACE can be TARGET_IFACE (wired) or AP_IFACE (ap) .this is after prepare_wifi_interface()
2021-01-19 23:10:02 -06:00
echo "$SUBNET_IFACE" > "$CONFDIR/subn_iface"
2021-01-19 23:10:02 -06:00
# if virtual wifi interface, will be destroyed, so only need to save status when not
[[ -z $VWIFI_IFACE ]] && backup_interface_status
# TODO: should these 2 before calling prepare_wifi_interface ? in check_wifi_settings() ?
# set iw country code
2021-01-19 23:10:02 -06:00
if [[ $WIFI_IFACE && -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then
iw reg set "$COUNTRY" || die "Failed setting country code"
fi
2021-01-19 23:10:02 -06:00
# judge channel availability after changing country code
2021-01-19 23:10:02 -06:00
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."
fi
2021-01-19 23:10:02 -06:00
[[ $WIFI_IFACE ]] && write_hostapd_conf
2018-08-31 05:41:06 -05:00
#===================================================
#===================================================
2021-01-19 23:10:02 -06:00
# set interface unmanaged by networkManager
2021-01-19 23:10:02 -06:00
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
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
[[ $NO_DNSMASQ -eq 0 ]] && write_dnsmasq_conf
2018-08-31 05:41:06 -05:00
#===========================
# initialize subnet interface
2021-01-19 23:10:02 -06:00
# take subnet interface down first
2018-08-31 05:41:06 -05:00
ip link set down dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} down"
2021-01-19 23:10:02 -06:00
# flush old IPs of subnet interface
2018-08-31 05:41:06 -05:00
ip addr flush ${SUBNET_IFACE} || die "Failed flush ${SUBNET_IFACE} IP"
2021-02-21 19:20:41 -06:00
dealwith_mac # setting MAC should be after setting NM unmanaged
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
[[ $WIFI_IFACE ]] && check_rfkill_unblock_wifi
2021-01-19 23:10:02 -06:00
2021-01-19 23:10:02 -06:00
# bring subnet interface up
2018-08-31 05:41:06 -05:00
ip link set up dev ${SUBNET_IFACE} || die "Failed bringing ${SUBNET_IFACE} up"
2021-01-19 23:10:02 -06:00
# hostapd , haveged
[[ $WIFI_IFACE ]] && run_wifi_ap_processes
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
# add ipv4 address to subnet interface
2021-01-19 23:10:02 -06:00
ip -4 addr add ${GATEWAY}/24 broadcast ${GATEWAY%.*}.255 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv4 address"
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
set_ipv6_bits
2021-01-19 23:10:02 -06:00
# add ipv6 address to subnet interface
if [[ $IPV6 -eq 1 ]] ; then
ip -6 addr add ${GATEWAY6}/64 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv6 address"
fi
2020-12-24 06:36:09 -06:00
2021-04-16 23:29:53 -05:00
check_iptables
2021-11-06 21:31:15 -05:00
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
2018-08-31 05:41:06 -05:00
# enable Internet sharing
if [[ "$SHARE_METHOD" == "none" ]]; then
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
echo "No Internet sharing"
2021-01-19 23:10:02 -06:00
2021-11-06 21:31:15 -05:00
echo -e "\nWARN: Since you're using in this mode (no Internet share), make sure you've read Notice 1\n" >&2
2020-12-24 06:36:09 -06:00
[[ "$BANLAN" -eq 1 ]] && start_ban_lan
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
elif [[ "$SHARE_METHOD" == "nat" ]]; then
2021-01-19 23:10:02 -06:00
2021-11-06 21:31:15 -05:00
[[ "$INTERNET_IFACE" ]] && echo -e "\nWARN: Since you're using in this mode (specify Internet interface), make sure you've read Notice 1\n" >&2
2021-11-06 21:28:36 -05:00
[[ "$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
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
start_nat
2021-01-19 23:10:02 -06:00
2020-12-24 06:36:09 -06:00
[[ "$BANLAN" -eq 1 ]] && start_ban_lan
2021-01-19 23:10:02 -06:00
2021-11-06 21:31:15 -05:00
echo 1 > "/proc/sys/net/ipv4/ip_forward" || die "Failed enabling system ipv4 forwarding" # TODO maybe uneeded in '--no4' mode
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
if [[ $IPV6 -eq 1 ]]; then
2021-11-06 21:31:15 -05:00
echo 1 > "/proc/sys/net/ipv6/conf/all/forwarding" || die "Failed enabling system ipv6 forwarding" # TODO if '-o' used, set only 2 interfaces' bits
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
# to enable clients to establish PPTP connections we must
# load nf_nat_pptp module
2021-01-19 23:10:02 -06:00
modprobe nf_nat_pptp > /dev/null 2>&1 && echo "Loaded kernel module nf_nat_pptp"
2018-08-31 05:41:06 -05:00
elif [[ "$SHARE_METHOD" == "redsocks" ]]; then
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
if [[ $IPV6 -eq 1 ]]; then
2021-01-19 23:10:02 -06:00
echo 1 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/forwarding" || die "Failed enabling $SUBNET_IFACE ipv6 forwarding" # to set NA router bit
2018-08-31 05:41:06 -05:00
fi
2021-01-19 23:10:02 -06:00
2021-11-06 21:28:36 -05:00
[[ "$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
2018-08-31 05:41:06 -05:00
2020-12-24 06:36:09 -06:00
[[ "$BANLAN" -eq 1 ]] && start_ban_lan
2021-01-19 23:10:02 -06:00
2018-08-31 05:41:06 -05:00
start_redsocks
fi
# start dhcp + dns (optional)
2021-01-19 23:10:02 -06:00
# allow dns port input even if we don't run dnsmasq
# user can serve their own dns server
[[ "$DHCP_DNS" == "gateway" || "$DHCP_DNS6" == "gateway" ]] && allow_dns_port
2018-08-31 05:41:06 -05:00
[[ "$CATCH_DNS" -eq 1 ]] && start_catch_dns
2021-01-19 23:10:02 -06:00
[[ $NO_DNSMASQ -eq 0 ]] && ( allow_dhcp ; start_dnsmasq )
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
echo
2022-01-05 06:01:38 -06:00
echo "== Setting up completed, now linux-router should be working =="
2018-08-31 05:41:06 -05:00
2021-01-19 23:10:02 -06:00
#============================================================
#============================================================
#============================================================
2018-08-31 05:41:06 -05:00
2020-12-24 06:36:09 -06:00
show_qr() {
local T S P H
S="$SSID"
if [[ -n "$PASSPHRASE" ]]; then
T="WPA"
P="$PASSPHRASE"
else
T="nopass"
fi
[[ "$HIDDEN" -eq 1 ]] && H="true"
echo "Scan QR code on phone to connect to WiFi"
qrencode -m 2 -t ANSIUTF8 "WIFI:T:${T};S:${S};P:${P};H:${H};"
echo "Use this command to save QR code to image file:"
echo " qrencode -m 2 -o <file> \"WIFI:T:${T};S:${S};P:${P};H:${H};\""
2021-01-19 23:10:02 -06:00
echo
2020-12-24 06:36:09 -06:00
}
[[ "$QR" -eq 1 ]] && show_qr
2018-08-31 05:41:06 -05:00
# need loop to keep this script running
bash -c "while :; do sleep 8000 ; done " &
KEEP_RUNNING_PID=$!
2021-01-19 23:10:02 -06:00
echo "$KEEP_RUNNING_PID" > "$CONFDIR/keep_running.pid"
2018-08-31 05:41:06 -05:00
wait $KEEP_RUNNING_PID
clean_exit