From patchwork Wed Nov 15 13:45:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "plaisthos (Code Review)" X-Patchwork-Id: 3446 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7300:3c06:b0:f2:62eb:61c1 with SMTP id e6csp2926421dys; Wed, 15 Nov 2023 05:46:30 -0800 (PST) X-Google-Smtp-Source: AGHT+IHGQ8lLtJaiC0m/JWoP7SU3u0NZam2+YJPj4qr32tmtWCdYLuHHMjaD/BDRvbbOCw9hUOCr X-Received: by 2002:a17:90a:a88b:b0:280:a476:6ec2 with SMTP id h11-20020a17090aa88b00b00280a4766ec2mr2759222pjq.2.1700055989713; Wed, 15 Nov 2023 05:46:29 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1700055989; cv=none; d=google.com; s=arc-20160816; b=aFBOb4TMR/z3Z/oeEvyuYRcgmEIGA9U852tXSB35FHrhaIWP9VkihEobEeby8DqUcG IqTHb3bzfQpy5MRClPmtzM4E9eScX+Sg9qF6JYcNSM1TyTgzYFyzwWQIdhnl8NNfQhjV 8pSlHahExF76nUKg74JXslTAbpefl4+L9KcLz+oY8IXmSnaW6B/eZCQRRC+vx9MWsHc0 E6hfrCm4uS4ThLj0Bb1uTs8ZMgwtM/eBRREpZcNckgs/6Wy4djPC/hlximg0IQ/u8hj5 oShdeoIej2IZy13MUS8pc6MjYDH9lwh9V/PFtgogLAy8ooKTvV1TrZBFEX4/VT1gsNqG +wRQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:cc:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:user-agent :mime-version:message-id:references:auto-submitted:to:date:from :dkim-signature:dkim-signature:dkim-signature; bh=38CanPSILF0U2NbeXBF3QmOWmBbzJREM/O/hHJQPTn8=; fh=U7wEyxtwz2o5+UdevFSA47vNeG9knhWH0KV//QhD5a0=; b=bMc+Lgu0qIR7NCKFqdjM43pa2E5c427leibangLB6srDhUQqtwFwIP7c2tyXXdNOtf iS2J4xmg/j/SDd05jeyF20UCKK+X9djsLsXKGiHHoIBNjXYSJkl+2ROi3BseJVaaYUJk GROPiu1tU3/2FBOR0zeJ+reUe+3XrmiNcgppdxjT/gK6GDePOLM7FXRjZYckgv00azKR SiqUlhmsrjaOoG+EEO2ML3Acg9WTQu8tSKZYW3uDzs9kJENZlyCDByAGIHuFGGH/sunK bnv/IxZ7r7jX/buOn/LikH/0pK2O/YI9oNXZ3G9PjnCmytxNbB4P7Md6ot0Rd6Axfs6E 5N3g== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=d3o79x4e; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=KAcgBS1e; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b=WMhE+4CK; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id s23-20020a17090a881700b0027d097b9c36si14471835pjn.75.2023.11.15.05.46.29 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 15 Nov 2023 05:46:29 -0800 (PST) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=d3o79x4e; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=KAcgBS1e; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b=WMhE+4CK; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1r3GD3-0001Rw-Uk; Wed, 15 Nov 2023 13:45:37 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1r3GCv-0001RT-6k for openvpn-devel@lists.sourceforge.net; Wed, 15 Nov 2023 13:45:29 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:Content-Transfer-Encoding:MIME-Version :Message-ID:Reply-To:References:Subject:List-Unsubscribe:List-Id:Cc:To:Date: From:Sender:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help: List-Subscribe:List-Post:List-Owner:List-Archive; bh=1tsRjHY5O2hLdry7c4nlopf4sxy0gyUJGNExGC220+E=; b=d3o79x4e+jMnheGQpIflC7ROox 5FvKMQM1duK9k1K63mlb6Blnq0ERLajz3WBPk118G5hYiBeJDTxk1wfkVsyvN3dhb/rOXa/JT8hOd 8p5JmuX+OYD8FLSOgCSwSIfkysGHVrIRb/gHDaZEWyx6sZM/OHW5xsFYb/iaQB9Z1hsw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:Content-Transfer-Encoding:MIME-Version:Message-ID:Reply-To: References:Subject:List-Unsubscribe:List-Id:Cc:To:Date:From:Sender:Content-ID :Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To: Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help:List-Subscribe:List-Post: List-Owner:List-Archive; bh=1tsRjHY5O2hLdry7c4nlopf4sxy0gyUJGNExGC220+E=; b=K AcgBS1e/3M4TOx9LBzO6RADAYl+wO25PTl2IFk0mrhUSmj6l5t8sb6jfY7gm0pz9n/zkPyexJajfK e7htu+zvkO1NAAszpK9mgCSCZl14ZwGffdPT6SkFf9jBTpckGJJO0G8CwYsg1oK5l/145JV7oeJ+m j/IuaeAYOz/Lgix4=; Received: from mail-wr1-f44.google.com ([209.85.221.44]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1r3GCq-006Vpg-0a for openvpn-devel@lists.sourceforge.net; Wed, 15 Nov 2023 13:45:29 +0000 Received: by mail-wr1-f44.google.com with SMTP id ffacd0b85a97d-32fd7fc9f19so4186517f8f.2 for ; Wed, 15 Nov 2023 05:45:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1700055917; x=1700660717; darn=lists.sourceforge.net; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from:from:to:cc :subject:date:message-id:reply-to; bh=1tsRjHY5O2hLdry7c4nlopf4sxy0gyUJGNExGC220+E=; b=WMhE+4CKSpR2oGqAgl2X4rzH1EW/TUfPTuTDNC/i+L7TlLwGSKqghMx5T5s36jZuB4 9yF77PcIhfAgsOEcV3Lt/t0TCsYgJz7cDD/YRkOWABob8HFOzjs8iJevjBWwldzBRp0P /7bcDN3QJ+TI+RGYsPIequfaGTUGHylaBAYKCCyjlKfhwK/tkmxPcuCKDNL/+hFtu45u Ev0cK3jj/K3lVK2JQQHzxCdlknJ1EsgJyiD0geP8BtK6QB/AQKBqxUtyatKSH8cgJTuQ aARKpqMPCtyAHTRn/NReuB5mU9UT3n9osnEgosC05yq/TfbkWYubJIItUDVHe+rTXFfF E3Wg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700055917; x=1700660717; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=1tsRjHY5O2hLdry7c4nlopf4sxy0gyUJGNExGC220+E=; b=Nl6vJuSVZqNjWBxT7fz9YRhD7DYstc+QQIHnueByanB6aIPYtA1BmjJ4vow+Gd/wmw /DzYS5TWNWs63t81EaWSOJyIK8EoeixSG76vb4lvIbboFx9ZgCT+urNA93HAnNLkEPpl O7ozl8r/n+V6hughN7I2+bT6E+keilfqEiP/drDmIHVHGF+jzXCmvU25rENvZhFNRojt VN0stb1K+HxJaBq9W9V+1RF/ioWyjsutUwPTMzJWqjlKbcw8hSckvk8uFIaAg1EZmPVK cYOlA7HIMQm6o0iVC0C8yv7IHAXUWHulCwRxX9+1B/QFOxo1wQCJutS8fVszaG0JXUB1 6Cbg== X-Gm-Message-State: AOJu0YyeZqh9LRiqm51etRPg1t2mIvxCE0cove2JFZ3hZ2pA7l42svqp xR49H5QH17b8v4AEbXohKntSof7ltmYnqcHNLXM= X-Received: by 2002:adf:f986:0:b0:314:1313:c3d6 with SMTP id f6-20020adff986000000b003141313c3d6mr7343398wrr.33.1700055917059; Wed, 15 Nov 2023 05:45:17 -0800 (PST) Received: from gerrit.openvpn.in (ec2-18-159-0-78.eu-central-1.compute.amazonaws.com. [18.159.0.78]) by smtp.gmail.com with ESMTPSA id x15-20020adfffcf000000b0031984b370f2sm10642912wrs.47.2023.11.15.05.45.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Nov 2023 05:45:16 -0800 (PST) From: "ordex (Code Review)" X-Google-Original-From: "ordex (Code Review)" X-Gerrit-PatchSet: 1 Date: Wed, 15 Nov 2023 13:45:15 +0000 To: plaisthos , flichtenheld Auto-Submitted: auto-generated X-Gerrit-MessageType: newchange X-Gerrit-Change-Id: Ia122d5cdc42c2969eef6f32f438e30b52652721f X-Gerrit-Change-Number: 438 X-Gerrit-Project: openvpn X-Gerrit-ChangeURL: X-Gerrit-Commit: 35ea86d0e2878a53e3fda6470474d78f6559aaf2 References: Message-ID: <9d07277a7ccea9186aa16fea80935634ae99d10d-HTML@gerrit.openvpn.net> MIME-Version: 1.0 User-Agent: Gerrit/3.8.2 X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "util-spamd-2.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit Content analysis details: (-0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.221.44 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.221.44 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 WEIRD_PORT URI: Uses non-standard port number for HTTP 0.0 HTML_MESSAGE BODY: HTML included in message -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.0 T_SCC_BODY_TEXT_LINE No description available. 0.0 T_KAM_HTML_FONT_INVALID Test for Invalidly Named or Formatted Colors in HTML X-Headers-End: 1r3GCq-006Vpg-0a Subject: [Openvpn-devel] [L] Change in openvpn[master]: Bind to multiple ipv4/ipv6 addresses X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: a@unstable.cc, arne-openvpn@rfc2549.org, openvpn-devel@lists.sourceforge.net, frank@lichtenheld.com Cc: openvpn-devel Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1782637909177985642?= X-GMAIL-MSGID: =?utf-8?q?1782637909177985642?= X-getmail-filter-classifier: gerrit message type newchange Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit http://gerrit.openvpn.net/c/openvpn/+/438?usp=email to review the following change. Change subject: Bind to multiple ipv4/ipv6 addresses ...................................................................... Bind to multiple ipv4/ipv6 addresses Enables the binding of multiple listen sockets based on the specified "--local" directives. The main server loop has been updated to handle both TCP and UDP connections. The hash function has also been modified to include the protocol during the creation of new client instances. Change-Id: Ia122d5cdc42c2969eef6f32f438e30b52652721f Signed-off-by: Gianmarco De Gregori --- M src/openvpn/forward.c M src/openvpn/forward.h M src/openvpn/init.c M src/openvpn/mroute.c M src/openvpn/mroute.h M src/openvpn/mtcp.c M src/openvpn/mtcp.h M src/openvpn/mudp.c M src/openvpn/mudp.h M src/openvpn/multi.c M src/openvpn/multi.h M src/openvpn/options.c M src/openvpn/options.h 13 files changed, 613 insertions(+), 116 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/38/438/1 diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 9a6dcd8..27415ee 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1760,7 +1760,7 @@ if (c->options.shaper) { int overhead = datagram_overhead(c->c2.to_link_addr->dest.addr.sa.sa_family, - c->options.ce.proto); + ls->info.proto); shaper_wrote_bytes(&c->c2.shaper, BLEN(&c->c2.to_link) + overhead); } @@ -2050,6 +2050,250 @@ */ void +io_wait_dowork_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags) +{ + unsigned int socket = 0; + unsigned int tuntap = 0; + struct event_set_return esr[4]; + + /* These shifts all depend on EVENT_READ and EVENT_WRITE */ + static uintptr_t socket_shift = 0; /* depends on SOCKET_READ and SOCKET_WRITE */ + static uintptr_t tun_shift = 2; /* depends on TUN_READ and TUN_WRITE */ + static uintptr_t err_shift = 4; /* depends on ES_ERROR */ +#ifdef ENABLE_MANAGEMENT + static uintptr_t management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */ +#endif +#ifdef ENABLE_ASYNC_PUSH + static int file_shift = FILE_SHIFT; +#endif +#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) + static int dco_shift = DCO_SHIFT; /* Event from DCO linux kernel module */ +#endif + int i; + + /* + * Decide what kind of events we want to wait for. + */ + /*c->c2.event_set = mtcp->es; */ + /*event_reset(mtcp->es); */ + /*event_reset(c->c2.event_set); */ + + /* + * On win32 we use the keyboard or an event object as a source + * of asynchronous signals. + */ + if (flags & IOW_WAIT_SIGNAL) + { + wait_signal(mtcp->es, (void *)err_shift); + } + + /* + * If outgoing data (for TCP/UDP port) pending, wait for ready-to-send + * status from TCP/UDP port. Otherwise, wait for incoming data on + * TUN/TAP device. + */ + if (flags & IOW_TO_LINK) + { + if (flags & IOW_SHAPER) + { + /* + * If sending this packet would put us over our traffic shaping + * quota, don't send -- instead compute the delay we must wait + * until it will be OK to send the packet. + */ + int delay = 0; + + /* set traffic shaping delay in microseconds */ + if (c->options.shaper) + { + delay = max_int(delay, shaper_delay(&c->c2.shaper)); + } + + if (delay < 1000) + { + socket |= EVENT_WRITE; + } + else + { + shaper_soonest_event(&c->c2.timeval, delay); + } + } + else + { + socket |= EVENT_WRITE; + } + } + else if (!((flags & IOW_FRAG) && TO_LINK_FRAG(c))) + { + if (flags & IOW_READ_TUN) + { + tuntap |= EVENT_READ; + } + } + + /* + * If outgoing data (for TUN/TAP device) pending, wait for ready-to-send status + * from device. Otherwise, wait for incoming data on TCP/UDP port. + */ + if (flags & IOW_TO_TUN) + { + tuntap |= EVENT_WRITE; + } + else + { + if (flags & IOW_READ_LINK) + { + socket |= EVENT_READ; + } + } + + /* + * outgoing bcast buffer waiting to be sent? + */ + if (flags & IOW_MBUF) + { + socket |= EVENT_WRITE; + } + + /* + * Force wait on TUN input, even if also waiting on TCP/UDP output + */ + if (flags & IOW_READ_TUN_FORCE) + { + tuntap |= EVENT_READ; + } + +#ifdef _WIN32 + if (tuntap_is_wintun(c->c1.tuntap)) + { + /* + * With wintun we are only interested in read event. Ring buffer is + * always ready for write, so we don't do wait. + */ + tuntap = EVENT_READ; + } +#endif + + /* + * Configure event wait based on socket, tuntap flags. + */ + for (i = 0; i < c->c1.link_sockets_num; i++) + { + socket_set(c->c2.link_sockets[i], mtcp->es, socket, + &c->c2.link_sockets[i]->ev_arg, NULL); + } + tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)tun_shift, NULL); +#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) + if (socket & EVENT_READ && c->c2.did_open_tun) + { + dco_event_set(&c->c1.tuntap->dco, mtcp->es, (void *)&dco_shift); + } +#endif + +#ifdef ENABLE_MANAGEMENT + if (management) + { + management_socket_set(management, mtcp->es, (void *)management_shift, NULL); + } +#endif + +#ifdef ENABLE_ASYNC_PUSH + /* arm inotify watcher */ + if (c->options.mode == MODE_SERVER) + { + event_ctl(mtcp->es, c->c2.inotify_fd, EVENT_READ, (void *)&file_shift); + } +#endif + + /* + * Possible scenarios: + * (1) tcp/udp port has data available to read + * (2) tcp/udp port is ready to accept more data to write + * (3) tun dev has data available to read + * (4) tun dev is ready to accept more data to write + * (5) we received a signal (handler sets signal_received) + * (6) timeout (tv) expired + */ + + mtcp->event_set_status = ES_ERROR; + + if (!c->sig->signal_received) + { + if (!(flags & IOW_CHECK_RESIDUAL) || !sockets_read_residual(c)) + { + int status; + +#ifdef ENABLE_DEBUG + if (check_debug_level(D_EVENT_WAIT)) + { + show_wait_status(c); + } +#endif + + /* + * Wait for something to happen. + */ + status = event_wait(mtcp->es, &c->c2.timeval, esr, SIZE(esr)); + + check_status(status, "event_wait", NULL, NULL); + + if (status > 0) + { + int i; + mtcp->event_set_status = 0; + for (i = 0; i < status; ++i) + { + const struct event_set_return *e = &esr[i]; + uintptr_t shift; + + if (e->arg >= MULTI_N) + { + struct event_arg *ev_arg = (struct event_arg *)e->arg; + if (ev_arg->type != EVENT_ARG_LINK_SOCKET) + { + mtcp->event_set_status = ES_ERROR; + msg(D_LINK_ERRORS, + "io_work: non socket event delivered"); + return; + } + + shift = socket_shift; + /* mark socket so that the multi code knows where we + * have pending i/o */ + ev_arg->pending = true; + } + else + { + shift = (uintptr_t)e->arg; + } + + mtcp->event_set_status |= ((e->rwflags & 3) << shift); + } + } + else if (status == 0) + { + mtcp->event_set_status = ES_TIMEOUT; + } + } + else + { + mtcp->event_set_status = SOCKET_READ; + } + } + + /* 'now' should always be a reasonably up-to-date timestamp */ + update_time(); + + /* set signal_received if a signal was received */ + if (mtcp->event_set_status & ES_ERROR) + { + get_signal(&c->sig->signal_received); + } + + dmsg(D_EVENT_WAIT, "I/O WAIT status=0x%04x", mtcp->event_set_status); +} + +void io_wait_dowork(struct context *c, const unsigned int flags) { unsigned int socket = 0; @@ -2291,6 +2535,7 @@ dmsg(D_EVENT_WAIT, "I/O WAIT status=0x%04x", c->c2.event_set_status); } + void process_io(struct context *c, struct link_socket *ls) { diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 333dcdc..cb184a8 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -50,6 +50,7 @@ #include "openvpn.h" #include "occ.h" #include "ping.h" +#include "mtcp.h" #define IOW_TO_TUN (1<<0) #define IOW_TO_LINK (1<<1) @@ -68,6 +69,8 @@ extern counter_type link_write_bytes_global; +void io_wait_dowork_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags); + void io_wait_dowork(struct context *c, const unsigned int flags); void pre_select(struct context *c); @@ -363,6 +366,58 @@ return flags; } +static inline void +io_wait_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags) +{ + if (c->c2.fast_io && (flags & (IOW_TO_TUN|IOW_TO_LINK|IOW_MBUF))) + { + /* fast path -- only for TUN/TAP/UDP writes */ + unsigned int ret = 0; + if (flags & IOW_TO_TUN) + { + ret |= TUN_WRITE; + } + if (flags & (IOW_TO_LINK|IOW_MBUF)) + { + ret |= SOCKET_WRITE; + } + mtcp->event_set_status = ret; + } + else + { +#ifdef _WIN32 + bool skip_iowait = flags & IOW_TO_TUN; + if (flags & IOW_READ_TUN) + { + /* + * don't read from tun if we have pending write to link, + * since every tun read overwrites to_link buffer filled + * by previous tun read + */ + skip_iowait = !(flags & IOW_TO_LINK); + } + if (tuntap_is_wintun(c->c1.tuntap) && skip_iowait) + { + unsigned int ret = 0; + if (flags & IOW_TO_TUN) + { + ret |= TUN_WRITE; + } + if (flags & IOW_READ_TUN) + { + ret |= TUN_READ; + } + mtcp->event_set_status = ret; + } + else +#endif /* ifdef _WIN32 */ + { + /* slow path */ + io_wait_dowork_udp(c, mtcp, flags); + } + } +} + /* * This is the core I/O wait function, used for all I/O waits except * for TCP in server mode. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 659c9e3..762793a 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -3791,6 +3791,24 @@ unsigned int sockflags = c->options.sockflags; int i; + int mode = LS_MODE_DEFAULT; + /* mode allows CM_CHILD_TCP + * instances to inherit acceptable fds + * from a top-level parent */ + if (c->options.mode == MODE_SERVER) + { + /* initializing listening socket */ + if (c->mode == CM_TOP) + { + mode = LS_MODE_TCP_LISTEN; + } + /* initializing socket to client */ + else if (c->mode == CM_CHILD_TCP) + { + mode = LS_MODE_TCP_ACCEPT_FROM; + } + } + #if PORT_SHARE if (c->options.port_share_host && c->options.port_share_port) { @@ -3800,33 +3818,37 @@ for (i = 0; i < c->c1.link_sockets_num; i++) { - int mode = LS_MODE_DEFAULT; + const char *host = c->options.ce.local_list->array[i]->local; + const char *port = c->options.ce.local_list->array[i]->port; + int proto = c->options.ce.local_list->array[i]->proto; + bool bind_local = c->options.ce.local_list->array[i]->bind_local; - /* mode allows CM_CHILD_TCP - * instances to inherit acceptable fds - * from a top-level parent */ - if (c->options.mode == MODE_SERVER) + if (c->mode == CM_CHILD_TCP || c->mode == CM_CHILD_UDP) { - /* initializing listening socket */ - if (c->mode == CM_TOP) + const struct link_socket *ls = NULL; + if (c->mode == CM_CHILD_TCP) { - mode = LS_MODE_TCP_LISTEN; + ls = c->c2.accept_from; } - /* initializing socket to client */ - else if (c->mode == CM_CHILD_TCP) + else if (c->mode == CM_CHILD_UDP) { - mode = LS_MODE_TCP_ACCEPT_FROM; + ls = c->c2.link_sockets[0]; } + + host = ls->local_host; + port = ls->local_port; + proto = ls->info.proto; + bind_local = ls->bind_local; } /* init each socket with its specific port */ link_socket_init_phase1(c->c2.link_sockets[i], - c->options.ce.local_list->array[i]->local, - c->options.ce.local_list->array[i]->port, + host, + port, c->options.ce.remote, c->options.ce.remote_port, c->c1.dns_cache, - c->options.ce.proto, + proto, c->options.ce.af, c->options.ce.bind_ipv6_only, mode, @@ -3836,7 +3858,7 @@ #ifdef ENABLE_DEBUG c->options.gremlin, #endif - c->options.ce.local_list->array[i]->bind_local, + bind_local, c->options.ce.remote_float, &c->c1.link_socket_addrs[i], c->options.ipchange, @@ -4655,7 +4677,7 @@ } /* our wait-for-i/o objects, different for posix vs. win32 */ - if (c->mode == CM_P2P) + if (c->mode == CM_P2P || c->mode == CM_TOP) { do_event_set_init(c, SHAPER_DEFINED(&c->options)); } @@ -4919,7 +4941,7 @@ CLEAR(*dest); /* proto_is_dgram will ASSERT(0) if proto is invalid */ - dest->mode = proto_is_dgram(src->options.ce.proto) ? CM_CHILD_UDP : CM_CHILD_TCP; + dest->mode = proto_is_dgram(ls->info.proto) ? CM_CHILD_UDP : CM_CHILD_TCP; dest->gc = gc_new(); @@ -4947,6 +4969,8 @@ dest->options = src->options; options_detach(&dest->options); + dest->c2.event_set = src->c2.event_set; + if (dest->mode == CM_CHILD_TCP) { /* diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c index 91af2b6..0017a48 100644 --- a/src/openvpn/mroute.c +++ b/src/openvpn/mroute.c @@ -421,6 +421,7 @@ { buf_printf(&out, ":%d", ntohs(maddr.v4.port)); } + buf_printf(&out, ":%d", maddr.proto); } break; diff --git a/src/openvpn/mroute.h b/src/openvpn/mroute.h index a06e872..7c8972f 100644 --- a/src/openvpn/mroute.h +++ b/src/openvpn/mroute.h @@ -76,6 +76,7 @@ uint8_t len; /* length of address */ uint8_t unused; uint8_t type; /* MR_ADDR/MR_WITH flags */ + uint8_t proto; uint8_t netbits; /* number of bits in network part of address, * valid if MR_WITH_NETBITS is set */ union { @@ -211,6 +212,10 @@ { return false; } + if (a1->proto != a2->proto) + { + return false; + } if (a1->netbits != a2->netbits) { return false; @@ -232,7 +237,7 @@ static inline uint32_t mroute_addr_hash_len(const struct mroute_addr *a) { - return (uint32_t) a->len + 2; + return (uint32_t) a->len + 3; } static inline void diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index 06073cd..d4ce642 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -37,21 +37,6 @@ #endif /* - * TCP States - */ -#define TA_UNDEF 0 -#define TA_SOCKET_READ 1 -#define TA_SOCKET_READ_RESIDUAL 2 -#define TA_SOCKET_WRITE 3 -#define TA_SOCKET_WRITE_READY 4 -#define TA_SOCKET_WRITE_DEFERRED 5 -#define TA_TUN_READ 6 -#define TA_TUN_WRITE 7 -#define TA_INITIAL 8 -#define TA_TIMEOUT 9 -#define TA_TUN_WRITE_TIMEOUT 10 - -/* * Special tags passed to event.[ch] functions */ #define MTCP_SOCKET ((void *)1) @@ -122,8 +107,9 @@ struct hash *hash = m->hash; mi = multi_create_instance(m, NULL, ls); - if (mi) + if (mi && !proto_is_dgram(ls->info.proto)) { + printf("\nTCP add\n"); struct hash_element *he; const uint32_t hv = hash_value(hash, &mi->real); struct hash_bucket *bucket = hash_bucket(hash, hv); @@ -174,7 +160,7 @@ ASSERT(mi->context.c2.link_sockets); ASSERT(mi->context.c2.link_sockets[0]); ASSERT(mi->context.c2.link_sockets[0]->info.lsa); - ASSERT(mi->context.c2.link_sockets[0]->mode == LS_MODE_TCP_ACCEPT_FROM); + /*ASSERT(mi->context.c2.link_sockets[0]->mode == LS_MODE_TCP_ACCEPT_FROM); */ ASSERT(mi->context.c2.link_sockets[0]->info.lsa->actual.dest.addr.sa.sa_family == AF_INET || mi->context.c2.link_sockets[0]->info.lsa->actual.dest.addr.sa.sa_family == AF_INET6 ); @@ -259,11 +245,11 @@ } } -static inline int -multi_tcp_wait(const struct context *c, +int +multi_tcp_wait(struct context *c, struct multi_tcp *mtcp) { - int i, status; + int status, i; unsigned int *persistent = &mtcp->tun_rwflags; for (i = 0; i < c->c1.link_sockets_num; i++) @@ -603,7 +589,7 @@ return newaction; } -static void +void multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll) { bool tun_input_pending = false; @@ -691,10 +677,14 @@ } while (action != TA_UNDEF); } -static void +void multi_tcp_process_io(struct multi_context *m) { + const unsigned int mpp_flags = m->top.c2.fast_io + ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL) + : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); struct multi_tcp *mtcp = m->mtcp; + const unsigned int status = mtcp->event_set_status; int i; for (i = 0; i < mtcp->n_esr; ++i) @@ -735,14 +725,45 @@ msg(D_MULTI_ERRORS, "MULTI: mtcp_proc_io: null socket"); break; } - socket_reset_listen_persistent(ev_arg->u.ls); - mi = multi_create_instance_tcp(m, ev_arg->u.ls); - if (mi) + if (!proto_is_dgram(ev_arg->u.ls->info.proto)) { - multi_tcp_action(m, mi, TA_INITIAL, false); + mi = multi_create_instance_tcp(m, ev_arg->u.ls); + if (mi) + { + multi_tcp_action(m, mi, TA_INITIAL, false); + } + break; } - break; + else + { + if (status & SOCKET_READ) + { + read_incoming_link(&m->top, ev_arg->u.ls); + if (!IS_SIG(&m->top)) + { + multi_process_incoming_link(m, NULL, mpp_flags, + ev_arg->u.ls); + } + } + multi_get_timeout(m, &m->top.c2.timeval); + io_wait_udp(&m->top, m->mtcp, p2mp_iow_flags(m)); + MULTI_CHECK_SIG(m); + + multi_process_per_second_timers(m); + + if (m->mtcp->event_set_status == ES_TIMEOUT) + { + multi_process_timeout(m, MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); + } + else + { + multi_process_io_udp(m); + MULTI_CHECK_SIG(m); + } + + break; + } } } else @@ -838,7 +859,7 @@ } /* initialize global multi_context object */ - multi_init(&multi, top, true); + multi_init(&multi, top); /* initialize our cloned top object */ multi_top_init(&multi, top); @@ -874,12 +895,12 @@ if (status > 0) { /* process the I/O which triggered select */ - multi_tcp_process_io(&multi); + /*multi_tcp_process_io(&multi); */ MULTI_CHECK_SIG(&multi); } else if (status == 0) { - multi_tcp_action(&multi, NULL, TA_TIMEOUT, false); + /*multi_tcp_action(&multi, NULL, TA_TIMEOUT, false); */ } perf_pop(); diff --git a/src/openvpn/mtcp.h b/src/openvpn/mtcp.h index bacf723..b2fdb6e 100644 --- a/src/openvpn/mtcp.h +++ b/src/openvpn/mtcp.h @@ -31,6 +31,21 @@ #include "event.h" /* + * TCP States + */ +#define TA_UNDEF 0 +#define TA_SOCKET_READ 1 +#define TA_SOCKET_READ_RESIDUAL 2 +#define TA_SOCKET_WRITE 3 +#define TA_SOCKET_WRITE_READY 4 +#define TA_SOCKET_WRITE_DEFERRED 5 +#define TA_TUN_READ 6 +#define TA_TUN_WRITE 7 +#define TA_INITIAL 8 +#define TA_TIMEOUT 9 +#define TA_TUN_WRITE_TIMEOUT 10 + +/* * Extra state info needed for TCP mode */ struct multi_tcp @@ -40,6 +55,7 @@ int n_esr; int maxevents; unsigned int tun_rwflags; + unsigned int event_set_status; #ifdef ENABLE_MANAGEMENT unsigned int management_persist_flags; #endif @@ -58,6 +74,13 @@ void multi_tcp_instance_specific_free(struct multi_instance *mi); +int multi_tcp_wait(struct context *c, struct multi_tcp *mtcp); + +void multi_tcp_process_io(struct multi_context *m); + +void multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll); + + void multi_tcp_link_out_deferred(struct multi_context *m, struct multi_instance *mi); diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index dd45720..e9182c8 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -192,10 +192,12 @@ struct mroute_addr real; struct multi_instance *mi = NULL; struct hash *hash = m->hash; + real.proto = ls->info.proto; if (mroute_extract_openvpn_sockaddr(&real, &m->top.c2.from.dest, true) && m->top.c2.buf.len > 0) { + /*real.proto = ls->info.proto; */ struct hash_element *he; const uint32_t hv = hash_value(hash, &real); struct hash_bucket *bucket = hash_bucket(hash, hv); @@ -318,18 +320,68 @@ msg_set_prefix("Connection Attempt"); m->top.c2.to_link = m->hmac_reply; m->top.c2.to_link_addr = m->hmac_reply_dest; - process_outgoing_link(&m->top, m->top.c2.link_sockets[0]); + for (int i = 0; i < m->top.c1.link_sockets_num; i++) + { + if (!proto_is_dgram(m->top.c2.link_sockets[i]->info.proto)) + { + continue; + } + + process_outgoing_link(&m->top, m->top.c2.link_sockets[i]); + } m->hmac_reply_dest = NULL; } } /* + * Return the io_wait() flags appropriate for + * a point-to-multipoint tunnel. + */ +unsigned int +p2mp_iow_flags(const struct multi_context *m) +{ + unsigned int flags = IOW_WAIT_SIGNAL; + if (m->pending) + { + if (TUN_OUT(&m->pending->context)) + { + flags |= IOW_TO_TUN; + } + if (LINK_OUT(&m->pending->context)) + { + flags |= IOW_TO_LINK; + } + } + else if (mbuf_defined(m->mbuf)) + { + flags |= IOW_MBUF; + } + else if (m->hmac_reply_dest) + { + flags |= IOW_TO_LINK; + } + else + { + flags |= IOW_READ; + } +#ifdef _WIN32 + if (tuntap_ring_empty(m->top.c1.tuntap)) + { + flags &= ~IOW_READ_TUN; + } +#endif + return flags; +} + +/* * Process an I/O event. */ -static void +void multi_process_io_udp(struct multi_context *m) { - const unsigned int status = m->top.c2.event_set_status; + const unsigned int status = m->mtcp->event_set_status; + /*p2mp_iow_flags(m); */ + /*m->top.c2.event_set_status; */ const unsigned int mpp_flags = m->top.c2.fast_io ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL) : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); @@ -428,47 +480,6 @@ #endif } -/* - * Return the io_wait() flags appropriate for - * a point-to-multipoint tunnel. - */ -static inline unsigned int -p2mp_iow_flags(const struct multi_context *m) -{ - unsigned int flags = IOW_WAIT_SIGNAL; - if (m->pending) - { - if (TUN_OUT(&m->pending->context)) - { - flags |= IOW_TO_TUN; - } - if (LINK_OUT(&m->pending->context)) - { - flags |= IOW_TO_LINK; - } - } - else if (mbuf_defined(m->mbuf)) - { - flags |= IOW_MBUF; - } - else if (m->hmac_reply_dest) - { - flags |= IOW_TO_LINK; - } - else - { - flags |= IOW_READ; - } -#ifdef _WIN32 - if (tuntap_ring_empty(m->top.c1.tuntap)) - { - flags &= ~IOW_READ_TUN; - } -#endif - return flags; -} - - void tunnel_server_udp(struct context *top) { @@ -485,7 +496,7 @@ } /* initialize global multi_context object */ - multi_init(&multi, top, false); + multi_init(&multi, top); /* initialize our cloned top object */ multi_top_init(&multi, top); @@ -511,7 +522,7 @@ /* set up and do the io_wait() */ multi_get_timeout(&multi, &multi.top.c2.timeval); - io_wait(&multi.top, p2mp_iow_flags(&multi)); + /*io_wait(&multi.top, p2mp_iow_flags(&multi)); */ MULTI_CHECK_SIG(&multi); /* check on status of coarse timers */ @@ -525,7 +536,7 @@ else { /* process I/O */ - multi_process_io_udp(&multi); + /*multi_process_io_udp(&multi); */ MULTI_CHECK_SIG(&multi); } diff --git a/src/openvpn/mudp.h b/src/openvpn/mudp.h index 1088246..75e5a5e 100644 --- a/src/openvpn/mudp.h +++ b/src/openvpn/mudp.h @@ -31,6 +31,8 @@ struct context; struct multi_context; +unsigned int +p2mp_iow_flags(const struct multi_context *m); /** * Main event loop for OpenVPN in UDP server mode. @@ -40,9 +42,11 @@ * * @param top - Top-level context structure. */ + + void tunnel_server_udp(struct context *top); - +void multi_process_io_udp(struct multi_context *m); /**************************************************************************/ /** * Get, and if necessary create, the multi_instance associated with a diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index e9a3945..3522206 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -289,7 +289,7 @@ * Main initialization function, init multi_context object. */ void -multi_init(struct multi_context *m, struct context *t, bool tcp_mode) +multi_init(struct multi_context *m, struct context *t) { int dev = DEV_TYPE_UNDEF; @@ -435,13 +435,13 @@ m->instances = calloc(m->max_clients, sizeof(struct multi_instance *)); + m->top.c2.event_set = t->c2.event_set; + /* * Initialize multi-socket TCP I/O wait object */ - if (tcp_mode) - { - m->mtcp = multi_tcp_init(t->options.max_clients, &m->max_clients); - } + m->mtcp = multi_tcp_init(t->options.max_clients, &m->max_clients); + m->tcp_queue_limit = t->options.tcp_queue_limit; /* @@ -665,7 +665,7 @@ mi->did_iroutes = false; } - if (m->mtcp) + if (m->mtcp && !proto_is_dgram(m->top.options.ce.proto)) { multi_tcp_dereference_instance(m->mtcp, mi); } @@ -776,7 +776,6 @@ mi->real = *real; generate_prefix(mi); } - mi->did_open_context = true; inherit_context_child(&mi->context, &m->top, ls); if (IS_SIG(&mi->context)) @@ -798,6 +797,7 @@ { goto err; } + mi->real.proto = ls->info.proto; generate_prefix(mi); } @@ -4163,6 +4163,92 @@ } +void +tunnel_server_loop(struct multi_context *multi) +{ + int status; + + while (true) + { + perf_push(PERF_EVENT_LOOP); + + /* wait on tun/socket list */ + multi_get_timeout(multi, &multi->top.c2.timeval); + status = multi_tcp_wait(&multi->top, multi->mtcp); + MULTI_CHECK_SIG(multi); + + /* check on status of coarse timers */ + multi_process_per_second_timers(multi); + + /* timeout? */ + if (status > 0) + { + /* process the I/O which triggered select */ + multi_tcp_process_io(multi); + MULTI_CHECK_SIG(multi); + } + /*else if (status == 0) + * { + * multi_tcp_action(multi, NULL, TA_TIMEOUT, false); + * }*/ + + perf_pop(); + } +} + +void +tunnel_server_init(struct context *top) +{ + struct multi_context multi; + + top->mode = CM_TOP; + context_clear_2(top); + + /* initialize top-tunnel instance */ + init_instance_handle_signals(top, top->es, CC_HARD_USR1_TO_HUP); + if (IS_SIG(top)) + { + return; + } + + /* initialize global multi_context object */ + multi_init(&multi, top); + + /* initialize our cloned top object */ + multi_top_init(&multi, top); + + /* initialize management interface */ + init_management_callback_multi(&multi); + + /* finished with initialization */ + initialization_sequence_completed(top, ISC_SERVER); /* --mode server --proto tcp-server */ + +#ifdef ENABLE_ASYNC_PUSH + multi.top.c2.inotify_fd = inotify_init(); + if (multi.top.c2.inotify_fd < 0) + { + msg(D_MULTI_ERRORS | M_ERRNO, "MULTI: inotify_init error"); + } +#endif + + tunnel_server_loop(&multi); + + #ifdef ENABLE_ASYNC_PUSH + close(top->c2.inotify_fd); +#endif + + /* shut down management interface */ + uninit_management_callback(); + + /* save ifconfig-pool */ + multi_ifconfig_pool_persist(&multi, true); + + /* tear down tunnel instance (unless --persist-tun) */ + multi_uninit(&multi); + multi_top_free(&multi); + close_instance(top); +} + /* * Top level event loop. */ @@ -4171,12 +4257,6 @@ { ASSERT(top->options.mode == MODE_SERVER); - if (proto_is_dgram(top->options.ce.proto)) - { - tunnel_server_udp(top); - } - else - { - tunnel_server_tcp(top); - } + tunnel_server_init(top); + } diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 0d4ec63..472c2a3 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -262,7 +262,7 @@ * Called by mtcp.c, mudp.c, or other (to be written) protocol drivers */ -void multi_init(struct multi_context *m, struct context *t, bool tcp_mode); +void multi_init(struct multi_context *m, struct context *t); void multi_uninit(struct multi_context *m); diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9611423..9e800bb 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2188,6 +2188,7 @@ } ALLOC_OBJ_CLEAR_GC(e, struct local_entry, gc); + e->proto = PROTO_NONE; l->array[l->len++] = e; return e; @@ -3154,14 +3155,30 @@ if (ce->proto == PROTO_TCP) { ce->proto = PROTO_TCP_SERVER; + o->ce.proto = ce->proto; + } + if (ce->local_list) + { + for (int i = 0; i < ce->local_list->len; i++) + { + if (ce->local_list->array[i]->proto == PROTO_TCP) + { + ce->local_list->array[i]->proto = PROTO_TCP_SERVER; + } + else if (ce->local_list->array[i]->proto == PROTO_NONE) + { + ce->local_list->array[i]->proto = ce->proto; + } + } } } - if (o->client) + if (o->mode != MODE_SERVER) { if (ce->proto == PROTO_TCP) { ce->proto = PROTO_TCP_CLIENT; + o->ce.proto = ce->proto; } } @@ -3312,6 +3329,10 @@ { le->port = o->ce.local_port; } + if (!le->proto) + { + le->proto = o->ce.proto; + } } #ifdef _WIN32 @@ -3775,6 +3796,7 @@ ASSERT(e); e->port = o->ce.local_port; e->bind_local = o->ce.bind_local; + e->proto = o->ce.proto; } /* use the same listen list for every outgoing connection */ @@ -6164,7 +6186,7 @@ VERIFY_PERMISSION(OPT_P_UP); options->ifconfig_nowarn = true; } - else if (streq(p[0], "local") && p[1] && !p[3]) + else if (streq(p[0], "local") && p[1] && !p[4]) { struct local_entry *e; @@ -6185,7 +6207,12 @@ if (p[2]) { e->port = p[2]; - e->bind_local = true; + /*e->bind_local = true; */ + } + + if (p[3]) + { + e->proto = ascii2proto(p[3]); } } else if (streq(p[0], "remote-random") && !p[1]) diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 747ed56..cba0333 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -99,6 +99,7 @@ const char *local; const char *port; bool bind_local; + int proto; }; struct connection_entry