From patchwork Wed Sep 6 21:08:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Michelson X-Patchwork-Id: 810802 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xnbmz2HyVz9t2r for ; Thu, 7 Sep 2017 07:09:23 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 5C13EB78; Wed, 6 Sep 2017 21:08:45 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id F0670B4C for ; Wed, 6 Sep 2017 21:08:42 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 981F048E for ; Wed, 6 Sep 2017 21:08:42 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0B5048535D for ; Wed, 6 Sep 2017 21:08:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 0B5048535D Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=mmichels@redhat.com Received: from monae.redhat.com (ovpn-121-224.rdu2.redhat.com [10.10.121.224]) by smtp.corp.redhat.com (Postfix) with ESMTP id 75E92179D3 for ; Wed, 6 Sep 2017 21:08:41 +0000 (UTC) From: Mark Michelson To: dev@openvswitch.org Date: Wed, 6 Sep 2017 16:08:36 -0500 Message-Id: <20170906210839.26091-2-mmichels@redhat.com> In-Reply-To: <20170906210839.26091-1-mmichels@redhat.com> References: <20170906210839.26091-1-mmichels@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Wed, 06 Sep 2017 21:08:42 +0000 (UTC) X-Spam-Status: No, score=-5.0 required=5.0 tests=RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH 1/4] Add general-purpose IP/port parsing function. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org OVS has functions for parsing IPv4 addresses, parsing IPv4 addresses with a port, and parsing IPv6 addresses. What is lacking though is a function that can take an IPv4 or IPv6 address, with or without a port. This commit adds ipv46_parse(), which breaks the given input string into its component parts and stores them in a sockaddr_storage structure. The function accepts flags that determine how it should behave if a port is present in the input string. Signed-off-by: Mark Michelson --- lib/packets.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/packets.h | 10 ++++++++ 2 files changed, 88 insertions(+) diff --git a/lib/packets.c b/lib/packets.c index 74d87eda8..51044df4c 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "byte-order.h" #include "csum.h" #include "crc32c.h" @@ -656,6 +658,82 @@ ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen) return error; } +/* Parses the string into an IPv4 or IPv6 address. + * The port flags act as follows: + * * PORT_OPTIONAL: A port may be present but is not required + * * PORT_REQUIRED: A port must be present + * * PORT_FORBIDDEN: A port must not be present + */ +char * OVS_WARN_UNUSED_RESULT +ipv46_parse(const char *s, enum port_flags flags, struct sockaddr_storage *ss) +{ + char *error = NULL; + + char *copy; + copy = xstrdup(s); + + char *addr; + char *port; + if (*copy == '[') { + char *end; + + addr = copy + 1; + end = strchr(addr, ']'); + if (!end) { + error = xasprintf("No closing bracket on address %s", s); + goto finish; + } + *end++ = '\0'; + if (*end == ':') { + port = end + 1; + } else { + port = NULL; + } + } else { + addr = copy; + port = strchr(copy, ':'); + if (port) { + if (strchr(port + 1, ':')) { + port = NULL; + } else { + *port++ = '\0'; + } + } + } + + if (port && !*port) { + error = xasprintf("Port is an empty string"); + goto finish; + } + + if (port && flags == PORT_FORBIDDEN) { + error = xasprintf("Port forbidden in address %s", s); + goto finish; + } else if (!port && flags == PORT_REQUIRED) { + error = xasprintf("Port required in address %s", s); + goto finish; + } + + struct addrinfo hints = { + .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV, + .ai_family = AF_UNSPEC, + }; + struct addrinfo *res; + int status; + status = getaddrinfo(addr, port, &hints, &res); + if (status) { + error = xasprintf("Error parsing address %s: %s", + s, gai_strerror(status)); + goto finish; + } + memcpy(ss, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + +finish: + free(copy); + return error; +} + /* Parses string 's', which must be an IPv6 address. Stores the IPv6 address * into '*ip'. Returns true if successful, otherwise false. */ bool diff --git a/lib/packets.h b/lib/packets.h index 705d0b270..866a3335a 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -1325,6 +1325,16 @@ struct in6_addr ipv6_create_mask(int mask); int ipv6_count_cidr_bits(const struct in6_addr *netmask); bool ipv6_is_cidr(const struct in6_addr *netmask); +enum port_flags { + PORT_OPTIONAL, + PORT_REQUIRED, + PORT_FORBIDDEN, +}; + +char *ipv46_parse(const char *s, enum port_flags flags, + struct sockaddr_storage *ss) + OVS_WARN_UNUSED_RESULT; + bool ipv6_parse(const char *s, struct in6_addr *ip); char *ipv6_parse_masked(const char *s, struct in6_addr *ipv6, struct in6_addr *mask);