Απλή διάτρηση οπών UDP χρησιμοποιώντας ως παράδειγμα μια σήραγγα IPIP

Καλή μέρα!

Σε αυτό το άρθρο θέλω να σας πω πώς υλοποίησα (ένα ακόμα) ένα σενάριο Bash για τη σύνδεση δύο υπολογιστών που βρίσκονται πίσω από το NAT χρησιμοποιώντας τεχνολογία διάτρησης οπών UDP χρησιμοποιώντας το Ubuntu/Debian OS ως παράδειγμα.

Η δημιουργία μιας σύνδεσης αποτελείται από πολλά βήματα:

  1. Εκκίνηση ενός κόμβου και αναμονή για τον απομακρυσμένο κόμβο να είναι έτοιμος.
  2. Προσδιορισμός της εξωτερικής διεύθυνσης IP και της θύρας UDP.
  3. Μεταφορά εξωτερικής διεύθυνσης IP και θύρας UDP σε απομακρυσμένο κεντρικό υπολογιστή.
  4. Λήψη εξωτερικής διεύθυνσης IP και θύρας UDP από απομακρυσμένο κεντρικό υπολογιστή.
  5. Οργάνωση μιας σήραγγας IPIP.
  6. Παρακολούθηση σύνδεσης;
  7. Εάν η σύνδεση χαθεί, διαγράψτε τη σήραγγα IPIP.

Σκέφτηκα για πολύ καιρό και ακόμα σκέφτομαι τι μπορεί να χρησιμοποιηθεί για την ανταλλαγή δεδομένων μεταξύ κόμβων, το πιο απλό και γρήγορο για μένα αυτή τη στιγμή είναι η εργασία μέσω του Yandex.disk.

  • Πρώτον, είναι εύκολο στη χρήση - χρειάζεστε 3 ενέργειες: δημιουργία, ανάγνωση, διαγραφή. Με μπούκλα αυτό είναι:
    Δημιουργώ:

    curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folder

    Ανάγνωση:

    curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folder

    Διαγράφω:

    curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder
  • Δεύτερον, είναι εύκολο να εγκατασταθεί:
    apt install curl

Για να προσδιορίσετε την εξωτερική διεύθυνση IP και τη θύρα UDP, χρησιμοποιήστε την εντολή stun-client:

stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"

Εγκατάσταση με εντολή:

apt install stun-client

Για την οργάνωση ενός τούνελ, χρησιμοποιούνται τυπικά εργαλεία λειτουργικού συστήματος από το πακέτο iproute2. Υπάρχει πολλές σήραγγες το οποίο μπορεί να αυξηθεί χρησιμοποιώντας τυπικά μέσα (L2TPv3, GRE, κ.λπ.), αλλά επέλεξα το IPIP επειδή δημιουργεί ελάχιστο πρόσθετο φορτίο στο σύστημα. Δοκίμασα το L2TPv3 μέσω UDP και απογοητεύτηκα, η ταχύτητα έπεσε 10 φορές, αλλά αυτοί θα μπορούσαν να είναι διάφοροι περιορισμοί που σχετίζονται με παρόχους ή κάτι άλλο. Εφόσον η σήραγγα IPIP λειτουργεί σε επίπεδο IP, η σήραγγα FOU χρησιμοποιείται για να λειτουργεί σε επίπεδο θύρας UDP. Για να οργανώσετε μια σήραγγα IPIP χρειάζεστε:

— φορτώστε τη μονάδα FOU:

modprobe fou

— ακούστε το τοπικό λιμάνι:

ip fou add port $localport ipproto 4

— Δημιουργήστε μια σήραγγα:

ip link add name fou$name type ipip remote $remoteip local $localip encap fou  encap-sport $localport encap-dport $remoteport

— ανυψώστε τη διεπαφή της σήραγγας:

ip link set up dev fou$name

— εκχώρηση εσωτερικών τοπικών και εσωτερικών απομακρυσμένων διευθύνσεων IP της σήραγγας:

ip addr add $intIP peer $peerip dev fou$name

Διαγραφή ενός τούνελ:

ip link del dev fou$name

ip fou del port $localport

Η κατάσταση της σήραγγας παρακολουθείται κάνοντας περιοδικά ping στην εσωτερική διεύθυνση IP του τούνελ απομακρυσμένου κόμβου με την εντολή:

ping -c 1 $peerip -s 0

Χρειάζεται περιοδικό ping κυρίως για τη διατήρηση του καναλιού, διαφορετικά, όταν το τούνελ είναι αδρανές, οι πίνακες NAT στους δρομολογητές μπορεί να διαγραφούν και στη συνέχεια η σύνδεση θα διακοπεί.

Εάν το ping εξαφανιστεί, τότε η σήραγγα IPIP διαγράφεται και περιμένει για ετοιμότητα από τον απομακρυσμένο κεντρικό υπολογιστή.

Το ίδιο το σενάριο:

#!/bin/bash
username="[email protected]"
password="password"
folder="vpnid"
intip="10.0.0.1"
localport=`shuf -i 10000-65000 -n 1`
cid=`shuf -i 10000-99999 -n 1`
tid=`shuf -i 10-99 -n 1`
function yaread {
        curl -s --user "$1:$2" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$3 | sed 's/></>n</g' | grep "displayname" | sed 's/<d:displayname>//g' | sed 's/</d:displayname>//g' | grep -v $3 | grep -v $4 | sort -r
}
function yacreate {
        curl -s -X MKCOL --user "$1:$2" https://webdav.yandex.ru/$3
}
function yadelete {
        curl -s -X DELETE --user "$1:$2" https://webdav.yandex.ru/$3
}
function myipport {
        stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress" | sort | uniq | awk '{print $3}' | head -n1
}
function tunnel-up {
	modprobe fou
	ip fou add port $4 ipproto 4
	ip link add name fou$7 type ipip remote $1 local $3 encap fou encap-sport $4 encap-dport $2
	ip link set up dev fou$7
	ip addr add $6 peer $5 dev fou$7
}
function tunnel-check {
	sleep 10
        pings=0
        until [[ $pings == 4 ]]; do
                if ping -c 1 $1 -s 0 &>/dev/null;
                        then    echo -n .; n=0
                        else    echo -n !; ((pings++))
                fi
		sleep 15
        done
}
function tunnel-down {
	ip link del dev fou$1
	ip fou del port $2
}
trap 'echo -e "nDisconnecting..." && yadelete $username $password $folder; tunnel-down $tunnelid $localport; echo "IPIP tunnel disconnected!"; exit 1' 1 2 3 8 9 14 15
until [[ -n $end ]]; do
    yacreate $username $password $folder
    until [[ -n $ip ]]; do
        mydate=`date +%s`
        timeout="60"
        list=`yaread $username $password $folder $cid | head -n1`
        yacreate $username $password $folder/$mydate:$cid
        for l in $list; do
                if [ `echo $l | sed 's/:/ /g' | awk {'print $1'}` -ge $(($mydate-65)) ]; then
			#echo $list
                        myipport=`myipport $localport`
                        yacreate $username $password $folder/$mydate:$cid:$myipport:$intip:$tid
                        timeout=$(( $timeout + `echo $l | sed 's/:/ /g' | awk {'print $1'}` - $mydate + 3 ))
                        ip=`echo $l | sed 's/:/ /g' | awk '{print $3}'`
                        port=`echo $l | sed 's/:/ /g' | awk '{print $4}'`
                        peerip=`echo $l | sed 's/:/ /g' | awk '{print $5}'`
			peerid=`echo $l | sed 's/:/ /g' | awk '{print $6}'`
			if [[ -n $peerid ]]; then tunnelid=$(($peerid*$tid)); fi
                fi
        done
        if ( [[ -z "$ip" ]] && [ "$timeout" -gt 0 ] ) ; then
                echo -n "!"
                sleep $timeout
        fi
    done
    localip=`ip route get $ip | head -n1 | sed 's|.*src ||' | cut -d' ' -f1`
    tunnel-up $ip $port $localip $localport $peerip $intip $tunnelid
    tunnel-check $peerip
    tunnel-down $tunnelid $localport
    yadelete $username $password $folder
    unset ip port myipport
done
exit 0

Μεταβλητές όνομα χρήστη, κωδικό πρόσβασης и φάκελο πρέπει να είναι το ίδιο και στις δύο πλευρές, αλλά κρυφοκοίταγμα - διαφορετικά, για παράδειγμα: 10.0.0.1 και 10.0.0.2. Η ώρα στους κόμβους πρέπει να συγχρονιστεί. Μπορείτε να εκτελέσετε το σενάριο ως εξής:

nohup script.sh &

Θα ήθελα να επιστήσω την προσοχή σας στο γεγονός ότι η σήραγγα IPIP δεν είναι ασφαλής από την άποψη του γεγονότος ότι η κίνηση δεν είναι κρυπτογραφημένη, αλλά αυτό μπορεί εύκολα να λυθεί χρησιμοποιώντας το IPsec over Αυτό το άρθρο, μου φάνηκε απλό και κατανοητό.

Χρησιμοποιώ αυτό το σενάριο για σύνδεση σε υπολογιστή εργασίας εδώ και αρκετές εβδομάδες και δεν έχω παρατηρήσει κανένα πρόβλημα. Βολικό όσον αφορά τη ρύθμιση και το ξεχνώντας.

Ίσως θα έχετε σχόλια και προτάσεις, θα χαρώ να ακούσω.

Спасибо за внимание!

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο