diff options
Diffstat (limited to 'openvpn/helper.c')
-rw-r--r-- | openvpn/helper.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/openvpn/helper.c b/openvpn/helper.c new file mode 100644 index 0000000..30b5220 --- /dev/null +++ b/openvpn/helper.c @@ -0,0 +1,372 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef WIN32 +#include "config-win32.h" +#else +#include "config.h" +#endif + +#include "syshead.h" + +#include "forward.h" +#include "helper.h" +#include "pool.h" +#include "push.h" + +#include "memdbg.h" + +#if P2MP_SERVER + +static const char * +print_netmask (int netbits, struct gc_arena *gc) +{ + struct buffer out = alloc_buf_gc (128, gc); + const in_addr_t netmask = netbits_to_netmask (netbits); + + buf_printf (&out, "%s (/%d)", print_in_addr_t (netmask, 0, gc), netbits); + + return BSTR (&out); +} + +static const char * +print_opt_route_gateway (const in_addr_t route_gateway, struct gc_arena *gc) +{ + struct buffer out = alloc_buf_gc (128, gc); + ASSERT (route_gateway); + buf_printf (&out, "route-gateway %s", print_in_addr_t (route_gateway, 0, gc)); + return BSTR (&out); +} + +static const char * +print_opt_route (const in_addr_t network, const in_addr_t netmask, struct gc_arena *gc) +{ + struct buffer out = alloc_buf_gc (128, gc); + ASSERT (network); + + if (netmask) + buf_printf (&out, "route %s %s", + print_in_addr_t (network, 0, gc), + print_in_addr_t (netmask, 0, gc)); + else + buf_printf (&out, "route %s", + print_in_addr_t (network, 0, gc)); + + return BSTR (&out); +} + +static const char * +print_str_int (const char *str, const int i, struct gc_arena *gc) +{ + struct buffer out = alloc_buf_gc (128, gc); + buf_printf (&out, "%s %d", str, i); + return BSTR (&out); +} + +static void +helper_add_route (const in_addr_t network, const in_addr_t netmask, struct options *o) +{ + rol_check_alloc (o); + add_route_to_option_list (o->routes, + print_in_addr_t (network, 0, &o->gc), + print_in_addr_t (netmask, 0, &o->gc), + NULL, + NULL); +} + +static void +verify_common_subnet (const char *opt, const in_addr_t a, const in_addr_t b, const in_addr_t subnet) +{ + struct gc_arena gc = gc_new (); + if ((a & subnet) != (b & subnet)) + msg (M_USAGE, "%s IP addresses %s and %s are not in the same %s subnet", + opt, + print_in_addr_t (a, 0, &gc), + print_in_addr_t (b, 0, &gc), + print_in_addr_t (subnet, 0, &gc)); + gc_free (&gc); +} + +#endif + +/* + * Process server, server-bridge, and client helper + * directives after the parameters themselves have been + * parsed and placed in struct options. + */ +void +helper_client_server (struct options *o) +{ + struct gc_arena gc = gc_new (); + +#if P2MP +#if P2MP_SERVER + /* + * + * HELPER DIRECTIVE: + * + * server 10.8.0.0 255.255.255.0 + * + * EXPANDS TO: + * + * mode server + * tls-server + * + * if tun: + * ifconfig 10.8.0.1 10.8.0.2 + * ifconfig-pool 10.8.0.4 10.8.0.251 + * route 10.8.0.0 255.255.255.0 + * if client-to-client: + * push "route 10.8.0.0 255.255.255.0" + * else if !linear-addr: + * push "route 10.8.0.1" + * + * if tap: + * ifconfig 10.8.0.1 255.255.255.0 + * ifconfig-pool 10.8.0.2 10.8.0.254 255.255.255.0 + * push "route-gateway 10.8.0.1" + */ + + /* + * Get tun/tap/null device type + */ + const int dev = dev_type_enum (o->dev, o->dev_type); + + if (o->server_defined) + { + int netbits = -2; + bool status = false; + + if (o->client) + msg (M_USAGE, "--server and --client cannot be used together"); + + if (o->server_bridge_defined) + msg (M_USAGE, "--server and --server-bridge cannot be used together"); + + if (o->shared_secret_file) + msg (M_USAGE, "--server and --secret cannot be used together (you must use SSL/TLS keys)"); + + if (o->ifconfig_pool_defined) + msg (M_USAGE, "--server already defines an ifconfig-pool, so you can't also specify --ifconfig-pool explicitly"); + + if (!(dev == DEV_TYPE_TAP || dev == DEV_TYPE_TUN)) + msg (M_USAGE, "--server directive only makes sense with --dev tun or --dev tap"); + + status = netmask_to_netbits (o->server_network, o->server_netmask, &netbits); + if (!status) + msg (M_USAGE, "--server directive network/netmask combination is invalid"); + + if (netbits < 0) + msg (M_USAGE, "--server directive netmask is invalid"); + + if (netbits < IFCONFIG_POOL_MIN_NETBITS) + msg (M_USAGE, "--server directive netmask allows for too many host addresses (subnet must be %s or higher)", + print_netmask (IFCONFIG_POOL_MIN_NETBITS, &gc)); + + if (dev == DEV_TYPE_TUN) + { + int pool_end_reserve = 4; + + if (netbits > 29) + msg (M_USAGE, "--server directive when used with --dev tun must define a subnet of %s or lower", + print_netmask (29, &gc)); + + if (netbits == 29) + pool_end_reserve = 0; + + o->mode = MODE_SERVER; + o->tls_server = true; + o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc); + o->ifconfig_remote_netmask = print_in_addr_t (o->server_network + 2, 0, &o->gc); + o->ifconfig_pool_defined = true; + o->ifconfig_pool_start = o->server_network + 4; + o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - pool_end_reserve; + ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); + helper_add_route (o->server_network, o->server_netmask, o); + if (o->enable_c2c) + push_option (o, print_opt_route (o->server_network, o->server_netmask, &o->gc), M_USAGE); + else if (!o->ifconfig_pool_linear) + push_option (o, print_opt_route (o->server_network + 1, 0, &o->gc), M_USAGE); + } + else if (dev == DEV_TYPE_TAP) + { + if (netbits > 30) + msg (M_USAGE, "--server directive when used with --dev tap must define a subnet of %s or lower", + print_netmask (30, &gc)); + + o->mode = MODE_SERVER; + o->tls_server = true; + o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc); + o->ifconfig_remote_netmask = print_in_addr_t (o->server_netmask, 0, &o->gc); + o->ifconfig_pool_defined = true; + o->ifconfig_pool_start = o->server_network + 2; + o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1; + ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); + o->ifconfig_pool_netmask = o->server_netmask; + push_option (o, print_opt_route_gateway (o->server_network + 1, &o->gc), M_USAGE); + } + else + { + ASSERT (0); + } + + if (o->proto == PROTO_TCPv4) + o->proto = PROTO_TCPv4_SERVER; + } + + /* + * HELPER DIRECTIVE: + * + * server-bridge 10.8.0.4 255.255.255.0 10.8.0.128 10.8.0.254 + * + * EXPANDS TO: + * + * mode server + * tls-server + * + * ifconfig-pool 10.8.0.128 10.8.0.254 255.255.255.0 + * push "route-gateway 10.8.0.4" + */ + else if (o->server_bridge_defined) + { + if (o->client) + msg (M_USAGE, "--server-bridge and --client cannot be used together"); + + if (o->ifconfig_pool_defined) + msg (M_USAGE, "--server-bridge already defines an ifconfig-pool, so you can't also specify --ifconfig-pool explicitly"); + + if (o->shared_secret_file) + msg (M_USAGE, "--server-bridge and --secret cannot be used together (you must use SSL/TLS keys)"); + + if (dev != DEV_TYPE_TAP) + msg (M_USAGE, "--server-bridge directive only makes sense with --dev tap"); + + verify_common_subnet ("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_start, o->server_bridge_netmask); + verify_common_subnet ("--server-bridge", o->server_bridge_pool_start, o->server_bridge_pool_end, o->server_bridge_netmask); + verify_common_subnet ("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_end, o->server_bridge_netmask); + + o->mode = MODE_SERVER; + o->tls_server = true; + o->ifconfig_pool_defined = true; + o->ifconfig_pool_start = o->server_bridge_pool_start; + o->ifconfig_pool_end = o->server_bridge_pool_end; + ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); + o->ifconfig_pool_netmask = o->server_bridge_netmask; + push_option (o, print_opt_route_gateway (o->server_bridge_ip, &o->gc), M_USAGE); + + if (o->proto == PROTO_TCPv4) + o->proto = PROTO_TCPv4_SERVER; + } + else +#endif /* P2MP_SERVER */ + + /* + * HELPER DIRECTIVE: + * + * client + * + * EXPANDS TO: + * + * pull + * tls-client + */ + if (o->client) + { + if (o->key_method != 2) + msg (M_USAGE, "--client requires --key-method 2"); + + o->pull = true; + o->tls_client = true; + + if (o->proto == PROTO_TCPv4) + o->proto = PROTO_TCPv4_CLIENT; + } + +#endif /* P2MP */ + + if (o->proto == PROTO_TCPv4) + msg (M_USAGE, "--proto tcp is ambiguous in this context. Please specify --proto tcp-server or --proto tcp-client"); + + gc_free (&gc); +} + +/* + * + * HELPER DIRECTIVE: + * + * keepalive 10 60 + * + * EXPANDS TO: + * + * if mode server: + * ping 10 + * ping-restart 120 + * push "ping 10" + * push "ping-restart 60" + * else + * ping 10 + * ping-restart 60 + */ +void +helper_keepalive (struct options *o) +{ + if (o->keepalive_ping || o->keepalive_timeout) + { + /* + * Sanity checks. + */ + if (o->keepalive_ping <= 0 || o->keepalive_timeout <= 0) + msg (M_USAGE, "--keepalive parameters must be > 0"); + if (o->keepalive_ping * 2 > o->keepalive_timeout) + msg (M_USAGE, "the second parameter to --keepalive (restart timeout=%d) must be at least twice the value of the first parameter (ping interval=%d). A ratio of 1:5 or 1:6 would be even better. Recommended setting is --keepalive 10 60.", + o->keepalive_timeout, + o->keepalive_ping); + if (o->ping_send_timeout || o->ping_rec_timeout) + msg (M_USAGE, "--keepalive conflicts with --ping, --ping-exit, or --ping-restart. If you use --keepalive, you don't need any of the other --ping directives."); + + /* + * Expand. + */ + if (o->mode == MODE_POINT_TO_POINT) + { + o->ping_rec_timeout_action = PING_RESTART; + o->ping_send_timeout = o->keepalive_ping; + o->ping_rec_timeout = o->keepalive_timeout; + } +#if P2MP_SERVER + else if (o->mode == MODE_SERVER) + { + o->ping_rec_timeout_action = PING_RESTART; + o->ping_send_timeout = o->keepalive_ping; + o->ping_rec_timeout = o->keepalive_timeout * 2; + push_option (o, print_str_int ("ping", o->keepalive_ping, &o->gc), M_USAGE); + push_option (o, print_str_int ("ping-restart", o->keepalive_timeout, &o->gc), M_USAGE); + } +#endif + else + { + ASSERT (0); + } + } +} |