From patchwork Mon Sep 23 13:41:30 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: 3862 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:10cd:b0:5b9:581e:f939 with SMTP id j13csp2172131mae; Mon, 23 Sep 2024 06:42:03 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCV2m6V1od321nfXltFvpgTifY2xe6wnNUxva4aIlsWoRypJEjaXMFHFFPq8c6EKzsceKW0ua+QKY4U=@openvpn.net X-Google-Smtp-Source: AGHT+IF9rNAJL1JF7X8k/1pSLAYlq9bAOiQ8X1xH2xpx9JgWNgWOyakcTT1hOgm8psRVL1/n4m1V X-Received: by 2002:a05:6870:8292:b0:260:fb01:5651 with SMTP id 586e51a60fabf-2803cf487e7mr6602378fac.12.1727098922382; Mon, 23 Sep 2024 06:42:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1727098922; cv=none; d=google.com; s=arc-20240605; b=C02oihqB7NDeksMNP3Z2Harxm2t8076/ruPlZY9augZLaVpVIdtxo/P+5O4Yw79Od7 E+9oSpKU9XuyR4hICsqEa070FoM5HkY5B7U+B67Ap4crixxq5E54G95O9VfECIWHwSyL Lx6I9IXvgWJFu4fC3tko40GTNXz/SdakS9GqA2MoqS9CGbKKv2L/chjQzbaA0I2TOTq8 W7PhQSJv66+kE0ifTl/PXSrlpmR7MfFrETeNzEaUKEkuHukygFcxrMdQ15faE2ulDbUd 4d5AwuVluw8M9POgdDAP77FONgm7jnVLXBslCQtaybm7AcPdCrRY1JlKZDGhCHM8lVFb IiMQ== 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=EVP+JW3HQgiKNMyvYAjnWUSnWmMl9zTLyoUnPOjzLdE=; fh=U7wEyxtwz2o5+UdevFSA47vNeG9knhWH0KV//QhD5a0=; b=i26mexaQUKDhrXuqxv2F2tyvplKMbzyIZaayb2HotC6Ry7kR7LCpsYxkfCoKjsm05E CIaQn2AacgRMwazoNLBuGcRpoS5uMgL1SIxUMB6KbOUmnby99CTnjmIGa9dzyF7zCaNJ 6mgYz3cbXEZhhAT7S5HGhkj8FUFSqMoboLpzn5CK5BWWB6mdO/h9TyErOC4hlwO3zGZG pv7uelLhMtsh/HM/LrVGtIBcHRy1j10ppNGaFFRnbXpG6XPeKzXPr6fsUsI0uMDfW646 7PiUM2xfHRI3EzO8RzJGUCnA9levwJOnq6sbxN9f+hhV8owNjEDwtCKxDgyr85Ps6nNV FkMA==; 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=ReqYso9Z; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=INZs4XTh; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b=CDtXOuq6; 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 586e51a60fabf-27d0b426fc7si4851826fac.125.2024.09.23.06.42.02 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Sep 2024 06:42:02 -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=ReqYso9Z; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=INZs4XTh; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b=CDtXOuq6; 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-3.v29.lw.sourceforge.com) by sfs-ml-3.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1ssjK3-0008Rm-UA; Mon, 23 Sep 2024 13:41:51 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-3.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1ssjJz-0008RZ-W3 for openvpn-devel@lists.sourceforge.net; Mon, 23 Sep 2024 13:41:47 +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=r67hVa907CxuYeFC2s+lCUOZ6XLmbqkNg7d3eghNwqA=; b=ReqYso9Z1hbdx3/S8KA6gL3mfG n3yquYwKMP2YyUVuKqhQqd+6vJnCLvrDosFlawbA2kALXrE1+mnEOHuChud6UAEsv8gluP0jtAGpJ XBsAwJC5ubzD+qxdVLsKRurEwAIptTtGB1IP6N4tXHsWju2f192VdDmz2ucI32+wAhXU=; 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=r67hVa907CxuYeFC2s+lCUOZ6XLmbqkNg7d3eghNwqA=; b=I NZs4XThEEgqECAGMA9eHs81MKniXsUvxAhz3sHPDaGiKZzH/0iM7Ar7+64ObViZkSkuNw2hj0823C s4S17xPOPUunFSXP2wY48z0cYWlLWuSBvK8pcyMpM0HMrFA6J67aUlnKhg0A8iUSFrJcjhM/rN1E8 yTTjf+WysoGqZYC4=; Received: from mail-wr1-f54.google.com ([209.85.221.54]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1ssjJv-0006rl-A8 for openvpn-devel@lists.sourceforge.net; Mon, 23 Sep 2024 13:41:47 +0000 Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-374c962e5adso2648992f8f.1 for ; Mon, 23 Sep 2024 06:41:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1727098892; x=1727703692; 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=r67hVa907CxuYeFC2s+lCUOZ6XLmbqkNg7d3eghNwqA=; b=CDtXOuq6bqEJ8BADTi/TR56GuQXKUqi+e+bdhybu7r9K1UpgMDGApgywjc4ExAoK4w zm9lRnU11QFzoadJ4CdlfUCvrx/wdQUO0zULtf8dlaGlVNozLGEMQWA/3dsw8HnpfNTZ fTZXZkhFyOnKojusrqk/UfWC/xSB0XcWt4FJswq7aoBDDTryXSCfMGenEpeYTLbuXeVO khm0i2MGP5dpX7ZRsrlZXsPLLHeuhqIKJPO+KalHcI7DWspaC92jOLdb+QDTHNGpLn81 YrAcgzgKRBtlsr8kFm6pP3hcQipG1rNifNOag412F/OY9KAn0wKUKVaDqeVyqu9YZUTt LthA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727098892; x=1727703692; 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=r67hVa907CxuYeFC2s+lCUOZ6XLmbqkNg7d3eghNwqA=; b=JfgWzTdwp9K05wIUU/SODL2BqTd/euUDxfTZHsdJxP/d/nZxICPbJ8FPOLMMKGRZ4U jz3Swvh7soLI2Da+R0vtA7GcfUGLqQjp2avov6UP3+cUi1bbMK5QCjybmWnuE0/9z4a0 FxR2UjZpYj6jpXvX8GniswAJDOOU5BLIG6PH5+lnWAorjijqoqcNxlhfd2IVBhvBgp3Q UQ8CXajy3zLEmASMjacGXkBJ0aiSEEjFdw3KfdRqqLLHsAsyTTrlxQY231KZh81ISiQe eDKbhSxc5z3q9JV/qXmXIzzE6HHEuRPdQwWG3ZTMzKhVgIcwb+UuCY6wC3V1U71Ze6jP UQZg== X-Gm-Message-State: AOJu0YypBOjzzZzi2pWkHiSTrAa5s+kg5Yt5WQafHyVaxcoBiYy7ZH8I LkvWro1eC90PWCS0Xh6Yvye2uG10iPGIyE8PcPmv70BhLGt6fNYY71Gg5dKksOc= X-Received: by 2002:a05:6000:18a1:b0:374:c6b6:c656 with SMTP id ffacd0b85a97d-37a415780d1mr10022114f8f.21.1727098891173; Mon, 23 Sep 2024 06:41:31 -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 ffacd0b85a97d-378e7800067sm24617761f8f.77.2024.09.23.06.41.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Sep 2024 06:41:30 -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:30 +0000 To: plaisthos , flichtenheld Auto-Submitted: auto-generated X-Gerrit-MessageType: newchange X-Gerrit-Change-Id: I31bbf87e4e568021445c7512ecefadfd4a69b363 X-Gerrit-Change-Number: 764 X-Gerrit-Project: openvpn X-Gerrit-ChangeURL: X-Gerrit-Commit: ade1309d237b01c462ca5b03619705a456488928 References: Message-ID: <2080b9e7d6e7f700844b3735ff6424243c019849-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-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: (-1.1 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.54 listed in list.dnswl.org] -0.9 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.221.54 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_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: 1ssjJv-0006rl-A8 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: 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?1810994479592220065?= X-GMAIL-MSGID: =?utf-8?q?1810994479592220065?= 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/+/764?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: I31bbf87e4e568021445c7512ecefadfd4a69b363 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/openvpn.h M src/openvpn/options.c M src/openvpn/options.h 14 files changed, 419 insertions(+), 278 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/64/764/1 diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 2246cf7..7559a71 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1764,7 +1764,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); } @@ -1805,8 +1805,8 @@ /* Send packet */ size = (int)link_socket_write(ls, - &c->c2.to_link, - to_addr); + &c->c2.to_link, + to_addr); /* Undo effect of prepend */ link_socket_write_post_size_adjust(&size, size_delta, &c->c2.to_link); @@ -2054,6 +2054,173 @@ */ void +get_io_flags_dowork_udp(struct context *c, struct multi_protocol *multi_io, const unsigned int flags) +{ + unsigned int socket = 0; + unsigned int tuntap = 0; + static uintptr_t tun_shift = 2; + static uintptr_t err_shift = 4; + + /* + * Calculate the flags based on the provided 'flags' argument. + */ + if (flags & IOW_WAIT_SIGNAL) + { + wait_signal(multi_io->es, (void *)err_shift); + } + + 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 (int i = 0; i < c->c1.link_sockets_num; i++) + { + if (proto_is_dgram(c->c2.link_sockets[i]->info.proto)) + { + socket_set(c->c2.link_sockets[i], multi_io->es, socket, + &c->c2.link_sockets[i]->ev_arg, NULL); + } + } + tun_set(c->c1.tuntap, multi_io->es, tuntap, (void *)tun_shift, NULL); + + multi_io->udp_flags = socket | tuntap; +} + +void +get_io_flags_udp(struct context *c, struct multi_protocol *multi_io, const unsigned int flags) +{ + multi_io->udp_flags = ES_ERROR; + 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; + } + multi_io->udp_flags = 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; + } + multi_io->udp_flags = ret; + } + else +#endif /* ifdef _WIN32 */ + { + /* slow path - delegate to io_wait_dowork_udp to calculate flags */ + get_io_flags_dowork_udp(c, multi_io, flags); + } + } +} + +void io_wait_dowork(struct context *c, const unsigned int flags) { unsigned int socket = 0; @@ -2295,6 +2462,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 3acbdd0..5fb631f 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -69,6 +69,10 @@ extern counter_type link_write_bytes_global; +void get_io_flags_dowork_udp(struct context *c, struct multi_protocol *multi_io, const unsigned int flags); + +void get_io_flags_udp(struct context *c, struct multi_protocol *multi_io, const unsigned int flags); + void io_wait_dowork(struct context *c, const unsigned int flags); void pre_select(struct context *c); diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 6f21752..c817ce6 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -3756,6 +3756,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) { @@ -3765,33 +3783,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, @@ -3801,7 +3823,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, @@ -4612,7 +4634,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)); } @@ -4876,7 +4898,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(); @@ -4904,6 +4926,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 f4539dc..6c8e8dd 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 8b457d4..fd1dbfe 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 { @@ -201,6 +202,10 @@ { return false; } + if (a1->proto != a2->proto) + { + return false; + } if (a1->netbits != a2->netbits) { return false; @@ -222,7 +227,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 29706d0..73f6bcc 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -54,7 +54,7 @@ struct hash *hash = m->hash; mi = multi_create_instance(m, NULL, ls); - if (mi) + if (mi && !proto_is_dgram(ls->info.proto)) { struct hash_element *he; const uint32_t hv = hash_value(hash, &mi->real); @@ -241,87 +241,3 @@ } return ret; } - -/* - * Top level event loop for single-threaded operation. - * TCP mode. - */ -void -tunnel_server_tcp(struct context *top) -{ - struct multi_context multi; - int status; - - 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, true); - - /* 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 - - /* per-packet event loop */ - while (true) - { - perf_push(PERF_EVENT_LOOP); - - /* wait on tun/socket list */ - multi_get_timeout(&multi, &multi.top.c2.timeval); - status = multi_protocol_io_wait(&multi); - 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_protocol_process_io(&multi); - MULTI_CHECK_SIG(&multi); - } - else if (status == 0) - { - multi_protocol_action(&multi, NULL, TA_TIMEOUT, false); - } - - perf_pop(); - } - -#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); -} diff --git a/src/openvpn/mtcp.h b/src/openvpn/mtcp.h index e48481a..1cc1a51 100644 --- a/src/openvpn/mtcp.h +++ b/src/openvpn/mtcp.h @@ -51,17 +51,6 @@ void multi_tcp_link_out_deferred(struct multi_context *m, struct multi_instance *mi); - -/**************************************************************************/ -/** - * Main event loop for OpenVPN in TCP server mode. - * @ingroup eventloop - * - * @param top - Top-level context structure. - */ -void tunnel_server_tcp(struct context *top); - - void multi_tcp_delete_event(struct multi_protocol *multi_io, event_t event); #endif /* ifndef MTCP_H */ diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 37af88e..a7e6e1d 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -192,6 +192,7 @@ struct mroute_addr real = {0}; 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) @@ -318,18 +319,66 @@ 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->multi_io->udp_flags; 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); @@ -427,123 +476,3 @@ } #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) -{ - 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, false); - - /* 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 udp */ - -#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 - - /* per-packet event loop */ - while (true) - { - perf_push(PERF_EVENT_LOOP); - - /* set up and do the io_wait() */ - multi_get_timeout(&multi, &multi.top.c2.timeval); - io_wait(&multi.top, p2mp_iow_flags(&multi)); - MULTI_CHECK_SIG(&multi); - - /* check on status of coarse timers */ - multi_process_per_second_timers(&multi); - - /* timeout? */ - if (multi.top.c2.event_set_status == ES_TIMEOUT) - { - multi_process_timeout(&multi, MPP_PRE_SELECT|MPP_CLOSE_ON_SIGNAL); - } - else - { - /* process I/O */ - multi_process_io_udp(&multi); - MULTI_CHECK_SIG(&multi); - } - - perf_pop(); - } - -#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); -} diff --git a/src/openvpn/mudp.h b/src/openvpn/mudp.h index b378754..68d2d6d 100644 --- a/src/openvpn/mudp.h +++ b/src/openvpn/mudp.h @@ -31,18 +31,9 @@ struct context; struct multi_context; +unsigned int p2mp_iow_flags(const struct multi_context *m); -/** - * Main event loop for OpenVPN in UDP server mode. - * @ingroup eventloop - * - * This function implements OpenVPN's main event loop for UDP server mode. - * - * @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 d7b4e3b..2d4fbe7 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,12 @@ 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 + * Initialize multi-socket I/O wait object */ - if (tcp_mode) - { - m->multi_io = multi_protocol_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,7 +664,7 @@ mi->did_iroutes = false; } - if (m->multi_io) + if (m->multi_io && !proto_is_dgram(m->top.options.ce.proto)) { multi_tcp_dereference_instance(m->multi_io, mi); } @@ -776,7 +775,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 +796,7 @@ { goto err; } + mi->real.proto = ls->info.proto; generate_prefix(mi); } @@ -4158,6 +4157,98 @@ ASSERT(mi->context.c2.tls_multi->peer_id < m->max_clients); } +/**************************************************************************/ +/** + * Main event loop for OpenVPN in multi-protocol server mode. + * @ingroup eventloop + * + * @param top - Top-level context structure. + */ +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_protocol_io_wait(multi); + 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_protocol_process_io(multi); + MULTI_CHECK_SIG(multi); + } + else if (status == 0) + { + multi_protocol_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. @@ -4167,12 +4258,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 a25aeda..65fd320 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -247,10 +247,8 @@ * Main event loop for OpenVPN in server mode. * @ingroup eventloop * - * This function calls the appropriate main event loop function depending - * on the transport protocol used: - * - \c tunnel_server_udp() - * - \c tunnel_server_tcp() + * This function calls the main event loop function + * on the transport protocols: * * @param top - Top-level context structure. */ @@ -263,7 +261,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); @@ -659,9 +657,12 @@ multi_process_outgoing_tun(struct multi_context *m, const unsigned int mpp_flags) { struct multi_instance *mi = m->pending; + if (!mi) + { + return false; + } bool ret = true; - ASSERT(mi); #ifdef MULTI_DEBUG_EVENT_LOOP printf("%s -> TUN len=%d\n", id(mi), diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 77bb41d..821ac2e 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -220,8 +220,8 @@ * \c SIGUSR1 restarts. * * This structure is initialized at the top of the \c - * tunnel_point_to_point(), \c tunnel_server_udp(), and \c - * tunnel_server_tcp() functions. In other words, it is reset for every + * tunnel_point_to_point(), \c tunnel_server() \c + * functions. In other words, it is reset for every * iteration of the \c main() function's inner \c SIGUSR1 loop. */ struct context_2 diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 25bdd44..42210da 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2199,6 +2199,7 @@ } ALLOC_OBJ_CLEAR_GC(e, struct local_entry, gc); + e->proto = PROTO_NONE; l->array[l->len++] = e; return e; @@ -3170,14 +3171,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; } } @@ -3331,6 +3348,10 @@ { le->port = o->ce.local_port; } + if (!le->proto) + { + le->proto = o->ce.proto; + } } #ifdef _WIN32 @@ -3822,6 +3843,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 */ @@ -6232,7 +6254,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; @@ -6253,7 +6275,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 6942455..f3cf7e5 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