. /lib/functions/network.sh
. ../netifd-proto.sh
init_proto "$@"
+IPv4_REGEX="((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
append_args() {
while [ $# -gt 0 ]; do
proto_openfortivpn_setup() {
local config="$1"
- local msg ifname ip server_ip pwfile callfile
+ local msg ifname ip server_ips pwfile callfile
local host peeraddr port tunlink local_ip username password trusted_cert \
remote_status_check
[ -n "$tunlink" ] && {
- network_get_device iface_device_name "$tunlink"
- network_is_up "$tunlink" || {
- msg="$tunlink is not up $iface_device_up"
- logger -t "openfortivpn" "$config: $msg"
- proto_notify_error "$config" "$msg"
- proto_block_restart "$config"
- exit 1
- }
+ network_get_device iface_device_name "$tunlink"
+ network_is_up "$tunlink" || {
+ msg="$tunlink is not up $iface_device_up"
+ logger -t "openfortivpn" "$config: $msg"
+ proto_notify_error "$config" "$msg"
+ proto_block_restart "$config"
+ exit 1
+ }
}
- server_ip=$(resolveip -4 -t 10 "$peeraddr")
+ if echo "$peeraddr" | grep -q -E "$IPv4_REGEX"; then
+ server_ips="$peeraddr"
+ elif command -v resolveip >/dev/null ; then
+ server_ips="$(resolveip -4 -t 10 "$peeraddr")"
+ [ $? -eq 0 ] || {
+ msg="$config: failed to resolve server ip for $peeraddr"
+ logger -t "openfortivpn" "$msg"
+ sleep 10
+ proto_notify_error "$config" "$msg"
+ proto_setup_failed "$config"
+ exit 1
+ }
+ else
+ logger -t "openfortivpn" "resolveip not present, could not resolve $peeraddr"
+ fi
- [ $? -eq 0 ] || {
- msg="$config: failed to resolve server ip for $peeraddr"
- logger -t "openfortivpn" "$msg"
- sleep 10
- proto_notify_error "$config" "$msg"
- proto_setup_failed "$config"
- exit 1
- }
[ "$remote_status_check" = "curl" ] && {
- curl -k --head -s --connect-timeout 10 ${tunlink:+--interface} $iface_device_name https://$server_ip > /dev/null || {
- msg="failed to reach https://${server_ip}${tunlink:+ on $iface_device_name}"
- logger -t "openfortivpn" "$config: $msg"
- sleep 10
- proto_notify_error "$config" "$msg"
- proto_setup_failed "$config"
- exit 1
- }
+ curl -k --head -s --connect-timeout 10 ${tunlink:+--interface} $iface_device_name https://$peeraddr > /dev/null || {
+ msg="failed to reach https://$peeraddr${tunlink:+ on $iface_device_name}"
+ logger -t "openfortivpn" "$config: $msg"
+ sleep 10
+ proto_notify_error "$config" "$msg"
+ proto_setup_failed "$config"
+ exit 1
+ }
}
[ "$remote_status_check" = "ping" ] && {
- ping ${tunlink:+-I} $iface_device_name -c 1 -w 10 $server_ip > /dev/null 2>&1 || {
- msg="$config: failed to ping $server_ip on $iface_device_name"
- logger -t "openfortvpn" "$config: $msg"
- sleep 10
- proto_notify_error "$config" "failed to ping $server_ip on $iface_device_name"
- proto_setup_failed "$config"
- exit 1
- }
+ ping ${tunlink:+-I} $iface_device_name -c 1 -w 10 $peeraddr > /dev/null 2>&1 || {
+ msg="$config: failed to ping $peeraddr on $iface_device_name"
+ logger -t "openfortvpn" "$config: $msg"
+ sleep 10
+ proto_notify_error "$config" "$msg"
+ proto_setup_failed "$config"
+ exit 1
+ }
}
- for ip in $(resolveip -4 -t 10 "$peeraddr"); do
- logger -p 6 -t "openfortivpn" "$config: adding host dependency for $ip on $tunlink at $config"
- proto_add_host_dependency "$config" "$ip" "$tunlink"
- done
-
+ if [ -n "$server_ips" ]; then
+ for ip in $server_ips; do
+ logger -p 6 -t "openfortivpn" "$config: adding host dependency for $ip on $tunlink at $config"
+ proto_add_host_dependency "$config" "$ip" "$tunlink"
+ done
+ fi
+
+ # uclient-fetch cannot bind to interface, so perform check after adding host dependency
+ [ "$remote_status_check" = "fetch" ] && {
+ uclient-fetch --no-check-certificate -q -s --timeout=10 https://$peeraddr > /dev/null 2>&1 || {
+ msg="$config: failed to reach ${server_ip:-$peeraddr} on $iface_device_name"
+ logger -t "openfortvpn" "$config: $msg"
+ sleep 10
+ proto_notify_error "$config" "$msg"
+ proto_setup_failed "$config"
+ exit 1
+ }
+ }
[ -n "$port" ] && port=":$port"
echo "$password" > "$pwfile"
}
- [ -n "$local_ip" ] || local_ip=$server_ip
+ [ -n "$local_ip" ] || local_ip=192.0.2.1
[ -e '/etc/ppp/peers' ] || mkdir -p '/etc/ppp/peers'
[ -e '/etc/ppp/peers/openfortivpn' ] || {
ln -s -T '/var/etc/openfortivpn/peers' '/etc/ppp/peers/openfortivpn' 2> /dev/null
+++ /dev/null
---- a/doc/openfortivpn.1.in
-+++ b/doc/openfortivpn.1.in
-@@ -12,6 +12,7 @@ openfortivpn \- Client for PPP+SSL VPN t
- [\fB\-\-otp\-prompt=\fI<prompt>\fR]
- [\fB\-\-otp\-delay=\fI<delay>\fR]
- [\fB\-\-realm=\fI<realm>\fR]
-+[\fB\-\-ifname=\fI<interface>\fR]
- [\fB\-\-set\-routes=<bool>\fR]
- [\fB\-\-no\-routes\fR]
- [\fB\-\-set\-dns=<bool>\fR]
-@@ -83,6 +84,9 @@ no wait (this is the default).
- Connect to the specified authentication realm. Defaults to empty, which
- is usually what you want.
- .TP
-+\fB\-\-ifname=\fI<interface>\fR
-+Bind the connection to the specified network interface.
-+.TP
- \fB\-\-set\-routes=\fI<bool>\fR, \fB\-\-no-routes\fR
- Set if openfortivpn should try to configure IP routes through the VPN when
- tunnel is up. If used multiple times, the last one takes priority.
---- a/src/config.c
-+++ b/src/config.c
-@@ -50,6 +50,7 @@ const struct vpn_config invalid_cfg = {
- .otp_delay = -1,
- .pinentry = NULL,
- .realm = {'\0'},
-+ .iface_name = {'\0'},
- .set_routes = -1,
- .set_dns = -1,
- .pppd_use_peerdns = -1,
-@@ -490,6 +491,8 @@ void merge_config(struct vpn_config *dst
- }
- if (src->realm[0])
- strcpy(dst->realm, src->realm);
-+ if (src->iface_name[0])
-+ strcpy(dst->iface_name, src->iface_name);
- if (src->set_routes != invalid_cfg.set_routes)
- dst->set_routes = src->set_routes;
- if (src->set_dns != invalid_cfg.set_dns)
---- a/src/config.h
-+++ b/src/config.h
-@@ -86,6 +86,7 @@ struct vpn_config {
- char *otp_prompt;
- unsigned int otp_delay;
- char *pinentry;
-+ char iface_name[FIELD_SIZE + 1];
- char realm[FIELD_SIZE + 1];
-
- int set_routes;
---- a/src/main.c
-+++ b/src/main.c
-@@ -51,16 +51,16 @@
- " resolver and routes directly.\n" \
- " --pppd-ifname=<string> Set the pppd interface name, if supported by pppd.\n" \
- " --pppd-ipparam=<string> Provides an extra parameter to the ip-up, ip-pre-up\n" \
--" and ip-down scripts. See man (8) pppd\n" \
-+" and ip-down scripts. See man (8) pppd.\n" \
- " --pppd-call=<name> Move most pppd options from pppd cmdline to\n" \
- " /etc/ppp/peers/<name> and invoke pppd with\n" \
--" 'call <name>'\n"
-+" 'call <name>'.\n"
- #elif HAVE_USR_SBIN_PPP
- #define PPPD_USAGE \
- " [--ppp-system=<system>]\n"
- #define PPPD_HELP \
- " --ppp-system=<system> Connect to the specified system as defined in\n" \
--" /etc/ppp/ppp.conf\n"
-+" /etc/ppp/ppp.conf.\n"
- #else
- #error "Neither HAVE_USR_SBIN_PPPD nor HAVE_USR_SBIN_PPP have been defined."
- #endif
-@@ -69,7 +69,7 @@
- #define RESOLVCONF_USAGE \
- "[--use-resolvconf=<0|1>] "
- #define RESOLVCONF_HELP \
--" --use-resolvconf=[01] If possible use resolvconf to update /etc/resolv.conf\n"
-+" --use-resolvconf=[01] If possible use resolvconf to update /etc/resolv.conf.\n"
- #else
- #define RESOLVCONF_USAGE ""
- #define RESOLVCONF_HELP ""
-@@ -77,14 +77,14 @@
-
- #define usage \
- "Usage: openfortivpn [<host>[:<port>]] [-u <user>] [-p <pass>]\n" \
--" [--pinentry=<program>]\n" \
--" [--realm=<realm>] [--otp=<otp>] [--otp-delay=<delay>]\n" \
--" [--otp-prompt=<prompt>] [--set-routes=<0|1>]\n" \
-+" [--otp=<otp>] [--otp-delay=<delay>] [--otp-prompt=<prompt>]\n" \
-+" [--pinentry=<program>] [--realm=<realm>]\n" \
-+" [--ifname=<ifname>] [--set-routes=<0|1>]\n" \
- " [--half-internet-routes=<0|1>] [--set-dns=<0|1>]\n" \
- PPPD_USAGE \
- " " RESOLVCONF_USAGE "[--ca-file=<file>]\n" \
- " [--user-cert=<file>] [--user-key=<file>]\n" \
--" [--trusted-cert=<digest>] [--use-syslog]\n" \
-+" [--use-syslog] [--trusted-cert=<digest>]\n" \
- " [--persistent=<interval>] [-c <file>] [-v|-q]\n" \
- " openfortivpn --help\n" \
- " openfortivpn --version\n" \
-@@ -115,10 +115,11 @@ PPPD_USAGE \
- " -u <user>, --username=<user> VPN account username.\n" \
- " -p <pass>, --password=<pass> VPN account password.\n" \
- " -o <otp>, --otp=<otp> One-Time-Password.\n" \
--" --otp-prompt=<prompt> Search for the OTP prompt starting with this string\n" \
-+" --otp-prompt=<prompt> Search for the OTP prompt starting with this string.\n" \
- " --otp-delay=<delay> Wait <delay> seconds before sending the OTP.\n" \
--" --pinentry=<program> Use the program to supply a secret instead of asking for it\n" \
-+" --pinentry=<program> Use the program to supply a secret instead of asking for it.\n" \
- " --realm=<realm> Use specified authentication realm.\n" \
-+" --ifname=<interface> Bind to interface.\n" \
- " --set-routes=[01] Set if openfortivpn should configure routes\n" \
- " when tunnel is up.\n" \
- " --no-routes Do not configure routes, same as --set-routes=0.\n" \
-@@ -127,7 +128,7 @@ PPPD_USAGE \
- " --set-dns=[01] Set if openfortivpn should add DNS name servers\n" \
- " and domain search list in /etc/resolv.conf.\n" \
- " If installed resolvconf is used for the update.\n" \
--" --no-dns Do not reconfigure DNS, same as --set-dns=0\n" \
-+" --no-dns Do not reconfigure DNS, same as --set-dns=0.\n" \
- " --ca-file=<file> Use specified PEM-encoded certificate bundle\n" \
- " instead of system-wide store to verify the gateway\n" \
- " certificate.\n" \
-@@ -199,6 +200,7 @@ int main(int argc, char **argv)
- .otp_delay = 0,
- .pinentry = NULL,
- .realm = {'\0'},
-+ .iface_name = {'\0'},
- .set_routes = 1,
- .set_dns = 1,
- .use_syslog = 0,
-@@ -245,6 +247,7 @@ int main(int argc, char **argv)
- {"otp", required_argument, NULL, 'o'},
- {"otp-prompt", required_argument, NULL, 0},
- {"otp-delay", required_argument, NULL, 0},
-+ {"ifname", required_argument, NULL, 0},
- {"set-routes", required_argument, NULL, 0},
- {"no-routes", no_argument, &cli_cfg.set_routes, 0},
- {"half-internet-routes", required_argument, NULL, 0},
-@@ -427,6 +430,12 @@ int main(int argc, char **argv)
- break;
- }
- if (strcmp(long_options[option_index].name,
-+ "ifname") == 0) {
-+ strncpy(cli_cfg.iface_name, optarg, FIELD_SIZE);
-+ cli_cfg.iface_name[FIELD_SIZE] = '\0';
-+ break;
-+ }
-+ if (strcmp(long_options[option_index].name,
- "set-routes") == 0) {
- int set_routes = strtob(optarg);
-
---- a/src/tunnel.c
-+++ b/src/tunnel.c
-@@ -523,12 +523,28 @@ static int tcp_connect(struct tunnel *tu
- int ret, handle;
- struct sockaddr_in server;
- char *env_proxy;
-+ const int iface_len = strnlen(tunnel->config->iface_name, IFNAMSIZ);
-
- handle = socket(AF_INET, SOCK_STREAM, 0);
-+
- if (handle == -1) {
- log_error("socket: %s\n", strerror(errno));
- goto err_socket;
- }
-+ if (iface_len == IFNAMSIZ) {
-+ log_error("socket: Too long iface name");
-+ goto err_socket;
-+ }
-+ if (iface_len > 0) {
-+ ret = setsockopt(handle, SOL_SOCKET, SO_BINDTODEVICE,
-+ tunnel->config->iface_name, iface_len);
-+ if (ret) {
-+ log_error("socket: setting interface name failed with error: %d",
-+ errno);
-+ goto err_socket;
-+ }
-+ }
-+
- env_proxy = getenv("https_proxy");
- if (env_proxy == NULL)
- env_proxy = getenv("HTTPS_PROXY");