diff options
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | openvpn.8 | 15 | ||||
-rw-r--r-- | options.c | 50 | ||||
-rw-r--r-- | options.h | 1 | ||||
-rw-r--r-- | socket.c | 42 |
5 files changed, 93 insertions, 16 deletions
@@ -12,6 +12,7 @@ $Id$ contains a CA cert or not (Mathias Sundman). * Merged --capath patch (Thomas Noel). * Merged --multihome patch. +* Added --bind option for TCP client connections (Ewan Bhamrah Harley). * NOTE TO PACKAGE MAINTAINERS: Moved "plugin" directory to "plugins". This is to work around a strange problem with the "make dist" target in the automake-generated makefile, where the target tries to @@ -190,6 +190,7 @@ openvpn \- secure IP tunnel daemon. [\ \fB\-\-nice\fR\ \fIn\fR\ ] [\ \fB\-\-no\-iv\fR\ ] [\ \fB\-\-no\-replay\fR\ ] +[\ \fB\-\-bind\fR\ ] [\ \fB\-\-nobind\fR\ ] [\ \fB\-\-ns\-cert\-type\fR\ \fIclient|server\fR\ ] [\ \fB\-\-passtos\fR\ ] @@ -443,7 +444,7 @@ server capability. .\"********************************************************* .TP .B --local host -Local host name or IP address. +Local host name or IP address for bind. If specified, OpenVPN will bind to this address only. If unspecified, OpenVPN will bind to all interfaces. .\"********************************************************* @@ -727,13 +728,23 @@ Previous versions used port 5000 as the default. .\"********************************************************* .TP .B --lport port -TCP/UDP port number for local. +TCP/UDP port number for bind. .\"********************************************************* .TP .B --rport port TCP/UDP port number for remote. .\"********************************************************* .TP +.B --bind +Bind to local address and port. This is the default unless any of +.B --proto tcp-client +, +.B --http-proxy +or +.B --socks-proxy +are used. +.\"********************************************************* +.TP .B --nobind Do not bind to local address and port. The IP stack will allocate a dynamic port for returning packets. Since the value of the dynamic port @@ -87,7 +87,7 @@ static const char usage_message[] = "--version : Show copyright and version information.\n" "\n" "Tunnel Options:\n" - "--local host : Local host name or ip address.\n" + "--local host : Local host name or ip address. Implies --bind.\n" "--remote host [port] : Remote host name or ip address.\n" "--remote-random : If multiple --remote options specified, choose one randomly.\n" "--mode m : Major mode, m = 'p2p' (default, point-to-point) or 'server'.\n" @@ -121,8 +121,17 @@ static const char usage_message[] = "--ipchange cmd : Execute shell command cmd on remote ip address initial\n" " setting or change -- execute as: cmd ip-address port#\n" "--port port : TCP/UDP port # for both local and remote.\n" - "--lport port : TCP/UDP port # for local (default=%d).\n" + "--lport port : TCP/UDP port # for local (default=%d). Implies --bind.\n" "--rport port : TCP/UDP port # for remote (default=%d).\n" + "--bind : Bind to local address and port. (This is the default unless\n" + " --proto tcp-client" +#ifdef ENABLE_HTTP_PROXY + " or --http-proxy" +#endif +#ifdef ENABLE_SOCKS + " or --socks-proxy" +#endif + " is used).\n" "--nobind : Do not bind to local address and port.\n" "--dev tunX|tapX : tun/tap device (X can be omitted for dynamic device.\n" "--dev-type dt : Which device type are we using? (dt = tun or tap) Use\n" @@ -688,6 +697,20 @@ setenv_settings (struct env_set *es, const struct options *o) setenv_int (es, remote_port_string, o->remote_list->array[i].port); } } +#ifdef ENABLE_HTTP_PROXY + if (o->http_proxy_options) + { + setenv_str (es, "http_proxy_server", o->http_proxy_options->server); + setenv_int (es, "http_proxy_port", o->http_proxy_options->port); + } +#endif +#ifdef ENABLE_SOCKS + if(o->socks_proxy_server) + { + setenv_str (es, "socks_proxy_server", o->socks_proxy_server); + setenv_int (es, "socks_proxy_port", o->socks_proxy_port); + } +#endif } static in_addr_t @@ -997,6 +1020,7 @@ show_settings (const struct options *o) SHOW_INT (remote_port); SHOW_BOOL (remote_float); SHOW_STR (ipchange); + SHOW_BOOL (bind_defined); SHOW_BOOL (bind_local); SHOW_STR (dev); SHOW_STR (dev_type); @@ -1395,12 +1419,29 @@ options_postprocess (struct options *options, bool first_time) if (string_defined_equal (options->ifconfig_local, options->ifconfig_remote_netmask)) msg (M_USAGE, "local and remote/netmask --ifconfig addresses must be different"); + if (options->bind_defined && !options->bind_local) + msg (M_USAGE, "--bind and --nobind can't be used together"); + + if (options->local && !options->bind_local) + msg (M_USAGE, "--local and --nobind don't make sense when used together"); + if (options->local_port_defined && !options->bind_local) msg (M_USAGE, "--lport and --nobind don't make sense when used together"); if (!options->remote_list && !options->bind_local) msg (M_USAGE, "--nobind doesn't make sense unless used with --remote"); + if (options->proto == PROTO_TCPv4_CLIENT && !options->local && !options->local_port_defined && !options->bind_defined) + options->bind_local = false; + +#ifdef ENABLE_SOCKS + if (options->proto == PROTO_UDPv4 && options->socks_proxy_server && !options->local && !options->local_port_defined && !options->bind_defined) + options->bind_local = false; +#endif + + if (!options->bind_local) + options->local_port = 0; + /* * Check for consistency of management options */ @@ -3521,6 +3562,11 @@ add_option (struct options *options, options->port_option_used = true; options->remote_port = port; } + else if (streq (p[0], "bind")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->bind_defined = true; + } else if (streq (p[0], "nobind")) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -120,6 +120,7 @@ struct options struct remote_list *remote_list; bool remote_random; const char *ipchange; + bool bind_defined; bool bind_local; const char *dev; const char *dev_type; @@ -686,7 +686,25 @@ socket_listen_accept (socket_descriptor_t sd, } static void +socket_bind (socket_descriptor_t sd, + struct openvpn_sockaddr *local) +{ + struct gc_arena gc = gc_new (); + + if (bind (sd, (struct sockaddr *) &local->sa, sizeof (local->sa))) + { + const int errnum = openvpn_errno_socket (); + msg (M_FATAL, "TCP/UDP: Socket bind failed on local address %s: %s", + print_sockaddr (local, &gc), + strerror_ts (errnum, &gc)); + } + gc_free (&gc); +} + +static void socket_connect (socket_descriptor_t *sd, + struct openvpn_sockaddr *local, + bool bind_local, struct openvpn_sockaddr *remote, struct remote_list *remote_list, const char *remote_dynamic, @@ -727,6 +745,8 @@ socket_connect (socket_descriptor_t *sd, } *sd = create_socket_tcp (); + if (bind_local) + socket_bind (*sd, local); update_remote (remote_dynamic, remote, remote_changed); } @@ -796,14 +816,12 @@ resolve_bind_local (struct link_socket *sock) /* bind to local address/port */ if (sock->bind_local) { - if (bind (sock->sd, (struct sockaddr *) &sock->info.lsa->local.sa, - sizeof (sock->info.lsa->local.sa))) - { - const int errnum = openvpn_errno_socket (); - msg (M_FATAL, "TCP/UDP: Socket bind failed on local address %s: %s", - print_sockaddr (&sock->info.lsa->local, &gc), - strerror_ts (errnum, &gc)); - } +#ifdef ENABLE_SOCKS + if (sock->socks_proxy && sock->info.proto == PROTO_UDPv4) + socket_bind (sock->ctrl_sd, &sock->info.lsa->local); + else +#endif + socket_bind (sock->sd, &sock->info.lsa->local); } gc_free (&gc); } @@ -1070,10 +1088,6 @@ link_socket_init_phase1 (struct link_socket *sock, else sock->bind_local = true; } - else if (sock->info.proto == PROTO_TCPv4_CLIENT) - { - sock->bind_local = false; - } /* were we started by inetd or xinetd? */ if (sock->inetd) @@ -1176,6 +1190,8 @@ link_socket_init_phase2 (struct link_socket *sock, else if (sock->info.proto == PROTO_TCPv4_CLIENT) { socket_connect (&sock->sd, + &sock->info.lsa->local, + sock->bind_local, &sock->info.lsa->actual.dest, sock->remote_list, remote_dynamic, @@ -1214,6 +1230,8 @@ link_socket_init_phase2 (struct link_socket *sock, else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy) { socket_connect (&sock->ctrl_sd, + &sock->info.lsa->local, + sock->bind_local, &sock->info.lsa->actual.dest, NULL, remote_dynamic, |