Yukarıdaki güzel kesmek için Sasha Pachev'e teşekkürler .
vpnagentd
ayrıca yapılan değişikliklerin üzerine yazarak çözümleyiciye bulaşır /etc/resolv.conf
. Sonunda buna karşı yarışı kazanarak çözdüm:
#!/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
Bağlantıyı keserken unutma .
Yukarıdaki rota yönteminde olduğu gibi geri aramayı keserek çözmeye çalışıyorum ancak karşılık gelen geri aramayı veya yöntemi henüz bulamıyorum.
Güncelleme1 / 2: Çözümleyici dosyası değişikliklerini izlemek için API kullanan bir strace
açıklama . Oradan itibaren yokuş aşağı oldu. İşte ek kesmek:vpnagentd
inotify
int _ZN18CFileSystemWatcher11AddNewWatchESsj(void *string, unsigned int integer)
{
return 0;
}
Bu , aracı için tüm dosyaları izlemeyi devre dışı bıraktığı için, biraz fazladan bir izin verilir . Ama iyi çalışıyor gibi görünüyor.
Aşağıdaki vpn client wrapper betiği tüm işlevselliği bir araya getirir (bu ek kesmeyi içerecek şekilde güncellenmiştir). chattr
artık kullanılmıyor / gerekli değil.
Güncelleme 3: Koddaki sabit kullanıcı adı / şifre ayarları. Şimdi vpn.conf
aşağıda açıklanan formatta bir dosya kullanıyor (ve sadece root izinleri).
#!/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