By using the netifd for open fortivpn we are able to set up multiple VPN connections and manage them through the netifd toolset. This also adds support for binding an openfortivpn client to a given interface, in which case when that interface comes online, the vpn will be initiated via a hotplug script. This is a breaking commit and configurations will need to be migrated from openfortivpn.config into the /etc/config/networks. Example configuration via /etc/config/network: config interface 'ftvpn' option proto 'openfortivpn' option server 'example.com' option username 'USERNAME' option password 'PASSWORD' # optional arguments follow option local_ip '192.0.5.1' option port '443' option iface_name 'wan' option trusted_cert 'CERT_HASH' option set_dns '0' option pppd_use_peerdns '0' option metric '10' Signed-off-by: Aaron Goodman <aaronjg@stanford.edu>
182 lines
7.5 KiB
Diff
182 lines
7.5 KiB
Diff
--- 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");
|