diff options
Diffstat (limited to 'networking/libiproute/utils.c')
-rw-r--r-- | networking/libiproute/utils.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c new file mode 100644 index 0000000..cd101f1 --- /dev/null +++ b/networking/libiproute/utils.c @@ -0,0 +1,324 @@ +/* vi: set sw=4 ts=4: */ +/* + * utils.c + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> + * + * Changes: + * + * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses + */ + +#include "libbb.h" +#include "utils.h" +#include "inet_common.h" + +int get_integer(int *val, char *arg, int base) +{ + long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtol(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN) + return -1; + *val = res; + return 0; +} +//XXX: FIXME: use some libbb function instead +int get_unsigned(unsigned *val, char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtoul(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > UINT_MAX) + return -1; + *val = res; + return 0; +} + +int get_u32(uint32_t * val, char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtoul(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL) + return -1; + *val = res; + return 0; +} + +int get_u16(uint16_t * val, char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtoul(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0xFFFF) + return -1; + *val = res; + return 0; +} + +int get_u8(uint8_t * val, char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtoul(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0xFF) + return -1; + *val = res; + return 0; +} + +int get_s16(int16_t * val, char *arg, int base) +{ + long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtol(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000) + return -1; + *val = res; + return 0; +} + +int get_s8(int8_t * val, char *arg, int base) +{ + long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtol(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80) + return -1; + *val = res; + return 0; +} + +int get_addr_1(inet_prefix * addr, char *name, int family) +{ + memset(addr, 0, sizeof(*addr)); + + if (strcmp(name, bb_str_default) == 0 || + strcmp(name, "all") == 0 || strcmp(name, "any") == 0) { + addr->family = family; + addr->bytelen = (family == AF_INET6 ? 16 : 4); + addr->bitlen = -1; + return 0; + } + + if (strchr(name, ':')) { + addr->family = AF_INET6; + if (family != AF_UNSPEC && family != AF_INET6) + return -1; + if (inet_pton(AF_INET6, name, addr->data) <= 0) + return -1; + addr->bytelen = 16; + addr->bitlen = -1; + return 0; + } + + addr->family = AF_INET; + if (family != AF_UNSPEC && family != AF_INET) + return -1; + if (inet_pton(AF_INET, name, addr->data) <= 0) + return -1; + addr->bytelen = 4; + addr->bitlen = -1; + return 0; +} + +int get_prefix_1(inet_prefix * dst, char *arg, int family) +{ + int err; + unsigned plen; + char *slash; + + memset(dst, 0, sizeof(*dst)); + + if (strcmp(arg, bb_str_default) == 0 || strcmp(arg, "any") == 0) { + dst->family = family; + dst->bytelen = 0; + dst->bitlen = 0; + return 0; + } + + slash = strchr(arg, '/'); + if (slash) + *slash = '\0'; + err = get_addr_1(dst, arg, family); + if (err == 0) { + dst->bitlen = (dst->family == AF_INET6) ? 128 : 32; + if (slash) { + inet_prefix netmask_pfx; + + netmask_pfx.family = AF_UNSPEC; + if ((get_unsigned(&plen, slash + 1, 0) || plen > dst->bitlen) + && (get_addr_1(&netmask_pfx, slash + 1, family))) + err = -1; + else if (netmask_pfx.family == AF_INET) { + /* fill in prefix length of dotted quad */ + uint32_t mask = ntohl(netmask_pfx.data[0]); + uint32_t host = ~mask; + + /* a valid netmask must be 2^n - 1 */ + if (!(host & (host + 1))) { + for (plen = 0; mask; mask <<= 1) + ++plen; + if (plen >= 0 && plen <= dst->bitlen) { + dst->bitlen = plen; + /* dst->flags |= PREFIXLEN_SPECIFIED; */ + } else + err = -1; + } else + err = -1; + } else { + /* plain prefix */ + dst->bitlen = plen; + } + } + } + if (slash) + *slash = '/'; + return err; +} + +int get_addr(inet_prefix * dst, char *arg, int family) +{ + if (family == AF_PACKET) { + bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "address"); + } + if (get_addr_1(dst, arg, family)) { + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "address", arg); + } + return 0; +} + +int get_prefix(inet_prefix * dst, char *arg, int family) +{ + if (family == AF_PACKET) { + bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix"); + } + if (get_prefix_1(dst, arg, family)) { + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg); + } + return 0; +} + +uint32_t get_addr32(char *name) +{ + inet_prefix addr; + + if (get_addr_1(&addr, name, AF_INET)) { + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "IP", "address", name); + } + return addr.data[0]; +} + +void incomplete_command(void) +{ + bb_error_msg_and_die("command line is not complete, try option \"help\""); +} + +void invarg(const char *arg, const char *opt) +{ + bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt); +} + +void duparg(const char *key, const char *arg) +{ + bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg); +} + +void duparg2(const char *key, const char *arg) +{ + bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg); +} + +int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits) +{ + uint32_t *a1 = a->data; + uint32_t *a2 = b->data; + int words = bits >> 0x05; + + bits &= 0x1f; + + if (words) + if (memcmp(a1, a2, words << 2)) + return -1; + + if (bits) { + uint32_t w1, w2; + uint32_t mask; + + w1 = a1[words]; + w2 = a2[words]; + + mask = htonl((0xffffffff) << (0x20 - bits)); + + if ((w1 ^ w2) & mask) + return 1; + } + + return 0; +} + +const char *rt_addr_n2a(int af, int UNUSED_PARAM len, + void *addr, char *buf, int buflen) +{ + switch (af) { + case AF_INET: + case AF_INET6: + return inet_ntop(af, addr, buf, buflen); + default: + return "???"; + } +} + + +const char *format_host(int af, int len, void *addr, char *buf, int buflen) +{ +#ifdef RESOLVE_HOSTNAMES + if (resolve_hosts) { + struct hostent *h_ent; + + if (len <= 0) { + switch (af) { + case AF_INET: + len = 4; + break; + case AF_INET6: + len = 16; + break; + default:; + } + } + if (len > 0) { + h_ent = gethostbyaddr(addr, len, af); + if (h_ent != NULL) { + safe_strncpy(buf, h_ent->h_name, buflen); + return buf; + } + } + } +#endif + return rt_addr_n2a(af, len, addr, buf, buflen); +} |