From patchwork Mon Sep 23 13:41:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "flichtenheld (Code Review)" X-Patchwork-Id: 3860 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:10cd:b0:5b9:581e:f939 with SMTP id j13csp2172059mae; Mon, 23 Sep 2024 06:41:53 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCV9d5jmJ7lOtAu1T9oKoCw+IeX4NPOU2+nDRml72anEYEdS3zXELJfUXnZRZfU2UEBV/bCrZrzTB2A=@openvpn.net X-Google-Smtp-Source: AGHT+IF4Nyb89KzXb7GMoEDthnV3sVH3mIhdt5IqkaoxJ6VrZPY1WH5dtdgzpf/SI36OIPXQc1sX X-Received: by 2002:a05:6808:211c:b0:3db:3b15:7e7f with SMTP id 5614622812f47-3e271cd3fc0mr8657243b6e.46.1727098913392; Mon, 23 Sep 2024 06:41:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1727098913; cv=none; d=google.com; s=arc-20240605; b=bXKqVoB4RMWfcipsa7i/JXmY1G5Rj45WZu1ttaM+V04k4C+QAztH5bhr4TOPB9+Vvx iCM86RpWPIyuWTN4ll4ekCov0JoHUY3Rz1muIbdmYKvxx+mkI+c2s1wYxwyOGVjm3gLC lpJcl504ozGzRcijMg52V8FMRJgCy3zJ+gTjymnujvCU1uXigFVHYMMH1m1rmAwNejJg QYJv5h8E31W6izkXw233bitMtEUMIKbYPqogcqViCVneKrDd6ARJ7qKzAxBjp+xJtqtu EmtBfYfChF0MzheR+qnGesVFm9RbPeKtxT2ZdV2Ijm2zqojQwQgZK9E8+BOlZqjtHPFc fGug== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; 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=/6XmC1gx7JGKhRnzNlsunPBf1zHsOjoAAiHQdK0QaLQ=; fh=U7wEyxtwz2o5+UdevFSA47vNeG9knhWH0KV//QhD5a0=; b=j/FLmow0QMrga4n+Q27twggF+TxLhoY/E0kuFfmJJt4esQwoKOTScg8jLdeNs6EbIV NVriPJIU7841U/WOUPJ99hBmlvSqOku1mUBXH/DRx+09RO4w8xKd5Bepwr9A4esIgiGh 4lbSUOt30f9NO1RycZjbgC/8+KZbcPHWd083+chAiKnif8HQlmstdDAoVm/zefElda2D I3BPSXK1qkc5QZPuiXxgMuyIrfjgCnHQjnbNpdaCadfBDrMi7SBWWLEEYqV6POqQmbkt OCW7qJouOJmCWMHLjPjAdONIy1Mw2JNzuT46wQ/tNkhxBYdZEOqEu8ZChN7TbT0bD8RX uxNw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=FGWIW1mv; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=EG4tKRaZ; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b="UjVi7/D9"; 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; dara=fail header.i=@openvpn.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 46e09a7af769-71389bf0cdesi4092395a34.344.2024.09.23.06.41.53 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Sep 2024 06:41:53 -0700 (PDT) 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=FGWIW1mv; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=EG4tKRaZ; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b="UjVi7/D9"; 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; dara=fail header.i=@openvpn.net Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1ssjK1-0004Kh-GI; Mon, 23 Sep 2024 13:41:49 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1ssjJy-0004KC-F3 for openvpn-devel@lists.sourceforge.net; Mon, 23 Sep 2024 13:41:46 +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=dL7SNkDg2tb7cMWWncl/qGtUILZLIQsichb7TSa9KqY=; b=FGWIW1mv8mK2juHmbcsUjHM/o7 ltAKiFnOud6H4ATAQmoniL0Ih/oEizlrmXmFednuBjxIBCqpiEI/Y50TN7rL6/pVju8Mm+K44d3AM M6UX8N9QVL2a9Q1wBo+m9PIeN0hpiFLBUIFksE0rZGvOZgM9xGQqLTTLAQ3ryI0M4tT8=; 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=dL7SNkDg2tb7cMWWncl/qGtUILZLIQsichb7TSa9KqY=; b=E G4tKRaZTgEjSMSoeQHURp1HLGMK7TG61E2Jj6dgeIwNQwMwjcN5o/g4OEoMnUj0ntpjuAxji3Mt0p zxLEasvqKUMpOIHbnfJrOGn//XWJnBCi43kzHSqfdvbdqWppFYqLe5xtElZnUXxVhDsX3w+IwMJQl a/k/YYRCYjmxQNQo=; Received: from mail-wr1-f48.google.com ([209.85.221.48]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1ssjJt-0006r6-GJ for openvpn-devel@lists.sourceforge.net; Mon, 23 Sep 2024 13:41:46 +0000 Received: by mail-wr1-f48.google.com with SMTP id ffacd0b85a97d-374c180d123so2558600f8f.3 for ; Mon, 23 Sep 2024 06:41:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1727098890; x=1727703690; 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=dL7SNkDg2tb7cMWWncl/qGtUILZLIQsichb7TSa9KqY=; b=UjVi7/D9tOhzDCx/hVjZJ7xb7UBHhbLR6t/BKV87YX1No6IvkOE8Yd+/ZFBMn0pl++ ngZ3zXkkwzI0+f84oarxK8cwdtX0U5g6T9NYaIpWXkSwoNNy41bZvbNKHnber8PrdSPm CULjJJiIt4y8a31Os+9V2MjNMjMuZF9MsPfJ9UIrN6aI+FU0CZoKfahrN9S9VYGL+Pto ZYnEsaa9V1elh+pxXGC3zsL6Me+slypD7IidCjNlJUur3UYaXvvUzRBIAeaM1L/e0dNg chytRNu7/e7Y69nG8rTBk1YbcT+K/PtAd+1RsPOzVLBcAnftBPBhEG2KsNOYCSBTmwuk ztwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727098890; x=1727703690; 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=dL7SNkDg2tb7cMWWncl/qGtUILZLIQsichb7TSa9KqY=; b=nWgaigJlGlYGSY0v+IM4s1hFJ8AeYpys/2+XquCZunrZKRjXz5hagl70m0BmzU55Ye C56LLEw0Oeks4gzGolZkh3ulbEMGlK3V3p/Rc+lJJ7SyxTEiyzPmwS5rKC0AaPyN4jPh 7Ljj+gIvgbH6EsHawhn3zpgsG29vi4InNdigBlzgSbw74ayYuxjJp9Sm81u7dvNjcQyY M4QaXBUdzRoIDTX+2SbSU9ZaOokfSA6Jj8TLMTgHCbeSaXGPoB+Kmlr4v2/G+FLXpMCW 2yG5ngh0n5FXbzE8p310NwNl2//MoGvgg7+xGyWZzb+X/CVaC2GW6jHF2HWTwDKrQuHL VhDw== X-Gm-Message-State: AOJu0Yx4T0z3BPlt+iCoTactgtgv0owH4rBAm2xLpPzuhednbjlrXTEE 8S9gkQbegkDwldaCCs70KBMfK28qtPLZZgbhpJzFG58lIcHkb2AbuKMSp27GkRU= X-Received: by 2002:a5d:6b42:0:b0:378:e8b4:1900 with SMTP id ffacd0b85a97d-37a4234d20amr6303146f8f.41.1727098889506; Mon, 23 Sep 2024 06:41:29 -0700 (PDT) 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 5b1f17b1804b1-42e7ae60de0sm102043555e9.7.2024.09.23.06.41.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Sep 2024 06:41:28 -0700 (PDT) From: "its_Giaan (Code Review)" X-Google-Original-From: "its_Giaan (Code Review)" X-Gerrit-PatchSet: 1 Date: Mon, 23 Sep 2024 13:41:27 +0000 To: plaisthos , flichtenheld Auto-Submitted: auto-generated X-Gerrit-MessageType: newchange X-Gerrit-Change-Id: I1e5a84969988e4f027a18658d4ab268c13fbf929 X-Gerrit-Change-Number: 763 X-Gerrit-Project: openvpn X-Gerrit-ChangeURL: X-Gerrit-Commit: e2097ec249d934e7a2ea998a90ac7fb098f26cf7 References: Message-ID: <7e6bdc87ccf6158a14ea7846576078ea49cba822-HTML@gerrit.openvpn.net> MIME-Version: 1.0 User-Agent: Gerrit/3.8.2 X-Spam-Score: -1.1 (-) X-Spam-Report: Spam detection software, running on the system "util-spamd-1.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: (-1.1 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.9 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.221.48 listed in wl.mailspike.net] -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.221.48 listed in list.dnswl.org] -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_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 T_KAM_HTML_FONT_INVALID Test for Invalidly Named or Formatted Colors in HTML X-Headers-End: 1ssjJt-0006r6-GJ Subject: [Openvpn-devel] [XL] Change in openvpn[master]: multiproto: move generic event handling code in dedicated files 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: gianmarco@mandelbit.com, 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?1810994470230253148?= X-GMAIL-MSGID: =?utf-8?q?1810994470230253148?= 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/+/763?usp=email to review the following change. Change subject: multiproto: move generic event handling code in dedicated files ...................................................................... multiproto: move generic event handling code in dedicated files Introduced multi_io.h and multi_io.c files to centralize all codes related to multiple protocols. Renamed the struct mtcp to struct multi_protocol since it encompasses the event_set used by the parent context in server mode. Several methods have also been renamed and moved to fit the multiproto structure: - multi_tcp_init() -> multi_protocol_init(); - multi_tcp_free() -> multi_protocol_free(); - multi_tcp_wait() -> multi_protocol_io_wait(); and so forth. Change-Id: I1e5a84969988e4f027a18658d4ab268c13fbf929 Signed-off-by: Gianmarco De Gregori --- M CMakeLists.txt M src/openvpn/Makefile.am M src/openvpn/forward.h M src/openvpn/mtcp.c M src/openvpn/mtcp.h M src/openvpn/multi.c M src/openvpn/multi.h A src/openvpn/multi_io.c A src/openvpn/multi_io.h M src/openvpn/socket.c 10 files changed, 740 insertions(+), 621 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/63/763/1 diff --git a/CMakeLists.txt b/CMakeLists.txt index ad620fa..38df4ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -455,6 +455,8 @@ src/openvpn/mudp.h src/openvpn/multi.c src/openvpn/multi.h + src/openvpn/multi_io.h + src/openvpn/multi_io.c src/openvpn/ntlm.c src/openvpn/ntlm.h src/openvpn/occ.c diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 3784a98..d9cb599 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -92,6 +92,7 @@ mtu.c mtu.h \ mudp.c mudp.h \ multi.c multi.h \ + multi_io.c multi_io.h \ networking_freebsd.c \ networking_iproute2.c networking_iproute2.h \ networking_sitnl.c networking_sitnl.h \ diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 6840b1a..3acbdd0 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 "multi_io.h" #define IOW_TO_TUN (1<<0) #define IOW_TO_LINK (1<<1) diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index 9243b7f..29706d0 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -29,6 +29,8 @@ #include "multi.h" #include "forward.h" +#include "mtcp.h" +#include "multi_io.h" #include "memdbg.h" @@ -36,31 +38,6 @@ #include #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) -#define MTCP_TUN ((void *)2) -#define MTCP_SIG ((void *)3) /* Only on Windows */ -#define MTCP_MANAGEMENT ((void *)4) -#define MTCP_FILE_CLOSE_WRITE ((void *)5) -#define MTCP_DCO ((void *)6) - struct ta_iow_flags { unsigned int flags; @@ -69,52 +46,7 @@ unsigned int sock; }; -#ifdef ENABLE_DEBUG -static const char * -pract(int action) -{ - switch (action) - { - case TA_UNDEF: - return "TA_UNDEF"; - - case TA_SOCKET_READ: - return "TA_SOCKET_READ"; - - case TA_SOCKET_READ_RESIDUAL: - return "TA_SOCKET_READ_RESIDUAL"; - - case TA_SOCKET_WRITE: - return "TA_SOCKET_WRITE"; - - case TA_SOCKET_WRITE_READY: - return "TA_SOCKET_WRITE_READY"; - - case TA_SOCKET_WRITE_DEFERRED: - return "TA_SOCKET_WRITE_DEFERRED"; - - case TA_TUN_READ: - return "TA_TUN_READ"; - - case TA_TUN_WRITE: - return "TA_TUN_WRITE"; - - case TA_INITIAL: - return "TA_INITIAL"; - - case TA_TIMEOUT: - return "TA_TIMEOUT"; - - case TA_TUN_WRITE_TIMEOUT: - return "TA_TUN_WRITE_TIMEOUT"; - - default: - return "?"; - } -} -#endif /* ENABLE_DEBUG */ - -static struct multi_instance * +struct multi_instance * multi_create_instance_tcp(struct multi_context *m, struct link_socket *ls) { struct gc_arena gc = gc_new(); @@ -194,126 +126,42 @@ mbuf_free(mi->tcp_link_out_deferred); } -struct multi_tcp * -multi_tcp_init(int maxevents, int *maxclients) -{ - struct multi_tcp *mtcp; - const int extra_events = BASE_N_EVENTS; - - ASSERT(maxevents >= 1); - ASSERT(maxclients); - - ALLOC_OBJ_CLEAR(mtcp, struct multi_tcp); - mtcp->maxevents = maxevents + extra_events; - mtcp->es = event_set_init(&mtcp->maxevents, 0); - wait_signal(mtcp->es, MTCP_SIG); - ALLOC_ARRAY(mtcp->esr, struct event_set_return, mtcp->maxevents); - *maxclients = max_int(min_int(mtcp->maxevents - extra_events, *maxclients), 1); - msg(D_MULTI_LOW, "MULTI: TCP INIT maxclients=%d maxevents=%d", *maxclients, mtcp->maxevents); - return mtcp; -} - void -multi_tcp_delete_event(struct multi_tcp *mtcp, event_t event) +multi_tcp_delete_event(struct multi_protocol *multi_io, event_t event) { - if (mtcp && mtcp->es) + if (multi_io && multi_io->es) { - event_del(mtcp->es, event); + event_del(multi_io->es, event); } } void -multi_tcp_free(struct multi_tcp *mtcp) -{ - if (mtcp) - { - event_free(mtcp->es); - free(mtcp->esr); - free(mtcp); - } -} - -void -multi_tcp_dereference_instance(struct multi_tcp *mtcp, struct multi_instance *mi) +multi_tcp_dereference_instance(struct multi_protocol *multi_io, struct multi_instance *mi) { struct link_socket *ls = mi->context.c2.link_sockets[0]; if (ls && mi->socket_set_called) { - event_del(mtcp->es, socket_event_handle(ls)); + event_del(multi_io->es, socket_event_handle(ls)); mi->socket_set_called = false; } - mtcp->n_esr = 0; + multi_io->n_esr = 0; } -static inline void +void multi_tcp_set_global_rw_flags(struct multi_context *m, struct multi_instance *mi) { if (mi) { mi->socket_set_called = true; socket_set(mi->context.c2.link_sockets[0], - m->mtcp->es, + m->multi_io->es, mbuf_defined(mi->tcp_link_out_deferred) ? EVENT_WRITE : EVENT_READ, &mi->ev_arg, &mi->tcp_rwflags); } } -static inline int -multi_tcp_wait(const struct context *c, - struct multi_tcp *mtcp) -{ - int status, i; - - for (i = 0; i < c->c1.link_sockets_num; i++) - { - socket_set_listen_persistent(c->c2.link_sockets[i], mtcp->es, - &c->c2.link_sockets[i]->ev_arg); - } - -#ifdef _WIN32 - if (tuntap_is_wintun(c->c1.tuntap)) - { - if (!tuntap_ring_empty(c->c1.tuntap)) - { - /* there is data in wintun ring buffer, read it immediately */ - mtcp->esr[0].arg = MTCP_TUN; - mtcp->esr[0].rwflags = EVENT_READ; - mtcp->n_esr = 1; - return 1; - } - persistent = NULL; - } -#endif - - tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); -#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) - dco_event_set(&c->c1.tuntap->dco, mtcp->es, MTCP_DCO); -#endif - -#ifdef ENABLE_MANAGEMENT - if (management) - { - management_socket_set(management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags); - } -#endif - -#ifdef ENABLE_ASYNC_PUSH - /* arm inotify watcher */ - event_ctl(mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE); -#endif - - status = event_wait(mtcp->es, &c->c2.timeval, mtcp->esr, mtcp->maxevents); - update_time(); - mtcp->n_esr = 0; - if (status > 0) - { - mtcp->n_esr = status; - } - return status; -} - -static inline struct context * +struct context * multi_tcp_context(struct multi_context *m, struct multi_instance *mi) { if (mi) @@ -326,7 +174,7 @@ } } -static bool +bool multi_tcp_process_outgoing_link_ready(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) { struct mbuf_item item; @@ -350,7 +198,7 @@ return ret; } -static bool +bool multi_tcp_process_outgoing_link(struct multi_context *m, bool defer, const unsigned int mpp_flags) { struct multi_instance *mi = multi_process_outgoing_link_pre(m); @@ -394,429 +242,6 @@ return ret; } -static int -multi_tcp_wait_lite(struct multi_context *m, struct multi_instance *mi, const int action, bool *tun_input_pending) -{ - struct context *c = multi_tcp_context(m, mi); - unsigned int looking_for = 0; - - dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_wait_lite a=%s mi=" ptr_format, - pract(action), - (ptr_type)mi); - - tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */ - - switch (action) - { - case TA_TUN_READ: - looking_for = TUN_READ; - tun_input_pending = NULL; - io_wait(c, IOW_READ_TUN); - break; - - case TA_SOCKET_READ: - looking_for = SOCKET_READ; - tun_input_pending = NULL; - io_wait(c, IOW_READ_LINK); - break; - - case TA_TUN_WRITE: - looking_for = TUN_WRITE; - tun_input_pending = NULL; - c->c2.timeval.tv_sec = 1; /* For some reason, the Linux 2.2 TUN/TAP driver hits this timeout */ - perf_push(PERF_PROC_OUT_TUN_MTCP); - io_wait(c, IOW_TO_TUN); - perf_pop(); - break; - - case TA_SOCKET_WRITE: - looking_for = SOCKET_WRITE; - io_wait(c, IOW_TO_LINK|IOW_READ_TUN_FORCE); - break; - - default: - msg(M_FATAL, "MULTI TCP: multi_tcp_wait_lite, unhandled action=%d", action); - } - - if (tun_input_pending && (c->c2.event_set_status & TUN_READ)) - { - *tun_input_pending = true; - } - - if (c->c2.event_set_status & looking_for) - { - return action; - } - else - { - switch (action) - { - /* TCP socket output buffer is full */ - case TA_SOCKET_WRITE: - return TA_SOCKET_WRITE_DEFERRED; - - /* TUN device timed out on accepting write */ - case TA_TUN_WRITE: - return TA_TUN_WRITE_TIMEOUT; - } - - return TA_UNDEF; - } -} - -static struct multi_instance * -multi_tcp_dispatch(struct multi_context *m, struct multi_instance *mi, const int action) -{ - const unsigned int mpp_flags = MPP_PRE_SELECT|MPP_RECORD_TOUCH; - struct multi_instance *touched = mi; - m->mpp_touched = &touched; - - dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_dispatch a=%s mi=" ptr_format, - pract(action), - (ptr_type)mi); - - switch (action) - { - case TA_TUN_READ: - read_incoming_tun(&m->top); - if (!IS_SIG(&m->top)) - { - multi_process_incoming_tun(m, mpp_flags); - } - break; - - case TA_SOCKET_READ: - case TA_SOCKET_READ_RESIDUAL: - ASSERT(mi); - ASSERT(mi->context.c2.link_sockets); - ASSERT(mi->context.c2.link_sockets[0]); - set_prefix(mi); - read_incoming_link(&mi->context, mi->context.c2.link_sockets[0]); - clear_prefix(); - if (!IS_SIG(&mi->context)) - { - multi_process_incoming_link(m, mi, mpp_flags, - mi->context.c2.link_sockets[0]); - if (!IS_SIG(&mi->context)) - { - stream_buf_read_setup(mi->context.c2.link_sockets[0]); - } - } - break; - - case TA_TIMEOUT: - multi_process_timeout(m, mpp_flags); - break; - - case TA_TUN_WRITE: - multi_process_outgoing_tun(m, mpp_flags); - break; - - case TA_TUN_WRITE_TIMEOUT: - multi_process_drop_outgoing_tun(m, mpp_flags); - break; - - case TA_SOCKET_WRITE_READY: - ASSERT(mi); - multi_tcp_process_outgoing_link_ready(m, mi, mpp_flags); - break; - - case TA_SOCKET_WRITE: - multi_tcp_process_outgoing_link(m, false, mpp_flags); - break; - - case TA_SOCKET_WRITE_DEFERRED: - multi_tcp_process_outgoing_link(m, true, mpp_flags); - break; - - case TA_INITIAL: - ASSERT(mi); - multi_tcp_set_global_rw_flags(m, mi); - multi_process_post(m, mi, mpp_flags); - break; - - default: - msg(M_FATAL, "MULTI TCP: multi_tcp_dispatch, unhandled action=%d", action); - } - - m->mpp_touched = NULL; - return touched; -} - -static int -multi_tcp_post(struct multi_context *m, struct multi_instance *mi, const int action) -{ - struct context *c = multi_tcp_context(m, mi); - int newaction = TA_UNDEF; - -#define MTP_NONE 0 -#define MTP_TUN_OUT (1<<0) -#define MTP_LINK_OUT (1<<1) - unsigned int flags = MTP_NONE; - - if (TUN_OUT(c)) - { - flags |= MTP_TUN_OUT; - } - if (LINK_OUT(c)) - { - flags |= MTP_LINK_OUT; - } - - switch (flags) - { - case MTP_TUN_OUT|MTP_LINK_OUT: - case MTP_TUN_OUT: - newaction = TA_TUN_WRITE; - break; - - case MTP_LINK_OUT: - newaction = TA_SOCKET_WRITE; - break; - - case MTP_NONE: - if (mi && sockets_read_residual(c)) - { - newaction = TA_SOCKET_READ_RESIDUAL; - } - else - { - multi_tcp_set_global_rw_flags(m, mi); - } - break; - - default: - { - struct gc_arena gc = gc_new(); - msg(M_FATAL, "MULTI TCP: multi_tcp_post bad state, mi=%s flags=%d", - multi_instance_string(mi, false, &gc), - flags); - gc_free(&gc); - break; - } - } - - dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_post %s -> %s", - pract(action), - pract(newaction)); - - return newaction; -} - -static void -multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll) -{ - bool tun_input_pending = false; - - do - { - dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_action a=%s p=%d", - pract(action), - poll); - - /* - * If TA_SOCKET_READ_RESIDUAL, it means we still have pending - * input packets which were read by a prior TCP recv. - * - * Otherwise do a "lite" wait, which means we wait with 0 timeout - * on I/O events only related to the current instance, not - * the big list of events. - * - * On our first pass, poll will be false because we already know - * that input is available, and to call io_wait would be redundant. - */ - if (poll && action != TA_SOCKET_READ_RESIDUAL) - { - const int orig_action = action; - action = multi_tcp_wait_lite(m, mi, action, &tun_input_pending); - if (action == TA_UNDEF) - { - msg(M_FATAL, "MULTI TCP: I/O wait required blocking in multi_tcp_action, action=%d", orig_action); - } - } - - /* - * Dispatch the action - */ - struct multi_instance *touched = multi_tcp_dispatch(m, mi, action); - - /* - * Signal received or TCP connection - * reset by peer? - */ - if (touched && IS_SIG(&touched->context)) - { - if (mi == touched) - { - mi = NULL; - } - multi_close_instance_on_signal(m, touched); - } - - - /* - * If dispatch produced any pending output - * for a particular instance, point to - * that instance. - */ - if (m->pending) - { - mi = m->pending; - } - - /* - * Based on the effects of the action, - * such as generating pending output, - * possibly transition to a new action state. - */ - action = multi_tcp_post(m, mi, action); - - /* - * If we are finished processing the original action, - * check if we have any TUN input. If so, transition - * our action state to processing this input. - */ - if (tun_input_pending && action == TA_UNDEF) - { - action = TA_TUN_READ; - mi = NULL; - tun_input_pending = false; - poll = false; - } - else - { - poll = true; - } - - } while (action != TA_UNDEF); -} - -static void -multi_tcp_process_io(struct multi_context *m) -{ - struct multi_tcp *mtcp = m->mtcp; - int i; - - for (i = 0; i < mtcp->n_esr; ++i) - { - struct event_set_return *e = &mtcp->esr[i]; - struct event_arg *ev_arg = (struct event_arg *)e->arg; - - /* incoming data for instance or listening socket? */ - if (e->arg >= MULTI_N) - { - switch (ev_arg->type) - { - struct multi_instance *mi; - - /* react to event on child instance */ - case EVENT_ARG_MULTI_INSTANCE: - if (!ev_arg->u.mi) - { - msg(D_MULTI_ERRORS, "MULTI: mtcp_proc_io: null minstance"); - break; - } - - mi = ev_arg->u.mi; - if (e->rwflags & EVENT_WRITE) - { - multi_tcp_action(m, mi, TA_SOCKET_WRITE_READY, false); - } - else if (e->rwflags & EVENT_READ) - { - multi_tcp_action(m, mi, TA_SOCKET_READ, false); - } - break; - - /* new incoming TCP client attempting to connect? */ - case EVENT_ARG_LINK_SOCKET: - if (!ev_arg->u.ls) - { - 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) - { - multi_tcp_action(m, mi, TA_INITIAL, false); - } - break; - } - } - else - { -#ifdef ENABLE_MANAGEMENT - if (e->arg == MTCP_MANAGEMENT) - { - ASSERT(management); - management_io(management); - } - else -#endif - /* incoming data on TUN? */ - if (e->arg == MTCP_TUN) - { - if (e->rwflags & EVENT_WRITE) - { - multi_tcp_action(m, NULL, TA_TUN_WRITE, false); - } - else if (e->rwflags & EVENT_READ) - { - multi_tcp_action(m, NULL, TA_TUN_READ, false); - } - } - /* new incoming TCP client attempting to connect? */ - else if (e->arg == MTCP_SOCKET) - { - struct multi_instance *mi; - ASSERT(m->top.c2.link_sockets[0]); - socket_reset_listen_persistent(m->top.c2.link_sockets[0]); - mi = multi_create_instance_tcp(m, m->top.c2.link_sockets[0]); - if (mi) - { - multi_tcp_action(m, mi, TA_INITIAL, false); - } - } -#if defined(ENABLE_DCO) && (defined(TARGET_LINUX) || defined(TARGET_FREEBSD)) - /* incoming data on DCO? */ - else if (e->arg == MTCP_DCO) - { - multi_process_incoming_dco(m); - } -#endif - /* signal received? */ - else if (e->arg == MTCP_SIG) - { - get_signal(&m->top.sig->signal_received); - } -#ifdef ENABLE_ASYNC_PUSH - else if (e->arg == MTCP_FILE_CLOSE_WRITE) - { - multi_process_file_closed(m, MPP_PRE_SELECT | MPP_RECORD_TOUCH); - } -#endif - } - if (IS_SIG(&m->top)) - { - break; - } - } - mtcp->n_esr = 0; - - /* - * Process queued mbuf packets destined for TCP socket - */ - { - struct multi_instance *mi; - while (!IS_SIG(&m->top) && (mi = mbuf_peek(m->mbuf)) != NULL) - { - multi_tcp_action(m, mi, TA_SOCKET_WRITE, true); - } - } -} - /* * Top level event loop for single-threaded operation. * TCP mode. @@ -864,7 +289,7 @@ /* wait on tun/socket list */ multi_get_timeout(&multi, &multi.top.c2.timeval); - status = multi_tcp_wait(&multi.top, multi.mtcp); + status = multi_protocol_io_wait(&multi); MULTI_CHECK_SIG(&multi); /* check on status of coarse timers */ @@ -874,12 +299,12 @@ if (status > 0) { /* process the I/O which triggered select */ - multi_tcp_process_io(&multi); + multi_protocol_process_io(&multi); MULTI_CHECK_SIG(&multi); } else if (status == 0) { - multi_tcp_action(&multi, NULL, TA_TIMEOUT, false); + multi_protocol_action(&multi, NULL, TA_TIMEOUT, false); } perf_pop(); diff --git a/src/openvpn/mtcp.h b/src/openvpn/mtcp.h index 886d2cc..e48481a 100644 --- a/src/openvpn/mtcp.h +++ b/src/openvpn/mtcp.h @@ -30,34 +30,25 @@ #include "event.h" -/* - * Extra state info needed for TCP mode - */ -struct multi_tcp -{ - struct event_set *es; - struct event_set_return *esr; - int n_esr; - int maxevents; - unsigned int tun_rwflags; -#ifdef ENABLE_MANAGEMENT - unsigned int management_persist_flags; -#endif -}; - struct multi_instance; struct context; -struct multi_tcp *multi_tcp_init(int maxevents, int *maxclients); - -void multi_tcp_free(struct multi_tcp *mtcp); - -void multi_tcp_dereference_instance(struct multi_tcp *mtcp, struct multi_instance *mi); +void multi_tcp_dereference_instance(struct multi_protocol *multi_io, struct multi_instance *mi); bool multi_tcp_instance_specific_init(struct multi_context *m, struct multi_instance *mi); void multi_tcp_instance_specific_free(struct multi_instance *mi); +struct context *multi_tcp_context(struct multi_context *m, struct multi_instance *mi); + +void multi_tcp_set_global_rw_flags(struct multi_context *m, struct multi_instance *mi); + +bool multi_tcp_process_outgoing_link(struct multi_context *m, bool defer, const unsigned int mpp_flags); + +bool multi_tcp_process_outgoing_link_ready(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags); + +struct multi_instance *multi_create_instance_tcp(struct multi_context *m, struct link_socket *ls); + void multi_tcp_link_out_deferred(struct multi_context *m, struct multi_instance *mi); @@ -71,6 +62,6 @@ void tunnel_server_tcp(struct context *top); -void multi_tcp_delete_event(struct multi_tcp *mtcp, event_t event); +void multi_tcp_delete_event(struct multi_protocol *multi_io, event_t event); #endif /* ifndef MTCP_H */ diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index e7d742b..d7b4e3b 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -440,7 +440,7 @@ */ if (tcp_mode) { - m->mtcp = multi_tcp_init(t->options.max_clients, &m->max_clients); + m->multi_io = multi_protocol_init(t->options.max_clients, &m->max_clients); } m->tcp_queue_limit = t->options.tcp_queue_limit; @@ -665,9 +665,9 @@ mi->did_iroutes = false; } - if (m->mtcp) + if (m->multi_io) { - multi_tcp_dereference_instance(m->mtcp, mi); + multi_tcp_dereference_instance(m->multi_io, mi); } mbuf_dereference_instance(m->mbuf, mi); @@ -745,7 +745,7 @@ initial_rate_limit_free(m->initial_rate_limiter); multi_reap_free(m->reaper); mroute_helper_free(m->route_helper); - multi_tcp_free(m->mtcp); + multi_protocol_free(m->multi_io); } } @@ -3978,9 +3978,9 @@ management_delete_event(void *arg, event_t event) { struct multi_context *m = (struct multi_context *) arg; - if (m->mtcp) + if (m->multi_io) { - multi_tcp_delete_event(m->mtcp, event); + multi_tcp_delete_event(m->multi_io, event); } } diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index e2e5ef6..a25aeda 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -37,6 +37,7 @@ #include "pool.h" #include "mudp.h" #include "mtcp.h" +#include "multi_io.h" #include "perf.h" #include "vlan.h" #include "reflect_filter.h" @@ -169,8 +170,8 @@ struct mbuf_set *mbuf; /**< Set of buffers for passing data * channel packets between VPN tunnel * instances. */ - struct multi_tcp *mtcp; /**< State specific to OpenVPN using TCP - * as external transport. */ + struct multi_protocol *multi_io; /**< State specific to OpenVPN using TCP + * as external transport. */ struct ifconfig_pool *ifconfig_pool; struct frequency_limit *new_connection_limiter; struct initial_packet_rate_limit *initial_rate_limiter; diff --git a/src/openvpn/multi_io.c b/src/openvpn/multi_io.c new file mode 100644 index 0000000..57ed10e --- /dev/null +++ b/src/openvpn/multi_io.c @@ -0,0 +1,619 @@ +/* + * 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-2023 OpenVPN Inc + * + * 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; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "syshead.h" + +#include "memdbg.h" + +#include "multi.h" +#include "forward.h" +#include "multi_io.h" + +#ifdef HAVE_SYS_INOTIFY_H +#include +#endif + +/* + * Special tags passed to event.[ch] functions + */ +#define MULTI_IO_SOCKET ((void *)1) +#define MULTI_IO_TUN ((void *)2) +#define MULTI_IO_SIG ((void *)3) /* Only on Windows */ +#define MULTI_IO_MANAGEMENT ((void *)4) +#define MULTI_IO_FILE_CLOSE_WRITE ((void *)5) +#define MULTI_IO_DCO ((void *)6) + +struct ta_iow_flags +{ + unsigned int flags; + unsigned int ret; + unsigned int tun; + unsigned int sock; +}; + +#ifdef ENABLE_DEBUG +static const char * +pract(int action) +{ + switch (action) + { + case TA_UNDEF: + return "TA_UNDEF"; + + case TA_SOCKET_READ: + return "TA_SOCKET_READ"; + + case TA_SOCKET_READ_RESIDUAL: + return "TA_SOCKET_READ_RESIDUAL"; + + case TA_SOCKET_WRITE: + return "TA_SOCKET_WRITE"; + + case TA_SOCKET_WRITE_READY: + return "TA_SOCKET_WRITE_READY"; + + case TA_SOCKET_WRITE_DEFERRED: + return "TA_SOCKET_WRITE_DEFERRED"; + + case TA_TUN_READ: + return "TA_TUN_READ"; + + case TA_TUN_WRITE: + return "TA_TUN_WRITE"; + + case TA_INITIAL: + return "TA_INITIAL"; + + case TA_TIMEOUT: + return "TA_TIMEOUT"; + + case TA_TUN_WRITE_TIMEOUT: + return "TA_TUN_WRITE_TIMEOUT"; + + default: + return "?"; + } +} +#endif /* ENABLE_DEBUG */ + +struct multi_protocol * +multi_protocol_init(int maxevents, int *maxclients) +{ + struct multi_protocol *multi_io; + const int extra_events = BASE_N_EVENTS; + + ASSERT(maxevents >= 1); + ASSERT(maxclients); + + ALLOC_OBJ_CLEAR(multi_io, struct multi_protocol); + multi_io->maxevents = maxevents + extra_events; + multi_io->es = event_set_init(&multi_io->maxevents, 0); + wait_signal(multi_io->es, MULTI_IO_SIG); + ALLOC_ARRAY(multi_io->esr, struct event_set_return, multi_io->maxevents); + *maxclients = max_int(min_int(multi_io->maxevents - extra_events, *maxclients), 1); + msg(D_MULTI_LOW, "MULTI: TCP INIT maxclients=%d maxevents=%d", *maxclients, multi_io->maxevents); + return multi_io; +} + +void +multi_protocol_free(struct multi_protocol *multi_io) +{ + if (multi_io) + { + event_free(multi_io->es); + free(multi_io->esr); + free(multi_io); + } +} + +int +multi_protocol_io_wait(struct multi_context *m) +{ + int status, i; + unsigned int *persistent = &m->multi_io->tun_rwflags; + + for (i = 0; i < m->top.c1.link_sockets_num; i++) + { + socket_set_listen_persistent(m->top.c2.link_sockets[i], m->multi_io->es, + &m->top.c2.link_sockets[i]->ev_arg); + } + +#ifdef _WIN32 + if (tuntap_is_wintun(m->top.c1.tuntap)) + { + if (!tuntap_ring_empty(m->top.c1.tuntap)) + { + /* there is data in wintun ring buffer, read it immediately */ + m->multi_io->esr[0].arg = MULTI_IO_TUN; + m->multi_io->esr[0].rwflags = EVENT_READ; + m->multi_io->n_esr = 1; + return 1; + } + persistent = NULL; + } +#endif + tun_set(m->top.c1.tuntap, m->multi_io->es, EVENT_READ, MULTI_IO_TUN, persistent); +#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) + dco_event_set(&m->top.c1.tuntap->dco, m->multi_io->es, MULTI_IO_DCO); +#endif + +#ifdef ENABLE_MANAGEMENT + if (management) + { + management_socket_set(management, m->multi_io->es, MULTI_IO_MANAGEMENT, &m->multi_io->management_persist_flags); + } +#endif + +#ifdef ENABLE_ASYNC_PUSH + /* arm inotify watcher */ + event_ctl(m->multi_io->es, m->top.c2.inotify_fd, EVENT_READ, MULTI_IO_FILE_CLOSE_WRITE); +#endif + + status = event_wait(m->multi_io->es, &m->top.c2.timeval, m->multi_io->esr, m->multi_io->maxevents); + update_time(); + m->multi_io->n_esr = 0; + if (status > 0) + { + m->multi_io->n_esr = status; + } + return status; +} + +static int +multi_protocol_wait_lite(struct multi_context *m, struct multi_instance *mi, const int action, bool *tun_input_pending) +{ + struct context *c = multi_tcp_context(m, mi); + unsigned int looking_for = 0; + + dmsg(D_MULTI_DEBUG, "MULTI PROTOCOL: multi_protocol_wait_lite a=%s mi=" ptr_format, + pract(action), + (ptr_type)mi); + + tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */ + + switch (action) + { + case TA_TUN_READ: + looking_for = TUN_READ; + tun_input_pending = NULL; + io_wait(c, IOW_READ_TUN); + break; + + case TA_SOCKET_READ: + looking_for = SOCKET_READ; + tun_input_pending = NULL; + io_wait(c, IOW_READ_LINK); + break; + + case TA_TUN_WRITE: + looking_for = TUN_WRITE; + tun_input_pending = NULL; + c->c2.timeval.tv_sec = 1; /* For some reason, the Linux 2.2 TUN/TAP driver hits this timeout */ + perf_push(PERF_PROC_OUT_TUN_MTCP); + io_wait(c, IOW_TO_TUN); + perf_pop(); + break; + + case TA_SOCKET_WRITE: + looking_for = SOCKET_WRITE; + io_wait(c, IOW_TO_LINK|IOW_READ_TUN_FORCE); + break; + + default: + msg(M_FATAL, "MULTI PROTOCOL: multi_protocol_wait_lite, unhandled action=%d", action); + } + + if (tun_input_pending && (c->c2.event_set_status & TUN_READ)) + { + *tun_input_pending = true; + } + + if (c->c2.event_set_status & looking_for) + { + return action; + } + else + { + switch (action) + { + /* MULTI PROTOCOL socket output buffer is full */ + case TA_SOCKET_WRITE: + return TA_SOCKET_WRITE_DEFERRED; + + /* TUN device timed out on accepting write */ + case TA_TUN_WRITE: + return TA_TUN_WRITE_TIMEOUT; + } + + return TA_UNDEF; + } +} + +static struct multi_instance * +multi_protocol_dispatch(struct multi_context *m, struct multi_instance *mi, const int action) +{ + const unsigned int mpp_flags = MPP_PRE_SELECT|MPP_RECORD_TOUCH; + struct multi_instance *touched = mi; + m->mpp_touched = &touched; + + dmsg(D_MULTI_DEBUG, "MULTI PROTOCOL: multi_protocol_dispatch a=%s mi=" ptr_format, + pract(action), + (ptr_type)mi); + + switch (action) + { + case TA_TUN_READ: + read_incoming_tun(&m->top); + if (!IS_SIG(&m->top)) + { + multi_process_incoming_tun(m, mpp_flags); + } + break; + + case TA_SOCKET_READ: + case TA_SOCKET_READ_RESIDUAL: + ASSERT(mi); + ASSERT(mi->context.c2.link_sockets); + ASSERT(mi->context.c2.link_sockets[0]); + set_prefix(mi); + read_incoming_link(&mi->context, mi->context.c2.link_sockets[0]); + clear_prefix(); + if (!IS_SIG(&mi->context)) + { + multi_process_incoming_link(m, mi, mpp_flags, + mi->context.c2.link_sockets[0]); + if (!IS_SIG(&mi->context)) + { + stream_buf_read_setup(mi->context.c2.link_sockets[0]); + } + } + break; + + case TA_TIMEOUT: + multi_process_timeout(m, mpp_flags); + break; + + case TA_TUN_WRITE: + multi_process_outgoing_tun(m, mpp_flags); + break; + + case TA_TUN_WRITE_TIMEOUT: + multi_process_drop_outgoing_tun(m, mpp_flags); + break; + + case TA_SOCKET_WRITE_READY: + ASSERT(mi); + multi_tcp_process_outgoing_link_ready(m, mi, mpp_flags); + break; + + case TA_SOCKET_WRITE: + multi_tcp_process_outgoing_link(m, false, mpp_flags); + break; + + case TA_SOCKET_WRITE_DEFERRED: + multi_tcp_process_outgoing_link(m, true, mpp_flags); + break; + + case TA_INITIAL: + ASSERT(mi); + multi_tcp_set_global_rw_flags(m, mi); + multi_process_post(m, mi, mpp_flags); + break; + + default: + msg(M_FATAL, "MULTI PROTOCOL: multi_protocol_dispatch, unhandled action=%d", action); + } + + m->mpp_touched = NULL; + return touched; +} + +static int +multi_protocol_post(struct multi_context *m, struct multi_instance *mi, const int action) +{ + struct context *c = multi_tcp_context(m, mi); + int newaction = TA_UNDEF; + +#define MTP_NONE 0 +#define MTP_TUN_OUT (1<<0) +#define MTP_LINK_OUT (1<<1) + unsigned int flags = MTP_NONE; + + if (TUN_OUT(c)) + { + flags |= MTP_TUN_OUT; + } + if (LINK_OUT(c)) + { + flags |= MTP_LINK_OUT; + } + + switch (flags) + { + case MTP_TUN_OUT|MTP_LINK_OUT: + case MTP_TUN_OUT: + newaction = TA_TUN_WRITE; + break; + + case MTP_LINK_OUT: + newaction = TA_SOCKET_WRITE; + break; + + case MTP_NONE: + if (mi && sockets_read_residual(c)) + { + newaction = TA_SOCKET_READ_RESIDUAL; + } + else + { + multi_tcp_set_global_rw_flags(m, mi); + } + break; + + default: + { + struct gc_arena gc = gc_new(); + msg(M_FATAL, "MULTI PROTOCOL: multi_protocol_post bad state, mi=%s flags=%d", + multi_instance_string(mi, false, &gc), + flags); + gc_free(&gc); + break; + } + } + + dmsg(D_MULTI_DEBUG, "MULTI PROTOCOL: multi_protocol_post %s -> %s", + pract(action), + pract(newaction)); + + return newaction; +} + +void +multi_protocol_process_io(struct multi_context *m) +{ + struct multi_protocol *multi_io = m->multi_io; + int i; + + for (i = 0; i < multi_io->n_esr; ++i) + { + struct event_set_return *e = &multi_io->esr[i]; + struct event_arg *ev_arg = (struct event_arg *)e->arg; + + /* incoming data for instance or listening socket? */ + if (e->arg >= MULTI_N) + { + switch (ev_arg->type) + { + struct multi_instance *mi; + + /* react to event on child instance */ + case EVENT_ARG_MULTI_INSTANCE: + if (!ev_arg->u.mi) + { + msg(D_MULTI_ERRORS, "MULTI PROTOCOL: multi_proto_proc_io: null minstance"); + break; + } + + mi = ev_arg->u.mi; + if (e->rwflags & EVENT_WRITE) + { + multi_protocol_action(m, mi, TA_SOCKET_WRITE_READY, false); + } + else if (e->rwflags & EVENT_READ) + { + multi_protocol_action(m, mi, TA_SOCKET_READ, false); + } + break; + + /* new incoming TCP client attempting to connect? */ + case EVENT_ARG_LINK_SOCKET: + if (!ev_arg->u.ls) + { + msg(D_MULTI_ERRORS, "MULTI PROTOCOL: multi_proto_proc_io: null socket"); + break; + } + + if (!proto_is_dgram(ev_arg->u.ls->info.proto)) + { + socket_reset_listen_persistent(ev_arg->u.ls); + mi = multi_create_instance_tcp(m, ev_arg->u.ls); + if (mi) + { + multi_protocol_action(m, mi, TA_INITIAL, false); + } + break; + } + } + } + else + { +#ifdef ENABLE_MANAGEMENT + if (e->arg == MULTI_IO_MANAGEMENT) + { + ASSERT(management); + management_io(management); + } + else +#endif + /* incoming data on TUN? */ + if (e->arg == MULTI_IO_TUN) + { + if (e->rwflags & EVENT_WRITE) + { + multi_protocol_action(m, NULL, TA_TUN_WRITE, false); + } + else if (e->rwflags & EVENT_READ) + { + multi_protocol_action(m, NULL, TA_TUN_READ, false); + } + } + /* new incoming TCP client attempting to connect? */ + else if (e->arg == MULTI_IO_SOCKET) + { + struct multi_instance *mi; + ASSERT(m->top.c2.link_sockets[0]); + socket_reset_listen_persistent(m->top.c2.link_sockets[0]); + mi = multi_create_instance_tcp(m, m->top.c2.link_sockets[0]); + if (mi) + { + multi_protocol_action(m, mi, TA_INITIAL, false); + } + } +#if defined(ENABLE_DCO) && (defined(TARGET_LINUX) || defined(TARGET_FREEBSD)) + /* incoming data on DCO? */ + else if (e->arg == MULTI_IO_DCO) + { + multi_process_incoming_dco(m); + } +#endif + /* signal received? */ + else if (e->arg == MULTI_IO_SIG) + { + get_signal(&m->top.sig->signal_received); + } +#ifdef ENABLE_ASYNC_PUSH + else if (e->arg == MULTI_IO_FILE_CLOSE_WRITE) + { + multi_process_file_closed(m, MPP_PRE_SELECT | MPP_RECORD_TOUCH); + } +#endif + } + if (IS_SIG(&m->top)) + { + break; + } + } + multi_io->n_esr = 0; + + /* + * Process queued mbuf packets destined for TCP socket + */ + { + struct multi_instance *mi; + while (!IS_SIG(&m->top) && (mi = mbuf_peek(m->mbuf)) != NULL) + { + multi_protocol_action(m, mi, TA_SOCKET_WRITE, true); + } + } +} + +void +multi_protocol_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll) +{ + bool tun_input_pending = false; + + do + { + dmsg(D_MULTI_DEBUG, "MULTI PROTOCOL: multi_protocol_action a=%s p=%d", + pract(action), + poll); + + /* + * If TA_SOCKET_READ_RESIDUAL, it means we still have pending + * input packets which were read by a prior recv. + * + * Otherwise do a "lite" wait, which means we wait with 0 timeout + * on I/O events only related to the current instance, not + * the big list of events. + * + * On our first pass, poll will be false because we already know + * that input is available, and to call io_wait would be redundant. + */ + if (poll && action != TA_SOCKET_READ_RESIDUAL) + { + const int orig_action = action; + action = multi_protocol_wait_lite(m, mi, action, &tun_input_pending); + if (action == TA_UNDEF) + { + msg(M_FATAL, "MULTI PROTOCOL: I/O wait required blocking in multi_protocol_action, action=%d", orig_action); + } + } + + /* + * Dispatch the action + */ + struct multi_instance *touched = multi_protocol_dispatch(m, mi, action); + + /* + * Signal received or connection + * reset by peer? + */ + if (touched && IS_SIG(&touched->context)) + { + if (mi == touched) + { + mi = NULL; + } + multi_close_instance_on_signal(m, touched); + } + + + /* + * If dispatch produced any pending output + * for a particular instance, point to + * that instance. + */ + if (m->pending) + { + mi = m->pending; + } + + /* + * Based on the effects of the action, + * such as generating pending output, + * possibly transition to a new action state. + */ + action = multi_protocol_post(m, mi, action); + + /* + * If we are finished processing the original action, + * check if we have any TUN input. If so, transition + * our action state to processing this input. + */ + if (tun_input_pending && action == TA_UNDEF) + { + action = TA_TUN_READ; + mi = NULL; + tun_input_pending = false; + poll = false; + } + else + { + poll = true; + } + + } while (action != TA_UNDEF); +} + +void +multi_protocol_delete_event(struct multi_protocol *multi_io, event_t event) +{ + if (multi_io && multi_io->es) + { + event_del(multi_io->es, event); + } +} diff --git a/src/openvpn/multi_io.h b/src/openvpn/multi_io.h new file mode 100644 index 0000000..07fc935 --- /dev/null +++ b/src/openvpn/multi_io.h @@ -0,0 +1,77 @@ +/* + * 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-2023 OpenVPN Inc + * + * 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; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * Multi-protocol specific code for --mode server + */ + +#ifndef MULTI_IO_H +#define MULTI_IO_H + +#include "event.h" + +/* + * I/O processing 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 Multi-protocol + */ +struct multi_protocol +{ + struct event_set *es; + struct event_set_return *esr; + int n_esr; + int maxevents; + unsigned int tun_rwflags; + unsigned int udp_flags; +#ifdef ENABLE_MANAGEMENT + unsigned int management_persist_flags; +#endif +}; + +struct multi_protocol *multi_protocol_init(int maxevents, int *maxclients); + +void multi_protocol_free(struct multi_protocol *multi_io); + +int multi_protocol_io_wait(struct multi_context *m); + +void multi_protocol_process_io(struct multi_context *m); + +void multi_protocol_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll); + +void multi_protocol_delete_event(struct multi_protocol *multi_io, event_t event); + +#endif /* ifndef MULTI_IO_H */ diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index f152071..5c7186e 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1123,7 +1123,9 @@ /* force binding IPv6-only if an address was specified * an it is a IPv6 */ if (sock->local_host && ai_family == AF_INET6) + { v6only = true; + } socket_bind(sock->sd, sock->info.lsa->bind_local, ai_family, "TCP/UDP", v6only);