78

Как я могу поддерживать локальный доступ к локальной сети при подключении к Cisco VPN?

При подключении с использованием Cisco VPN сервер должен указывать клиенту запретить доступ к локальной сети.

Предполагая, что эту опцию на стороне сервера нельзя отключить, как разрешить локальный доступ к локальной сети при подключении к клиенту Cisco VPN?


Раньше я думал, что это просто вопрос добавления маршрутов, которые захватывают трафик локальной сети с более высоким показателем, например:

  Network 
Destination      Netmask        Gateway       Interface  Metric
   10.0.0.0  255.255.0.0       10.0.0.3        10.0.0.3      20  <--Local LAN
   10.0.0.0  255.255.0.0  192.168.199.1  192.168.199.12       1  <--VPN Link

И попытка удалить 10.0.x.x -> 192.168.199.12 не имеет никакого эффекта:

>route delete 10.0.0.0
>route delete 10.0.0.0 mask 255.255.0.0
>route delete 10.0.0.0 mask 255.255.0.0 192.168.199.1
>route delete 10.0.0.0 mask 255.255.0.0 192.168.199.1 if 192.168.199.12
>route delete 10.0.0.0 mask 255.255.0.0 192.168.199.1 if 0x3

И хотя это все еще может быть просто проблемой маршрутизации, попытки добавить или удалить маршруты терпят неудачу.

На каком уровне драйвер клиента Cisco VPN делает то, что в сетевом стеке, который принимает, отвергает способность локального администратора администрировать свою машину?

Клиент Cisco VPN не может использовать магию. Это все еще программное обеспечение, работающее на моем компьютере. Какой механизм он использует для вмешательства в сеть моей машины? Что происходит, когда в сеть поступает пакет IP/ICMP? Где в сетевом стеке пакет съедается?

Смотрите также


Изменить: вещи, которые я еще не пробовал:

>route delete 10.0.*

Обновление: поскольку Cisco отказалась от своего старого клиента в пользу AnyConnect (VPN на основе HTTP SSL), этот вопрос, нерешенный, можно оставить как пережиток истории.

В дальнейшем мы можем попытаться решить ту же проблему со своим новым клиентом.

10 ответов10

53

Проблема с Anyconnect заключается в том, что он сначала изменяет таблицу маршрутизации, затем присматривает за ней и исправляет ее, если вы измените ее вручную. Я нашел обходной путь для этого. Работает с версиями 3.1.00495, 3.1.05152, 3.1.05170 и, возможно, с чем-либо еще из семейства 3.1. Может работать с другими версиями, по крайней мере, аналогичная идея должна работать при условии, что код не будет переписан. К счастью для нас, компания Cisco поместила вызов няни "бодрствующий ребенок" в общую библиотеку. Таким образом, идея заключается в том, что мы предотвращаем действия vpnagentd через LD_PRELOAD.

  1. Сначала мы создаем файл hack.c:

    #include <sys/socket.h>
    #include <linux/netlink.h>
    
    int _ZN27CInterfaceRouteMonitorLinux20routeCallbackHandlerEv()
    {
      int fd=50;          // max fd to try
      char buf[8192];
      struct sockaddr_nl sa;
      socklen_t len = sizeof(sa);
    
      while (fd) {
         if (!getsockname(fd, (struct sockaddr *)&sa, &len)) {
            if (sa.nl_family == AF_NETLINK) {
               ssize_t n = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
            }
         }
         fd--;
      }
      return 0;
    }
    
  2. Затем скомпилируйте это так:

    gcc -o libhack.so -shared -fPIC hack.c
    
  3. Установите libhack.so в путь к библиотеке Cisco:

    sudo cp libhack.so  /opt/cisco/anyconnect/lib/
    
  4. Сбить агента:

    /etc/init.d/vpnagentd stop
    
  5. Убедитесь, что это действительно вниз

    ps auxw | grep vpnagentd
    

    Если нет, kill -9 просто для уверенности.

  6. Затем исправьте /etc/init.d/vpnagentd, добавив LD_PRELOAD=/opt/cisco/anyconnect/lib/libhack.so где вызывается vpnagentd, чтобы он выглядел так:

    LD_PRELOAD=/opt/cisco/anyconnect/lib/libhack.so /opt/cisco/anyconnect/bin/vpnagentd
    
  7. Теперь запустите агент:

    /etc/init.d/vpnagentd start
    
  8. Исправьте iptables, потому что AnyConnect портится с ними:

    iptables-save | grep -v DROP | iptables-restore
    

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

  9. Теперь исправьте маршруты по своему усмотрению, например:

    route add -net 192.168.1.0 netmask 255.255.255.0 dev wlan0
    
  10. Проверьте, действительно ли они там:

    route -n
    

Предыдущая, более простая версия этого хака дала функцию, которая только «возвращала 0;» - на этом постере отмечалось, что «единственный побочный эффект, который я наблюдал до сих пор, заключается в том, что vpnagentd использует 100% ЦП, о чем сообщает top, но общий ЦП составляет всего 3% пользователей и 20% системы, и система прекрасно реагирует». , Я ограничил это, кажется, что он делает два выбора в цикле, когда простаивает, возвращаясь из обоих быстро, но он никогда не читает и не записывает - я предполагаю, что вызов, который я вырезал с помощью LD_PRELOAD, должен был прочитать. Возможно, есть более чистый способ сделать это, но для меня это пока достаточно. Если у кого-то есть лучшее решение, пожалуйста, поделитесь. "

Проблема с тривиальным взломом заключается в том, что оно заставляет одно ядро процессора постоянно работать на 100%, эффективно уменьшая количество потоков аппаратного процессора на единицу - было ли ваше соединение vpn активным или нет. Я заметил, что выборки, которые делал код, находились в сокете netlink, который отправляет данные vpnagentd при изменении таблицы маршрутизации. vpnagentd продолжает замечать, что в сокете netlink есть новое сообщение и вызывает routeCallBackHandler, чтобы разобраться с ним, но поскольку тривиальный хак не очищает новое сообщение, он просто продолжает вызываться снова и снова. новый код, приведенный выше, сбрасывает данные netlink, поэтому бесконечный цикл, который привел к 100% -ному процессору, не происходит.

Если что-то не работает, выполните gdb -p $(pidof vpnagentd) , как только присоедините:

b socket
c
bt

и посмотреть, в каком вы звоните. Затем просто догадайтесь, какой из них вы хотите вырезать, добавьте его в hack.c и перекомпилируйте.

11

Это ОЧЕНЬ запутанно, но если вы создаете минимальную виртуальную машину с помощью VMWare Player или аналогичного устройства и запускаете в ней клиент Cisco AnyConnect VPN, возможно, можно настроить маршрутизацию по своему усмотрению с использованием виртуальных сетевых адаптеров VMWare или просто использовать ВМ для доступа к любым ресурсам, которые требуются через Cisco SSL VPN и файлы «перетаскивания» на / с вашей реальной машины.

5

Спасибо Саше Пачеву за хороший взлом выше.

vpnagentd также портит распознаватель, перезаписывая изменения, внесенные в /etc/resolv.conf . Я решил это, в конечном итоге выиграв гонку против него:

#!/bin/bash

dnsfix() {
    [ -f /etc/resolv.conf.vpnbackup ] || echo "Not connected?" >&2 || return 0 # do nothing in case of failure
    while ! diff -q /etc/resolv.conf /etc/resolv.conf.vpnbackup #>/dev/null
    do
         cat /etc/resolv.conf.vpnbackup >/etc/resolv.conf
    done
    chattr +i /etc/resolv.conf
    diff -q /etc/resolv.conf /etc/resolv.conf.vpnbackup >/dev/null 
}

while ! dnsfix
do
    echo "Retrying..."
    chattr -i /etc/resolv.conf
done

Не забудьте использовать chattr -i /etc/resolv.conf при отключении.

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

Update1/2: strace показал , что vpnagentd использует inotify API для отслеживания изменений распознаватель файлов. С этого момента это было вниз по склону. Вот дополнительный хак:

int _ZN18CFileSystemWatcher11AddNewWatchESsj(void *string, unsigned int integer)
{
  return 0;
}

Это немного излишне, так как отключает просмотр всех файлов для агента. Но, похоже, работает хорошо.

Сценарий оболочки клиента vpn ниже объединяет все функциональные возможности (обновлен, чтобы включить этот дополнительный хак). chattr больше не используется / нужен.

Обновление 3: исправлены настройки имени пользователя / пароля в скрипте. Теперь он использует файл vpn.conf в формате, описанном ниже (и разрешения только для root).

#!/bin/bash

# Change this as needed
CONF="/etc/vpnc/vpn.conf"
# vpn.conf format
#gateway <IP>
#username <username>
#password <password>
#delete_routes <"route spec"...> eg. "default gw 0.0.0.0 dev cscotun0"
#add_routes <"route spec"...> eg. "-net 192.168.10.0 netmask 255.255.255.0 dev cscotun0" "-host 10.10.10.1 dev cscotun0"

ANYCONNECT="/opt/cisco/anyconnect"

usage() {
    echo "Usage: $0 {connect|disconnect|state|stats|hack}"
    exit 1
}

CMD="$1"
[ -z "$CMD" ] && usage

ID=`id -u`

VPNC="$ANYCONNECT/bin/vpn"

dnsfix() {
    [ -f /etc/resolv.conf.vpnbackup ] || echo "Not connected?" >&2 || return 0 # do nothing in case of failure
    while ! diff -q /etc/resolv.conf /etc/resolv.conf.vpnbackup >/dev/null
    do
         cat /etc/resolv.conf.vpnbackup >/etc/resolv.conf
    done
#    chattr +i /etc/resolv.conf
    diff -q /etc/resolv.conf /etc/resolv.conf.vpnbackup >/dev/null 
}

case "$CMD" in
    "connect")
        [ $ID -ne 0 ] && echo "Needs root." && exit 1
        HOST=`grep ^gateway $CONF | awk '{print $2}'`
        USER=`grep ^user $CONF | awk '{print $2}'`
        PASS=`grep ^password $CONF | awk '{print $2}'`
        OLDIFS=$IFS
        IFS='"'
        DEL_ROUTES=(`sed -n '/^delete_routes/{s/delete_routes[ \t\"]*//;s/\"[ \t]*\"/\"/g;p}' $CONF`)
        ADD_ROUTES=(`sed -n '/^add_routes/{s/add_routes[ \t\"]*//;s/\"[ \t]*\"/\"/g;p}' $CONF`)
        IFS=$OLDIFS

        /usr/bin/expect <<EOF
set vpn_client "$VPNC";
set ip "$HOST";
set user "$USER";
set pass "$PASS";
set timeout 5
spawn \$vpn_client connect \$ip
match_max 100000
expect { 
    timeout {
        puts "timeout error\n"
        spawn killall \$vpn_client
        exit 1
    }
    ">> The VPN client is not connected." { exit 0};
    ">> state: Disconnecting" { exit 0};
    "Connect Anyway?"
}
sleep .1
send -- "y\r"
expect { 
    timeout {
        puts "timeout error\n"
        spawn killall \$vpn_client
        exit 1
    }
    "Username:"
}
sleep .1
send -- "\$user\r"
expect { 
    timeout {
        puts "timeout error\n"
        spawn killall \$vpn_client
        exit 1
    }
    "Password: "
}
send -- "\$pass\r";
expect eof
EOF
        sleep 2
        # iptables
        iptables-save | grep -v DROP | iptables-restore

        # routes
        for ROUTE in "${DEL_ROUTES[@]}"
        do
#            echo route del $ROUTE
            route del $ROUTE
        done
        for ROUTE in "${ADD_ROUTES[@]}"
        do
#            echo route add $ROUTE
            route add $ROUTE
        done

        # dns
        while ! dnsfix
        do
            echo "Try again..."
#            chattr -i /etc/resolv.conf
        done

        echo "done."
        ;;
    "disconnect")
#        [ $ID -ne 0 ] && echo "Needs root." && exit 1
        # dns
#        chattr -i /etc/resolv.conf

        $VPNC disconnect
        ;;
    "state"|"stats")
        $VPNC $CMD
        ;;
    "hack")
        [ $ID -ne 0 ] && echo "Needs root." && exit 1
        /etc/init.d/vpnagentd stop
        sleep 1
        killall -9 vpnagentd 2>/dev/null
        cat - >/tmp/hack.c <<EOF
#include <sys/socket.h>
#include <linux/netlink.h>

int _ZN27CInterfaceRouteMonitorLinux20routeCallbackHandlerEv()
{
  int fd=50;          // max fd to try
  char buf[8192];
  struct sockaddr_nl sa;
  socklen_t len = sizeof(sa);

  while (fd) {
     if (!getsockname(fd, (struct sockaddr *)&sa, &len)) {
        if (sa.nl_family == AF_NETLINK) {
           ssize_t n = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
        }
     }
     fd--;
  }
  return 0;
}

int _ZN18CFileSystemWatcher11AddNewWatchESsj(void *string, unsigned int integer)
{
  return 0;
}
EOF
        gcc -o /tmp/libhack.so -shared -fPIC /tmp/hack.c
        mv /tmp/libhack.so $ANYCONNECT
        sed -i "s+^\([ \t]*\)$ANYCONNECT/bin/vpnagentd+\1LD_PRELOAD=$ANYCONNECT/lib/libhack.so $ANYCONNECT/bin/vpnagentd+" /etc/init.d/vpnagentd
        rm -f /tmp/hack.c
        /etc/init.d/vpnagentd start
        echo "done."
        ;;
    *)
        usage
        ;;
esac
5

Программное обеспечение Shrew Soft VPN также помогло мне, как предположил Иан Бойд .

Он может импортировать профили клиента Cisco VPN. Я использовал Cisco VPN Client версии 5.0.05.0290, и после установки Shrew VPN (версия 2.1.7) и импорта профиля Cisco я смог получить доступ к локальной локальной сети при подключении к корпоративной VPN без какой-либо дополнительной настройки подключения Shrew VPN (или программного обеспечения).

4

Моя компания до сих пор использует этот VPN. Клиент vpnc просто меняет настройки iptables таким образом:

# iptables-save
# Generated by iptables-save v1.4.10 on Sun Jun 17 14:12:20 2012
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT DROP [0:0]
-A INPUT -s 123.244.255.254/32 -d 192.168.0.14/32 -j ACCEPT 
-A INPUT -i tun0 -j ACCEPT 
-A INPUT -i lo0 -j ACCEPT
-A INPUT -j DROP 
-A OUTPUT -s 192.168.0.14/32 -d 123.244.255.254/32 -j ACCEPT 
-A OUTPUT -o tun0 -j ACCEPT 
-A OUTPUT -o lo0 -j ACCEPT 
-A OUTPUT -j DROP 
COMMIT

Он фильтрует все, кроме трафика VPN.

Просто добавьте фильтр в файл с помощью iptables-save, добавьте строки доступа INPUT и OUTPOUT, соответствующие вашим потребностям, и повторно примените файл с помощью iptables-restore.

например, для доступа к локальной сети на 192.168.0

# Generated by iptables-save v1.4.10 on Sun Jun 17 14:12:20 2012
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT DROP [0:0]
-A INPUT -s 123.244.255.254/32 -d 192.168.0.14/32 -j ACCEPT 
-A INPUT -s 192.168.0.0/24 -d 192.168.0.14/32 -j ACCEPT      #local in
-A INPUT -i tun0 -j ACCEPT 
-A INPUT -i lo0 -j ACCEPT 
-A INPUT -j DROP 
-A OUTPUT -s 192.168.0.14/32 -d 123.244.255.254/32 -j ACCEPT 
-A OUTPUT -s 192.168.0.14/32 -d 192.168.0.0/24 -j ACCEPT     #local out
-A OUTPUT -o tun0 -j ACCEPT 
-A OUTPUT -o lo0 -j ACCEPT 
-A OUTPUT -j DROP 
COMMIT
3

Есть новости по этому поводу?

На каком уровне драйвер клиента Cisco VPN делает то, что в сетевом стеке, который принимает, отвергает способность локального администратора администрировать свою машину?

Я полностью согласен и задавался вопросом об одном и том же.

В любом случае, это приложение, для установки которого требуются права администратора, и во время работы оно может очень хорошо фильтровать то, что вы делаете ...

Мои попытки на Windows тоже терпят неудачу:

route change 0.0.0.0 mask 0.0.0.0 192.168.1.1 metric 1
 OK!

IPv4 Route Table
===========================================================================
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0      192.168.1.1    192.168.1.230     21 <-- LAN
          0.0.0.0          0.0.0.0    192.168.120.1    192.168.120.3      2 <-- VPN

Ха-ха. Нет метрики ниже 20 здесь, кажется.

3

Я не знаю, правильно ли я это понял, но сначала уточню свое понимание:

У вас есть локальная локальная сеть (например, 10.0.0.0/16) и удаленный сервер Cisco VPN (например, 64.0.0.0/16). Вы хотите подключиться к VPN-серверу через VPN-клиент Cisco, но вам необходим доступ к локальной сети. В этом случае вы хотите отделить все 10.0.xx /16 от VPN-соединения). В клиенте Mac должен быть добавлен следующий маршрут:

/sbin/route add -net 10.0 -interface en1

где en1 - интерфейс, через который вы подключены к вашей локальной сети. Я знаю, что вы можете добавить то же самое в Windows и Linux.

2

Поскольку я не могу добавлять комментарии, я опубликую здесь. Я работаю на Windows.

Решение, использующее виртуальную машину и запускающее AnyConnect внутри виртуальной машины, а затем использующее виртуальную машину в качестве посредника между вашей рабочей средой и сетью компании, не будет работать, если ваш "любимый" ИТ-отдел маршрутизирует 0.0.0.0 через VPN, то есть даже в вашу локальную сеть (включая эту). между вашим локальным ПК и виртуальной машиной) маршрутизируется через VPN (так!).

Я пытался применить решение, опубликованное @Sasha Pachev, но в итоге я исправил .dll так, что он возвращает 0 в начале функции. В конце концов, после некоторой борьбы с динамической библиотекой, я смог изменить таблицы маршрутизации в соответствии со своими потребностями, но этого явно недостаточно!

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

  • Мой шлюз в интернет 192.168.163.2
  • Мой выход в сеть компании является 10.64.202.1 (таким образом , вся 10... * Подсеть Лечу , как «Comapny в»)

Вот так сейчас выглядит моя таблица маршрутизации (после ручных изменений, когда VPN включен)

пока результат пинга следующий

C:\Users\Mike>ping -n 1 10.64.10.11
Reply from 10.64.10.11: bytes=32 time=162ms TTL=127

C:\Users\Mike>ping -n 1 8.8.8.8
PING: transmit failed. General failure.

C:\Users\Mike>ping -n 1 192.168.163.2
General failure.

Просто для справки, ниже, как выглядит таблица маршрутов при отключении VPN (без изменений)

и вот так выглядит таблица, когда VPN подключен (неизменен) в том случае, когда я пытаюсь 8.8.8.8 я просто получаю тайм-аут (поскольку брандмауэр компании не позволяет трафику выходить за пределы интрасети)

1

Для тех, кто хочет сохранить контроль над своей таблицей маршрутизации при использовании SSL AnyConnect SSL VPN, проверьте OpenConnect. Он поддерживает Cisco AnyConnect SSL VPN и не пытается нарушать или «защищать» записи таблицы маршрутизации. @Vadzim ссылается на это в комментарии выше.

Попробовав все, кроме исправления клиента AnyConnect Secure Mobility, я смог успешно заменить его в Windows на графический интерфейс OpenConnect. Это позволило мне поддерживать подключение к локальным ресурсам (и обновлять таблицу маршрутизации).

Я использую OpenConnect в Windows, но он также поддерживает Linux, BSD и macOS (среди других платформ) в соответствии со страницей проекта.

0

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

Как вы исправили DLL. Я даже не могу изменить таблицу маршрутизации, потому что она продолжает добавлять 0.0.0.0 с VPN-шлюзом обратно.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .