From patchwork Thu Apr 15 03:39:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 12204207 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 519BBC433ED for ; Thu, 15 Apr 2021 03:41:56 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9ED56611F1 for ; Thu, 15 Apr 2021 03:41:55 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9ED56611F1 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:53108 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lWst8-0001gj-PF for qemu-devel@archiver.kernel.org; Wed, 14 Apr 2021 23:41:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51164) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3jLV3YAMKCt8EKFHPPHMF.DPNRFNV-EFWFMOPOHOV.PSH@flex--dje.bounces.google.com>) id 1lWsrJ-0000JM-7g for qemu-devel@nongnu.org; Wed, 14 Apr 2021 23:40:01 -0400 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]:33590) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3jLV3YAMKCt8EKFHPPHMF.DPNRFNV-EFWFMOPOHOV.PSH@flex--dje.bounces.google.com>) id 1lWsrH-0004jv-D2 for qemu-devel@nongnu.org; Wed, 14 Apr 2021 23:40:01 -0400 Received: by mail-pj1-x104a.google.com with SMTP id p11-20020a17090ad30bb029014dcd9154e1so2972120pju.0 for ; Wed, 14 Apr 2021 20:39:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=p1ab23m8r3m0UpAYw3EBQJeJa7d9BxO3N5r4kXpaF/Q=; b=PdwN59aHghGVYCHLuKvgPvuFiWa9A7gkL5P4UUc/OfoBWbEDbE7C1Zv0hQmDIDyTkq LNU3jGhawih/1GBvltgDV4+j6RdKzK2jaDaO4gKPDgGgPoQHiW5/m+6kilFydAFYQOKB 93egm3A7v2+5MWeMJ3PY238TW3P/p/GrZeMYQKDqbOVB/RU73pbryGpS0j6XYLDQKGDD XpJmx3OdA0VxRwZeK+CKa89WN/WZ1toat1i1EVyqy0Q7+h/o+w+zDmlkEjfIC3umaojY 4zlObfMehxwJbxa7/Otm79Gz60gnfL6Fwpm/4fYyBlKSwNe1l4l5arZHCytAVToHVxOB VudQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=p1ab23m8r3m0UpAYw3EBQJeJa7d9BxO3N5r4kXpaF/Q=; b=Oqie51F31BdX79nQhk8NGRdjsQe31ouR0Ir217q+a0Q9CtF4ZpScvAEkttO7t4MlNE AORlFyafRDsiOByH7FuoTevdwwCSDN4WRKTQhxdEOalhNZKJYYzpaSLvDzVMRdIkZFsX /csOB8UTY6/SjgTWKrUAcT9WGOkj9+xTfIMugYLd45WTAxCp7KEH1GBXzDt+jpEKm0z0 GcTCw+Fth6IqAABP+jOdYESHgT0Jf3O3CCB0f9u4rP39hP1yIlWBVvE3REgWoo3rXMNz qcsRMgYfQvKcIndUz0lvW6B9TJGtHV0ouMb+dZ+H2dYu+NARMiJLHeOaaPT53VvUVdwn 3Z9A== X-Gm-Message-State: AOAM533vPBH7/GAo2mIh41cRZshz1Zk0Gavf34dooRTCem2JdBx8Awgg 89Sw/ZlmMZua04HbPl8lsi2hCGIQ0KQsoh+1G80qZDMH+CplC/2b1niXqS9O6Dis1nYKszjdbdL 3BkrSfMu8rlB1bt4seFiWeCN6IrWTjAmNIjj/K9cf3R1ld5H66HZ8 X-Google-Smtp-Source: ABdhPJyvbn3CFkxmr0eOP9FLwnYIueXzpvYi6xKdIzYgQ7iwKyaTqbmAIkle9I85A2VYhxFWUMCPOuA= X-Received: from ruffy.mtv.corp.google.com ([2620:0:1000:1412:83d5:e012:e680:1449]) (user=dje job=sendgmr) by 2002:a63:4652:: with SMTP id v18mr1583950pgk.386.1618457996899; Wed, 14 Apr 2021 20:39:56 -0700 (PDT) Date: Wed, 14 Apr 2021 20:39:22 -0700 In-Reply-To: <20210415033925.1290401-1-dje@google.com> Message-Id: <20210415033925.1290401-2-dje@google.com> Mime-Version: 1.0 References: <20210415033925.1290401-1-dje@google.com> X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH v6 1/4] slirp: Advance libslirp submodule to add ipv6 host-forward support From: Doug Evans To: qemu-devel@nongnu.org Cc: Samuel Thibault , " =?utf-8?q?Daniel_P_?= =?utf-8?q?=2E_Berrang=C3=A9?= " , Doug Evans Received-SPF: pass client-ip=2607:f8b0:4864:20::104a; envelope-from=3jLV3YAMKCt8EKFHPPHMF.DPNRFNV-EFWFMOPOHOV.PSH@flex--dje.bounces.google.com; helo=mail-pj1-x104a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" 5eraph (2): disable_dns option limit vnameserver_addr to port 53 Akihiro Suda (1): libslirp.h: fix SlirpConfig v3 documentation Doug Evans (11): Add ipv6 host forward support tcpx_listen: Pass sizeof(addr) to memset Reject host forwarding to ipv6 "addr-any" Add /build/ to .gitignore New utility slirp_ether_ntoa m_cleanup_list: make static New API routine slirp_neighbor_info Move DEBUG_CALL("if_start") to DEBUG_VERBOSE_CALL tcpx_listen: tcp_newtcpcb doesn't fail slirp_add_host*fwd: Ensure all error paths set errno Perform lazy guest address resolution for IPv6 Dr. David Alan Gilbert (1): ip_stripoptions use memmove Giuseppe Scrivano (1): socket: consume empty packets Hafiz Abid Qadeer (1): Fix a typo that can cause slow socket response on Windows. Jindrich Novy (4): Fix possible infinite loops and use-after-free Use secure string copy to avoid overflow Be sure to initialize sockaddr structure Check lseek() for failure Marc-André Lureau (26): Merge branch 'master' into 'master' Merge branch 'fix-slirpconfig-3-doc' into 'master' Fix use-afte-free in ip_reass() (CVE-2020-1983) Update CHANGELOG Merge branch 'cve-2020-1983' into 'master' Release v4.3.0 Merge branch 'release-v4.3.0' into 'master' changelog: post-release util: do not silently truncate Merge branch 'slirp-fmt-truncate' into 'master' Release v4.3.1 Merge branch 'release-v4.3.1' into 'master' changelog: post-release .gitlab-ci: add a Coverity stage Merge branch 'coverity' into 'master' Merge branch 'ios-support' into 'master' Merge branch 'master' into 'master' Remove the QEMU-special make build-system Merge branch 'qemu' into 'master' Release v4.4.0 Merge branch '4.4.0-release' into 'master' changelog: post-release Remove some needless (void)casts Fix unused variables Merge branch 'gitignore-build' into 'master' Merge branch 'macos-deployment-target' into 'master' Nathaniel Wesley Filardo (1): fork_exec_child_setup: improve signal handling Paolo Bonzini (2): meson: remove meson-dist script meson: support compiling as subproject Philippe Mathieu-Daudé (3): Fix win32 builds by using the SLIRP_PACKED definition Fix constness warnings Remove unnecessary break Prasad J Pandit (1): slirp: check pkt_len before reading protocol header Ralf Haferkamp (2): Drop bogus IPv6 messages Fix MTU check Samuel Thibault (45): Merge branch 'ip6_payload_len' into 'master' Merge branch 'lp1878043' into 'master' udp, udp6, icmp: handle TTL value icmp, icmp6: Add icmp_forward_error and icmp6_forward_error udp, udp6, icmp, icmp6: Enable forwarding errors on Linux TCPIPHDR_DELTA: Fix potential negative value sosendoob: better document what urgc is used for Merge branch 'G_GNUC_PRINTF' into 'master' Merge branch 'CVE-2020-29129' into 'master' Merge branch 'ttl' into 'master' Merge branch 'errors' into 'master' Merge branch 'consume-empty-packet' into 'master' Merge branch 'void' into 'master' Merge branch 'master' into 'master' Merge branch 'unused' into 'master' Merge branch 'socket_delay' into 'master' tcp_subr: simplify code Merge branch 'ipv6-host-fwd-9-patch' into 'master' Document the slirp API Complete timeout documentation Merge branch 'memset-sizeof' into 'master' Merge branch 'reject-ipv6-addr-any' into 'master' ip6_output: fix memory leak on fast-send Merge branch 'ndp-leak' into 'master' Merge branch 'memory_leaks' into 'master' TODO for generalizing the hostfwd calls socket.h: add missing sbuf.h inclusion Expose udpx_listen and tcpx_listen as taking sockaddr Disable polling for PRI on MacOS Merge branch 'macos-pri' into 'master' Merge branch 'x_listen' into 'master' udpx/tcpx_listen: Add missing const qualifier sockaddr_*: add missing const qualifiers Merge branch 'm-cleanup-list-prototype' into 'master' Merge branch 'neighbor-info' into 'master' udpx/tcpx_listen: Use struct sockaddr * types Add ipv4/ipv6-agnostic host forwarding functions hostfwd: Add SLIRP_HOSTFWD_V6ONLY flag Merge branch 'hostxfwd' into 'master' Merge branch 'verbose-if-start' into 'master' Remove slirp_add/remove_ipv6_hostfwd Merge branch 'listen-errno' into 'master' Merge branch 'newtcpcb-no-fail' into 'master' Merge branch 'listen_v6only' into 'master' Merge branch 'lazy-ipv6-resolution' into 'master' Stefan Weil (1): Add G_GNUC_PRINTF to local function slirp_vsnprintf WaluigiWare64 (1): Set macOS deployment target to macOS 10.4 Without a macOS deployment target, the resulting library does not work on macOS versions lower than it was currently built on. For example, if libslirp was built on macOS 10.15, it would not work on macOS 10.14. jeremy marchand (4): m_free: remove the M_EXT flag after freeing the mbuf extended buffer refactor m_cleanup as requested in slirp/libslirp!68 m_cleanup: fix memory leaks m_cleanup: set qh_link and qh_rlink to the list head osy (1): Add DNS resolving for iOS Signed-off-by: Doug Evans Reviewed-by: Marc-André Lureau --- Changes from v5: 1/4 slirp: Advance libslirp submodule to current master NOTE TO REVIEWERS: It may be a better use of everyone's time if a maintainer takes on advancing QEMU's libslirp to libslirp's master. Beyond that, I really don't know what to do except submit this patch as is currently provided. slirp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp b/slirp index 8f43a99191..4e6444e842 160000 --- a/slirp +++ b/slirp @@ -1 +1 @@ -Subproject commit 8f43a99191afb47ca3f3c6972f6306209f367ece +Subproject commit 4e6444e842695a6bfb00e15a8d0edfceb5c4628d From patchwork Thu Apr 15 03:39:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 12204209 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A1E64C433B4 for ; Thu, 15 Apr 2021 03:42:07 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2377C6120E for ; Thu, 15 Apr 2021 03:42:07 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2377C6120E Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:53284 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lWstK-0001l8-7R for qemu-devel@archiver.kernel.org; Wed, 14 Apr 2021 23:42:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51180) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3j7V3YAMKCuIHNIKSSKPI.GSQUIQY-HIZIPRSRKRY.SVK@flex--dje.bounces.google.com>) id 1lWsrL-0000LI-IA for qemu-devel@nongnu.org; Wed, 14 Apr 2021 23:40:03 -0400 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]:35341) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3j7V3YAMKCuIHNIKSSKPI.GSQUIQY-HIZIPRSRKRY.SVK@flex--dje.bounces.google.com>) id 1lWsrJ-0004lD-LX for qemu-devel@nongnu.org; Wed, 14 Apr 2021 23:40:03 -0400 Received: by mail-pf1-x449.google.com with SMTP id t17-20020a056a001391b02902472d81c024so2040767pfg.2 for ; Wed, 14 Apr 2021 20:40:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=BF27c8tCK2QEDJ0jFvx+k383ni9FkfA0jQaGoYxDeIY=; b=clFPWOHNKhujnFRdU/t+88+NgMso048nAD1SlNs0WfA7HJCvWKjZu97tbXwf/UvL2G wc7K8HxM9meW2D4aF5qEFKQBowSkTrTv+IIh2W6sZhtsVQlCeK6NXNLf9DEoObdqffdc DaPXziTJyG6upTP22bjvVMCC+BL8+i7aeW1Ui+yFq/E1qbwkmOsBels3BeDVQoA8hXgE QJ+k2b5MO5FFXLCeDl2N4mFnGH6yqIogfWl29VxTyyStz06fki1OVKvGObFk6uf7ttx1 F5qRGSp8qPfrw+OVoLmxK4MUW7jdM1bydrf+fLnrdsl7XUEhsJX1z/Cy9z3A4+azVQlP CC+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=BF27c8tCK2QEDJ0jFvx+k383ni9FkfA0jQaGoYxDeIY=; b=J948d5Bn5Ky4Khu0mjLfSBVTZaQ+Kn74mZ8MY5CRAQuW/RRITWPO09c7po7aFu+wkl ZmdMEgAqdCW1RyVhlBCyzy/VNR5IH4kiuDsbqG9M4Vr+dga8lFu4nmC9h0AZn57c6SNx h6dtORc5T3iPoPir3s9cN6hi7HC7VAjXLxMshIs7vVqHxdBrErEEcLUMU9rLc2MO1SiG 4yXMgshfaMWHWeSJxNjHikjZ5X6dlFc1xUGbLSW2Hqx4N+xs6B/ws+Hl4RPIw+6lCl/g qe8Pu+VYSj8ykcZhkDreXxXz/0Gdx+N09eHuw3dZ8Q6ZkLFhTpXId5lZ5YOkxKvcvndQ qHLA== X-Gm-Message-State: AOAM533vCR5lkt3WijaeuCGhPXsZOABzqjOycwoi6UNav1x5Ro7Aj+og uH2QwyjmGLZDolhp4lC2J3+xvUbS7/hhV9dPyaolvGPjqyZqXGYtLA0pAnf9JlKyyvdE+AKG0U8 AxJUaquX9OGrgqULXI5lGdmQyuJksNu7uaMb/MYczVidXOx05/FI4 X-Google-Smtp-Source: ABdhPJyWiKzY49vGSFhN7KgtC9KEkqD9stqrp38G/uFr5LyejhAI+MucLs1OLQih9+dPiepoeZ7FKmk= X-Received: from ruffy.mtv.corp.google.com ([2620:0:1000:1412:83d5:e012:e680:1449]) (user=dje job=sendgmr) by 2002:a63:5807:: with SMTP id m7mr1535438pgb.73.1618457999316; Wed, 14 Apr 2021 20:39:59 -0700 (PDT) Date: Wed, 14 Apr 2021 20:39:23 -0700 In-Reply-To: <20210415033925.1290401-1-dje@google.com> Message-Id: <20210415033925.1290401-3-dje@google.com> Mime-Version: 1.0 References: <20210415033925.1290401-1-dje@google.com> X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH v6 2/4] util/qemu-sockets.c: Split host:port parsing out of inet_parse From: Doug Evans To: qemu-devel@nongnu.org Cc: Samuel Thibault , " =?utf-8?q?Daniel_P_?= =?utf-8?q?=2E_Berrang=C3=A9?= " , Doug Evans Received-SPF: pass client-ip=2607:f8b0:4864:20::449; envelope-from=3j7V3YAMKCuIHNIKSSKPI.GSQUIQY-HIZIPRSRKRY.SVK@flex--dje.bounces.google.com; helo=mail-pf1-x449.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The parsing is moved into new function inet_parse_host_port. Also split out is ipv4=flag, ipv6=flag processing into inet_parse_ipv46. This is done in preparation for using these functions in net/slirp.c. Signed-off-by: Doug Evans Reviewed-by: Marc-André Lureau --- Changes from v5: Also split out parsing of ipv4=on|off, ipv6=on|off include/qemu/sockets.h | 3 ++ util/qemu-sockets.c | 65 +++++++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 7d1f813576..94f4e8de83 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -31,6 +31,9 @@ int socket_set_fast_reuse(int fd); int inet_ai_family_from_address(InetSocketAddress *addr, Error **errp); +const char *inet_parse_host_port(InetSocketAddress *addr, + const char *str, Error **errp); +int inet_parse_ipv46(InetSocketAddress *addr, const char *optstr, Error **errp); int inet_parse(InetSocketAddress *addr, const char *str, Error **errp); int inet_connect(const char *str, Error **errp); int inet_connect_saddr(InetSocketAddress *saddr, Error **errp); diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 8af0278f15..c0069f2565 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -615,14 +615,12 @@ static int inet_parse_flag(const char *flagname, const char *optstr, bool *val, return 0; } -int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) +const char *inet_parse_host_port(InetSocketAddress *addr, const char *str, + Error **errp) { - const char *optstr, *h; char host[65]; char port[33]; - int to; int pos; - char *begin; memset(addr, 0, sizeof(*addr)); @@ -632,38 +630,32 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) host[0] = '\0'; if (sscanf(str, ":%32[^,]%n", port, &pos) != 1) { error_setg(errp, "error parsing port in address '%s'", str); - return -1; + return NULL; } } else if (str[0] == '[') { /* IPv6 addr */ if (sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos) != 2) { error_setg(errp, "error parsing IPv6 address '%s'", str); - return -1; + return NULL; } } else { /* hostname or IPv4 addr */ if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) { error_setg(errp, "error parsing address '%s'", str); - return -1; + return NULL; } } addr->host = g_strdup(host); addr->port = g_strdup(port); - /* parse options */ - optstr = str + pos; - h = strstr(optstr, ",to="); - if (h) { - h += 4; - if (sscanf(h, "%d%n", &to, &pos) != 1 || - (h[pos] != '\0' && h[pos] != ',')) { - error_setg(errp, "error parsing to= argument"); - return -1; - } - addr->has_to = true; - addr->to = to; - } + return str + pos; +} + +int inet_parse_ipv46(InetSocketAddress *addr, const char *optstr, Error **errp) +{ + char *begin; + begin = strstr(optstr, ",ipv4"); if (begin) { if (inet_parse_flag("ipv4", begin + 5, &addr->ipv4, errp) < 0) { @@ -678,6 +670,39 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) } addr->has_ipv6 = true; } + + return 0; +} + +int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) +{ + const char *optstr, *h; + int to; + int pos; + char *begin; + + optstr = inet_parse_host_port(addr, str, errp); + if (optstr == NULL) { + return -1; + } + + /* parse options */ + + if (inet_parse_ipv46(addr, optstr, errp) < 0) { + return -1; + } + + h = strstr(optstr, ",to="); + if (h) { + h += 4; + if (sscanf(h, "%d%n", &to, &pos) != 1 || + (h[pos] != '\0' && h[pos] != ',')) { + error_setg(errp, "error parsing to= argument"); + return -1; + } + addr->has_to = true; + addr->to = to; + } begin = strstr(optstr, ",keep-alive"); if (begin) { if (inet_parse_flag("keep-alive", begin + strlen(",keep-alive"), From patchwork Thu Apr 15 03:39:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 12204211 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CAE77C433ED for ; Thu, 15 Apr 2021 03:44:20 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 348146120E for ; Thu, 15 Apr 2021 03:44:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 348146120E Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:57612 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lWsvT-0003aP-Ak for qemu-devel@archiver.kernel.org; Wed, 14 Apr 2021 23:44:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51204) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3kbV3YAMKCuQJPKMUUMRK.IUSWKSa-JKbKRTUTMTa.UXM@flex--dje.bounces.google.com>) id 1lWsrN-0000Ox-Qy for qemu-devel@nongnu.org; Wed, 14 Apr 2021 23:40:05 -0400 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]:46779) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3kbV3YAMKCuQJPKMUUMRK.IUSWKSa-JKbKRTUTMTa.UXM@flex--dje.bounces.google.com>) id 1lWsrL-0004mI-8B for qemu-devel@nongnu.org; Wed, 14 Apr 2021 23:40:05 -0400 Received: by mail-pf1-x449.google.com with SMTP id b22-20020aa78ad60000b02902111131d63dso2048473pfd.13 for ; Wed, 14 Apr 2021 20:40:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=3tX84cwPvnNGoLgPdJWFKopUcMLTGMgYoo7gZbfKdUk=; b=V8eJ4HXZyYevzU7H/Wkp+v2JNsPBg7QM/P3We9j5yexjY9QOEe3hiIcSE4dJv+fCBx frgcDoiBlDgg3paul5RNvijeNAOQGbl3nlHtZzCF7Ro1TNhGOQ4tHC9nEGj6Fo342n9k 3SBEyiGNh+r8VPWnuY59+mIrmm7UIl/yYAfLRHknsXfWLfEiX0+UUnM//48x/btYPhSf JvPJuZRr0299EVx6Xw9QNZ2ndwn+bdiAwUhTxuaQ+S1vz7x6qIoC+Q/Aqxn8WYxfsi3K jtb6wvuM7vCxV/qYHNDauSYOFri5LeoyN9BeibFcgagDxbNT3ey6++6qn5tjmQyCIaii sdFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=3tX84cwPvnNGoLgPdJWFKopUcMLTGMgYoo7gZbfKdUk=; b=Gwoa0BX2m9/GHMsNIbmwKOqhZuzZxjaaZ9vzEuSBawWIYq9xxnEo4z/2tdVmet+nwA FjBgfawXKWm4nqj7Y7VuqQADOlNkUKwcfxzhb/cbb+s3flhYDl/Eu67w9xhRpyJWxJdR IX/n2O+14NPdM6s33834oZ+XfSThHSDHJCzWZqiTmBf8H1xV7x8rQgnqL7B0al+bpNHQ MG7q/c0WhqAZ2wbO9k9Kd46ziB6kG165vCyh3JtEdPZx9YrSqkehP2sMnfq0Z+3SMCIU m2bHUtmDwHl01T4VrTFfgTe+zf9qIKuky8BrVz3GH5vdnVD3RB8w0W7Ef1YfEEMaEple lAtg== X-Gm-Message-State: AOAM532zXgjml9vHQQE7R5NQJcR50A2qLC61E1aTCUx/KlIV7mgeoIN+ JM7dfJp9TZ3mXT01d7JkSCvSpRIYUHNzAba160447o2E4qEXKtUdDIfMx/EqKXYoA+tohAAja1L u82iSU0tAz3N4ddyoKXW1kAkX76v3KqK3Qdwc3tedCiBfQRo/Nrah X-Google-Smtp-Source: ABdhPJyv+7/qscGmZAk5yXSb+NRZn1WCJPT5UrVpaTzhhuaBg+ummTL5zl35Ma6ufd4AaYk/BU+jZ3c= X-Received: from ruffy.mtv.corp.google.com ([2620:0:1000:1412:83d5:e012:e680:1449]) (user=dje job=sendgmr) by 2002:a65:6282:: with SMTP id f2mr1513478pgv.289.1618458001530; Wed, 14 Apr 2021 20:40:01 -0700 (PDT) Date: Wed, 14 Apr 2021 20:39:24 -0700 In-Reply-To: <20210415033925.1290401-1-dje@google.com> Message-Id: <20210415033925.1290401-4-dje@google.com> Mime-Version: 1.0 References: <20210415033925.1290401-1-dje@google.com> X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH v6 3/4] net/slirp.c: Refactor address parsing From: Doug Evans To: qemu-devel@nongnu.org Cc: Samuel Thibault , " =?utf-8?q?Daniel_P_?= =?utf-8?q?=2E_Berrang=C3=A9?= " , Doug Evans Received-SPF: pass client-ip=2607:f8b0:4864:20::449; envelope-from=3kbV3YAMKCuQJPKMUUMRK.IUSWKSa-JKbKRTUTMTa.UXM@flex--dje.bounces.google.com; helo=mail-pf1-x449.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" ... in preparation for adding ipv6 host forwarding support. Tested: avocado run tests/acceptance/hostfwd.py Signed-off-by: Doug Evans --- Changes from v5: Use InetSocketAddress and getaddrinfo(). Use new libslirp calls: slirp_remove_hostxfwd, slirp_add_hostxfwd. include/qemu/sockets.h | 2 + net/slirp.c | 200 ++++++++++++++++++++++++------------ tests/acceptance/hostfwd.py | 91 ++++++++++++++++ util/qemu-sockets.c | 17 +-- 4 files changed, 241 insertions(+), 69 deletions(-) create mode 100644 tests/acceptance/hostfwd.py diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 94f4e8de83..6fd71775ce 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -29,6 +29,8 @@ int socket_set_fast_reuse(int fd); #define SHUT_RDWR 2 #endif +int sockaddr_getport(const struct sockaddr *addr); + int inet_ai_family_from_address(InetSocketAddress *addr, Error **errp); const char *inet_parse_host_port(InetSocketAddress *addr, diff --git a/net/slirp.c b/net/slirp.c index a01a0fccd3..4be065c30b 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -641,15 +641,108 @@ static SlirpState *slirp_lookup(Monitor *mon, const char *id) } } +static const char *parse_protocol(const char *str, bool *is_udp, + Error **errp) +{ + char buf[10]; + const char *p = str; + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + error_setg(errp, "missing protocol name separator"); + return NULL; + } + + if (!strcmp(buf, "tcp") || buf[0] == '\0') { + *is_udp = false; + } else if (!strcmp(buf, "udp")) { + *is_udp = true; + } else { + error_setg(errp, "bad protocol name '%s'", buf); + return NULL; + } + + return p; +} + +static int parse_hostfwd_sockaddr(const char *str, int socktype, + struct sockaddr_storage *saddr, + Error **errp) +{ + struct addrinfo hints, *res = NULL, *e; + InetSocketAddress *addr = g_new(InetSocketAddress, 1); + int gai_rc; + int rc = -1; + + const char *optstr = inet_parse_host_port(addr, str, errp); + if (optstr == NULL) { + goto fail_return; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; /* ignored if host is not ""(->NULL) */ + hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; + hints.ai_socktype = socktype; + hints.ai_family = PF_INET; + + /* + * Calling getaddrinfo for guest addresses is dubious, but addresses are + * restricted to numeric only. Convert "" to NULL for getaddrinfo's + * benefit. + */ + gai_rc = getaddrinfo(*addr->host ? addr->host : NULL, + *addr->port ? addr->port : NULL, &hints, &res); + if (gai_rc != 0) { + error_setg(errp, "address resolution failed for '%s': %s", + str, gai_strerror(gai_rc)); + goto fail_return; + } + if (res->ai_next != NULL) { + /* + * The caller only wants one address, and except for "any" for both + * ipv4 and ipv6 (which we've already precluded above), we shouldn't + * get more than one. To assist debugging print all we find. + */ + GString *s = g_string_new(NULL); + for (e = res; e != NULL; e = e->ai_next) { + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + int ret = getnameinfo((struct sockaddr *)e->ai_addr, e->ai_addrlen, + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret == 0) { + g_string_append_printf(s, "\n %s:%s", host, serv); + } else { + g_string_append_printf(s, "\n unknown, got: %s", + gai_strerror(ret)); + } + } + error_setg(errp, "multiple addresses resolved for '%s':%s", + str, s->str); + g_string_free(s, TRUE); + goto fail_return; + } + + memcpy(saddr, res->ai_addr, res->ai_addrlen); + rc = 0; + + fail_return: + qapi_free_InetSocketAddress(addr); + if (res) { + freeaddrinfo(res); + } + return rc; +} + void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict) { - struct in_addr host_addr = { .s_addr = INADDR_ANY }; - int host_port; - char buf[256]; + struct sockaddr_storage host_addr; const char *src_str, *p; SlirpState *s; - int is_udp = 0; + bool is_udp; + Error *error = NULL; int err; + int flags = 0; const char *arg1 = qdict_get_str(qdict, "arg1"); const char *arg2 = qdict_get_try_str(qdict, "arg2"); @@ -664,110 +757,91 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict) return; } + g_assert(src_str != NULL); p = src_str; - if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (!strcmp(buf, "tcp") || buf[0] == '\0') { - is_udp = 0; - } else if (!strcmp(buf, "udp")) { - is_udp = 1; - } else { + p = parse_protocol(p, &is_udp, &error); + if (p == NULL) { goto fail_syntax; } - - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { - goto fail_syntax; + if (is_udp) { + flags |= SLIRP_HOSTFWD_UDP; } - if (qemu_strtoi(p, NULL, 10, &host_port)) { + if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM, + &host_addr, &error) < 0) { goto fail_syntax; } - err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port); + err = slirp_remove_hostxfwd(s->slirp, (struct sockaddr *) &host_addr, + sizeof(host_addr), flags); monitor_printf(mon, "host forwarding rule for %s %s\n", src_str, err ? "not found" : "removed"); return; fail_syntax: - monitor_printf(mon, "invalid format\n"); + monitor_printf(mon, "Invalid format: %s\n", error_get_pretty(error)); + error_free(error); } static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) { - struct in_addr host_addr = { .s_addr = INADDR_ANY }; - struct in_addr guest_addr = { .s_addr = 0 }; - int host_port, guest_port; + struct sockaddr_storage host_addr, guest_addr; const char *p; char buf[256]; - int is_udp; - char *end; - const char *fail_reason = "Unknown reason"; + bool is_udp; + Error *error = NULL; + int flags = 0; + int port; + g_assert(redir_str != NULL); p = redir_str; - if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - fail_reason = "No : separators"; - goto fail_syntax; - } - if (!strcmp(buf, "tcp") || buf[0] == '\0') { - is_udp = 0; - } else if (!strcmp(buf, "udp")) { - is_udp = 1; - } else { - fail_reason = "Bad protocol name"; - goto fail_syntax; - } - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - fail_reason = "Missing : separator"; + p = parse_protocol(p, &is_udp, &error); + if (p == NULL) { goto fail_syntax; } - if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { - fail_reason = "Bad host address"; - goto fail_syntax; + if (is_udp) { + flags |= SLIRP_HOSTFWD_UDP; } if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) { - fail_reason = "Bad host port separator"; - goto fail_syntax; - } - host_port = strtol(buf, &end, 0); - if (*end != '\0' || host_port < 0 || host_port > 65535) { - fail_reason = "Bad host port"; + error_setg(&error, "missing host-guest separator"); goto fail_syntax; } - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - fail_reason = "Missing guest address"; + if (parse_hostfwd_sockaddr(buf, is_udp ? SOCK_DGRAM : SOCK_STREAM, + &host_addr, &error) < 0) { + error_prepend(&error, "For host address: "); goto fail_syntax; } - if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) { - fail_reason = "Bad guest address"; + + if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM, + &guest_addr, &error) < 0) { + error_prepend(&error, "For guest address: "); goto fail_syntax; } - - guest_port = strtol(p, &end, 0); - if (*end != '\0' || guest_port < 1 || guest_port > 65535) { - fail_reason = "Bad guest port"; + port = sockaddr_getport((struct sockaddr *) &guest_addr); + if (port == 0) { + error_setg(&error, "For guest address: invalid port '0'"); goto fail_syntax; } - if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, - guest_port) < 0) { - error_setg(errp, "Could not set up host forwarding rule '%s'", - redir_str); + if (slirp_add_hostxfwd(s->slirp, + (struct sockaddr *) &host_addr, sizeof(host_addr), + (struct sockaddr *) &guest_addr, sizeof(guest_addr), + flags) < 0) { + error_setg(errp, "Could not set up host forwarding rule '%s': %s", + redir_str, strerror(errno)); return -1; } return 0; fail_syntax: error_setg(errp, "Invalid host forwarding rule '%s' (%s)", redir_str, - fail_reason); + error_get_pretty(error)); + error_free(error); return -1; } diff --git a/tests/acceptance/hostfwd.py b/tests/acceptance/hostfwd.py new file mode 100644 index 0000000000..9b9db142c3 --- /dev/null +++ b/tests/acceptance/hostfwd.py @@ -0,0 +1,91 @@ +# Hostfwd command tests +# +# Copyright 2021 Google LLC +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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. + + +from avocado_qemu import Test + + +class Hostfwd(Test): + """ + :avocado: tags=hostfwd + """ + def hmc(self, cmd): + return self.vm.command('human-monitor-command', command_line=cmd) + + def test_qmp_hostfwd_ipv4(self): + self.vm.add_args('-nodefaults', + '-netdev', 'user,id=vnet', + '-device', 'virtio-net,netdev=vnet') + self.vm.launch() + self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022-:22'), '') + self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022'), + 'host forwarding rule for tcp::65022 removed\r\n') + self.assertEquals(self.hmc('hostfwd_add tcp::65022-:22'), '') + self.assertEquals(self.hmc('hostfwd_remove tcp::65022'), + 'host forwarding rule for tcp::65022 removed\r\n') + self.assertEquals(self.hmc('hostfwd_add udp::65042-:42'), '') + self.assertEquals(self.hmc('hostfwd_remove udp::65042'), + 'host forwarding rule for udp::65042 removed\r\n') + + def test_qmp_hostfwd_ipv4_functional_errors(self): + """Verify handling of various kinds of errors given valid addresses.""" + self.vm.add_args('-nodefaults', + '-netdev', 'user,id=vnet', + '-device', 'virtio-net,netdev=vnet') + self.vm.launch() + self.assertEquals(self.hmc('hostfwd_remove ::65022'), + 'host forwarding rule for ::65022 not found\r\n') + self.assertEquals(self.hmc('hostfwd_add udp::65042-:42'), '') + self.assertEquals(self.hmc('hostfwd_add udp::65042-:42'), + "Could not set up host forwarding rule" + \ + " 'udp::65042-:42': Address already in use\r\n") + self.assertEquals(self.hmc('hostfwd_remove ::65042'), + 'host forwarding rule for ::65042 not found\r\n') + self.assertEquals(self.hmc('hostfwd_remove udp::65042'), + 'host forwarding rule for udp::65042 removed\r\n') + self.assertEquals(self.hmc('hostfwd_remove udp::65042'), + 'host forwarding rule for udp::65042 not found\r\n') + + def test_qmp_hostfwd_ipv4_parsing_errors(self): + """Verify handling of various kinds of parsing errors.""" + self.vm.add_args('-nodefaults', + '-netdev', 'user,id=vnet', + '-device', 'virtio-net,netdev=vnet') + self.vm.launch() + self.assertEquals(self.hmc('hostfwd_remove abc::42'), + "Invalid format: bad protocol name 'abc'\r\n") + self.assertEquals(self.hmc('hostfwd_add abc::65022-:22'), + "Invalid host forwarding rule 'abc::65022-:22'" + \ + " (bad protocol name 'abc')\r\n") + self.assertEquals(self.hmc('hostfwd_add :foo'), + "Invalid host forwarding rule ':foo'" + \ + " (missing host-guest separator)\r\n") + self.assertEquals(self.hmc('hostfwd_add :a.b.c.d:66-:66'), + "Invalid host forwarding rule ':a.b.c.d:66-:66'" + \ + " (For host address: address resolution failed for" \ + " 'a.b.c.d:66': Name or service not known)\r\n") + self.assertEquals(self.hmc('hostfwd_add ::66-a.b.c.d:66'), + "Invalid host forwarding rule '::66-a.b.c.d:66'" + \ + " (For guest address: address resolution failed" + \ + " for 'a.b.c.d:66': Name or service not known)\r\n") + self.assertEquals(self.hmc('hostfwd_add ::-1-foo'), + "Invalid host forwarding rule '::-1-foo'" + \ + " (For host address: error parsing port in" + \ + " address ':')\r\n") + self.assertEquals(self.hmc('hostfwd_add ::66-foo'), + "Invalid host forwarding rule '::66-foo' (For" + \ + " guest address: error parsing address 'foo')\r\n") + self.assertEquals(self.hmc('hostfwd_add ::66-:0'), + "Invalid host forwarding rule '::66-:0'" + \ + " (For guest address: invalid port '0')\r\n") diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index c0069f2565..983efeee2f 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -46,23 +46,28 @@ #endif -static int inet_getport(struct addrinfo *e) +int sockaddr_getport(const struct sockaddr *addr) { - struct sockaddr_in *i4; - struct sockaddr_in6 *i6; + const struct sockaddr_in *i4; + const struct sockaddr_in6 *i6; - switch (e->ai_family) { + switch (addr->sa_family) { case PF_INET6: - i6 = (void*)e->ai_addr; + i6 = (void *)addr; return ntohs(i6->sin6_port); case PF_INET: - i4 = (void*)e->ai_addr; + i4 = (void *)addr; return ntohs(i4->sin_port); default: return 0; } } +static int inet_getport(struct addrinfo *e) +{ + return sockaddr_getport(e->ai_addr); +} + static void inet_setport(struct addrinfo *e, int port) { struct sockaddr_in *i4; From patchwork Thu Apr 15 03:39:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 12204213 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 91843C433B4 for ; Thu, 15 Apr 2021 03:46:21 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DE7D1611F1 for ; Thu, 15 Apr 2021 03:46:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DE7D1611F1 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:59790 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lWsxP-0004bu-VL for qemu-devel@archiver.kernel.org; Wed, 14 Apr 2021 23:46:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51230) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3lLV3YAMKCucMSNPXXPUN.LXVZNVd-MNeNUWXWPWd.XaP@flex--dje.bounces.google.com>) id 1lWsrQ-0000Tb-3L for qemu-devel@nongnu.org; Wed, 14 Apr 2021 23:40:08 -0400 Received: from mail-qv1-xf4a.google.com ([2607:f8b0:4864:20::f4a]:38444) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3lLV3YAMKCucMSNPXXPUN.LXVZNVd-MNeNUWXWPWd.XaP@flex--dje.bounces.google.com>) id 1lWsrN-0004nu-KP for qemu-devel@nongnu.org; Wed, 14 Apr 2021 23:40:07 -0400 Received: by mail-qv1-xf4a.google.com with SMTP id c18-20020a0cd6120000b029017e89b07723so927908qvj.5 for ; Wed, 14 Apr 2021 20:40:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=0eAktSp+0q4k860RAJZmoAP5ixLezya1TBl9Xu85hJA=; b=PLUAnPE+0cxO8ShGm/nLgxIP1pK+qp/nPtJyAWd65fXsVzAcoVGausYD/IJNHnQlfa uwEK5XT9Ag+1qQgQzDfKGeOrefwns95mwemzFYhuSfkvoUbmN0S2WIcsriuWpGOsJ5WC NXDiq0l90ITfAlghty/ZbAILUX8BkzSczV8OpyL/e3fxyNEud93IH06JrZtzUU7mlkCr 3gCbW5p+xFCRpGQp59gy8Ox8Xsn5zHRfOaWczmKJF624d2vfhL8xhV2ZHFjj86PnF8Dy w3RTujaxRyIIllc0SyHcEhWPJlCjxRLLzRXlYSxgSu1ZnY67Y4pDxRFHGz8aHFIbMSlk 1VaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=0eAktSp+0q4k860RAJZmoAP5ixLezya1TBl9Xu85hJA=; b=d2ir1OwaSxbllfXO7DC5Xfz7Os+Vb3ko6dnmJnjNmztOM3OQOSd4ZfosFAEIcYI/BX 6EBmoKcL3m1akZK/d1BrKTnyQPE7DB0IkCfccKPYe6xCrhHdatXYEugC3FeJ44ilfYF5 GxdJvDl26yPHXO8uI18OIL0Xj6KdFmi+1SD96DPXrN8rNFKP0gU1HZN58FJPjQJjh5TE 8eGKTMJkxfaVU6gDqZ89KiNj5acEqZqT0IB1PJcA7rmQvpPAKfMS083sA84e6efCj2o7 83PMmuarvTahGtamltODW8/4YH50eKNMqFL4CuT6q/RsPbmttgeEzzZbFEUNAhk0SZGm kHsg== X-Gm-Message-State: AOAM5306fUCguOK1utG+5vDuFb495E/TrYRh+6WCO58dtLUJAFzd8Wvx hOXPi2OGLrG9AEXBrL7SZzamI0fPKgWu9mAn7DNW1THJSz3K2b1Fqc/xtEb2Z/uZmHC8HDoMW5W ypHB0jKu+euo/K1abEB9So9wwcAoVjFNtEUzT1SR7g39ZLk+BJTm3 X-Google-Smtp-Source: ABdhPJzdfMzd48tsPCPAgUEwWlYbTyRd8YLuBfr5nX97SgmQ8prNj7qpCAp4TknH1av5pObzKAoKhfM= X-Received: from ruffy.mtv.corp.google.com ([2620:0:1000:1412:83d5:e012:e680:1449]) (user=dje job=sendgmr) by 2002:a05:620a:cc1:: with SMTP id b1mr1580087qkj.356.1618458004028; Wed, 14 Apr 2021 20:40:04 -0700 (PDT) Date: Wed, 14 Apr 2021 20:39:25 -0700 In-Reply-To: <20210415033925.1290401-1-dje@google.com> Message-Id: <20210415033925.1290401-5-dje@google.com> Mime-Version: 1.0 References: <20210415033925.1290401-1-dje@google.com> X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH v6 4/4] net: Extend host forwarding to support IPv6 From: Doug Evans To: qemu-devel@nongnu.org Cc: Samuel Thibault , " =?utf-8?q?Daniel_P_?= =?utf-8?q?=2E_Berrang=C3=A9?= " , Doug Evans Received-SPF: pass client-ip=2607:f8b0:4864:20::f4a; envelope-from=3lLV3YAMKCucMSNPXXPUN.LXVZNVd-MNeNUWXWPWd.XaP@flex--dje.bounces.google.com; helo=mail-qv1-xf4a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Net option "-hostfwd" now supports IPv6 addresses. Commands hostfwd_add, hostfwd_remove now support IPv6 addresses. Tested: avocado run tests/acceptance/hostfwd.py Signed-off-by: Doug Evans --- Changes from v5: Recognize ipv4=,ipv6= options. hmp-commands.hx | 18 ++++++- net/slirp.c | 54 +++++++++++++++++---- tests/acceptance/hostfwd.py | 94 +++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 11 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 435c591a1c..05f88e893b 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1322,7 +1322,8 @@ ERST { .name = "hostfwd_add", .args_type = "arg1:s,arg2:s?", - .params = "[netdev_id] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport", + .params = "[netdev_id] [tcp|udp]:[hostaddr]:hostport\n" + "[,ipv4=on|off][,ipv6=on|off]-[guestaddr]:guestport", .help = "redirect TCP or UDP connections from host to guest (requires -net user)", .cmd = hmp_hostfwd_add, }, @@ -1330,13 +1331,20 @@ ERST SRST ``hostfwd_add`` Redirect TCP or UDP connections from host to guest (requires -net user). + IPV6 addresses are wrapped in square brackets, IPV4 addresses are not. + + Examples: + hostfwd_add net0 tcp:127.0.0.1:10022-:22 + hostfwd_add net0 tcp:[::1]:10022-[fe80::1:2:3:4]:22 + hostfwd_add net0 ::10022,ipv6-:22 ERST #ifdef CONFIG_SLIRP { .name = "hostfwd_remove", .args_type = "arg1:s,arg2:s?", - .params = "[netdev_id] [tcp|udp]:[hostaddr]:hostport", + .params = "[netdev_id] [tcp|udp]:[hostaddr]:hostport\n" + "[,ipv4=on|off][,ipv6=on|off]", .help = "remove host-to-guest TCP or UDP redirection", .cmd = hmp_hostfwd_remove, }, @@ -1345,6 +1353,12 @@ ERST SRST ``hostfwd_remove`` Remove host-to-guest TCP or UDP redirection. + IPV6 addresses are wrapped in square brackets, IPV4 addresses are not. + + Examples: + hostfwd_remove net0 tcp:127.0.0.1:10022 + hostfwd_remove net0 tcp:[::1]:10022 + hostfwd_remove net0 ::10022,ipv6 ERST { diff --git a/net/slirp.c b/net/slirp.c index 4be065c30b..82d4b71bef 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -664,25 +664,55 @@ static const char *parse_protocol(const char *str, bool *is_udp, return p; } -static int parse_hostfwd_sockaddr(const char *str, int socktype, +static int parse_hostfwd_sockaddr(const char *str, int family, int socktype, struct sockaddr_storage *saddr, - Error **errp) + bool *v6_only, Error **errp) { struct addrinfo hints, *res = NULL, *e; InetSocketAddress *addr = g_new(InetSocketAddress, 1); int gai_rc; int rc = -1; + Error *err = NULL; const char *optstr = inet_parse_host_port(addr, str, errp); if (optstr == NULL) { goto fail_return; } + if (inet_parse_ipv46(addr, optstr, errp) < 0) { + goto fail_return; + } + + if (v6_only) { + bool v4 = addr->has_ipv4 && addr->ipv4; + bool v6 = addr->has_ipv6 && addr->ipv6; + *v6_only = v6 && !v4; + } + memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; /* ignored if host is not ""(->NULL) */ hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; hints.ai_socktype = socktype; - hints.ai_family = PF_INET; + hints.ai_family = inet_ai_family_from_address(addr, &err); + if (err) { + error_propagate(errp, err); + goto fail_return; + } + if (family != PF_UNSPEC) { + /* Guest must use same family as host (for now). */ + if (hints.ai_family != PF_UNSPEC && hints.ai_family != family) { + error_setg(errp, + "unexpected address family for %s: expecting %s", + str, family == PF_INET ? "ipv4" : "ipv6"); + goto fail_return; + } + hints.ai_family = family; + } + + /* For backward compatibility, treat an empty host spec as IPv4. */ + if (*addr->host == '\0' && hints.ai_family == PF_UNSPEC) { + hints.ai_family = PF_INET; + } /* * Calling getaddrinfo for guest addresses is dubious, but addresses are @@ -768,8 +798,8 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict) flags |= SLIRP_HOSTFWD_UDP; } - if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM, - &host_addr, &error) < 0) { + if (parse_hostfwd_sockaddr(p, PF_UNSPEC, is_udp ? SOCK_DGRAM : SOCK_STREAM, + &host_addr, /*v6_only=*/NULL, &error) < 0) { goto fail_syntax; } @@ -794,6 +824,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) Error *error = NULL; int flags = 0; int port; + bool v6_only; g_assert(redir_str != NULL); p = redir_str; @@ -811,14 +842,19 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) goto fail_syntax; } - if (parse_hostfwd_sockaddr(buf, is_udp ? SOCK_DGRAM : SOCK_STREAM, - &host_addr, &error) < 0) { + if (parse_hostfwd_sockaddr(buf, PF_UNSPEC, + is_udp ? SOCK_DGRAM : SOCK_STREAM, + &host_addr, &v6_only, &error) < 0) { error_prepend(&error, "For host address: "); goto fail_syntax; } + if (v6_only) { + flags |= SLIRP_HOSTFWD_V6ONLY; + } - if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM, - &guest_addr, &error) < 0) { + if (parse_hostfwd_sockaddr(p, host_addr.ss_family, + is_udp ? SOCK_DGRAM : SOCK_STREAM, + &guest_addr, /*v6_only=*/NULL, &error) < 0) { error_prepend(&error, "For guest address: "); goto fail_syntax; } diff --git a/tests/acceptance/hostfwd.py b/tests/acceptance/hostfwd.py index 9b9db142c3..f8493c5bdc 100644 --- a/tests/acceptance/hostfwd.py +++ b/tests/acceptance/hostfwd.py @@ -37,6 +37,17 @@ def test_qmp_hostfwd_ipv4(self): self.assertEquals(self.hmc('hostfwd_add udp::65042-:42'), '') self.assertEquals(self.hmc('hostfwd_remove udp::65042'), 'host forwarding rule for udp::65042 removed\r\n') + self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv4-:22'), '') + self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv4'), + 'host forwarding rule for tcp::65022,ipv4 removed\r\n') + self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv4=on-:22'), + '') + self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv4=on'), + 'host forwarding rule for tcp::65022,ipv4=on removed\r\n') + self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv6=off-:22'), + '') + self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv6=off'), + 'host forwarding rule for tcp::65022,ipv6=off removed\r\n') def test_qmp_hostfwd_ipv4_functional_errors(self): """Verify handling of various kinds of errors given valid addresses.""" @@ -89,3 +100,86 @@ def test_qmp_hostfwd_ipv4_parsing_errors(self): self.assertEquals(self.hmc('hostfwd_add ::66-:0'), "Invalid host forwarding rule '::66-:0'" + \ " (For guest address: invalid port '0')\r\n") + self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv4=abc-:22'), + "Invalid host forwarding rule" + \ + " 'tcp::65022,ipv4=abc-:22' (For host address:" + \ + " error parsing 'ipv4' flag '=abc')\r\n") + + def test_qmp_hostfwd_ipv6(self): + self.vm.add_args('-nodefaults', + '-netdev', 'user,id=vnet', + '-device', 'virtio-net,netdev=vnet') + self.vm.launch() + self.assertEquals(self.hmc('hostfwd_add vnet tcp:[::1]:65022-[fe80::1]:22'), + '') + self.assertEquals(self.hmc('hostfwd_remove vnet tcp:[::1]:65022'), + 'host forwarding rule for tcp:[::1]:65022 removed\r\n') + self.assertEquals(self.hmc('hostfwd_add udp:[::1]:65042-[fe80::1]:42'), + '') + self.assertEquals(self.hmc('hostfwd_remove udp:[::1]:65042'), + 'host forwarding rule for udp:[::1]:65042 removed\r\n') + self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv6=on-:22'), '') + self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv6=on'), + 'host forwarding rule for tcp::65022,ipv6=on removed\r\n') + self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv4=off-:22'), '') + self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv4=off'), + 'host forwarding rule for tcp::65022,ipv4=off removed\r\n') + + def test_qmp_hostfwd_ipv6_functional_errors(self): + """Verify handling of various kinds of errors given valid addresses.""" + self.vm.add_args('-nodefaults', + '-netdev', 'user,id=vnet', + '-device', 'virtio-net,netdev=vnet') + self.vm.launch() + self.assertEquals(self.hmc('hostfwd_remove :[::1]:65022'), + 'host forwarding rule for :[::1]:65022 not found\r\n') + self.assertEquals(self.hmc('hostfwd_add udp:[::1]:65042-[fe80::1]:42'), + '') + self.assertEquals(self.hmc('hostfwd_add udp:[::1]:65042-[fe80::1]:42'), + "Could not set up host forwarding rule" + \ + " 'udp:[::1]:65042-[fe80::1]:42': Address already in use\r\n") + self.assertEquals(self.hmc('hostfwd_remove :[::1]:65042'), + 'host forwarding rule for :[::1]:65042 not found\r\n') + self.assertEquals(self.hmc('hostfwd_remove udp:[::1]:65042'), + 'host forwarding rule for udp:[::1]:65042 removed\r\n') + self.assertEquals(self.hmc('hostfwd_remove udp:[::1]:65042'), + 'host forwarding rule for udp:[::1]:65042 not found\r\n') + + def test_qmp_hostfwd_ipv6_errors(self): + """Verify handling of various kinds of errors.""" + self.vm.add_args('-nodefaults', + '-netdev', 'user,id=vnet', + '-device', 'virtio-net,netdev=vnet') + self.vm.launch() + self.assertEquals(self.hmc('hostfwd_add :[::1-'), + "Invalid host forwarding rule ':[::1-'" + \ + " (For host address: error parsing IPv6 address '[::1')\r\n") + self.assertEquals(self.hmc('hostfwd_add :[::1]:66-[fe80::1'), + "Invalid host forwarding rule ':[::1]:66-[fe80::1'" + \ + " (For guest address: error parsing IPv6 address" + \ + " '[fe80::1')\r\n") + self.assertEquals(self.hmc('hostfwd_add :[:::]:66-foo'), + "Invalid host forwarding rule ':[:::]:66-foo'" + \ + " (For host address: address resolution failed for" + \ + " '[:::]:66': Name or service not known)\r\n") + self.assertEquals(self.hmc('hostfwd_add :[::1]-foo'), + "Invalid host forwarding rule ':[::1]-foo'" + \ + " (For host address: error parsing IPv6 address '[::1]')\r\n") + self.assertEquals(self.hmc('hostfwd_add :[::1]:66-[foo]'), + "Invalid host forwarding rule ':[::1]:66-[foo]'" + \ + " (For guest address: error parsing IPv6 address '[foo]')\r\n") + self.assertEquals(self.hmc('hostfwd_add :[::1]:66-[fe80::1]:0'), + "Invalid host forwarding rule ':[::1]:66-[fe80::1]:0'" + \ + " (For guest address: invalid port '0')\r\n") + self.assertEquals(self.hmc('hostfwd_add :[::1]:66-1.2.3.4:66'), + "Invalid host forwarding rule ':[::1]:66-1.2.3.4:66'" + \ + " (For guest address: address resolution failed for" + \ + " '1.2.3.4:66': Address family for hostname not supported)\r\n") + self.assertEquals(self.hmc('hostfwd_add :1.2.3.4:66-[fe80::1]:66'), + "Invalid host forwarding rule ':1.2.3.4:66-[fe80::1]:66'" + \ + " (For guest address: address resolution failed for" + \ + " '[fe80::1]:66': Address family for hostname not" + \ + " supported)\r\n") + self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv6=abc-:22'), + "Invalid host forwarding rule 'tcp::65022,ipv6=abc-:22'" + \ + " (For host address: error parsing 'ipv6' flag '=abc')\r\n")