You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
5.9 KiB
Plaintext

#
# Copyright 2018 devolo AG
#
set_delos_peer_isolation() { (
#local EBLOG=--log
action="$1"
delos_determine_prefixes
# throw away current user-defined chains
ebtables -D FORWARD -i ${INTERFACE_PREFIX}0+ -o ${INTERFACE_PREFIX}1+ -j ssid-isolation $EBLOG 2>/dev/null
ebtables -D FORWARD -i ${INTERFACE_PREFIX}1+ -o ${INTERFACE_PREFIX}0+ -j ssid-isolation $EBLOG 2>/dev/null
ebtables -X ssid-isolation 2>/dev/null
[ "$action" = "disable" ] && return 0
# enabled radios
radios=$(ubus call uci get '{"config":"wireless","type":"wifi-device"}' | jsonfilter -e '$.*[!(@.disabled="1")][".name"]')
radios=$(echo $radios) # sic! DO NOT ADD QUOTES!
# if at most 1 radio is enabled no rules are required
[ $(echo $radios | wc -w) -lt 2 ] && return
. /usr/share/libubox/jshn.sh
json_load "$(ubus call uci get '{"config":"wireless","type":"wifi-iface"}')"
json_select values
# Note: result is returned in devs (radios), aps_<radio> (for each radio)
delos_enumerate_${DRIVER}
# if SSIDs for at most 1 radio are enabled no rules are required
[ $(echo "$devs" | wc -w) -lt 2 ] && return
# add the specific peer isolation rules to chain ssid-isolation
# problem: must use same wlan iface enumeration as netifd/mac80211.sh
# ebtables -A ssid-isolation -i <wlan0...> -o <wlan1...> -j DROP
# ebtables -A ssid-isolation -i <wlan1...> -o <wlan0...> -j DROP
# match paired APs ifnames (conditions as in delos-webui: same ssid+encr+key)
# for APs with client isolation/guest wifi restrictions enabled!
## works for 2 radios only. match first device SSIDs with those of 2nd
echo $devs | {
read dev1 dev2 _
eval "ifs1=\${aps_$dev1}"
eval "ifs2=\${aps_$dev2}"
pairs=$(for if1 in $ifs1; do
json_select $if1
json_get_vars ifname ssid encryption key isolate:0 dvl_guest:0 dvl_unrestricted_access:0
# isolate too if guest wifi internet is not unrestricted
[ "$isolate" = "1" ] || ([ "$dvl_guest" = "1" ] && [ "$dvl_unrestricted_access" = "0" ]) && (
# subshell! for separate json context
ifname1=$ifname
ssid1=$ssid
encryption1=$encryption
key1=$key
json_get_var dynamic_vlan dynamic_vlan 0
for if2 in $ifs2; do
json_select ..
json_select $if2
json_get_vars ifname ssid encryption key
[ "$ssid1" = "$ssid" ] &&
[ "$encryption1" = "$encryption" ] &&
[ "$key1" = "$key" ] && {
echo "$if1;$if2"
break
}
done
)
json_select ..
done)
# make rules
chains_installed=
for pair in $pairs; do
json_select ${pair%;*}
json_get_var ifname1 ifname
json_get_vars dynamic_vlan
json_select ..
json_select ${pair#*;}
json_get_var ifname2 ifname
json_select ..
# Once install user-defined chains to group rules for easier deletion
[ -z "$chains_installed" ] && {
chains_installed=1
ebtables -N ssid-isolation -P RETURN
ebtables -A FORWARD -i ${INTERFACE_PREFIX}0+ -o ${INTERFACE_PREFIX}1+ -j ssid-isolation $EBLOG
ebtables -A FORWARD -i ${INTERFACE_PREFIX}1+ -o ${INTERFACE_PREFIX}0+ -j ssid-isolation $EBLOG
}
# rule for plain vlan
ebtables -A ssid-isolation -i $ifname1 -o $ifname2 -j DROP $EBLOG
ebtables -A ssid-isolation -i $ifname2 -o $ifname1 -j DROP $EBLOG
[ "$dynamic_vlan" -gt 0 ] && {
# rule for dynamic vlans
ebtables -A ssid-isolation -i $ifname1.+ -o $ifname2.+ -j DROP $EBLOG
ebtables -A ssid-isolation -i $ifname2.+ -o $ifname1.+ -j DROP $EBLOG
}
done
}
json_select ..
json_cleanup
) }
delos_determine_prefixes() {
if [ -d /sys/class/net/wifi0 ]; then
DRIVER=qcawifi
RADIO_PREFIX="wifi"
INTERFACE_PREFIX="ath"
else
DRIVER=mac80211
RADIO_PREFIX="radio"
INTERFACE_PREFIX="wlan"
fi
}
delos_enumerate_mac80211() {
# APs' ifnames are generated after those of non AP-interfaces (idx covers this)
# find enabled APs of enabled radios, save new radios list in devs
devs=
json_get_keys ifs
for iface in $ifs; do
json_select $iface
json_get_vars disabled mode device
list_contains radios $device && [ "$disabled" != "1" ] && {
list_contains devs $device || {
append devs $device
eval "non_aps_$device="
eval "aps_$device="
}
[ "$mode" != "ap" ] && {
eval ": \$((non_aps_$device++))"
}
[ "$mode" = "ap" ] && {
eval "append aps_$device $iface"
}
}
json_select ..
done
for i in $devs; do
eval "logger \"$i: \${non_aps_$i:-0} non-APs. APs:\${aps_$i}\""
done
for i in $devs; do
eval "idx=\${non_aps_$i}"
eval "ifs=\${aps_$i}"
[ -z "$ifs" ] && return
for iface in $ifs; do
json_select $iface
json_get_vars ifname mode device
[ "$mode" = "ap" ] && [ -z "$ifname" ] && {
json_add_string ifname "${INTERFACE_PREFIX}${i#${RADIO_PREFIX}}${idx:+-${idx}}"
: $((idx++))
}
json_select ..
done
done
}
delos_enumerate_qcawifi() {
# enumerate APs ifnames as in qcawifi, add to json-config
# qcawifi script just takes one interface after another regardless of its type -> skip non-aps
devs=
json_get_keys ifs
for radio in $radios; do
eval idx_$radio=
done
for iface in $ifs; do
json_select $iface
json_get_vars disabled mode device
list_contains radios $device && [ "$disabled" != "1" ] && {
list_contains devs $device || {
append devs $device
}
[ "$mode" = "ap" ] && {
eval "append aps_$device $iface"
}
eval "json_add_string ifname \"${INTERFACE_PREFIX}\${device#\${RADIO_PREFIX}}\${idx_$device:+\$idx_$device}\""
eval ": \$((idx_$device++))"
}
json_select ..
done
}
delos_wifi_peer_isolation_post() {
set_delos_peer_isolation "$@"
}
# is DELOS_WIFI_DRIVERS defined at all (empty or non-empty)? (force exit code 0 if empty,
# don't exit current script if not defined)
if (: ${DELOS_WIFI_DRIVERS?}) 2>/dev/null; then
# we were sourced to register as a plugin
delos_wifi_driver_peer_isolation() {
type=$1; shift
type delos_wifi_peer_isolation_$type >/dev/null 2>/dev/null && delos_wifi_peer_isolation_$type "$@"
}
append DELOS_WIFI_DRIVERS delos_wifi_driver_peer_isolation
fi