Backport 'lladdr' feature from 2.1, by Mykola S. Grechukh, gns@altlinux.org http://git.altlinux.org/people/gns/packages/?p=openvpn.git;a=shortlog;h=refs/heads/lladdr http://lists.altlinux.org/pipermail/devel/2009-June/171406.html 'llattr' option allows to specify the link layer address, i.e. MAC address, for TAP devices. --- ./Makefile.am.orig +++ ./Makefile.am @@ -50,6 +50,7 @@ openvpn_SOURCES = \ fragment.c fragment.h \ gremlin.c gremlin.h \ helper.c helper.h \ + lladdr.c lladdr.h \ init.c init.h \ integer.h \ interval.c interval.h \ --- ./init.c.orig +++ ./init.c @@ -38,6 +38,7 @@ #include "otime.h" #include "pool.h" #include "gremlin.h" +#include "lladdr.h" #include "memdbg.h" @@ -348,6 +349,9 @@ do_persist_tuntap (const struct options *options) "options --mktun or --rmtun should only be used together with --dev"); tuncfg (options->dev, options->dev_type, options->dev_node, options->tun_ipv6, options->persist_mode); + if (options->persist_mode && options->lladdr) + set_lladdr(options->dev, options->lladdr, NULL); + return true; } #endif @@ -742,6 +746,10 @@ do_open_tun (struct context *c) open_tun (c->options.dev, c->options.dev_type, c->options.dev_node, c->options.tun_ipv6, c->c1.tuntap); + /* set the hardware address */ + if (c->options.lladdr) + set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es); + /* do ifconfig */ if (!c->options.ifconfig_noexec && ifconfig_order () == IFCONFIG_AFTER_TUN_OPEN) --- ./dev/null +++ ./lladdr.c @@ -0,0 +1,61 @@ +/* + * Support routine for configuring link layer address + */ + +#include "config.h" +#include "syshead.h" +#include "buffer.h" +#include "error.h" +#include "common.h" +#include "misc.h" + +const char *iproute_path = "/sbin/ip"; + +int set_lladdr(const char *ifname, const char *lladdr, + const struct env_set *es) +{ + char command_line[256]; + int r; + + if (!ifname || !lladdr) + return -1; + +#if defined(TARGET_LINUX) +#ifdef CONFIG_FEATURE_IPROUTE + openvpn_snprintf (command_line, sizeof (command_line), + "%s link set addr %s dev %s", + iproute_path, lladdr, ifname); +#else + openvpn_snprintf (command_line, sizeof (command_line), + "%s %s hw ether %s", + IFCONFIG_PATH, + ifname, lladdr); +#endif +#elif defined(TARGET_SOLARIS) + openvpn_snprintf (command_line, sizeof (command_line), + "%s %s ether %s", + IFCONFIG_PATH, + ifname, lladdr); +#elif defined(TARGET_OPENBSD) + openvpn_snprintf (command_line, sizeof (command_line), + "%s %s lladdr %s", + IFCONFIG_PATH, + ifname, lladdr); +#elif defined(TARGET_DARWIN) + openvpn_snprintf (command_line, sizeof (command_line), + "%s %s lladdr %s", + IFCONFIG_PATH, + ifname, lladdr); +#elif defined(TARGET_FREEBSD) + openvpn_snprintf (command_line, sizeof (command_line), + "%s %s ether %s", + IFCONFIG_PATH, + ifname, lladdr); +#else + msg (M_WARN, "Sorry, but I don't know how to configure link layer addresses on this operating system."); + return -1; +#endif + + msg (M_INFO, "%s", command_line); + system_check (command_line, es, S_FATAL, "Linux ip addr add failed"); +} --- /dev/null +++ ./lladdr.h @@ -0,0 +1,8 @@ +/* + * Support routine for configuring link layer address + */ + +#include "misc.h" + +int set_lladdr(const char *ifname, const char *lladdr, + const struct env_set *es); --- ./openvpn.8.orig +++ ./openvpn.8 @@ -798,6 +798,10 @@ to enumerate all available TAP-Win32 adapters and will show both the network connections control panel name and the GUID for each TAP-Win32 adapter. +.TP +.B --lladdr address +Specify the link layer address, more commonly known as the MAC address. +Only applied to TAP devices. .\"********************************************************* .TP .B --ifconfig l rn --- ./options.c.orig +++ ./options.c @@ -129,6 +129,7 @@ static const char usage_message[] = " does not begin with \"tun\" or \"tap\".\n" "--dev-node node : Explicitly set the device node rather than using\n" " /dev/net/tun, /dev/tun, /dev/tap, etc.\n" + "--lladdr hw : Set the link layer address of the tap device.\n" "--tun-ipv6 : Build tun link capable of forwarding IPv6 traffic.\n" "--ifconfig l rn : TUN: configure device to use IP address l as a local\n" " endpoint and rn as a remote endpoint. l & rn should be\n" @@ -959,6 +960,7 @@ show_settings (const struct options *o) SHOW_STR (dev); SHOW_STR (dev_type); SHOW_STR (dev_node); + SHOW_STR (lladdr); SHOW_BOOL (tun_ipv6); SHOW_STR (ifconfig_local); SHOW_STR (ifconfig_remote_netmask); @@ -1256,6 +1258,8 @@ options_postprocess (struct options *options, bool first_time) */ if (options->inetd == INETD_NOWAIT) options->ifconfig_noexec = true; + if (options->lladdr && dev != DEV_TYPE_TAP) + msg (M_USAGE, "--lladdr can only be used in --dev tap mode"); /* * Sanity check on TCP mode options @@ -2802,6 +2806,17 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->dev_node = p[1]; } + else if (streq (p[0], "lladdr") && p[1]) + { + VERIFY_PERMISSION (OPT_P_UP); + if (mac_addr_safe (p[1])) /* MAC address only */ + options->lladdr = p[1]; + else + { + msg (msglevel, "lladdr parm '%s' must be a MAC address", p[1]); + goto err; + } + } else if (streq (p[0], "tun-ipv6")) { VERIFY_PERMISSION (OPT_P_UP); --- ./options.h.orig +++ ./options.h @@ -123,6 +123,7 @@ struct options const char *dev; const char *dev_type; const char *dev_node; + const char *lladdr; const char *ifconfig_local; const char *ifconfig_remote_netmask; bool ifconfig_noexec; --- ./socket.c.orig +++ ./socket.c @@ -234,6 +234,45 @@ openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr) return OIA_HOSTNAME; /* probably a hostname */ } +bool +mac_addr_safe (const char *mac_addr) +{ + /* verify non-NULL */ + if (!mac_addr) + return false; + + /* verify length is within limits */ + if (strlen (mac_addr) > 17) + return false; + + /* verify that all chars are either alphanumeric or ':' and that no + alphanumeric substring is greater than 2 chars */ + { + int nnum = 0; + const char *p = mac_addr; + int c; + + while ((c = *p++)) + { + if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) + { + ++nnum; + if (nnum > 2) + return false; + } + else if (c == ':') + { + nnum = 0; + } + else + return false; + } + } + + /* error-checking is left to script invoked in lladdr.c */ + return true; +} + static void update_remote (const char* host, struct sockaddr_in *addr, --- ./socket.h.orig +++ ./socket.h @@ -345,6 +345,8 @@ void remote_list_randomize (struct remote_list *l); #define OIA_ERROR -1 int openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr); +bool mac_addr_safe (const char *mac_addr); + socket_descriptor_t create_socket_tcp (void); socket_descriptor_t socket_do_accept (socket_descriptor_t sd,