From 047866672c66e51b557721cf50ba101305c252d2 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 8 Oct 2015 18:04:49 -0700 Subject: [PATCH] Fix inet_addr/inet_aton/inet_network. Rewrite inet_addr and inet_network in terms of inet_aton, and reimplement that to include all the missing error checks. Bug: http://b/24754503 Change-Id: I5dfa971c87201968985a0894df419f0fbf54768a --- libc/Android.mk | 3 +- libc/bionic/arpa_inet.cpp | 71 +++++++++ libc/upstream-openbsd/lib/libc/net/inet_addr.c | 175 ---------------------- libc/upstream-openbsd/lib/libc/net/inet_network.c | 84 ----------- tests/arpa_inet_test.cpp | 77 +++++++++- 5 files changed, 148 insertions(+), 262 deletions(-) create mode 100644 libc/bionic/arpa_inet.cpp delete mode 100644 libc/upstream-openbsd/lib/libc/net/inet_addr.c delete mode 100644 libc/upstream-openbsd/lib/libc/net/inet_network.c diff --git a/libc/Android.mk b/libc/Android.mk index 6919fbbeb..5d875794a 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -104,6 +104,7 @@ libc_bionic_ndk_src_files := \ bionic/accept.cpp \ bionic/accept4.cpp \ bionic/access.cpp \ + bionic/arpa_inet.cpp \ bionic/assert.cpp \ bionic/atof.cpp \ bionic/bionic_systrace.cpp \ @@ -395,11 +396,9 @@ libc_upstream_openbsd_ndk_src_files := \ upstream-openbsd/lib/libc/locale/wctomb.c \ upstream-openbsd/lib/libc/net/htonl.c \ upstream-openbsd/lib/libc/net/htons.c \ - upstream-openbsd/lib/libc/net/inet_addr.c \ upstream-openbsd/lib/libc/net/inet_lnaof.c \ upstream-openbsd/lib/libc/net/inet_makeaddr.c \ upstream-openbsd/lib/libc/net/inet_netof.c \ - upstream-openbsd/lib/libc/net/inet_network.c \ upstream-openbsd/lib/libc/net/inet_ntoa.c \ upstream-openbsd/lib/libc/net/inet_ntop.c \ upstream-openbsd/lib/libc/net/inet_pton.c \ diff --git a/libc/bionic/arpa_inet.cpp b/libc/bionic/arpa_inet.cpp new file mode 100644 index 000000000..260d6a00f --- /dev/null +++ b/libc/bionic/arpa_inet.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "private/ErrnoRestorer.h" + +// The difference between inet_network(3) and inet_addr(3) is that +// inet_network uses host order and inet_addr network order. +in_addr_t inet_network(const char* cp) { + in_addr_t network_order = inet_addr(cp); + return ntohl(network_order); +} + +in_addr_t inet_addr(const char* cp) { + in_addr addr; + return inet_aton(cp, &addr) ? addr.s_addr : INADDR_NONE; +} + +int inet_aton(const char* cp, in_addr* addr) { + ErrnoRestorer errno_restorer; + + unsigned long parts[4]; + size_t i; + for (i = 0; i < 4; ++i) { + char* end; + parts[i] = strtoul(cp, &end, 0); + if (end == cp || (*end != '.' && *end != '\0')) return 0; + if (*end == '\0') break; + cp = end + 1; + } + + uint32_t result = 0; + if (i == 0) { + // a (a 32-bit). + if (parts[0] > 0xffffffff) return 0; + result = parts[0]; + } else if (i == 1) { + // a.b (b 24-bit). + if (parts[0] > 0xff || parts[1] > 0xffffff) return 0; + result = (parts[0] << 24) | parts[1]; + } else if (i == 2) { + // a.b.c (c 16-bit). + if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xffff) return 0; + result = (parts[0] << 24) | (parts[1] << 16) | parts[2]; + } else if (i == 3) { + // a.b.c.d (d 8-bit). + if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff || parts[3] > 0xff) return 0; + result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]; + } else { + return 0; + } + + if (addr != nullptr) addr->s_addr = htonl(result); + return 1; +} diff --git a/libc/upstream-openbsd/lib/libc/net/inet_addr.c b/libc/upstream-openbsd/lib/libc/net/inet_addr.c deleted file mode 100644 index 18762ab52..000000000 --- a/libc/upstream-openbsd/lib/libc/net/inet_addr.c +++ /dev/null @@ -1,175 +0,0 @@ -/* $OpenBSD: inet_addr.c,v 1.10 2013/11/24 23:51:28 deraadt Exp $ */ - -/* - * ++Copyright++ 1983, 1990, 1993 - * - - * Copyright (c) 1983, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - - * --Copyright-- - */ - -#include -#include -#include -#include -#include - -/* - * Ascii internet address interpretation routine. - * The value returned is in network order. - */ -in_addr_t -inet_addr(const char *cp) -{ - struct in_addr val; - - if (inet_aton(cp, &val)) - return (val.s_addr); - return (INADDR_NONE); -} - -/* - * Check whether "cp" is a valid ascii representation - * of an Internet address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * This replaces inet_addr, the return value from which - * cannot distinguish between failure and a local broadcast address. - */ -int -inet_aton(const char *cp, struct in_addr *addr) -{ - in_addr_t val; - int base, n; - char c; - u_int parts[4]; - u_int *pp = parts; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, isdigit=decimal. - */ - if (!isdigit((unsigned char)c)) - return (0); - val = 0; base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') - base = 16, c = *++cp; - else - base = 8; - } - for (;;) { - if (isascii((unsigned char)c) && - isdigit((unsigned char)c)) { - val = (val * base) + (c - '0'); - c = *++cp; - } else if (base == 16 && - isascii((unsigned char)c) && - isxdigit((unsigned char)c)) { - val = (val << 4) | - (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); - c = *++cp; - } else - break; - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3) - return (0); - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && - (!isascii((unsigned char)c) || !isspace((unsigned char)c))) - return (0); - /* - * Concoct the address according to - * the number of parts specified. - */ - n = pp - parts + 1; - switch (n) { - - case 0: - return (0); /* initial nondigit */ - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if ((val > 0xffffff) || (parts[0] > 0xff)) - return (0); - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - if (addr) - addr->s_addr = htonl(val); - return (1); -} diff --git a/libc/upstream-openbsd/lib/libc/net/inet_network.c b/libc/upstream-openbsd/lib/libc/net/inet_network.c deleted file mode 100644 index ecf554e4f..000000000 --- a/libc/upstream-openbsd/lib/libc/net/inet_network.c +++ /dev/null @@ -1,84 +0,0 @@ -/* $OpenBSD: inet_network.c,v 1.11 2013/11/25 17:29:19 deraadt Exp $ */ -/* - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include - -/* - * Internet network address interpretation routine. - * The library routines call this routine to interpret - * network numbers. - */ -in_addr_t -inet_network(const char *cp) -{ - in_addr_t val, base, n; - u_char c; - in_addr_t parts[4], *pp = parts; - int i; - -again: - val = 0; base = 10; - if (*cp == '0') - base = 8, cp++; - if (*cp == 'x' || *cp == 'X') - base = 16, cp++; - while ((c = *cp)) { - if (isdigit(c)) { - val = (val * base) + (c - '0'); - cp++; - continue; - } - if (base == 16 && isxdigit(c)) { - val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); - cp++; - continue; - } - break; - } - if (*cp == '.') { - if (pp >= parts + 3) - return (INADDR_NONE); - *pp++ = val, cp++; - goto again; - } - if (*cp && !isspace(*cp)) - return (INADDR_NONE); - *pp++ = val; - n = pp - parts; - for (val = 0, i = 0; i < 4; i++) { - val <<= 8; - if (i < n) - val |= parts[i] & 0xff; - } - return (val); -} diff --git a/tests/arpa_inet_test.cpp b/tests/arpa_inet_test.cpp index 5e533370d..8ba0d7a97 100644 --- a/tests/arpa_inet_test.cpp +++ b/tests/arpa_inet_test.cpp @@ -24,8 +24,81 @@ TEST(arpa_inet, inet_addr) { TEST(arpa_inet, inet_aton) { in_addr a; - ASSERT_EQ(1, inet_aton("127.0.0.1", &a)); + + // a.b.c.d + a.s_addr = 0; + ASSERT_EQ(1, inet_aton("127.1.2.3", &a)); + ASSERT_EQ((htonl)(0x7f010203), a.s_addr); + + // a.b.c + a.s_addr = 0; + ASSERT_EQ(1, inet_aton("127.1.2", &a)); + ASSERT_EQ((htonl)(0x7f010002), a.s_addr); + + // a.b + a.s_addr = 0; + ASSERT_EQ(1, inet_aton("127.1", &a)); + ASSERT_EQ((htonl)(0x7f000001), a.s_addr); + + // a + a.s_addr = 0; + ASSERT_EQ(1, inet_aton("0x7f000001", &a)); ASSERT_EQ((htonl)(0x7f000001), a.s_addr); + + // Hex (0x) and mixed-case hex digits. + a.s_addr = 0; + ASSERT_EQ(1, inet_aton("0xFf.0.0.1", &a)); + ASSERT_EQ((htonl)(0xff000001), a.s_addr); + + // Hex (0X) and mixed-case hex digits. + a.s_addr = 0; + ASSERT_EQ(1, inet_aton("0XfF.0.0.1", &a)); + ASSERT_EQ((htonl)(0xff000001), a.s_addr); + + // Octal. + a.s_addr = 0; + ASSERT_EQ(1, inet_aton("0177.0.0.1", &a)); + ASSERT_EQ((htonl)(0x7f000001), a.s_addr); + + a.s_addr = 0; + ASSERT_EQ(1, inet_aton("036", &a)); + ASSERT_EQ((htonl)(036U), a.s_addr); +} + +TEST(arpa_inet, inet_aton_nullptr) { + ASSERT_EQ(0, inet_aton("", nullptr)); + ASSERT_EQ(1, inet_aton("127.0.0.1", nullptr)); +} + +TEST(arpa_inet, inet_aton_invalid) { + ASSERT_EQ(0, inet_aton("", nullptr)); // Empty. + ASSERT_EQ(0, inet_aton("x", nullptr)); // Leading junk. + ASSERT_EQ(0, inet_aton("127.0.0.1x", nullptr)); // Trailing junk. + ASSERT_EQ(0, inet_aton("09.0.0.1", nullptr)); // Invalid octal. + ASSERT_EQ(0, inet_aton("0xg.0.0.1", nullptr)); // Invalid hex. + + ASSERT_EQ(0, inet_aton("1.2.3.4.5", nullptr)); // Too many dots. + ASSERT_EQ(0, inet_aton("1.2.3.4.", nullptr)); // Trailing dot. + + // Out of range a.b.c.d form. + ASSERT_EQ(0, inet_aton("999.0.0.1", nullptr)); + ASSERT_EQ(0, inet_aton("0.999.0.1", nullptr)); + ASSERT_EQ(0, inet_aton("0.0.999.1", nullptr)); + ASSERT_EQ(0, inet_aton("0.0.0.999", nullptr)); + + // Out of range a.b.c form. + ASSERT_EQ(0, inet_aton("256.0.0", nullptr)); + ASSERT_EQ(0, inet_aton("0.256.0", nullptr)); + ASSERT_EQ(0, inet_aton("0.0.0x10000", nullptr)); + + // Out of range a.b form. + ASSERT_EQ(0, inet_aton("256.0", nullptr)); + ASSERT_EQ(0, inet_aton("0.0x1000000", nullptr)); + + // Out of range a form. + ASSERT_EQ(0, inet_aton("0x100000000", nullptr)); + + ASSERT_EQ(0, inet_aton("0400.0.0.1", nullptr)); // Out of range octal. } TEST(arpa_inet, inet_lnaof) { @@ -45,6 +118,8 @@ TEST(arpa_inet, inet_netof) { TEST(arpa_inet, inet_network) { ASSERT_EQ(0x7f000001U, inet_network("127.0.0.1")); + ASSERT_EQ(0x7fU, inet_network("0x7f")); + ASSERT_EQ(~0U, inet_network("")); } TEST(arpa_inet, inet_ntoa) { -- 2.11.0