Перейти к содержанию

Рекомендуемые сообщения

Опубликовано (изменено)

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

Для получения данных о текущих 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 и т.п.?

Изменено пользователем Zeleza
Опубликовано
34 минуты назад, Serafim сказал:

ndmc -c show interface

Доброго дня,

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

Опубликовано
3 часа назад, Zeleza сказал:

Доброго дня,

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

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

Опубликовано
16 минут назад, r13 сказал:

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

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

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

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

 

Опубликовано
10 часов назад, Zeleza сказал:

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

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

Опубликовано (изменено)
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" - тоже самое.

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

Изменено пользователем Zeleza
Опубликовано (изменено)

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

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

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

 

Изменено пользователем Zeleza
Опубликовано (изменено)

Чуть модернизировал скрипт - преобразовал в функцию (все "в одном флаконе").
Однако при работе с включёнными уже 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}"

}

 

Изменено пользователем Zeleza
  • 1 год спустя...
Опубликовано

Собираю все интернет-интерфейсы, сопоставляю названия 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

Опубликовано

Доброго дня

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

  1. Какая задача стояла перед Вами при реализации данного решения?
  2. Как Вы реализовали WUI под данную задачу?
     
Опубликовано
2 минуты назад, ANDYBOND сказал:

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

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

Опубликовано
2 часа назад, ANDYBOND сказал:

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

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

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

  • 2 недели спустя...
Опубликовано

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

 

Опубликовано
1 час назад, Serafim сказал:

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

Доброго дня

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

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

Опубликовано
2 минуты назад, Zeleza сказал:

Доброго дня

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

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

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

Опубликовано
2 минуты назад, Serafim сказал:

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

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

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...

Важная информация

На этом сайте используются файлы cookie. Нажимая "Я принимаю" или продолжая просмотр сайта, вы разрешаете их использование: Политика конфиденциальности.