From patchwork Fri May 28 23:53:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 12287543 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 681F0C47087 for ; Fri, 28 May 2021 23:56:10 +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 E0E296135F for ; Fri, 28 May 2021 23:56:09 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E0E296135F 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]:50318 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lmmKn-0002rI-0Z for qemu-devel@archiver.kernel.org; Fri, 28 May 2021 19:56:09 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45808) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3hoKxYAMKCl08E9BJJBG9.7JHL9HP-89Q9GIJIBIP.JMB@flex--dje.bounces.google.com>) id 1lmmIX-0006n8-HL for qemu-devel@nongnu.org; Fri, 28 May 2021 19:53:49 -0400 Received: from mail-qt1-x849.google.com ([2607:f8b0:4864:20::849]:35693) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3hoKxYAMKCl08E9BJJBG9.7JHL9HP-89Q9GIJIBIP.JMB@flex--dje.bounces.google.com>) id 1lmmIS-0007b2-FJ for qemu-devel@nongnu.org; Fri, 28 May 2021 19:53:49 -0400 Received: by mail-qt1-x849.google.com with SMTP id b17-20020ac854110000b02901f279c73d75so3076218qtq.2 for ; Fri, 28 May 2021 16:53:43 -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=M8b0vsLt2XgaiCDtDtAcA3tSbLGoNeCgbDqa4GhPBYU=; b=TwXNjxvUis0a/zv2APTjnMF0OQO0oIliByehpTTCVaaWilkhQMeVgXIz0XUoJZmRPk szxexLRgkQkQhsoW/iwyX0ZgnQWAh9IVbbvFqR4IwJ3F1RUtXkg+6/0ohlKune2O0HNU XyUxTVa6Zooz7H14pVdyegqFEu1+EYTgL1rfWGwwvGqVQuLOMS1eMpyw1cdXf0+j4UsT gsUcjEMnAOTpB9JK140S6F3qpdLkHYY1JBq4srDnQoN0XV3vPPuMKKFFyFt1eYlVb/5V 8Y6Oy5vH+tucdJzkGne+qJv4S/gaj0U53TfP8LAHF2gVoeNnXN5vseiUT+8zL9uadUch aliw== 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=M8b0vsLt2XgaiCDtDtAcA3tSbLGoNeCgbDqa4GhPBYU=; b=b9Al4Hvjd2LWSY4qGmg+KuzbxLnWS01/JJXSqC+so9v9lx/uh6FTq1jWwxW2XraQ9S lpop3QzISzW5Al9+EiwaivGZbniJttNhJZC88LME9txpBgpsPLrNG8TF3juobTEHdCUn JimcHiZHT+D75mhejhpyscMBXI95prqqjYJm7exqEsME7sntgWgcvH6RNChyT9rKUV2/ UBaCgDEyS5YcQeMe7QZGxM2h4qhll2K02AEnWayXio9KeWqPUZJwlY9cD7QwIL6c/hK3 kkQ3ic35elLgF77o++XtZhbmoQuLl7C+V37R2MLYMZJeFrFaQEtXxONGVRgt/ix7ebEk pXsA== X-Gm-Message-State: AOAM532ZwYwJPKI1tpsnw8lxb1k/pH4WTz/Mrv36c9+n2TtT9HUxk7gx /7/2RHIQJpDvVktA0LLjVNhpAwevKbUx0+7yLL8ja2dPnc/hy3eVWinGrxKyVU7WgPq256YiXqQ RqntzHkUmURgYaqUcqFPNsDs3MjWpIvssmbN4WZadfqX6l2tr2k5v X-Google-Smtp-Source: ABdhPJwkTJN5EET9irMmEqRdbizw7Ra9Wz2fVqK4U5xq9aejZHnWQnPYNhNfnWeRkejL2SELzJdgj9k= X-Received: from ruffy.mtv.corp.google.com ([2620:0:1000:1412:da9a:e3bd:2fe6:1f1b]) (user=dje job=sendgmr) by 2002:ae9:eb83:: with SMTP id b125mr6389912qkg.266.1622246022323; Fri, 28 May 2021 16:53:42 -0700 (PDT) Date: Fri, 28 May 2021 16:53:28 -0700 In-Reply-To: <20210528235331.3727583-1-dje@google.com> Message-Id: <20210528235331.3727583-2-dje@google.com> Mime-Version: 1.0 References: <20210528235331.3727583-1-dje@google.com> X-Mailer: git-send-email 2.32.0.rc0.204.g9fa02ecfa5-goog Subject: [PATCH v7 1/4] slirp: Advance libslirp submodule to 4.5 release From: Doug Evans To: qemu-devel@nongnu.org Cc: Samuel Thibault , " =?utf-8?q?Daniel_P_?= =?utf-8?q?=2E_Berrang=C3=A9?= " , " =?utf-8?q?Marc-An?= =?utf-8?q?dr=C3=A9_Lureau?= " , Maxim Samoylov , Doug Evans Received-SPF: pass client-ip=2607:f8b0:4864:20::849; envelope-from=3hoKxYAMKCl08E9BJJBG9.7JHL9HP-89Q9GIJIBIP.JMB@flex--dje.bounces.google.com; helo=mail-qt1-x849.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 (28): 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' Merge branch 'philmd' into 'master' Release v4.5.0 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é (4): Fix win32 builds by using the SLIRP_PACKED definition Fix constness warnings Remove unnecessary break Remove alloca() call in get_dns_addr_resolv_conf() Prasad J Pandit (1): slirp: check pkt_len before reading protocol header Ralf Haferkamp (2): Drop bogus IPv6 messages Fix MTU check Samuel Thibault (48): 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' ndp_table: For unspecified address, return broadcast ethernet address Merge branch 'master' into 'master' SlirpCb: explicit that it is fine for a guest to drop frames 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 --- Changes from v6: The libslirp parts of the patch have been committed to the libslirp repo, and are now in QEMU's copy of the libslirp repo. Advancing QEMU to use Libslirp v4.5.0 is being done separately. Discussion of patch 1/4 is left to that thread: https://lists.nongnu.org/archive/html/qemu-devel/2021-05/msg06010.html 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..a62890e711 160000 --- a/slirp +++ b/slirp @@ -1 +1 @@ -Subproject commit 8f43a99191afb47ca3f3c6972f6306209f367ece +Subproject commit a62890e71126795ca593affa747f669bed88e89c From patchwork Fri May 28 23:53:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 12287539 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 8B620C47087 for ; Fri, 28 May 2021 23:55:22 +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 14A386135F for ; Fri, 28 May 2021 23:55:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 14A386135F 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]:47802 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lmmK1-0001A4-4C for qemu-devel@archiver.kernel.org; Fri, 28 May 2021 19:55:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45822) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3iYKxYAMKCmABHCEMMEJC.AMKOCKS-BCTCJLMLELS.MPE@flex--dje.bounces.google.com>) id 1lmmIZ-0006pt-4k for qemu-devel@nongnu.org; Fri, 28 May 2021 19:53:51 -0400 Received: from mail-qv1-xf49.google.com ([2607:f8b0:4864:20::f49]:55255) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3iYKxYAMKCmABHCEMMEJC.AMKOCKS-BCTCJLMLELS.MPE@flex--dje.bounces.google.com>) id 1lmmIV-0007cG-72 for qemu-devel@nongnu.org; Fri, 28 May 2021 19:53:50 -0400 Received: by mail-qv1-xf49.google.com with SMTP id b5-20020a0cc9850000b02901eece87073bso3747425qvk.21 for ; Fri, 28 May 2021 16:53:45 -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=g75G9nzfdsGcprDSWEEutXj8kTbcMPgEVXd8OwbePoQ=; b=ulAAxh3OwcXWqWrznAFby8kPZQDL4q/EEQUJEHgR8QgFazMMmzzut61iFQZbNbomFW rbOafvTBQsyzYkYR7Oa4lgxC91vhikP4BKpDvlXkdxdYJP9OoiNEaNqfHR++AkXsTfvn jDdPFa86MmTifnrwFER1IEyiQtAhDV/I0C9MKk3QdsAKX4dZoDrzTDWdeMfR118wnuHM MeURIelDoOOP4QR6ZyTW6gSvp+KWiI5UKHzQ71wB8UbOuibwBRZxI2ftlVKLHmnx0mYK HhxbqBhwbhjQ2wfKwIi/x105+pvQkHOrhWP2y5anbmk9BpcwLr+5xEXV5AL8NovIU2/u rfWg== 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=g75G9nzfdsGcprDSWEEutXj8kTbcMPgEVXd8OwbePoQ=; b=hLHoovQRoHqZS15GUqaAa+FaYxPJ0NPVME10biIx9Ppgo5gLDcAFU+n/lNjqs6z1VC eyqiMkPtbmyr25N46Osr0iEM0NVhfHvDAYGy/rjRFb4FzQ8Ue4X1LrT1aBw52wNdshky FlKc9u2DFLHz1skBJ05QLwlvb8Ef3/4hqdT3YzTeT/VqLHEBCypt+SSn8hje3BEl3ctR lQnDyGBHB42ZPRU/4X4WGTG59b2tOZzq4riEq1xWmxq8Tg+a/wQktGjhknmedxUKTtfw cBMgnTstUBqNBKvMeLqmoqq4AMx+2B+uc6lSyZu2BKj1yOlBiZoiWLMFOMuefEcNT1RU a1VA== X-Gm-Message-State: AOAM531r1h8ox1BX6oDoUP5Kv1vK8V9hKHtrxnx0zdbjwbaMgqFwQXda LGRtUhvDDSHN7h/FzVI2R1F8avAiJxMN7uwEDiGGnbou+m4JxoJ92L86DX6RjH9c4mPYM1cU4J5 vrND+IbC1IiRSJWsf0m7zywpdEdAsI4j0DTIzpC6jiLrbqN4dU4yb X-Google-Smtp-Source: ABdhPJxCi4dvhwawlVQOkaWJoIGlOXXngK0+27uV61GkjkXiTjRkBfA4UYL0HBAL8AglNmuHri2uosA= X-Received: from ruffy.mtv.corp.google.com ([2620:0:1000:1412:da9a:e3bd:2fe6:1f1b]) (user=dje job=sendgmr) by 2002:a0c:c481:: with SMTP id u1mr6541487qvi.48.1622246025092; Fri, 28 May 2021 16:53:45 -0700 (PDT) Date: Fri, 28 May 2021 16:53:29 -0700 In-Reply-To: <20210528235331.3727583-1-dje@google.com> Message-Id: <20210528235331.3727583-3-dje@google.com> Mime-Version: 1.0 References: <20210528235331.3727583-1-dje@google.com> X-Mailer: git-send-email 2.32.0.rc0.204.g9fa02ecfa5-goog Subject: [PATCH v7 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?= " , " =?utf-8?q?Marc-An?= =?utf-8?q?dr=C3=A9_Lureau?= " , Maxim Samoylov , Doug Evans Received-SPF: pass client-ip=2607:f8b0:4864:20::f49; envelope-from=3iYKxYAMKCmABHCEMMEJC.AMKOCKS-BCTCJLMLELS.MPE@flex--dje.bounces.google.com; helo=mail-qv1-xf49.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 v6: No changes. 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 2463c49773..aa883eb84f 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 Fri May 28 23:53:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 12287541 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 B4013C4708C for ; Fri, 28 May 2021 23:55:26 +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 3BFA2608FC for ; Fri, 28 May 2021 23:55:26 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3BFA2608FC 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]:48072 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lmmK5-0001LQ-9T for qemu-devel@archiver.kernel.org; Fri, 28 May 2021 19:55:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45840) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3i4KxYAMKCmIDJEGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--dje.bounces.google.com>) id 1lmmIb-0006w4-3T for qemu-devel@nongnu.org; Fri, 28 May 2021 19:53:53 -0400 Received: from mail-qt1-x84a.google.com ([2607:f8b0:4864:20::84a]:39591) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3i4KxYAMKCmIDJEGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--dje.bounces.google.com>) id 1lmmIY-0007ec-7i for qemu-devel@nongnu.org; Fri, 28 May 2021 19:53:52 -0400 Received: by mail-qt1-x84a.google.com with SMTP id h12-20020ac8776c0000b02901f1228fdb1bso3058849qtu.6 for ; Fri, 28 May 2021 16:53:48 -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=tochQxcwDbgxuE9aCwQ3mvlcaE6UdATSx8Y3Dl6oo7E=; b=DTHm45TnQKt5hzCRMa8lTLkDUqtViWwH0Tpu3yRloOjZX4ZcoNbzF5XbBXrXTeVRFu gzvyCYsWQiYjj4n62aFPna77MM0Sr8jRY1x2Kp9HHmZmmPDfAQK0FbxyRJ/so90gVR/d W5sIt5pINo3dSdA6UEXpniEWrP5V0WhzguzzxBBGHjUrBwqn3GErr53M/3+S4Gc2S6CZ R2+vWY4twV/VUwdyNNa4uFRsXLkmWSRsG8UtR7fo48p07pRfNj5VeC38umcFmiM8ySXK Vu8YVnzf2ABE9jEtPe0oUOsm8UF0izPKYFPzrzgh7c/beTzjoWISXq/mkPZKZGGg5YDw H+fw== 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=tochQxcwDbgxuE9aCwQ3mvlcaE6UdATSx8Y3Dl6oo7E=; b=rHOVAW6aUq/AXSNXY6pZwxpBGaEQ3vHHZ+y9gXqwKTnexQ45ZADTKgJtTGAyLA2U8G AJnffhcxTBdcB4NftZQItW3iJw0jdZTmcJqLc10ITP6+bpMEI+DR9/pfvw76PN2cpKH7 OkjHEYAVWkhAy4yPNUoxlOSqOx/8+ZRMgjjr1rpViPALb+kQuwVQwmS3pC/A85Eo7Gq0 TyhFCTdIbiHMeaMK6REq5ID73b7JVcY/nqMI7E8+DTuVCEe3CnWvkBXdTFi8u8JZH40E oy1QB1CVsUDxGHv1QrWw7wvB2g9tpEgVTXzi9yUw/CnjoI4ZhlNLkr//z3/cL6khKuyS IGyg== X-Gm-Message-State: AOAM532lnJZBdCy1mcgr6QSiRNenAewnbakm2WlwBf73/cyo/PPgfjE9 jbhrrBetcUhhgq/F44ucmfDY0JUxQ1tsWqkm+a0qeT79m+2lb3K2yzXtu80WLUttUNqN4W7+x5Z MDByip4bYIWlQDydgReq2xVAHxtWXwAAKwHyR7Q2hfQMkD1wcq0nP X-Google-Smtp-Source: ABdhPJy3y6lVu608JZwMWCqEU4cTAop4UEqviqj2ETfbLC2pIxI44R8Ve0ldkhCdysU/qOw9TE9bSRg= X-Received: from ruffy.mtv.corp.google.com ([2620:0:1000:1412:da9a:e3bd:2fe6:1f1b]) (user=dje job=sendgmr) by 2002:ad4:5907:: with SMTP id ez7mr6535575qvb.35.1622246027932; Fri, 28 May 2021 16:53:47 -0700 (PDT) Date: Fri, 28 May 2021 16:53:30 -0700 In-Reply-To: <20210528235331.3727583-1-dje@google.com> Message-Id: <20210528235331.3727583-4-dje@google.com> Mime-Version: 1.0 References: <20210528235331.3727583-1-dje@google.com> X-Mailer: git-send-email 2.32.0.rc0.204.g9fa02ecfa5-goog Subject: [PATCH v7 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?= " , " =?utf-8?q?Marc-An?= =?utf-8?q?dr=C3=A9_Lureau?= " , Maxim Samoylov , Doug Evans Received-SPF: pass client-ip=2607:f8b0:4864:20::84a; envelope-from=3i4KxYAMKCmIDJEGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--dje.bounces.google.com; helo=mail-qt1-x84a.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 v6: Add support for --enable-slirp=system Tested with system libslirp 4.4.0. 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 | 236 ++++++++++++++++++++++++++---------- tests/acceptance/hostfwd.py | 91 ++++++++++++++ util/qemu-sockets.c | 17 ++- 4 files changed, 278 insertions(+), 68 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 ad3a838e0b..2349eb2c23 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -641,14 +641,106 @@ 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; const char *arg1 = qdict_get_str(qdict, "arg1"); const char *arg2 = qdict_get_try_str(qdict, "arg2"); @@ -664,110 +756,130 @@ 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)) { + if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM, + &host_addr, &error) < 0) { goto fail_syntax; } - if (qemu_strtoi(p, NULL, 10, &host_port)) { - goto fail_syntax; +#if SLIRP_CHECK_VERSION(4, 5, 0) + { + int flags = is_udp ? SLIRP_HOSTFWD_UDP : 0; + err = slirp_remove_hostxfwd(s->slirp, (struct sockaddr *) &host_addr, + sizeof(host_addr), flags); } - - err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port); +#else + if (host_addr.ss_family != AF_INET) { + monitor_printf(mon, + "Could not remove host forwarding rule '%s':" + " only IPv4 supported", + src_str); + return; + } else { + struct sockaddr_in *host_in_addr = (struct sockaddr_in *) &host_addr; + err = slirp_remove_hostfwd(s->slirp, is_udp, + host_in_addr->sin_addr, + ntohs(host_in_addr->sin_port)); + } +#endif 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 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"; - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { - fail_reason = "Bad host address"; + p = parse_protocol(p, &is_udp, &error); + if (p == NULL) { goto fail_syntax; } if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) { - fail_reason = "Bad host port separator"; + error_setg(&error, "missing host-guest separator"); goto fail_syntax; } - host_port = strtol(buf, &end, 0); - if (*end != '\0' || host_port < 0 || host_port > 65535) { - fail_reason = "Bad host port"; + + 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 (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - fail_reason = "Missing 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; } - if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) { - fail_reason = "Bad guest address"; + port = sockaddr_getport((struct sockaddr *) &guest_addr); + if (port == 0) { + error_setg(&error, "For guest address: invalid port '0'"); goto fail_syntax; } - guest_port = strtol(p, &end, 0); - if (*end != '\0' || guest_port < 1 || guest_port > 65535) { - fail_reason = "Bad guest port"; - goto fail_syntax; +#if SLIRP_CHECK_VERSION(4, 5, 0) + { + int flags = is_udp ? SLIRP_HOSTFWD_UDP : 0; + 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; + } } - - 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'", +#else + if (host_addr.ss_family != AF_INET || guest_addr.ss_family != AF_INET) { + error_setg(errp, + "Could not set up host forwarding rule '%s':" + " only IPv4 supported", redir_str); return -1; + } else { + struct sockaddr_in *host_in_addr = (struct sockaddr_in *) &host_addr; + struct sockaddr_in *guest_in_addr = (struct sockaddr_in *) &guest_addr; + if (slirp_add_hostfwd(s->slirp, is_udp, + host_in_addr->sin_addr, + ntohs(host_in_addr->sin_port), + guest_in_addr->sin_addr, + ntohs(guest_in_addr->sin_port)) < 0) { + error_setg(errp, "Could not set up host forwarding rule '%s'", + redir_str); + return -1; + } } +#endif + 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 aa883eb84f..52fe056fbf 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 Fri May 28 23:53:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 12287579 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 3AC44C47087 for ; Fri, 28 May 2021 23:57:39 +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 A9FC3613B5 for ; Fri, 28 May 2021 23:57:38 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A9FC3613B5 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]:53972 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lmmMD-0005Lk-T9 for qemu-devel@archiver.kernel.org; Fri, 28 May 2021 19:57:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45850) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3joKxYAMKCmUGMHJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--dje.bounces.google.com>) id 1lmmId-00074W-G0 for qemu-devel@nongnu.org; Fri, 28 May 2021 19:53:55 -0400 Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]:34803) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3joKxYAMKCmUGMHJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--dje.bounces.google.com>) id 1lmmIa-0007hw-At for qemu-devel@nongnu.org; Fri, 28 May 2021 19:53:55 -0400 Received: by mail-yb1-xb49.google.com with SMTP id x187-20020a25e0c40000b029052a5f0bf9acso6019841ybg.1 for ; Fri, 28 May 2021 16:53:51 -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=wJUkmdMz6Gp1jgzONDcUOENnWqg5G77quRr8plfvXDo=; b=ugDsvYzhUKZny7EcdYjMnT3j3ZM76W0MLuCfr/dXo0uI+V2wqe9bsPbIV+NkurQehk oXrBhGswH4Lu+H6LAjKf3tcpzGa0oPsFKRQ0YcKYvGleJpt+mQlXYn6miQzLNqDZs3pY aTnopFug9IhnTwlsCrhqR/ImXT/Xz8TDSHGWdUaliVqy9N/XDTDjiQwcPsqTuTkUt7dr bqXbju8uvCzvcI6mgvUkj2qDNsWE5PYTI3HvcwUBhhZlxdPc1o9p0Oq0Rx0Z4Fqgp/o5 kb3v3d/2R5rbrRYKIJ45p19b/Ql9pLuoXAS2pu2UvKBFTce8J+3KkLoWhxxrzcGToXQt cohw== 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=wJUkmdMz6Gp1jgzONDcUOENnWqg5G77quRr8plfvXDo=; b=K6so/54MhTq1s9C1NiasUx5bKliSKlZtuh1YRFgGDNfF4Fpr3msJhy00A7dqzMerpq bJkz79eEP6D8pt7c1UHIVEctyqWLQ8heFGd2fW6wL8r32RyT8t5HwM00cMB98+o5iTE2 4l3UoUhBMcDHSLM8wdhAGj8shZvTOQc+SaYGiNhi85wNyUMAnNLhfs8Dudjm55zyJ4Xy H3UgKgwHtpT36r/IdvfZua/meHpZbyr888BIhG2OL3EnjOGSMXFkVZmJelHCqnID23qj MHPfqYMFWelRQu89gpEOaeTyax/vQoBqiASztvNJnHefFWBFeOiLhYigxjxc2t0JGDFI v9QQ== X-Gm-Message-State: AOAM532m9BVpkMbkBi0+/cosz4veOqSbEktZpjRjptwS4IdUhrk1EalH JIrgQPvUfUHMgflYyw2ZHR5frwYbEqWsHzaVRt+xuzX4NUGxYVZZ5MSpGQLas3f0/wV1Zrh8Hvx Qm05C9NGf0b9plukLMfLuHN83esmVj9bG0I3Aa49Ae91UbhBP2sGr X-Google-Smtp-Source: ABdhPJz4gvCQ911voFSVwSlVbqM2uEu66cQ+gMxwG+r51/HEj986eD7PVJBTnKir2MSQhpnCsW+qPbc= X-Received: from ruffy.mtv.corp.google.com ([2620:0:1000:1412:da9a:e3bd:2fe6:1f1b]) (user=dje job=sendgmr) by 2002:a25:7e47:: with SMTP id z68mr17364112ybc.85.1622246030688; Fri, 28 May 2021 16:53:50 -0700 (PDT) Date: Fri, 28 May 2021 16:53:31 -0700 In-Reply-To: <20210528235331.3727583-1-dje@google.com> Message-Id: <20210528235331.3727583-5-dje@google.com> Mime-Version: 1.0 References: <20210528235331.3727583-1-dje@google.com> X-Mailer: git-send-email 2.32.0.rc0.204.g9fa02ecfa5-goog Subject: [PATCH v7 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?= " , " =?utf-8?q?Marc-An?= =?utf-8?q?dr=C3=A9_Lureau?= " , Maxim Samoylov , Doug Evans Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3joKxYAMKCmUGMHJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--dje.bounces.google.com; helo=mail-yb1-xb49.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 v6: No changes. 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 2349eb2c23..075a283d35 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 @@ -764,8 +794,8 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict) goto fail_syntax; } - 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; } @@ -807,6 +837,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) bool is_udp; Error *error = NULL; int port; + bool v6_only; g_assert(redir_str != NULL); p = redir_str; @@ -821,14 +852,16 @@ 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 (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; } @@ -841,6 +874,9 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp) #if SLIRP_CHECK_VERSION(4, 5, 0) { int flags = is_udp ? SLIRP_HOSTFWD_UDP : 0; + if (v6_only) { + flags |= SLIRP_HOSTFWD_V6ONLY; + } if (slirp_add_hostxfwd(s->slirp, (struct sockaddr *) &host_addr, sizeof(host_addr), 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")