diff --git a/doc/openfortivpn.1.in b/doc/openfortivpn.1.in index fd68702c..b95675cf 100644 --- a/doc/openfortivpn.1.in +++ b/doc/openfortivpn.1.in @@ -26,6 +26,7 @@ openfortivpn \- Client for PPP+SSL VPN tunnel services [\fB\-\-pppd-plugin=\fI\fR] [\fB\-\-pppd-ipparam=\fI\fR] [\fB\-\-pppd-ifname=\fI\fR] +[\fB\-\-pppd-call=\fI\fR] [\fB\-\-persistent\fR] [\fB\-c\fR \fI\fR] [\fB\-v|\-q\fR] @@ -129,6 +130,13 @@ for further details \fB\-\-pppd-ifname=\fI\fR Set the ppp interface name. Only if supported by pppd. Patched versions of pppd implement this option but may not be available on your platform. +.TP +\fB\-\-pppd-call=\fI\fR +Drop usual arguments from pppd command line and add `call ' instead. +This can be useful on Debian and Ubuntu, where unprivileged users in +group `dip' can invoke `pppd call ' to make pppd read and apply +options from /etc/ppp/peers/ (including privileged ones). +.TP \fB\-\-persistent\=\fIfR Runs the vpn persistently in an endless loop and tries to reconnect forever. The reconnect interval may be specified in seconds, where 0 means diff --git a/etc/ppp/ip-down.local.example b/etc/ppp/ip-down.local.example new file mode 100755 index 00000000..984ae65a --- /dev/null +++ b/etc/ppp/ip-down.local.example @@ -0,0 +1,11 @@ +#!/bin/bash + +case "$PPP_IPPARAM" in + openfortivpn*) + rconf=/etc/resolv.conf + [[ -f $rconf.openfortivpn ]] && cp -pv $rconf.openfortivpn $rconf + exit 0 + ;; +esac 2>&1 | logger -p daemon.debug -i -t "$0" + +true diff --git a/etc/ppp/ip-up.local.example b/etc/ppp/ip-up.local.example new file mode 100755 index 00000000..b79e15c9 --- /dev/null +++ b/etc/ppp/ip-up.local.example @@ -0,0 +1,22 @@ +#!/bin/bash + +case "$PPP_IPPARAM" in + openfortivpn*) + rconf=/etc/resolv.conf + routes=$(echo $PPP_IPPARAM | tr , ' ') + for r in $routes; do + [[ $r = "openfortivpn" ]] && continue + com="ip route add ${r%/*} via ${r##*/}" + echo $com + $com + done + cp -pv $rconf $rconf.openfortivpn + if [[ "$DNS1" ]]; then + echo nameserver $DNS1 > $rconf + [[ "$DNS2" ]] && [[ "$DNS1" != "$DNS2" ]] && echo nameserver $DNS2 >> $rconf + fi + exit 0 + ;; +esac 2>&1 | logger -p daemon.debug -i -t "$0" + +true diff --git a/etc/ppp/peers/openfortivpn b/etc/ppp/peers/openfortivpn new file mode 100644 index 00000000..1d76f115 --- /dev/null +++ b/etc/ppp/peers/openfortivpn @@ -0,0 +1,12 @@ +38400 +:1.1.1.1 +noipdefault +noaccomp +noauth +default-asyncmap +nopcomp +receive-all +nodefaultroute +nodetach +lcp-max-configure 40 +mru 1354 diff --git a/src/config.c b/src/config.c index 5a0819aa..25499fc5 100644 --- a/src/config.c +++ b/src/config.c @@ -225,6 +225,8 @@ int load_config(struct vpn_config *cfg, const char *filename) cfg->pppd_ipparam = strdup(val); } else if (strcmp(key, "pppd-ifname") == 0) { cfg->pppd_ifname = strdup(val); + } else if (strcmp(key, "pppd-call") == 0) { + cfg->pppd_call = strdup(val); } else if (strcmp(key, "use-syslog") == 0) { int use_syslog = strtob(val); if (use_syslog < 0) { diff --git a/src/config.h b/src/config.h index d7e028a7..b0fae833 100644 --- a/src/config.h +++ b/src/config.h @@ -75,6 +75,7 @@ struct vpn_config { char *pppd_plugin; char *pppd_ipparam; char *pppd_ifname; + char *pppd_call; char *ca_file; char *user_cert; diff --git a/src/ipv4.c b/src/ipv4.c index d02794a4..75e80d00 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -515,12 +515,37 @@ int ipv4_protect_tunnel_route(struct tunnel *tunnel) return ret; } +static void add_text_route(struct tunnel *tunnel, const char *dest, + const char *mask, const char *gw) +{ + size_t l0, l1; + const char fmt[] = ",%s/%s/%s"; + const char trigger[] = "openfortivpn"; + char **target = &tunnel->config->pppd_ipparam; + char *ptr; + + if (*target == NULL || strncmp(*target, trigger, strlen(trigger))) + return; + if (!dest || !mask || !gw) + return; + log_info("Registering route %s/%s via %s\n", dest, mask, gw); + l0 = strlen(*target); + l1 = strlen(fmt) + strlen(dest) + strlen(mask) + strlen(gw) + 1; + if ((ptr = realloc(*target, l0 + l1))) { + *target = ptr; + snprintf(*target + l0, l1, fmt, dest, mask, gw); + } else { + log_error("realloc: %s\n", strerror(errno)); + } +} + int ipv4_add_split_vpn_route(struct tunnel *tunnel, char *dest, char *mask, char *gateway) { struct rtentry *route; char env_var[24]; + add_text_route(tunnel, dest, mask, gateway); if (tunnel->ipv4.split_routes == MAX_SPLIT_ROUTES) return ERR_IPV4_NO_MEM; if ((tunnel->ipv4.split_rt == NULL) diff --git a/src/main.c b/src/main.c index 298b4067..b3ef6988 100644 --- a/src/main.c +++ b/src/main.c @@ -33,6 +33,7 @@ " [--half-internet-routes=<0|1>] [--set-dns=<0|1>]\n" \ " [--pppd-no-peerdns] [--pppd-log=]\n" \ " [--pppd-ifname=] [--pppd-ipparam=]\n" \ +" [--pppd-call=]\n" \ " [--pppd-plugin=] [--ca-file=]\n" \ " [--user-cert=] [--user-key=]\n" \ " [--trusted-cert=] [--use-syslog]\n" \ @@ -94,6 +95,9 @@ " --pppd-ifname= Set the pppd interface name, if supported by pppd.\n" \ " --pppd-ipparam= Provides an extra parameter to the ip-up, ip-pre-up\n" \ " and ip-down scripts. See man (8) pppd\n" \ +" --pppd-call= Move most pppd options from pppd cmdline to\n" \ +" /etc/ppp/peers/ and invoke pppd with\n" \ +" 'call '\n" \ " --persistent= Run the vpn persistently in a loop and try to re-\n" \ " connect every seconds when dropping out\n" \ " -v Increase verbosity. Can be used multiple times\n" \ @@ -160,6 +164,7 @@ int main(int argc, char **argv) .pppd_log = NULL, .pppd_plugin = NULL, .pppd_ipparam = NULL, + .pppd_call = NULL, .ca_file = NULL, .user_cert = NULL, .user_key = NULL, @@ -195,6 +200,7 @@ int main(int argc, char **argv) {"pppd-plugin", required_argument, 0, 0}, {"pppd-ipparam", required_argument, 0, 0}, {"pppd-ifname", required_argument, 0, 0}, + {"pppd-call", required_argument, 0, 0}, {"plugin", required_argument, 0, 0}, // deprecated {0, 0, 0, 0} }; @@ -243,6 +249,11 @@ int main(int argc, char **argv) cfg.pppd_ipparam = strdup(optarg); break; } + if (strcmp(long_options[option_index].name, + "pppd-call") == 0) { + cfg.pppd_call = strdup(optarg); + break; + } // --plugin is deprecated, --pppd-plugin should be used if (cfg.pppd_plugin == NULL && strcmp(long_options[option_index].name, diff --git a/src/tunnel.c b/src/tunnel.c index e773d99b..ed397f7b 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -145,6 +145,16 @@ static int pppd_run(struct tunnel *tunnel) NULL // terminal null pointer required by execvp() }; + if (tunnel->config->pppd_call) { + /* overwrite args[]: keep pppd_path, replace all + * options with "call " */ + int j = 1; + args[j++] = "call"; + args[j++] = tunnel->config->pppd_call; + while (j < ARRAY_SIZE(args)) + args[j++] = NULL; + } + // Dynamically get first NULL pointer so that changes of // args above don't need code changes here int i = ARRAY_SIZE(args) - 1;