Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tatsh/8ad5aa75721d6ba018a20906a04a6fa3 to your computer and use it in GitHub Desktop.
Save Tatsh/8ad5aa75721d6ba018a20906a04a6fa3 to your computer and use it in GitHub Desktop.
From 9ed72ef140d40bc1ccea5911b38fa78e7faea160 Mon Sep 17 00:00:00 2001
From: Dan Aloni <dan@kernelim.com>
Date: Wed, 1 Apr 2020 12:28:15 +0300
Subject: [PATCH 1/2] Support a script to be executed when the device goes up
This adds the `ifup_script` config option. The script receives the
following environment variables as input:
- NET_DEVICE: The name of the network device of the VPN.
- DNS_SUFFIX: DNS domain search prefix, if provided by the VPN server.
- DNS_SERVERS: A list of the DNS server addresses if provided by the VPN
server.
---
src/config.c | 5 ++++-
src/config.h | 2 ++
src/tunnel.c | 37 +++++++++++++++++++++++++++++++++++--
3 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/src/config.c b/src/config.c
index 825febb..dc58dd2 100644
--- a/src/config.c
+++ b/src/config.c
@@ -297,8 +297,11 @@ int load_config(struct vpn_config *cfg, const char *filename)
free(cfg->pinentry);
cfg->pinentry = strdup(val);
} else if (strcmp(key, "realm") == 0) {
- strncpy(cfg->realm, val, REALM_SIZE);
+ strncpy(cfg->realm, val, REALM_SIZE - 1);
cfg->realm[REALM_SIZE] = '\0';
+ } else if (strcmp(key, "ifup-script") == 0) {
+ strncpy(cfg->ifup_script, val, MAXPATHLEN - 1);
+ cfg->ifup_script[MAXPATHLEN] = '\0';
} else if (strcmp(key, "set-dns") == 0) {
int set_dns = strtob(val);
diff --git a/src/config.h b/src/config.h
index f7783e1..9801f68 100644
--- a/src/config.h
+++ b/src/config.h
@@ -18,6 +18,7 @@
#ifndef OPENFORTIVPN_CONFIG_H
#define OPENFORTIVPN_CONFIG_H
+#include <sys/param.h>
#include <netinet/in.h>
#include <net/if.h>
@@ -96,6 +97,7 @@ struct vpn_config {
char *pinentry;
char iface_name[IF_NAMESIZE];
char realm[REALM_SIZE + 1];
+ char ifup_script[MAXPATHLEN + 1];
int set_routes;
int set_dns;
diff --git a/src/tunnel.c b/src/tunnel.c
index 7aede6f..658d1d4 100644
--- a/src/tunnel.c
+++ b/src/tunnel.c
@@ -107,13 +107,39 @@ static int ofv_append_varr(struct ofv_varr *p, const char *x)
return 0;
}
+static int ipv4_run_ifup_script(struct tunnel *tunnel)
+{
+ char ns[32];
+
+ setenv("NET_DEVICE", tunnel->ppp_iface, 0);
+
+ ns[0] = '\0';
+
+ if (tunnel->ipv4.ns1_addr.s_addr != 0)
+ strncat(ns, inet_ntoa(tunnel->ipv4.ns1_addr), 15);
+
+ if (tunnel->ipv4.ns2_addr.s_addr != 0) {
+ strcpy(ns, " ");
+ strncat(ns, inet_ntoa(tunnel->ipv4.ns2_addr), 15);
+ }
+
+ setenv("DNS_SERVERS", ns, 0);
+
+ if (tunnel->ipv4.dns_suffix != NULL)
+ setenv("DNS_SUFFIX", tunnel->ipv4.dns_suffix, 0);
+ else
+ setenv("DNS_SUFFIX", "", 0);
+
+ return system(tunnel->config->ifup_script);
+}
+
static int on_ppp_if_up(struct tunnel *tunnel)
{
+ int ret;
+
log_info("Interface %s is UP.\n", tunnel->ppp_iface);
if (tunnel->config->set_routes) {
- int ret;
-
log_info("Setting new routes...\n");
ret = ipv4_set_tunnel_routes(tunnel);
@@ -127,6 +153,13 @@ static int on_ppp_if_up(struct tunnel *tunnel)
ipv4_add_nameservers_to_resolv_conf(tunnel);
}
+ if (tunnel->config->ifup_script) {
+ log_info("Running `ifup` script...\n");
+ ret = ipv4_run_ifup_script(tunnel);
+ if (ret != 0)
+ log_warn("The `ifup` script failed. Please check your logs.\n");
+ }
+
log_info("Tunnel is up and running.\n");
#if HAVE_SYSTEMD
--
2.34.1
From 90a42f08ba08eb781b82450658a06be552f66ad9 Mon Sep 17 00:00:00 2001
From: Dan Aloni <dan@kernelim.com>
Date: Wed, 1 Apr 2020 12:28:15 +0300
Subject: [PATCH 2/2] Add a script to be used for updating systemd-resolved
---
contrib/ifup-systemd-resolved.sh | 119 +++++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100755 contrib/ifup-systemd-resolved.sh
diff --git a/contrib/ifup-systemd-resolved.sh b/contrib/ifup-systemd-resolved.sh
new file mode 100755
index 0000000..47d422a
--- /dev/null
+++ b/contrib/ifup-systemd-resolved.sh
@@ -0,0 +1,119 @@
+#!/bin/bash
+
+# -------------------------------------------------------------------------------
+# LICENSE:
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# -------------------------------------------------------------------------------
+
+# This is an `ifup` script to be used for integrating openfortivpn and
+# systemd-resolved. When the network interface goes up, the DNS server information
+# will be added to `systemd-resolved` without modifying /etc/resolve.conf.
+#
+# This script is largely based on the main script from the `update-systemd-resolved`
+# package, see: https://github.com/jonathanio/update-systemd-resolved
+
+DBUS_DEST="org.freedesktop.resolve1"
+DBUS_NODE="/org/freedesktop/resolve1"
+
+SCRIPT_NAME="${BASH_SOURCE[0]##*/}"
+
+log() {
+ logger -s -t "$SCRIPT_NAME" "$@"
+}
+
+for level in emerg err warning info debug; do
+ printf -v functext -- '%s() { log -p user.%s -- "$@" ; }' "$level" "$level"
+ eval "$functext"
+done
+
+get_link_info() {
+ dev="$1"
+ shift
+
+ link=''
+ link="$(ip link show dev "$dev")" || return $?
+
+ echo "$dev" "${link%%:*}"
+}
+
+busctl_call() {
+ # Preserve busctl's exit status
+ busctl call "$DBUS_DEST" "$DBUS_NODE" "${DBUS_DEST}.Manager" "$@" || {
+ local -i status=$?
+ emerg "'busctl' exited with status $status"
+ return $status
+ }
+}
+
+up() {
+ local link="$1"
+ shift
+ local if_index="$1"
+ shift
+
+ local -a dns_servers=() dns_domain=() dns_search=() dns_routed=()
+ local -i dns_server_count=0 dns_domain_count=0 dns_search_count=0 dns_routed_count=0
+ local dns_sec=""
+
+ for address in ${DNS_SERVERS}; do
+ (( dns_server_count += 1 ))
+ dns_servers+=(2 4 ${address//./ })
+ done
+
+ for domain in ${DNS_SUFFIX}; do
+ (( dns_search_count += 1 ))
+ dns_search+=("${domain}" false)
+ done
+
+ if [[ "${#dns_servers[*]}" -gt 0 ]]; then
+ busctl_params=("$if_index" "$dns_server_count" "${dns_servers[@]}")
+ info "SetLinkDNS(${busctl_params[*]})"
+ busctl_call SetLinkDNS 'ia(iay)' "${busctl_params[@]}" || return $?
+ fi
+
+ if [[ "${#dns_domain[*]}" -gt 0 \
+ || "${#dns_search[*]}" -gt 0 \
+ || "${#dns_routed[*]}" -gt 0 ]]; then
+ dns_count=$((dns_domain_count+dns_search_count+dns_routed_count))
+ busctl_params=("$if_index" "$dns_count")
+ if [[ "${#dns_domain[*]}" -gt 0 ]]; then
+ busctl_params+=("${dns_domain[@]}")
+ fi
+ if [[ "${#dns_search[*]}" -gt 0 ]]; then
+ busctl_params+=("${dns_search[@]}")
+ fi
+ if [[ "${#dns_routed[*]}" -gt 0 ]]; then
+ busctl_params+=("${dns_routed[@]}")
+ fi
+ info "SetLinkDomains(${busctl_params[*]})"
+ busctl_call SetLinkDomains 'ia(sb)' "${busctl_params[@]}" || return $?
+ fi
+
+ if [[ -n "${dns_sec}" ]]; then
+ if [[ "${dns_sec}" == "default" ]]; then
+ # We need to provide an empty string to use the default settings
+ info "SetLinkDNSSEC($if_index '')"
+ busctl_call SetLinkDNSSEC 'is' "$if_index" "" || return $?
+ else
+ info "SetLinkDNSSEC($if_index ${dns_sec})"
+ busctl_call SetLinkDNSSEC 'is' "$if_index" "${dns_sec}" || return $?
+ fi
+ fi
+}
+
+dev=${NET_DEVICE}
+read -r link if_index _ < <(get_link_info "$dev")
+up "$link" "$if_index"
+systemd-resolve --flush-caches
--
2.34.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment