Jump to content

Соответствие VPN интерфейсов


Recommended Posts

Всем доброго дня,
Прошу людей умудренных опытом подсказать как связать соответствие данных по имеющимся интерфейсам в системе.

Для получения данных о текущих VPN (и не только) интерфейсах используем API от keenetic:

curl -s "localhost:79/rci/show/interface"

Где можем получить данные по ID, типу интерфейса и его названию и пр.

Скрытый текст

    "OpenVPN0": {
    "id": "OpenVPN0",
    "index": 0,
    "type": "OpenVPN",
    "description": "OVPN",
    "interface-name": "OpenVPN0",
    "link": "down",
    "connected": "no",
    "state": "down",
    "role": [
      "misc"
    ],
--
  "Wireguard0": {
    "id": "Wireguard0",
    "index": 0,
    "type": "Wireguard",
    "description": "WireguardZ",
    "interface-name": "Wireguard0",
    "link": "down",
    "connected": "no",
    "state": "down",

В entware получить информацию о текущих интерфейсах можно 

ip a
ifconfig
Скрытый текст

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1
    link/ipip 0.0.0.0 brd 0.0.0.0
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1
    link/sit 0.0.0.0 brd 0.0.0.0
4: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop qlen 1000
    link/ether ba:9b:92:aw:sb:cd brd ff:ff:ff:ff:ff:ff
5: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop qlen 1
    link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
6: ezcfg0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel qlen 1000
    link/ether ea:ef:06:35:55:15 brd ff:ff:ff:ff:ff:ff
    inet 38.47.115.120/32 brd 38.255.255.255 scope global ezcfg0
       valid_lft forever preferred_lft forever


Так вот вопрос возник следующий - как связать эти данные? Как сопоставить названия интерфейсов?
Например, как определить автоматически, что название tunl0 соответствует OpenVPN0 и т.п.?

Edited by Zeleza
Link to comment
Share on other sites

34 минуты назад, Serafim сказал:

ndmc -c show interface

Доброго дня,

Благодарю Вас, только не совсем Вас понял.
Если речь идет о том, чтобы сопоставить mac адреса в обоих вариантах, то это возможно только для openvpn, а как быть с wireguard например?

Link to comment
Share on other sites

3 часа назад, Zeleza сказал:

Доброго дня,

Благодарю Вас, только не совсем Вас понял.
Если речь идет о том, чтобы сопоставить mac адреса в обоих вариантах, то это возможно только для openvpn, а как быть с wireguard например?

wireguard L3 интерфейс, у него нет mac

Link to comment
Share on other sites

16 минут назад, r13 сказал:

wireguard L3 интерфейс, у него нет mac

Простите, не понял, как Ваш комментарии может помочь в решении вопроса по теме?

10 часов назад, Zeleza сказал:

Как сопоставить названия интерфейсов?
Например, как определить автоматически, что название tunl0 соответствует OpenVPN0 и т.п.?

 

Link to comment
Share on other sites

10 часов назад, Zeleza сказал:

как связать соответствие данных по имеющимся интерфейсам в системе.

Может будет достаточно инфы из хук-скриптов. Вместе имена интерфейсов вместе только там.

Link to comment
Share on other sites

10 часов назад, Александр Рыжов сказал:

Может будет достаточно инфы из хук-скриптов. Вместе имена интерфейсов вместе только там.

Доброго утра,
Благодарю Вас, почти то, что нужно)

Скрытый текст

Wireguard0|nwg0
Wireguard1|nwg1
Wireguard2|nwg2
IKE1|nikecli1
IKE0|nikecli0
OpenVPN0|ovpn_br0

Остается придумать, как в процессе установки пакета запустить сами хуки для включения интерфейсов или смены их IP, или только вручную?

P.S.
Пробую curl -s "localhost:79/rci/interface/connect/via/OpenVPN0" - не поднимается и хук не срабатывает.
Пробую curl -s "localhost:79/rci/interface/openvpn/connect/via/OpenVPN0" - тоже самое.

Как запустить?

Edited by Zeleza
Link to comment
Share on other sites

Нашел "костыль", нужно просто перегрузить роутер, и все соединения срабатывают и получаем список 

Скрытый текст

Wireguard0|nwg0
OpenVPN0|ovpn_br0
GigabitEthernet0|eth2
GigabitEthernet1/0|eth3
WifiMaster0|ra0
WifiMaster1|rai0
CdcEthernet0|cdc_br0
UsbLte0|lte_br0
Bridge0|br0
GigabitEthernet0/Vlan2|eth2.2
Bridge1|br1
GigabitEthernet0/0|eth2
GigabitEthernet0/1|eth2
GigabitEthernet0/Vlan3|eth2.3
Bridge2|br2
IKE0|nikecli0
IKE1|nikecli1
Wireguard1|nwg1
Wireguard2|nwg2
GigabitEthernet0/Vlan1|eth2.1
WifiMaster0/AccessPoint2|ra2
WifiMaster0/AccessPoint0|ra0
WifiMaster1/AccessPoint0|rai0

С другой стороны так же нашел вариант включения хука:

curl -s -d '{"up":"true"}' "localhost:79/rci/interface/OpenVPN0"

Сам скрипт для получения соответствия интерфейсов через обработку "хука":
~ # cat /opt/etc/ndm/ifstatechanged.d/100-save-inface 

#!/bin/sh
# если файла с именами нет - создаем
if ! [ -f /opt/etc/infaces_names ]; then touch /opt/etc/infaces_names; fi

# если интефейса еще нет в списке, то добавляем его
if [ -z "$(grep "${id}" /opt/etc/infaces_names)" ]; then
	echo "${id}|${system_name}" >> /opt/etc/infaces_names
# пишем в лог, по необходимости
	logger "${id} -> ${system_name}"
fi
exit 0

помним про права:

chmod +/opt/etc/ndm/ifstatechanged.d/100-save-inface 

S.P.
Памяти ради, публикую скрипт для получения соответствия интерфейсов без перезагрузки роутера. Он работает в купе со скриптом по обработке "хука" выше:

#!/bin/sh

# очищаем файл с именами интерфейсов
rm /opt/etc/infaces_names

# обозначаем список типов обрабатываемых интерфейсов 
types_inface="openvpn|wireguard|ike|sstp|pppoe|l2tp|cdcethernet"

# получаем список ID интерфейсов в наличии на роутере через пробел  
inface_list=$(curl -s localhost:79/rci/show/interface | grep '"id"' | grep -Ei "${types_inface}" | cut -d':' -f2 | tr -d ' ",' | tr '\n' ' ')
# проходимся по каждому интерфейсу 
for inface in ${inface_list}; do
	# получаем текущее состояние инф-са для возвращения его к исходному состоянию  
	state=$(curl -s localhost:79/rci/show/interface | grep -i "${inface}" -A7| grep -Ei 'state' | cut -d: -f2 | tr -d ' ",')
	# в зависимости от состояния - включем и выключаем или выключаем и включаем интерфейс 
    # для того, чтобы сработал наш хук в файле /opt/etc/ndm/ifstatechanged.d/100-save-inface 
	if [ "${state}" = 'up' ]; then
	 	curl -s -d '{"down":"true"}' "localhost:79/rci/interface/${inface}" &>/dev/null
	else
		curl -s -d '{"up":"true"}' "localhost:79/rci/interface/${inface}" &>/dev/null
	fi
	curl -s -d "{\"${state}\":\"true\"}" "localhost:79/rci/interface/${inface}" &>/dev/null
	# получаем описание интерфейса
	description=$(curl -s localhost:79/rci/show/interface | grep -i "${inface}" -A3 | grep -Ei 'description' | cut -d: -f2 | tr -d ' ",' | sed 's|\/|\//|g')
	# вставляем описание в файл /opt/etc/infaces_names
	sed -i 's/\('"${inface}"'.*\)/\1|'"${description}"'/'  /opt/etc/infaces_names
done

cat /opt/etc/infaces_names

На выходе получаем файл /opt/etc/infaces_names в формате: <ID интерфейса в CLI>|<ID интерфейса в entware>|<Описание интерфейса в CLI>

Скрытый текст

CdcEthernet0|cdc_br0|My Yota
IKE0|nikecli0|L2TP/IPsec
IKE1|nikecli1|ikev2_main
OpenVPN0|ovpn_br0|My OVPN
Wireguard0|nwg0|My Wireguard-1
Wireguard1|nwg1|My Wireguard-2
Wireguard2|nwg2|My Gate

 

Edited by Zeleza
Link to comment
Share on other sites

Чуть модернизировал скрипт - преобразовал в функцию (все "в одном флаконе").
Однако при работе с включёнными уже vpn интерфейсами (у которых долгое время соединения, например openvpn), приходится ставить на паузу минимум в 2 секунды. Может кто из опыта подскажет, как побороть данный недуг?

HOOK_INFACE_FILE=/opt/etc/ndm/ifstatechanged.d/100-get-entware-inface
INFACE_NAMES_FILE=/opt/etc/inface_equals
URL_REQUEST='localhost:79/rci/interface'
# ------------------------------------------------------------------------------------------
#
#	Получаем список соотвествия имен интерфейсов CLI keenetic = Entware
#   	Список забираем из /opt/etc/inface_equals в формате:
#  	<ID интерфейса в CLI>|<ID интерфейса в entware>|<Описание интерфейса в CLI>
#
# ------------------------------------------------------------------------------------------
get_interface_name_list(){

	# если нет файла по отлавливанию хука
	if ! [ -f "${HOOK_INFACE_FILE}" ]; then
	#	создаем файл
cat <<EOF > "${HOOK_INFACE_FILE}"
#!/bin/sh
! [ -f "${INFACE_NAMES_FILE}" ] && touch "${INFACE_NAMES_FILE}"
[ -z "\$(grep "\${id}" "${INFACE_NAMES_FILE}")" ] && echo "\${id}|\${system_name}" >> "${INFACE_NAMES_FILE}"
exit 0
EOF
	chmod +x "${HOOK_INFACE_FILE}"
	fi
	# обозначаем список типов обрабатываемых интерфейсов
	types_inface="openvpn|wireguard|ike|sstp|pppoe|l2tp|cdcethernet"

	# получаем список ID интерфейсов в наличии на роутере через пробел
	inface_list=$(curl -s "${URL_REQUEST}" \
	             | grep '"id"' \
	             | grep -Ei "${types_inface}" \
	             | cut -d':' -f2 \
	             | tr -d ' ",' \
	             | tr '\n' ' '\
	             )
	# проходимся по каждому интерфейсу
	for inface_entware in ${inface_list}; do
		# получаем текущее состояние инф-са для возвращения его к исходному состоянию
		state=$(curl -s "${URL_REQUEST}" \
		       | grep -i "${inface_entware}" -A7 \
		       | grep -Ei 'state' \
		       | cut -d: -f2 | tr -d ' ",'\
		       )
		# в зависимости от состояния - включаем и выключаем или выключаем и включаем интерфейс
		# для того, чтобы сработал наш хук в файле /opt/etc/ndm/ifstatechanged.d/100-save-inface_entware
		if [ "${state}" = 'up' ]; then
			curl -s -d '{"down":"true"}' "${URL_REQUEST}/${inface_entware}" &>/dev/null
		else
			curl -s -d '{"up":"true"}' "${URL_REQUEST}/${inface_entware}" &>/dev/null
		fi
        # Пауза мин. в 2 сек. для получения результата в соединениях, которые не сразу подключаются (как пример OpenVPN)
		sleep 2
		curl -s -d "{\"${state}\":\"true\"}" "${URL_REQUEST}/${inface_entware}" &>/dev/null
		# получаем описание интерфейса
		description=$(curl -s "${URL_REQUEST}" \
		              | grep '"id"' -A7 \
		              | grep -i "${inface_entware}" -A4 \
		              | grep -Ei 'description' \
		              | cut -d: -f2 | tr -d ' ",' \
		              | sed 's|\/|\\/|g'\
		              )
		# вставляем описание в файл /opt/etc/infaces_names
		sed -i 's/\('"${inface_entware}"'.*\)/\1|'"${description}"'/'  "${INFACE_NAMES_FILE}"
	done
	rm -f "${HOOK_INFACE_FILE}"
	cat "${INFACE_NAMES_FILE}"

}

 

Edited by Zeleza
Link to comment
Share on other sites

  • 1 year later...

Собираю все интернет-интерфейсы, сопоставляю названия keenetic и entware:

1. /opt/etc/ndm/ifstatechanged.d/100-netimd

#!/bin/sh
#
# File place: /opt/etc/ndm/ifstatechanged.d
#
source /opt/etc/netimd/netimd.func
OnIfStateChanged
exit 0

2. /opt/etc/netimd/netimd.func

#!/bin/sh

export iface_list_entware=""

NETIMD=netimd
NETIMD_MOD=$NETIMD"v"
NETIMD_APP=$NETIMD"con"
NETIMD_APW=$NETIMD_APP" -web"
CFG_FILE="-cfg -file"

NETIMD_CFG_PATH="/opt/etc/"$NETIMD"/"
IFACE_NAMES_FILE=$NETIMD_CFG_PATH"pub.dev"
EXCL_IFACE_NAMES_FILE=$NETIMD_CFG_PATH"excl.dev"
LINK_DEV=$NETIMD_CFG_PATH"link.dev"
NDMC_SHOW_IFACE="ndmc -c show interface"
SECURITY_LEVEL="security-level"
SECURITY_LEVEL_PUBLIC=$SECURITY_LEVEL": public"

#

excluded_ifaces="ra tun gre ppp etho im"

#stringContain() { [ -z "${2##*$1*}" ]; }
iface_is_not_in_excluded_file() {
    if_name=$1
    
    if grep -q "$if_name" "$EXCL_IFACE_NAMES_FILE"; then
        retval=0
    else
        retval=1
    fi
    return "$retval"
}

iface_needed() {

    if_name=$1

        if [ -z "$if_name" -a "$if_name" != " " ] || \
        [[ $if_name == "lo" ]]; then
        retval=0
    else
        retval=1
        arr=$(echo $excluded_ifaces | tr " " )
        for item in $arr
        do
            #echo "$item $if_name"
            if [[ $if_name == $item* ]]; then
            retval=0
            break;
            fi
        done
        if [ "$retval" -eq 1 ]; then
            iface_is_not_in_excluded_file $if_name
            retval=$?
        fi        


    fi

    return "$retval"

}
iface_keenetic_security_level_public() {
    retval=0
    if_name=$1
        if ! [ -z "$if_name" -a "$if_name" != " " ]; then 
        ret=$($NDMC_SHOW_IFACE "$if_name" | grep "$SECURITY_LEVEL_PUBLIC")
        if ! [ -z "$ret" ]; then    
            retval=1
        fi    
        
    fi      
    return "$retval"

}

iface_keenetic_security_level() {
    if_name=$1

    echo $($NDMC_SHOW_IFACE "$if_name" | grep "$SECURITY_LEVEL" | awk '{print $2}')
}

get_entware_iface_list() {
    #iface_list_long=$(ifconfig | grep "Ethernet" | awk '{print $1}')
    iface_list_long=$(ip a |  grep "mtu" | awk '{print $2}')
    #echo $iface_list_long
    
    for iface_name in $iface_list_long ; do
        iface_name=${iface_name::-1}
    
        iface_needed $iface_name
        retval=$?
        if [ "$retval" == 0 ]
                then
            #echo "iface $iface_name not needed"
            continue;    
        fi    
        
        bInclude=1
        for iface_name2 in $iface_list_long ; do
            iface_name2=${iface_name2::-1}
            if [[ "$iface_name2" == "$iface_name" ]]; then
            continue;
            elif [[ $iface_name2 != *"@"* ]]; then
            continue;
            elif [[ $iface_name2 == *"@"* ]]; then 
              #echo "==> $iface_name2"
              if [[ "$iface_name2" == *"$iface_name" ]]; then
            #echo "found $iface_name in $iface_name2"
            bInclude=0
            break;
              fi
            fi
        done
        if [[ $bInclude -eq 0 ]]; then
            continue;
        fi
        if [[ $iface_name == *"@"* ]]; then 
            iface_name=$(echo "$iface_name" | cut -d "@" -f1)
        fi

        #echo $iface_name
        iface_list_entware="$iface_list_entware$iface_name "
    done
    #echo $iface_list_entware
}
get_keenetic_iface_descr()
{
    if_name=$1
    #echo "$if_name"
    echo $($NDMC_SHOW_IFACE "$if_name" | grep "description" | cut -d ":" -f 2  | cut -c 2- )

    
}

get_keenetic_iface_state()
{
    if_name=$1
    #echo "$if_name"
    echo $($NDMC_SHOW_IFACE "$if_name" | grep "state:" | cut -d ":" -f 2)
    
}

is_netimd_on_iface_exist() {

    if_name="im"${1:2}
    ! [ -z $( (ip a show $if_name | grep $if_name | \
        cut -d "@" -f1 | cut -d " " -f 2) 2> /dev/null) ]
    #! [ -z $(ifconfig $if_name | grep $if_name | cut -d " " -f1 > /dev/null 2>&1 ) ]
}
CheckFile() {
    filename=$1
    if [ -f $filename ]; then
      while IFS= read -r line
      do
        #echo "$line"
        if_linux=$(echo $line | cut -d " " -f 1)
        if_keenetic=$(echo $line | cut -d " " -f 2 | tr -d "\r")

        #echo "$if_linux $if_keenetic"
        
        if is_netimd_on_iface_exist $if_linux; then
            netimd_exist="Y"
        else
            netimd_exist=" "
        fi
        #if_descr=""
                #if_state=""                         
        if_descr=$(get_keenetic_iface_descr $if_keenetic)    
        if_state=$(get_keenetic_iface_state $if_keenetic)

        echo "$if_linux $if_keenetic $if_state im=$netimd_exist $if_descr"

      done < $filename
    fi
}


OnIfStateChanged () {
    # Create file if not exist:
    if ! [ -f $IFACE_NAMES_FILE ]; then touch $IFACE_NAMES_FILE; fi
    #if ! grep -q "${id}" "$IFACE_NAMES_FILE"; then
    iface_needed ${system_name}
    retval=$?
    if [ "$retval" == 0 ]; then
        exit 0
    fi    

    #iface_descr=$(get_keenetic_iface_descr ${id})

    #iface_im=$(is_netimd_on_iface_exist ${system_name})
    #if [ -z "$iface_im" ]; then
    #    status="0"    
    #else
    #    status="1"
    #fi

    seclevel=$(iface_keenetic_security_level ${id})
    #logger "netimd: sec=$seclevel ${id} -> ${system_name}"
    if [ -z "$seclevel" ]; then    
        exit 0
    fi
    
    if ! [[ $seclevel == "public" ]]; then
        exit 0
    fi

    if grep -q "${system_name}" "$IFACE_NAMES_FILE"; then
        exit 0    
    fi        
    # Add record in file if not exist:
    echo "${system_name} ${id}" >> $IFACE_NAMES_FILE
    #logger "add: ${id} -> ${system_name}"
}
 

3. Результат  в /opt/etc/netimd/pub.dev:

apcli0 WifiMaster0/WifiStation0
eth2.2 FastEthernet0/Vlan2
cdc_br0 CdcEthernet0
 

netimd_setting_linked_ifaces.jpg

Link to comment
Share on other sites

Доброго дня

Подскажите пожалуйста:

  1. Какая задача стояла перед Вами при реализации данного решения?
  2. Как Вы реализовали WUI под данную задачу?
     
Link to comment
Share on other sites

2 минуты назад, ANDYBOND сказал:

3. Согласны ли разработчики Кинетика с правомерностью такой модификации их проприентарного кода? @eralde

Ну вообще-то на гитхабе их сдк опуликовано....думаю да...

Link to comment
Share on other sites

2 часа назад, ANDYBOND сказал:

3. Согласны ли разработчики Кинетика с правомерностью такой модификации их проприентарного кода? @eralde

Исходный код веб-интерфейса весь доступен любому пользователю Кинетик. Правда, в минифицированном виде. Мы не можем запретить кому-либо скачать и изучить исходный код веб-интерфейса. Да и не хотим.

Если кому-то удалось добавить к веб-интерфейсу то, чего ему не хватало -- это просто замечательно. Не будь у меня доступа к исходникам, разработка моего расширения требовала бы на порядок больших усилий. Наоборот, мне очень интересно посмотреть как сделано то, что представлено на скриншоте :7_sweat_smile:

  • Thanks 1
Link to comment
Share on other sites

  • 2 weeks later...

Доброго дня! Отвечаю, для чего мне это понадобилось: http://imdtech.ru/technologies/netimd_keenetic/. Задача была простая: добавить модуль симметричного шифрования и управление им. Цепочка решения : собрать модуль и приложение управления под keenetic-sdk, добавить в entware, затем приступил к интерфейсу - добавил контроллер angularjs. Могу читать  и редактировать настроечный файл. Осталось научить работать с моим приложением. Видимо копаем в сторону NodeJs. Жаль  что не удалось через exec в web интерфейсе получить управление своей программой. До этого момента для решения по Web интерфейсу использовал nginx встроенный .

 

  • Upvote 2
Link to comment
Share on other sites

1 час назад, Serafim сказал:

Задача была простая: добавить модуль симметричного шифрования и управление им.

Доброго дня

Если, я все верно понял, то судя по коду (поправьте, если я не прав), Вы выбираете лишь часть интерфейсов, а именно - только те, которые имеют в своем имени '@', а это лишь часть решения описанной в начале этой темы задачи.
Полагаю, что иного решения, чем "передергивание" интерфейсов пока не найдено для получения полного списка соответствий.

Но меня, в большей степени, интересует Ваш опыт по встраиванию Вашего кода в WUI самого роутера. 
Буду Вам очень признателен, если сможете поделиться свои опытом в этом вопросе (можете написать в "личку"). 

Link to comment
Share on other sites

2 минуты назад, Zeleza сказал:

Доброго дня

Если, я все верно понял, то судя по коду (поправьте, если я не прав), Вы выбираете лишь часть интерфейсов, а именно - только те, которые имеют в своем имени '@', а это лишь часть решения описанной в начале этой темы задачи.
Полагаю, что иного решения, чем "передергивание" интерфейсов пока не найдено для получения полного списка соответствий.

Но меня, в большей степени, интересует Ваш опыт по встраиванию Вашего кода в WUI самого роутера. 
Буду Вам очень признателен, если сможете поделиться свои опытом в этом вопросе (можете написать в "личку"). 

Дело в том, что встраивания в фирваре я не производил. Запускаю параллельно с основным интерфейсом сайт на другом порту( в данном случае 81) под тем же nginx. Команда на запуск подается после запуска entware через s файл , находящийся в /opt/etc/init.d . Для размещения собственного кода в интерфейс  распаковываю файл App…..Js из каталога scrips сайта и работаю с ним. 

Link to comment
Share on other sites

2 минуты назад, Serafim сказал:

Дело в том, что встраивания в фирваре я не производил. Запускаю параллельно с основным интерфейсом сайт на другом порту( в данном случае 81) под тем же nginx. Команда на запуск подается после запуска entware через s файл , находящийся в /opt/etc/init.d . Для размещения собственного кода в интерфейс  распаковываю файл App…..Js из каталога scrips сайта и работаю с ним. 

Понял Вас, спасибо.
В любом случае, отличная работа!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...