# # 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_ (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 -o -j DROP # ebtables -A ssid-isolation -i -o -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