Yalnızca belirli bir ağ ad alanı için OpenVPN üzerinden tüm trafiği besleyin


16

Tüm süreçlerin ve yalnızca trafiğin belirli işlemlerden / VPN'den geçeceği bir VPN (OpenVPN kullanarak) kurmaya çalışıyorum ; diğer işlemler fiziksel cihazı doğrudan kullanmaya devam etmelidir. Linux'ta bunu yapmanın yolunun ağ ad alanları ile olduğunu anlamak benim.

OpenVPN'i normal şekilde kullanırsam (yani istemciden VPN üzerinden gelen tüm trafiği huni ), iyi çalışır. Özellikle, OpenVPN'i şu şekilde başlatıyorum:

# openvpn --config destination.ovpn --auth-user-pass credentials.txt

(Bu sorunun sonunda, target.ovpn dosyasının düzeltilmiş bir sürümü bulunmaktadır.)

Bir sonraki adımda takıldım, tünel cihazını ad alanlarıyla sınırlayan komut dosyaları yazıyorum. Denedim:

  1. Tünel cihazını doğrudan isim alanına koymak

    # ip netns add tns0
    # ip link set dev tun0 netns tns0
    # ip netns exec tns0 ( ... commands to bring up tun0 as usual ... )
    

    Bu komutlar başarıyla yürütülür, ancak ad alanının (ör. İle ip netns exec tns0 traceroute -n 8.8.8.8) içinde oluşturulan trafik bir kara deliğe düşer.

  2. Bir ağ ad alanına [hala] yalnızca sanal Ethernet (veth) arabirimleri atayabileceğiniz varsayımına göre (eğer doğruysa, bu yılki en gülünç gereksiz API kısıtlaması için bu ödülü alır), bir veth çifti ve bir köprü oluşturarak ve veth çiftinin bir ucunu isim alanına yerleştirir. Bu, zemindeki trafiği düşürmek kadar bile değil: Tüneli köprüye sokmama izin vermiyor! [DÜZENLE: Bunun nedeni köprülere yalnızca musluk aygıtları yerleştirilebileceğidir. Bir rasgele aygıtları bir ağ ad alanına yerleştirememenin aksine, bu gerçekten mantıklıdır, köprüler bir Ethernet katmanı kavramıdır; ne yazık ki, VPN sağlayıcım OpenVPN'i musluk modunda desteklemediğinden, bir geçici çözüme ihtiyacım var.]

    # ip addr add dev tun0 local 0.0.0.0/0 scope link
    # ip link set tun0 up
    # ip link add name teo0 type veth peer name tei0
    # ip link set teo0 up
    # brctl addbr tbr0
    # brctl addif tbr0 teo0
    # brctl addif tbr0 tun0
    can't add tun0 to bridge tbr0: Invalid argument
    

Bu sorunun sonundaki senaryolar veth yaklaşımı içindir. Doğrudan yaklaşım için komut dosyaları düzenleme geçmişinde bulunabilir. Komut dosyalarında ilk olarak ayarlanmadan kullanılan değişkenler, openvpnprogram tarafından çevrede ayarlanır - evet, özensizdir ve küçük harf adları kullanır.

Lütfen bunun nasıl işe yarayacağı konusunda özel tavsiyeler sunun. Buraya kargo tarikat tarafından programlama ediyorum acı farkındayım - gelmiştir herkes bu şeyler için kapsamlı belgeler yazılı? Herhangi bir - bulamıyorum komut dosyalarının genel kod incelemesi de takdir edilmektedir.

Önemli olması halinde:

# uname -srvm
Linux 3.14.5-x86_64-linode42 #1 SMP Thu Jun 5 15:22:13 EDT 2014 x86_64
# openvpn --version | head -1
OpenVPN 2.3.2 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [eurephia] [MH] [IPv6] built on Mar 17 2014
# ip -V
ip utility, iproute2-ss140804
# brctl --version
bridge-utils, 1.5

Çekirdek, sanal barındırma sağlayıcım ( Linode ) tarafından oluşturuldu ve derlenmiş olmasına rağmen CONFIG_MODULES=y, gerçek modülleri yok - buna göre CONFIG_*ayarlanan tek değişken oldu ve aslında bu modüle sahip değilim (çekirdek dosya sistemimin dışında depolanıyor; boştur ve sihirli bir şekilde yüklenmediğini belirtir). İstek üzerine alıntılar sağlanmıştır, ancak her şeyi buraya yapıştırmak istemiyorum.m/proc/config.gzCONFIG_XEN_TMEM/lib/modules/proc/modules/proc/config.gz

netns-up.sh

#! /bin/sh

mask2cidr () {
    local nbits dec
    nbits=0
    for dec in $(echo $1 | sed 's/\./ /g') ; do
        case "$dec" in
            (255) nbits=$(($nbits + 8)) ;;
            (254) nbits=$(($nbits + 7)) ;;
            (252) nbits=$(($nbits + 6)) ;;
            (248) nbits=$(($nbits + 5)) ;;
            (240) nbits=$(($nbits + 4)) ;;
            (224) nbits=$(($nbits + 3)) ;;
            (192) nbits=$(($nbits + 2)) ;;
            (128) nbits=$(($nbits + 1)) ;;
            (0)   ;;
            (*) echo "Error: $dec is not a valid netmask component" >&2
                exit 1
                ;;
        esac
    done
    echo "$nbits"
}

mask2network () {
    local host mask h m result
    host="$1."
    mask="$2."
    result=""
    while [ -n "$host" ]; do
        h="${host%%.*}"
        m="${mask%%.*}"
        host="${host#*.}"
        mask="${mask#*.}"
        result="$result.$(($h & $m))"
    done
    echo "${result#.}"
}

maybe_config_dns () {
    local n option servers
    n=1
    servers=""
    while [ $n -lt 100 ]; do
       eval option="\$foreign_option_$n"
       [ -n "$option" ] || break
       case "$option" in
           (*DNS*)
               set -- $option
               servers="$servers
nameserver $3"
               ;;
           (*) ;;
       esac
       n=$(($n + 1))
    done
    if [ -n "$servers" ]; then
        cat > /etc/netns/$tun_netns/resolv.conf <<EOF
# name servers for $tun_netns
$servers
EOF
    fi
}

config_inside_netns () {
    local ifconfig_cidr ifconfig_network

    ifconfig_cidr=$(mask2cidr $ifconfig_netmask)
    ifconfig_network=$(mask2network $ifconfig_local $ifconfig_netmask)

    ip link set dev lo up

    ip addr add dev $tun_vethI \
        local $ifconfig_local/$ifconfig_cidr \
        broadcast $ifconfig_broadcast \
        scope link
    ip route add default via $route_vpn_gateway dev $tun_vethI
    ip link set dev $tun_vethI mtu $tun_mtu up
}

PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH

set -ex

# For no good reason, we can't just put the tunnel device in the
# subsidiary namespace; we have to create a "virtual Ethernet"
# device pair, put one of its ends in the subsidiary namespace,
# and put the other end in a "bridge" with the tunnel device.

tun_tundv=$dev
tun_netns=tns${dev#tun}
tun_bridg=tbr${dev#tun}
tun_vethI=tei${dev#tun}
tun_vethO=teo${dev#tun}

case "$tun_netns" in
     (tns[0-9] | tns[0-9][0-9] | tns[0-9][0-9][0-9]) ;;
     (*) exit 1;;
esac

if [ $# -eq 1 ] && [ $1 = "INSIDE_NETNS" ]; then
    [ $(ip netns identify $$) = $tun_netns ] || exit 1
    config_inside_netns
else

    trap "rm -rf /etc/netns/$tun_netns ||:
          ip netns del $tun_netns      ||:
          ip link del $tun_vethO       ||:
          ip link set $tun_tundv down  ||:
          brctl delbr $tun_bridg       ||:
         " 0

    mkdir /etc/netns/$tun_netns
    maybe_config_dns

    ip addr add dev $tun_tundv local 0.0.0.0/0 scope link
    ip link set $tun_tundv mtu $tun_mtu up

    ip link add name $tun_vethO type veth peer name $tun_vethI
    ip link set $tun_vethO mtu $tun_mtu up

    brctl addbr $tun_bridg
    brctl setfd $tun_bridg 0
    #brctl sethello $tun_bridg 0
    brctl stp $tun_bridg off

    brctl addif $tun_bridg $tun_vethO
    brctl addif $tun_bridg $tun_tundv
    ip link set $tun_bridg up

    ip netns add $tun_netns
    ip link set dev $tun_vethI netns $tun_netns
    ip netns exec $tun_netns $0 INSIDE_NETNS

    trap "" 0
fi

netns-down.sh

#! /bin/sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH

set -ex

tun_netns=tns${dev#tun}
tun_bridg=tbr${dev#tun}

case "$tun_netns" in
     (tns[0-9] | tns[0-9][0-9] | tns[0-9][0-9][0-9]) ;;
     (*) exit 1;;
esac

[ -d /etc/netns/$tun_netns ] || exit 1

pids=$(ip netns pids $tun_netns)
if [ -n "$pids" ]; then
    kill $pids
    sleep 5
    pids=$(ip netns pids $tun_netns)
    if [ -n "$pids" ]; then
        kill -9 $pids
    fi
fi

# this automatically cleans up the the routes and the veth device pair
ip netns delete "$tun_netns"
rm -rf /etc/netns/$tun_netns

# the bridge and the tunnel device must be torn down separately
ip link set $dev down
brctl delbr $tun_bridg

destination.ovpn

client
auth-user-pass
ping 5
dev tun
resolv-retry infinite
nobind
persist-key
persist-tun
ns-cert-type server
verb 3
route-metric 1
proto tcp
ping-exit 90
remote [REDACTED]
<ca>
[REDACTED]
</ca>
<cert>
[REDACTED]
</cert>
<key>
[REDACTED]
</key>

Açıkça başlayalım: Veth cihazları destekleniyor mu? çekirdek modülleri (veth) yüklü mü?
countermode

@countermode grep veth /proc/moduleshiçbir şey listeler, ancak bunun kesin olup olmadığını bilmiyorum. Linode bulut sunucularının işletim sistemi bölümü içinde bir çekirdek yüklü olmadığından, eksik bir modülü yine de yükleyebileceğimden emin değilim.
zwol

lsmodHiç çıktı üretiyor mu ? Bir dizin var /lib/modulesmı?
karşı

lsmod: command not found. Bir var /lib/modules, ancak içinde herhangi bir modül yok, sadece boş modules.depdosyalar içeren bir grup çekirdek dizini var . Linode'a özgü yardımda konuşacağım ve bunun böyle olup olmadığını öğreneceğim.
zwol

hmm ... çok garip. Linode'la tanışmıyorum ama bana veth cihazları desteklenmiyor gibi görünüyor.
sayaç

Yanıtlar:


9

OpenVPN bağlantısını bir ad alanının içinde başlatabilir ve sonra ad alanının içindeki bu OpenVPN bağlantısını kullanmak istediğiniz her komutu çalıştırabilirsiniz. Nasıl yapılacağına dair ayrıntılar (işim değil):

http://www.naju.se/articles/openvpn-netns.html

Denedim ve işe yarıyor; fikir, OpenVPN bağlantısının yukarı ve rota aşamalarını global yerine belirli bir ad alanı içinde gerçekleştirmek için özel bir komut dosyası sağlamaktır. Gelecekte çevrimdışı olması durumunda yukarıdaki bağlantıdan alıntı yapıyorum:

Önce OpenVPN için bir --up betiği oluşturun. Bu komut dosyası, varsayılan ad alanı yerine vpn adında bir ağ ad alanı içinde VPN tünel arabirimini oluşturur.

$ cat > netns-up << EOF
#!/bin/sh
case $script_type in
        up)
                ip netns add vpn
                ip netns exec vpn ip link set dev lo up
                mkdir -p /etc/netns/vpn
                echo "nameserver 8.8.8.8" > /etc/netns/vpn/resolv.conf
                ip link set dev "$1" up netns vpn mtu "$2"
                ip netns exec vpn ip addr add dev "$1" \
                        "$4/${ifconfig_netmask:-30}" \
                        ${ifconfig_broadcast:+broadcast "$ifconfig_broadcast"}
                test -n "$ifconfig_ipv6_local" && \
          ip netns exec vpn ip addr add dev "$1" \
                        "$ifconfig_ipv6_local"/112
                ;;
        route-up)
                ip netns exec vpn ip route add default via "$route_vpn_gateway"
                test -n "$ifconfig_ipv6_remote" && \
          ip netns exec vpn ip route add default via \
                        "$ifconfig_ipv6_remote"
                ;;
        down)
                ip netns delete vpn
                ;;
esac
EOF

Ardından OpenVPN'i başlatın ve ifconfig ve route uygulamak yerine --up komut dosyamızı kullanmasını söyleyin.

openvpn --ifconfig-noexec --route-noexec --up netns-up --route-up netns-up --down netns-up

Şimdi bu şekilde tünellenecek programları başlatabilirsiniz:

ip netns exec vpn command

Tek yakalama, çağırmak için root olmanız ip netns exec ...ve belki de uygulamanızın root olarak çalışmasını istememenizdir. Çözüm basit:

sudo ip netns exec vpn sudo -u $ (whoami) komutu

1
Merhaba ve siteye hoş geldiniz! Kullanıcıları en azından yanıtlara yapıştırdıkları bağlantıların içeriğini (mümkünse) özetlemeye teşvik ediyoruz. Bu, bağlantının eski olması durumunda yanıt kalitesini korumaya yardımcı olur (örneğin siteye artık erişilemez). Lütfen bağlantılı makalenin en önemli bölümlerini / talimatlarını ekleyerek cevabınızı geliştirin.
Erathiel

Bu harika ama kabuğun tüm değişkenleri genişletmesini önlemek için açılış heredoc sınırlayıcısının etrafına tek tırnak koymanız gerekiyor.
ewatt

7

Bu çıkıyor olabilir bir ağ ad içine bir tünel arayüzü koydu. Benim tüm sorun arayüzü getirirken bir hataya düştü:

ip addr add dev $tun_tundv \
    local $ifconfig_local/$ifconfig_cidr \
    broadcast $ifconfig_broadcast \
    scope link

Sorun, sadece yönlendirmeyi etkilediğini yanlış anladığım "kapsam bağlantısı" dır. Çekirdeğin tünele gönderilen tüm paketlerin kaynak adresini 0.0.0.0; muhtemelen OpenVPN sunucusu bunları RFC1122'ye göre geçersiz olarak atacaktır; olmasa bile, hedef açıkça cevap veremez.

Ağ ad alanlarının yokluğunda her şey doğru çalıştı çünkü openvpn'nin yerleşik ağ yapılandırma komut dosyası bu hatayı yapmadı. Ve "kapsam bağlantısı" olmadan, orijinal betiğim de çalışır.

(Bunu nasıl keşfettim, soruyorsunuz? straceOpenvpn işleminde çalışarak, tünel tanımlayıcısından okuduğu her şeyi onaltılık olarak ayarlayıp paket başlıklarını manuel olarak çözerek ayarlayın.)


Bu konuda bir rehber yazma şansınız var mı? Benzer bir şey kurmaya çalışıyorum, ancak sorunuzun hangi bölümlerinin başlamak için iyi ve hangilerinin başarısızlığa yol açtığını söylemek zor.
tremby

@tremby Yakın gelecekte bunu yapacak zamanım olmayacak, ancak github.com/zackw/tbbscraper/blob/master/scripts/openvpn-netns.c dosyasını yararlı bulabilirsiniz .
zwol

Yeesh, 1100 satırlık bir C programının yardım edeceğinden emin değilim. Sadece işi sizin için halleten son yapılandırma, senaryolar ve büyülere ne dersiniz? ... Yoksa bu C programı bunu son uygulamanız mı?
tremby

@tremby Evet, bu C programı benim son uygulamam. (Benim kullanım senaryomda setuid olmalı, anlıyorsunuz.) Sadece bir şey bırakabilirsiniz - üstteki büyük yorum nasıl kullanılacağını açıklamazsa, bana bildirin.
zwol

@tremby Alternatif olarak, ağ ad alanının nasıl kurulduğunu ve parçalandığını görmek için github.com/zackw/tbbscraper/blob/master/scripts/… adresinden başlayarak "openvpn içinden yürütülen komut dosyaları" na bakın; ve ovpn müşterinin gerçek çağırma yer almaktadır github.com/zackw/tbbscraper/blob/master/scripts/... . Kodun geri kalanı, bu işlemleri yazmak için daha az yorucu hale getirmek için bir mini kabuk uygulaması olarak düşünülebilir.
zwol

4

Veth aygıtlarını oluşturmaya çalışma hatası ip, komut satırı bağımsız değişkenlerini yorumlama biçimindeki değişiklikten kaynaklanır .

ipBir çift veth cihazı oluşturmak için doğru çağrı

ip link add name veth0 type veth peer name veth1

( nameinstad dev)

Şimdi, ad alanından VPN tüneline giden trafiği nasıl çıkarabilirim? Sadece ayar cihazlarınız olduğundan, "ana bilgisayar" yönlendirilmelidir. Yani veth çiftini yaratıp isim alanına koyalım. Diğerini tünele yönlendirerek bağlayın. Böylece, yönlendirmeyi etkinleştirin ve ardından gerekli yolları ekleyin.

Örnek olarak, bunun eth0ana arayüzünüz tun0olduğunu, VPN tünel arayüzünüz olduğunu ve veth0/ veth1arayüzlerinin veth1ad alanında olduğunu varsayalım . Ad alanına yalnızca varsayılan bir rota eklersiniz veth1.

Ana bilgisayarda politika yönlendirmesi kullanmanız gerekir, örneğin buraya bakın . Ne yapmak gerekiyor:

Gibi bir giriş ekleyin / ekleyin

1   vpn

için /etc/iproute2/rt_tables. Bu şekilde (henüz oluşturulmamış) tabloyu adıyla çağırabilirsiniz.

Ardından aşağıdaki ifadeleri kullanın:

ip rule add iif veth0 priority 1000 table vpn
ip rule add iif tun0 priority 1001 table vpn
ip route add default via <ip-addr-of-tun0> table vpn
ip route add <ns-network> via <ip-addr-of-veth0> table vpn

Bunu sizinki gibi bir kurulumla deneyemiyorum, ama bu tam olarak istediğinizi yapmalı. Ne vpn ne de "guest" net'in rahatsız edilmeyeceği şekilde paket filtre kurallarına göre genişletebilirsiniz.

Not: tun0İlk etapta isim alanına geçmek doğru şey gibi görünüyor. Ama senin gibi işe yaramadım. Politika yönlendirme, yapılacak bir sonraki doğru şeye benziyor. VPN'nin arkasındaki ağları biliyorsanız ve diğer tüm uygulamalar bu ağlara asla erişmeyecekse Mahendra'nın çözümü geçerlidir . Ama ilk koşul ( "tüm trafiği ve sadece ikincisi kutu garanti edilemez sanki sesler trafik, belirli süreçlerden / olarak VPN üzerinden gider").


Teşekkürler, bu beni biraz daha ileriye götürüyor, ama şimdi "ve sonra veth cihazını tünele bağlamak için bir köprü kullanıyorsunuz" bölümüne takılıyorum - lütfen gözden geçirilmiş soruya bakın.
zwol

Gönderdiğim cevap başına, her şey orijinal senaryomda aptalca bir hataya düşüyor - "kapsam bağlantısı" ne demek istediğimi kastetmiyor. Ama sana lütuf vereceğim, çünkü çeşitli olasılıkları denememe yardım etmek için çok çalışıyorsun ve muhtemelen olmasaydı tamamen vazgeçerdim.
zwol

Hey Zack, çok teşekkürler. Ad alanları ve politika yönlendirme, araştırılması ilginç bir şeydi. Eğer kendi başına heyecan verici olmasaydı, gerçekten bu kadar çaba sarfetmezdim.
karşı

0

VPN üzerinden eriştiğiniz ağlar biliniyorsa, istediğinizi elde etmek için yönlendirme tablonuzu düzenleyebilirsiniz.

  1. Geçerli varsayılan rotanızı not edin.

    # ip route | grep default default via 192.168.43.1 dev wlo1 proto static metric 1024

  2. VPN'yi çalıştırdığınızda bir yönlendirme girişi tanıtılır.

  3. Geçerli varsayılan yolu (VPN tarafından eklenen), önceki varsayılan yol olarak tablodaki ilk varsayılan giriş olarak silin.

    # ip route | grep default default dev tun0 scope link default via 192.168.43.1 dev wlo1 proto static metric 1024

    # ip route del default dev tun0 scope link

  4. Tun0 üzerinden yönlendirmek için VPN'deki ağlara özel yollar ekleyin.

    # ip route add <net1>/16 dev tun0

    # ip route add <net2>/24 dev tun0

  5. VPN ve doğrudan bağlantı için her iki ad sunucusu girişini de (resolv.conf dosyasında) ekleyin.

Artık tüm net1 ve net2 bağlantıları VPN'den geçecek ve sıfırlama doğrudan geçecektir (bu örnekte wlo1 üzerinden).


Ne yazık ki, VPN üzerinden erişilen ağlar önceden bilinmemektedir, bu yüzden bu benim için çalışmaz.
zwol
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.