openconnect: add netifd support
git-svn-id: svn://svn.openwrt.org/openwrt/packages@31729 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
b60301cc27
commit
4b364e5b56
@ -20,7 +20,7 @@ include $(INCLUDE_DIR)/package.mk
|
||||
define Package/openconnect
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
DEPENDS:=+libxml2 +libopenssl +kmod-tun +vpnc-scripts
|
||||
DEPENDS:=+libxml2 +libopenssl +kmod-tun +resolveip +!PACKAGE_netifd:vpnc-scripts
|
||||
TITLE:=VPN client for Cisco's AnyConnect SSL VPN
|
||||
URL:=http://www.infradead.org/openconnect/
|
||||
SUBMENU:=VPN
|
||||
@ -35,13 +35,26 @@ define Package/openconnect/description
|
||||
endef
|
||||
|
||||
CONFIGURE_ARGS+=--disable-shared
|
||||
ifdef CONFIG_PACKAGE_netifd
|
||||
CONFIGURE_ARGS += --with-vpnc-script=/lib/netifd/vpnc-script
|
||||
|
||||
define Package/openconnect/install
|
||||
$(INSTALL_DIR) $(1)/lib/network
|
||||
$(INSTALL_BIN) ./files/openconnect.sh $(1)/lib/network/
|
||||
define Package/openconnect/install
|
||||
$(INSTALL_DIR) $(1)/lib/netifd/proto
|
||||
$(INSTALL_BIN) ./files/openconnect.sh $(1)/lib/netifd/proto/
|
||||
$(INSTALL_BIN) ./files/vpnc-script $(1)/lib/netifd/
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) ./files/run-openconnect $(1)/usr/sbin/
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/openconnect $(1)/usr/sbin/
|
||||
endef
|
||||
endef
|
||||
else
|
||||
CONFIGURE_ARGS += --with-vpnc-script=/etc/vpnc/vpnc-script
|
||||
|
||||
define Package/openconnect/install
|
||||
$(INSTALL_DIR) $(1)/lib/network
|
||||
$(INSTALL_BIN) ./files.old/openconnect.sh $(1)/lib/network/
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) ./files.old/run-openconnect $(1)/usr/sbin/
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/openconnect $(1)/usr/sbin/
|
||||
endef
|
||||
endif
|
||||
|
||||
$(eval $(call BuildPackage,openconnect))
|
||||
|
39
net/openconnect/files.old/openconnect.sh
Executable file
39
net/openconnect/files.old/openconnect.sh
Executable file
@ -0,0 +1,39 @@
|
||||
find_gw() {
|
||||
route -n | awk '$1 == "0.0.0.0" { print $2; exit }'
|
||||
}
|
||||
|
||||
scan_openconnect() {
|
||||
config_set "$1" device "vpn-$1"
|
||||
}
|
||||
|
||||
stop_interface_openconnect() {
|
||||
local config="$1"
|
||||
local lock="/var/lock/openconnect-$config"
|
||||
|
||||
uci_set_state network "$config" up 0
|
||||
|
||||
lock "$lock"
|
||||
|
||||
SERVICE_PID_FILE="/var/run/openconnect-${config}.pid" \
|
||||
SERVICE_SIG=HUP service_stop /bin/sh
|
||||
|
||||
remove_dns "$config"
|
||||
|
||||
lock -u "$lock"
|
||||
}
|
||||
|
||||
setup_interface_openconnect() {
|
||||
local config="$2"
|
||||
|
||||
/sbin/insmod tun 2>&- >&-
|
||||
|
||||
# creating the tunnel below will trigger a net subsystem event
|
||||
# prevent it from touching or iface by disabling .auto here
|
||||
uci_set_state network "$config" ifname "vpn-$config"
|
||||
uci_set_state network "$config" auto 0
|
||||
uci_set_state network "$config" up 1
|
||||
|
||||
SERVICE_PID_FILE="/var/run/openconnect-${config}.pid" \
|
||||
SERVICE_WRITE_PID=1 SERVICE_DAEMONIZE=1 \
|
||||
service_start /usr/sbin/run-openconnect $config
|
||||
}
|
@ -1,39 +1,56 @@
|
||||
find_gw() {
|
||||
route -n | awk '$1 == "0.0.0.0" { print $2; exit }'
|
||||
#!/bin/sh
|
||||
. /etc/functions.sh
|
||||
. ../netifd-proto.sh
|
||||
init_proto "$@"
|
||||
|
||||
proto_openconnect_init_config() {
|
||||
proto_config_add_string "server"
|
||||
proto_config_add_int "port"
|
||||
proto_config_add_string "username"
|
||||
proto_config_add_string "cookie"
|
||||
proto_config_add_string "password"
|
||||
no_device=1
|
||||
available=1
|
||||
}
|
||||
|
||||
scan_openconnect() {
|
||||
config_set "$1" device "vpn-$1"
|
||||
}
|
||||
|
||||
stop_interface_openconnect() {
|
||||
proto_openconnect_setup() {
|
||||
local config="$1"
|
||||
local lock="/var/lock/openconnect-$config"
|
||||
|
||||
uci_set_state network "$config" up 0
|
||||
json_get_vars server port username cookie password
|
||||
|
||||
lock "$lock"
|
||||
grep -q tun /proc/modules || insmod tun
|
||||
|
||||
SERVICE_PID_FILE="/var/run/openconnect-${config}.pid" \
|
||||
SERVICE_SIG=HUP service_stop /bin/sh
|
||||
serv_addr=
|
||||
for ip in $(resolveip -t 5 "$server"); do
|
||||
proto_add_host_dependency "$config" "$server"
|
||||
serv_addr=1
|
||||
done
|
||||
[ -n "$serv_addr" ] || {
|
||||
echo "Could not resolve server address"
|
||||
sleep 5
|
||||
proto_setup_failed "$config"
|
||||
exit 1
|
||||
}
|
||||
|
||||
remove_dns "$config"
|
||||
[ -n "$port" ] && port=":$port"
|
||||
|
||||
lock -u "$lock"
|
||||
cmdline="$server$port -i vpn-$config --no-cert-check --non-inter --syslog --script /lib/netifd/vpnc-script"
|
||||
|
||||
[ -n "$cookie" ] && append cmdline "-C $cookie"
|
||||
[ -n "$username" ] && append cmdline "-u $username"
|
||||
[ -n "$password" ] && {
|
||||
umask 077
|
||||
pwfile="/var/run/openconnect-$config.passwd"
|
||||
echo "$password" > "$pwfile"
|
||||
append cmdline "--passwd-file=$pwfile"
|
||||
}
|
||||
|
||||
proto_export INTERFACE="$config"
|
||||
proto_run_command "$config" /usr/sbin/openconnect $cmdline
|
||||
}
|
||||
|
||||
setup_interface_openconnect() {
|
||||
local config="$2"
|
||||
|
||||
/sbin/insmod tun 2>&- >&-
|
||||
|
||||
# creating the tunnel below will trigger a net subsystem event
|
||||
# prevent it from touching or iface by disabling .auto here
|
||||
uci_set_state network "$config" ifname "vpn-$config"
|
||||
uci_set_state network "$config" auto 0
|
||||
uci_set_state network "$config" up 1
|
||||
|
||||
SERVICE_PID_FILE="/var/run/openconnect-${config}.pid" \
|
||||
SERVICE_WRITE_PID=1 SERVICE_DAEMONIZE=1 \
|
||||
service_start /usr/sbin/run-openconnect $config
|
||||
proto_openconnect_teardown() {
|
||||
proto_kill_command "$config"
|
||||
}
|
||||
|
||||
add_protocol openconnect
|
||||
|
156
net/openconnect/files/vpnc-script
Executable file
156
net/openconnect/files/vpnc-script
Executable file
@ -0,0 +1,156 @@
|
||||
#!/bin/sh
|
||||
# List of parameters passed through environment
|
||||
#* reason -- why this script was called, one of: pre-init connect disconnect
|
||||
#* VPNGATEWAY -- vpn gateway address (always present)
|
||||
#* TUNDEV -- tunnel device (always present)
|
||||
#* INTERNAL_IP4_ADDRESS -- address (always present)
|
||||
#* INTERNAL_IP4_MTU -- mtu (often unset)
|
||||
#* INTERNAL_IP4_NETMASK -- netmask (often unset)
|
||||
#* INTERNAL_IP4_NETMASKLEN -- netmask length (often unset)
|
||||
#* INTERNAL_IP4_NETADDR -- address of network (only present if netmask is set)
|
||||
#* INTERNAL_IP4_DNS -- list of dns servers
|
||||
#* INTERNAL_IP4_NBNS -- list of wins servers
|
||||
#* INTERNAL_IP6_ADDRESS -- IPv6 address
|
||||
#* INTERNAL_IP6_NETMASK -- IPv6 netmask
|
||||
#* INTERNAL_IP6_DNS -- IPv6 list of dns servers
|
||||
#* CISCO_DEF_DOMAIN -- default domain name
|
||||
#* CISCO_BANNER -- banner from server
|
||||
#* CISCO_SPLIT_INC -- number of networks in split-network-list
|
||||
#* CISCO_SPLIT_INC_%d_ADDR -- network address
|
||||
#* CISCO_SPLIT_INC_%d_MASK -- subnet mask (for example: 255.255.255.0)
|
||||
#* CISCO_SPLIT_INC_%d_MASKLEN -- subnet masklen (for example: 24)
|
||||
#* CISCO_SPLIT_INC_%d_PROTOCOL -- protocol (often just 0)
|
||||
#* CISCO_SPLIT_INC_%d_SPORT -- source port (often just 0)
|
||||
#* CISCO_SPLIT_INC_%d_DPORT -- destination port (often just 0)
|
||||
#* CISCO_IPV6_SPLIT_INC -- number of networks in IPv6 split-network-list
|
||||
#* CISCO_IPV6_SPLIT_INC_%d_ADDR -- IPv6 network address
|
||||
#* CISCO_IPV6_SPLIT_INC_$%d_MASKLEN -- IPv6 subnet masklen
|
||||
|
||||
# FIXMEs:
|
||||
|
||||
# Section A: route handling
|
||||
|
||||
# 1) The 3 values CISCO_SPLIT_INC_%d_PROTOCOL/SPORT/DPORT are currently being ignored
|
||||
# In order to use them, we'll probably need os specific solutions
|
||||
# * Linux: iptables -t mangle -I PREROUTING <conditions> -j ROUTE --oif $TUNDEV
|
||||
# This would be an *alternative* to changing the routes (and thus 2) and 3)
|
||||
# shouldn't be relevant at all)
|
||||
# 2) There are two different functions to set routes: generic routes and the
|
||||
# default route. Why isn't the defaultroute handled via the generic route case?
|
||||
# 3) In the split tunnel case, all routes but the default route might get replaced
|
||||
# without getting restored later. We should explicitely check and save them just
|
||||
# like the defaultroute
|
||||
# 4) Replies to a dhcp-server should never be sent into the tunnel
|
||||
|
||||
# Section B: Split DNS handling
|
||||
|
||||
# 1) Maybe dnsmasq can do something like that
|
||||
# 2) Parse dns packets going out via tunnel and redirect them to original dns-server
|
||||
|
||||
do_connect() {
|
||||
if [ -n "$CISCO_BANNER" ]; then
|
||||
echo "Connect Banner:"
|
||||
echo "$CISCO_BANNER" | while read LINE ; do echo "|" "$LINE" ; done
|
||||
echo
|
||||
fi
|
||||
|
||||
proto_init_update "$TUNDEV" 1
|
||||
|
||||
if [ -n "$INTERNAL_IP4_MTU" ]; then
|
||||
MTU=$INTERNAL_IP4_MTU
|
||||
fi
|
||||
|
||||
if [ -z "$MTU" ]; then
|
||||
MTU=1412
|
||||
fi
|
||||
|
||||
proto_add_ipv4_address "$INTERNAL_IP4_ADDRESS" 32 "" "$INTERNAL_IP4_ADDRESS"
|
||||
|
||||
if [ -n "$INTERNAL_IP4_NETMASKLEN" ]; then
|
||||
proto_add_ipv4_route "$INTERNAL_IP4_NETADDR" "$INTERNAL_IP4_NETMASKLEN"
|
||||
fi
|
||||
|
||||
# If the netmask is provided, it contains the address _and_ netmask
|
||||
if [ -n "$INTERNAL_IP6_ADDRESS" ] && [ -z "$INTERNAL_IP6_NETMASK" ]; then
|
||||
INTERNAL_IP6_NETMASK="$INTERNAL_IP6_ADDRESS/128"
|
||||
fi
|
||||
|
||||
if [ -n "$INTERNAL_IP6_NETMASK" ]; then
|
||||
addr="${INTERNAL_IP6_NETMASK%%/*}"
|
||||
mask="${INTERNAL_IP6_NETMASK##*/}"
|
||||
[[ "$addr" != "$mask" ]] && proto_add_ipv6_address "$addr" "$mask"
|
||||
fi
|
||||
|
||||
[ -n "$INTERNAL_IP4_DNS" ] && proto_add_dns_server "$INTERNAL_IP4_DNS"
|
||||
[ -n "$CISCO_DEF_DOMAIN" ] && proto_add_dns_search "$CISCO_DEF_DOMAIN"
|
||||
|
||||
if [ -n "$CISCO_SPLIT_INC" ]; then
|
||||
i=0
|
||||
while [ $i -lt $CISCO_SPLIT_INC ] ; do
|
||||
eval NETWORK="\${CISCO_SPLIT_INC_${i}_ADDR}"
|
||||
eval NETMASK="\${CISCO_SPLIT_INC_${i}_MASK}"
|
||||
eval NETMASKLEN="\${CISCO_SPLIT_INC_${i}_MASKLEN}"
|
||||
if [ $NETWORK != "0.0.0.0" ]; then
|
||||
proto_add_ipv4_route "$NETWORK" "$NETMASKLEN"
|
||||
else
|
||||
proto_add_ipv4_route "0.0.0.0" 0
|
||||
fi
|
||||
i=$(($i + 1))
|
||||
done
|
||||
elif [ -n "$INTERNAL_IP4_ADDRESS" ]; then
|
||||
proto_add_ipv4_route "0.0.0.0" 0
|
||||
fi
|
||||
if [ -n "$CISCO_IPV6_SPLIT_INC" ]; then
|
||||
i=0
|
||||
while [ $i -lt $CISCO_IPV6_SPLIT_INC ] ; do
|
||||
eval NETWORK="\${CISCO_IPV6_SPLIT_INC_${i}_ADDR}"
|
||||
eval NETMASKLEN="\${CISCO_IPV6_SPLIT_INC_${i}_MASKLEN}"
|
||||
if [ $NETMASKLEN -lt 128 ]; then
|
||||
proto_add_ipv6_route "$NETWORK" "$NETMASKLEN"
|
||||
else
|
||||
proto_add_ipv6_route "::0" 0
|
||||
fi
|
||||
i=$(($i + 1))
|
||||
done
|
||||
elif [ -n "$INTERNAL_IP6_NETMASK" -o -n "$INTERNAL_IP6_ADDRESS" ]; then
|
||||
proto_add_ipv6_route "::0" 0
|
||||
fi
|
||||
proto_send_update "$INTERFACE"
|
||||
}
|
||||
|
||||
do_disconnect() {
|
||||
proto_init_update "$TUNDEV" 0
|
||||
proto_send_update "$INTERFACE"
|
||||
}
|
||||
|
||||
#### Main
|
||||
|
||||
if [ -z "$reason" ]; then
|
||||
echo "this script must be called from vpnc" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$INTERFACE" ]; then
|
||||
echo "this script must be called for an active interface"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. /lib/netifd/netifd-proto.sh
|
||||
|
||||
case "$reason" in
|
||||
pre-init)
|
||||
;;
|
||||
connect)
|
||||
do_connect
|
||||
;;
|
||||
disconnect)
|
||||
do_disconnect
|
||||
;;
|
||||
reconnect)
|
||||
;;
|
||||
*)
|
||||
echo "unknown reason '$reason'. Maybe vpnc-script is out of date" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
100
net/openconnect/patches/100-passwd_file.patch
Normal file
100
net/openconnect/patches/100-passwd_file.patch
Normal file
@ -0,0 +1,100 @@
|
||||
--- a/main.c
|
||||
+++ b/main.c
|
||||
@@ -77,6 +77,7 @@ enum {
|
||||
OPT_CAFILE,
|
||||
OPT_COOKIEONLY,
|
||||
OPT_COOKIE_ON_STDIN,
|
||||
+ OPT_COOKIE_FILE,
|
||||
OPT_CSD_USER,
|
||||
OPT_CSD_WRAPPER,
|
||||
OPT_DISABLE_IPV6,
|
||||
@@ -91,6 +92,7 @@ enum {
|
||||
OPT_NO_PROXY,
|
||||
OPT_PIDFILE,
|
||||
OPT_PASSWORD_ON_STDIN,
|
||||
+ OPT_PASSWORD_FILE,
|
||||
OPT_PRINTCOOKIE,
|
||||
OPT_RECONNECT_TIMEOUT,
|
||||
OPT_SERVERCERT,
|
||||
@@ -139,7 +141,9 @@ static struct option long_options[] = {
|
||||
OPTION("queue-len", 1, 'Q'),
|
||||
OPTION("xmlconfig", 1, 'x'),
|
||||
OPTION("cookie-on-stdin", 0, OPT_COOKIE_ON_STDIN),
|
||||
+ OPTION("cookie-file", 1, OPT_COOKIE_FILE),
|
||||
OPTION("passwd-on-stdin", 0, OPT_PASSWORD_ON_STDIN),
|
||||
+ OPTION("passwd-file", 1, OPT_PASSWORD_FILE),
|
||||
OPTION("no-passwd", 0, OPT_NO_PASSWD),
|
||||
OPTION("reconnect-timeout", 1, OPT_RECONNECT_TIMEOUT),
|
||||
OPTION("dtls-ciphers", 1, OPT_DTLS_CIPHERS),
|
||||
@@ -177,6 +181,7 @@ static void usage(void)
|
||||
printf(" -K, --key-type=TYPE %s\n", _("Private key type (PKCS#12 / TPM / PEM)"));
|
||||
printf(" -C, --cookie=COOKIE %s\n", _("Use WebVPN cookie COOKIE"));
|
||||
printf(" --cookie-on-stdin %s\n", _("Read cookie from standard input"));
|
||||
+ printf(" --cookie-file=FILE %s\n", _("Read cookie from a file"));
|
||||
printf(" -d, --deflate %s\n", _("Enable compression (default)"));
|
||||
printf(" -D, --no-deflate %s\n", _("Disable compression"));
|
||||
printf(" --force-dpd=INTERVAL %s\n", _("Set minimum Dead Peer Detection interval"));
|
||||
@@ -217,6 +222,7 @@ static void usage(void)
|
||||
printf(" --no-cert-check %s\n", _("Do not require server SSL cert to be valid"));
|
||||
printf(" --non-inter %s\n", _("Do not expect user input; exit if it is required"));
|
||||
printf(" --passwd-on-stdin %s\n", _("Read password from standard input"));
|
||||
+ printf(" --passwd-file=FILE %s\n", _("Read password from a file"));
|
||||
printf(" --reconnect-timeout %s\n", _("Connection retry timeout in seconds"));
|
||||
printf(" --servercert=FINGERPRINT %s\n", _("Server's certificate SHA1 fingerprint"));
|
||||
printf(" --useragent=STRING %s\n", _("HTTP header User-Agent: field"));
|
||||
@@ -226,15 +232,28 @@ static void usage(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
-static void read_stdin(char **string)
|
||||
+static void read_file(const char *file, char **string)
|
||||
{
|
||||
char *c = malloc(100);
|
||||
+ FILE *f;
|
||||
+
|
||||
+ if (file) {
|
||||
+ f = fopen(file, "r");
|
||||
+ if (!f) {
|
||||
+ fprintf(stderr, _("Failed to open password file\n"));
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ } else {
|
||||
+ file = "stdin";
|
||||
+ f = stdin;
|
||||
+ }
|
||||
+
|
||||
if (!c) {
|
||||
- fprintf(stderr, _("Allocation failure for string from stdin\n"));
|
||||
+ fprintf(stderr, _("Allocation failure for string from %s\n"), file);
|
||||
exit(1);
|
||||
}
|
||||
- if (!fgets(c, 100, stdin)) {
|
||||
- perror(_("fgets (stdin)"));
|
||||
+ if (!fgets(c, 100, f)) {
|
||||
+ perror(_("fgets"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -332,14 +351,20 @@ int main(int argc, char **argv)
|
||||
cookieonly = 2;
|
||||
break;
|
||||
case OPT_COOKIE_ON_STDIN:
|
||||
- read_stdin(&vpninfo->cookie);
|
||||
+ optarg = NULL;
|
||||
+ /* fall through */
|
||||
+ case OPT_COOKIE_FILE:
|
||||
+ read_file(optarg, &vpninfo->cookie);
|
||||
/* If the cookie is empty, ignore it */
|
||||
if (! *vpninfo->cookie) {
|
||||
vpninfo->cookie = NULL;
|
||||
}
|
||||
break;
|
||||
case OPT_PASSWORD_ON_STDIN:
|
||||
- read_stdin(&vpninfo->password);
|
||||
+ optarg = NULL;
|
||||
+ /* fall through */
|
||||
+ case OPT_PASSWORD_FILE:
|
||||
+ read_file(optarg, &vpninfo->password);
|
||||
break;
|
||||
case OPT_NO_PASSWD:
|
||||
vpninfo->nopasswd = 1;
|
Loading…
x
Reference in New Issue
Block a user