Author: Federico Heinz <fhe...@gmail.com> Accept "local if:<ifname>" option.
The current 'local' configuration directive allows for two types of values: IP addresses and DNS hostnames. This is not enough for users of dynamic DNS services who must restart OpenVPN when their IP address changes, because their new IP address may not have progagated yet through DNS when OpenVPN starts, and so they may end up binding to a bogus address. This patch introduces a parameter notation that helps solve the problem: if the option parameter is of the form "if:<ifname>", it will determine the IP address of the interface and use that as the IP address to bind to. The patch is small, and meant to be mininally intrusive: instead of adding a new option and/or new code paths to handle the new case, it simply replaces the value supplied by the user by a string representing the IP address, as if the user had entered it. I'm not entirely sure I'm using gc_malloc() correctly, and I'd appreciate feedback on that. Signed-off-by: Federico Heinz <fhe...@gmail.com>
diff -r 66ad68054f67 openvpn.8 --- a/openvpn.8 Tue Mar 01 10:21:42 2011 +0100 +++ b/openvpn.8 Tue Mar 08 18:36:39 2011 -0300 @@ -197,6 +197,12 @@ .B \-\-local host Local host name or IP address for bind. If specified, OpenVPN will bind to this address only. +If +.B local +is of the form +.B if:ifname, +OpenVPN will bind only to the IP address of the interface called +.B ifname. If unspecified, OpenVPN will bind to all interfaces. .\"********************************************************* .TP diff -r 66ad68054f67 options.c --- a/options.c Tue Mar 01 10:21:42 2011 +0100 +++ b/options.c Tue Mar 08 18:36:39 2011 -0300 @@ -51,6 +51,9 @@ #include "forward.h" #include "configure.h" #include <ctype.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include "memdbg.h" @@ -101,6 +104,7 @@ "\n" "Tunnel Options:\n" "--local host : Local host name or ip address. Implies --bind.\n" + " Use \"if:<ifname>\" for IP address of interface <ifname>." "--remote host [port] : Remote host name or ip address.\n" "--remote-random : If multiple --remote options specified, choose one randomly.\n" "--remote-random-hostname : Add a random string to remote DNS name.\n" @@ -4017,8 +4021,32 @@ } else if (streq (p[0], "local") && p[1]) { + static const char if_prefix[] = "if:"; VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.local = p[1]; + options->ce.local = NULL; + if (strneq(if_prefix, p[1], sizeof(if_prefix)-1)) + { + int fd; + struct ifreq ifr; + + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, &(p[1][sizeof(if_prefix)-1]), IFNAMSIZ-1); + if ((fd = socket(AF_INET, SOCK_DGRAM, 0))>= 0) + { + if (ioctl(fd, SIOCGIFADDR, &ifr) >= 0) + { + const char *addr = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr); + char *value = gc_malloc(strlen(addr)+1, true, &options->gc); + strcpy(value, addr); + options->ce.local = value; + } + close(fd); + } + } + if (options->ce.local == NULL) + { + options->ce.local = p[1]; + } } else if (streq (p[0], "remote-random")) { diff -r 66ad68054f67 options.h --- a/options.h Tue Mar 01 10:21:42 2011 +0100 +++ b/options.h Tue Mar 08 18:36:39 2011 -0300 @@ -563,6 +563,7 @@ }; #define streq(x, y) (!strcmp((x), (y))) +#define strneq(x, y, n) (!strncmp((x), (y), (n))) /* * Option classes.