/*
* Replacement for a missing inet_aton.
*
* Provides the same functionality as the standard library routine
* inet_aton for those platforms that don't have it. inet_aton is
* thread-safe.
*
* The canonical version of this file is maintained in the rra-c-util package,
* which can be found at .
*
* Written by Russ Allbery
* Copyright 2000-2001, 2017, 2019 Russ Allbery
* Copyright 2008, 2011, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
* Copying and distribution of this file, with or without modification, are
* permitted in any medium without royalty provided the copyright notice and
* this notice are preserved. This file is offered as-is, without any
* warranty.
*
* SPDX-License-Identifier: FSFAP
*/
#include
#include
#include
/*
* If we're running the test suite, rename inet_aton to avoid conflicts with
* the system version.
*/
#if TESTING
# undef inet_aton
# define inet_aton test_inet_aton
int test_inet_aton(const char *, struct in_addr *);
#endif
int
inet_aton(const char *s, struct in_addr *addr)
{
unsigned octet[4];
uint32_t address;
const char *p;
unsigned int base, i;
unsigned int part = 0;
if (s == NULL)
return 0;
/*
* Step through each period-separated part of the address. If we see
* more than four parts, the address is invalid.
*/
for (p = s; *p != 0; part++) {
if (part > 3)
return 0;
/*
* Determine the base of the section we're looking at. Numbers are
* represented the same as in C; octal starts with 0, hex starts
* with 0x, and anything else is decimal.
*/
if (*p == '0') {
p++;
if (*p == 'x') {
p++;
base = 16;
} else {
base = 8;
}
} else {
base = 10;
}
/*
* Make sure there's actually a number. (A section of just "0"
* would set base to 8 and leave us pointing at a period; allow
* that.)
*/
if (*p == '.' && base != 8)
return 0;
octet[part] = 0;
/*
* Now, parse this segment of the address. For each digit, multiply
* the result so far by the base and then add the value of the digit.
* Be careful of arithmetic overflow in cases where an unsigned long
* is 32 bits; we need to detect it *before* we multiply by the base
* since otherwise we could overflow and wrap and then not detect the
* error.
*/
for (; *p != 0 && *p != '.'; p++) {
if (octet[part] > 0xffffffffUL / base)
return 0;
/*
* Use a switch statement to parse each digit rather than assuming
* ASCII. Probably pointless portability.
*/
switch (*p) {
case '0': i = 0; break;
case '1': i = 1; break;
case '2': i = 2; break;
case '3': i = 3; break;
case '4': i = 4; break;
case '5': i = 5; break;
case '6': i = 6; break;
case '7': i = 7; break;
case '8': i = 8; break;
case '9': i = 9; break;
case 'A': case 'a': i = 10; break;
case 'B': case 'b': i = 11; break;
case 'C': case 'c': i = 12; break;
case 'D': case 'd': i = 13; break;
case 'E': case 'e': i = 14; break;
case 'F': case 'f': i = 15; break;
default: return 0;
}
if (i >= base)
return 0;
octet[part] = (octet[part] * base) + i;
}
/*
* Advance over periods; the top of the loop will increment the count
* of parts we've seen. We need a check here to detect an illegal
* trailing period.
*/
if (*p == '.') {
p++;
if (*p == 0)
return 0;
}
}
if (part == 0)
return 0;
/* IPv4 allows three types of address specification:
*
* a.b
* a.b.c
* a.b.c.d
*
* If there are fewer than four segments, the final segment accounts for
* all of the remaining portion of the address. For example, in the a.b
* form, b is the final 24 bits of the address. We also allow a simple
* number, which is interpreted as the 32-bit number corresponding to the
* full IPv4 address.
*
* The first for loop below ensures that any initial segments represent
* only 8 bits of the address and builds the upper portion of the IPv4
* address. Then, the remaining segment is checked to make sure it's no
* bigger than the remaining space in the address and then is added into
* the result.
*/
address = 0;
for (i = 0; i < part - 1; i++) {
if (octet[i] > 0xff)
return 0;
address |= octet[i] << (8 * (3 - i));
}
if (octet[i] > (0xffffffffUL >> (i * 8)))
return 0;
address |= octet[i];
if (addr != NULL)
addr->s_addr = htonl(address);
return 1;
}