Cómo forzar el enrutamiento de túnel dividido en Mac a una VPN de Cisco

40

¿Alguien sabe cómo hackear la tabla de enrutamiento (en una Mac) para derrotar el forzamiento del enrutamiento de VPN para cada cosa sobre una VPN de Cisco? más o menos lo que quiero hacer es tener solo 10.121. * y 10.122. * direcciones a través de la VPN y todo lo demás directamente a Internet.

Sathyajith Bhat
fuente

Respuestas:

27

Lo siguiente funciona para mí. Ejecútelos después de conectarse a la VPN de Cisco. (Estoy usando el cliente Cisco integrado de OS X, no el cliente de la marca Cisco).

sudo route -nv add -net 10 -interface utun0
sudo route change default 192.168.0.1

Reemplace 10en el primer comando con la red que está al otro lado del túnel.

Reemplace 192.168.0.1con la puerta de enlace de su red local.

Lo puse en un script bash, como este:

$ cat vpn.sh 
#!/bin/bash

if [[ $EUID -ne 0 ]]; then
    echo "Run this as root"
    exit 1
fi

route -nv add -net 10 -interface utun0
route change default 192.168.0.1

También encontré una explicación sobre cómo ejecutar esto automáticamente cuando conectas la VPN, pero es tarde el viernes y no tengo ganas de probarlo :)

Editar:

Desde entonces, dejé el trabajo donde estaba usando Cisco VPN, así que esto es de memoria.

El 10primer comando es la red que desea enrutar a través de la VPN. 10es una mano corta para 10.0.0.0/8. En el caso de Tuan Anh Tran, parece que la red lo es 192.168.5.0/24.

En cuanto a qué puerta de enlace especificar en el segundo comando, debería ser su puerta de enlace local. Cuando inicia sesión en una VPN que evita el túnel dividido, está aplicando esa política al cambiar sus tablas de enrutamiento para que todos los paquetes se enruten en la interfaz virtual. Por lo tanto, desea cambiar su ruta predeterminada a la que tenía antes de ingresar a la VPN .

La forma más fácil de descubrir la puerta de enlace es ejecutarla netstat -rnantes de iniciar sesión en la VPN y mirar la dirección IP a la derecha del destino "predeterminado". Por ejemplo, así es como se ve en mi caja en este momento:

Internet:
Destination        Gateway            Flags        Refs      Use   Netif Expire
default            10.0.1.1           UGSc           29        0     en1
10.0.1/24          link#5             UCS             3        0     en1
10.0.1.1           0:1e:52:xx:xx:xx   UHLWIi         55   520896     en1    481
10.0.1.51          7c:c5:37:xx:xx:xx  UHLWIi          0     1083     en1    350
10.0.1.52          127.0.0.1          UHS             0        0     lo0

Mi puerta de enlace es 10.0.1.1: está a la derecha del destino "predeterminado".

Mark E. Haase
fuente
1
¿Puedes explicarme un poco más? my ifconfig devuelve utun0: flags = 8051 <UP, POINTOPOINT, RUNNING, MULTICAST> mtu 1280 inet 192.168.5.102 -> 192.168.5.102 netmask 0xffffffff. Además, no entiendo qué debo reemplazar con el número 10 anterior. Gracias.
Tuan Anh Tran
@TuanAnhTran: Actualicé mi respuesta. Por favor, avíseme si eso ayuda.
Mark E. Haase
Para la última versión, tengo /Applications/VPNClient.app instalado y no veo utun0 en la lista de ifconfig. Veo adaptadores gif0, stf0 y fw0. ¿Cómo determino cuál es el adaptador correcto? No veo ninguna diferencia en la salida de ifconfig con y sin vpn conectado (excepto el valor MTU de en1).
haridsv
1
Para aquellos que no están familiarizados con LaunchDaemons, escribí una guía en mi respuesta aquí que describe cómo llamar a un script para que se ejecute cada vez que se conecta a VPN . (Por cierto, +1 excelente respuesta, pero necesitaba un poco más para que la esencia funcionara).
dr jimbob
1
Lamentablemente, esto no funciona en mi cliente Cisco AnyConnect.
jeremyjjbrown
5

Utilizando la información de mehaase, escribí un script de Python que realmente simplifica este proceso en la Mac. Cuando lo ejecute, el script guardará la información de su firewall, iniciará el cliente AnyConnect, esperará el inicio de sesión y luego arreglará las rutas y el firewall. Simplemente ejecute el script desde 'terminal'.

#!/usr/bin/python

# The Cisco AnyConnect VPN Client is often configured on the server to block
# all other Internet traffic. So you can be on the VPN <b>OR</b> you can have
# access to Google, etc.
#
# This script will fix that problem by repairing your routing table and
# firewall after you connect.
#
# The script does require admin (super user) access. If you are prompted for
# a password at the start of the script, just enter your normal Mac login
# password.
#
# The only thing you should need to configure is the vpn_ip_network.
# Mine is 10.x.x.x so I just specify '10' but you could be more specific
# and use something like '172.16'
vpn_ip_network = '10'

import sys
import subprocess


def output_of(cmd):
    lines = subprocess.Popen(cmd if isinstance(cmd, list) else cmd.split(' '), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0]
    try:
        lines = lines.decode('utf-8')
    except Exception:
        pass
    return [line.strip() for line in lines.strip().split('\n')]

sys.stdout.write("Mac Account Login ")
good_firewall_ids = set([line.partition(' ')[0] for line in output_of('sudo ipfw -a list')])
sys.stdout.write('Firewall Saved.\n')

gateway = None
for line in output_of('route get default'):
    name, delim, value = line.partition(':')
    if name == 'gateway':
        gateway = value.strip()
        p = subprocess.Popen(['/Applications/Cisco/Cisco AnyConnect VPN Client.app/Contents/MacOS/Cisco AnyConnect VPN Client'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        was_disconnected = False
        while True:
            line = p.stdout.readline()
            if line == '' or p.poll():
                sys.stdout.write("Never connected!\n")
                break
            try:
                line = line.decode('utf-8')
            except Exception:
                pass
            if 'Disconnected' in line:
                sys.stdout.write('Waiting for you to enter your VPN password in the VPN client...\n')
                was_disconnected = True
            if 'Connected' in line:
                if was_disconnected:
                    subprocess.Popen(['sudo','route','-nv','add','-net',vpn_ip_network,'-interface','utun0'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).wait()
                    subprocess.Popen(['sudo','route','change','default',gateway], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).wait()
                    unfriendly_firewall_ids = list(set([line.partition(' ')[0] for line in output_of('sudo ipfw -a list')])-good_firewall_ids)
                    extra = ''
                    if unfriendly_firewall_ids:
                        subprocess.Popen('sudo ipfw delete'.split(' ') + unfriendly_firewall_ids, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).wait()
                        sys.stdout.write("VPN connection established, routing table repaired and %d unfriendly firewall rules removed!\n" % len(unfriendly_firewall_ids))
                    else:
                        sys.stdout.write("VPN connection established and routing table repaired!\n")
                else:
                    try:
                        subprocess.Popen.kill(p)
                        sys.stdout.write('VPN was already connected. Extra VPN client closed automatically.\n')
                    except Exception:
                        sys.stdout.write('VPN was already connected. Please close the extra VPN client.\n')
                break
        break
else:
    sys.stdout.write("Couldn't get gateway. :-(\n")
usuario652641
fuente
4

El script de Python en esta respuesta anterior fue útil, sin embargo, no se ocupó de las rutas que AnyConnect solía tomar sobre otras interfaces en el dispositivo (como las interfaces de VMware). Tampoco pudo manejar múltiples redes VPN.

Aquí está el script que uso:

#!/bin/bash

HOME_NETWORK=192.168
HOME_GATEWAY=192.168.210.1
WORK_NETWORKS="X.X.X.X/12 10.0.0.0/8 X.X.X.X/16"

# What should the DNS servers be set to?
DNS_SERVERS="10.192.2.45 10.216.2.51 8.8.8.8"

##
## Do not edit below this line if you do not know what you are doing.
##
function valid_ip()
{
    local  ip=$1
    local  stat=1

    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        ip=($ip)
        IFS=$OIFS
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return $stat
}

# Nuke any DENY firewall rules
for RULE in `sudo ipfw list | grep deny | awk '{print $1}' | xargs`; do sudo ipfw delete $RULE; done

# Delete any routes for the home network that Anyconnect might have made
sudo route delete -net ${HOME_NETWORK}
sudo route add -net ${HOME_NETWORK} ${HOME_GATEWAY}

# Get the AnyConnect interface
ANYCONNECT_INTERFACE=`route get 0.0.0.0 | grep interface | awk '{print $2}'`

# Add the work routes
for NETWORK in ${WORK_NETWORKS}; do
    sudo route -nv add -net ${NETWORK} -interface ${ANYCONNECT_INTERFACE}
done

# Set the default gateway
sudo route change default ${HOME_GATEWAY}

# Mass route changes
for NET in `netstat -nr | grep -e ^${HOME_NETWORK} | grep utun1 | awk '{print $1}' | xargs`; do 
    if valid_ip ${NET}; then
        echo "Changing route for network"
        sudo route change ${NET} ${HOME_GATEWAY}
    else
        echo "Changing route for host"
        sudo route change -net ${NET} ${HOME_GATEWAY}
    fi      
done

# Set the nameservers
sudo scutil << EOF
open
d.init
d.add ServerAddresses * ${DNS_SERVERS}
set State:/Network/Service/com.cisco.anyconnect/DNS
quit
EOF
Kate Gray
fuente
¿Funciona esto con Cisco Anyconnect 3.1.0? No creo que sí ... ¿Tiene un script actualizado para 3.1.0? ¡Gracias!
costa
2

Es más que probable que su administrador desee configurar conexiones VPN para usar el enrutamiento local para las subredes 10.121. * Y 10.122. * Y dejar que el control remoto (su máquina doméstica) enrute el resto de las solicitudes. (les ahorra ancho de banda y responsabilidad)

¿Está utilizando el "Cliente VPN" de Cisco? os OS X?

si utiliza la VPN de OS X (configurada a través del Panel de preferencias de red), debería poder hacer clic en "avanzado" y seleccionar la pestaña "VPN a pedido". luego proporcione las subredes necesarias para que la VPN las use.

Toymakerii
fuente
44
El cliente OS X vpn tiene una opción "Cisco" separada (separada de PPTP y L2TP) que no tiene las opciones "VPN on Demand".
Mark E. Haase
2

Quería una 'aplicación' nativa que pueda ejecutar al iniciar sesión (y seguir ejecutándose / oculta) para habilitar el enrutamiento del túnel dividido, similar a una función de Locamatic . Quizás bifurque a Locamatic en algún momento y juegue con él. También puedo subir este AppleScript a Github. No quería meterme con un demonio como sugiere esta respuesta.

Este script asume que VPN tiene un VPN (Cisco IPSec)nombre predeterminado y la ruta VPN es 10.10.10.1/22> 10.10.20.10. Será necesario cambiarlos / agregar rutas adicionales. Ejecute terminal> netstat -rncuando VPN esté conectado (antes de habilitar este script) para ver rutas agregadas por VPN.

Este script también genera notificaciones de estilo gruñido en el Centro de notificaciones :)

ingrese la descripción de la imagen aquí

Me encontré con algunos problemas con la respuesta de Mark E. Haase , ya que mi VPN de Cisco modifica la puerta de enlace existente de una ruta a una (en0 interfaz específica) y agrega la puerta de enlace VPN como ruta, lo que requiere la eliminación de dos puertas de enlace predeterminadas y volver a agregar la puerta de enlace predeterminada originalUCScUGScIUCSUGSc

Gracias a Dios por StackExchange / google, este es mi primer AppleScript y no habría podido armarlo sin unas pocas horas de búsqueda en Google.

Sugerencias / correcciones / optimizaciones bienvenidas!

AppleScript ( GitHubGist ):

global done
set done to 0

on idle
    set status to do shell script "scutil --nc status "VPN (Cisco IPSec)" | sed -n 1p"
    # do shell script "scutil --nc start "VPN (Cisco IPSec)"
    if status is "Connected" then
        if done is not 1 then
            display notification "VPN Connected, splitting tunnel"
            set gateway to do shell script "( netstat -rn | awk '/default/ {if ( index($6, \"en\") > 0 ){print $2} }' ) # gets non-VPN default gateway"
            do shell script "sudo route delete default" # deletes VPN-assigned global (UCS) default gateway
            do shell script "sudo route delete default -ifscope en0" # deletes en0 interface-specific (UGScI) LOCAL non-vpn gateway that prevents it being re-added as global default gateway
            do shell script "sudo route add default " & gateway # re-adds LOCAL non-vpn gateway (from get command above) as global default gateway
            do shell script "sudo route add 10.10.10.1/22 10.10.20.10" # adds VPN route
            display notification "VPN tunnel has been split"
            set done to 1
        end if
    else
        if done is not 2 then
            display notification "VPN Disconnected"
            set done to 2

        end if
    end if
    return 5
end idle

guardar como una aplicación:

Configuración de guardado de la aplicación Split Tunnel

haga clic con el botón derecho> muestre el contenido del paquete, agregue lo siguiente a info.plist (esto oculta el ícono de la aplicación desde el dock, lo que requiere el uso de Activity Monitor o terminal> pkill -f 'Split Tunnel'para salir de la aplicación, omita si QUIERE un ícono de dock:

<key>LSBackgroundOnly</key>
<string>1</string>

cree un nuevo routeNOPASSWDarchivo de una línea (sin extensión) usando el siguiente código EXACTAMENTE (esto puede evitar el acceso a sudo si se hace incorrectamente, google visudopara obtener más información; esto permite que los comandos sudo en AppleScript se ejecuten SIN una solicitud de contraseña, omita si desea un mensaje de contraseña cuando la tabla de enrutamiento debe cambiarse

%admin ALL = (ALL) NOPASSWD: /sbin/route

copia este archivo a /etc/sudoers.d

ejecute los siguientes comandos en la terminal (el segundo comando solicitará la contraseña; esto permite que los sudo routecomandos en AppleScript se ejecuten SIN solicitar la contraseña, omita si se solicita una solicitud de contraseña cuando el script está cambiando la tabla de enrutamiento)

chmod 440 /private/etc/sudoers.d/routeNOPASSWD
sudo chown root /private/etc/sudoers.d/routeNOPASSWD

finalmente agregue la aplicación a Preferencias del sistema> Usuarios y grupos> elementos de inicio de sesión

Elemento de inicio de sesión de túnel dividido

goofología
fuente
1

Debería poder pedirle al administrador del enrutador al que se está conectando que configure un "grupo" separado que haga un túnel dividido y le proporcione un archivo PCF que contenga el nombre y la contraseña del grupo para ese grupo.

Vebjorn Ljosa
fuente
2
eso no va a suceder :) Son paranoicos
1

Tuve el mismo problema y lo conseguí gracias a @mehaase

Después de crear la ~/vpn.shrespuesta de @mehaase, puede colocar esto en una secuencia de comandos de ejecución automática de la aplicación siguiendo estos pasos:

  1. Usando Automator crea una nueva aplicación
  2. Agregue "Ejecutar un AppleScript" en Biblioteca> Utilidades
  3. Entrar: do shell script "sudo ~/vpn.sh" with administrator privileges
  4. Salvar

También es posible que deba ejecutar chmod 700 ~/vpn.shdesde la Terminal para otorgar privilegios de ejecución al script.

Después de conectarse a la VPN, simplemente puede ejecutar este script de aplicación. Ingrese su contraseña de administrador y haga clic en Aceptar - Listo. :)

Dwight Brown
fuente