busybox/networking/libiproute/utils.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   4 *
   5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   6 *
   7 * Changes:
   8 *
   9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
  10 */
  11
  12#include "libbb.h"
  13#include "utils.h"
  14#include "inet_common.h"
  15
  16unsigned get_unsigned(char *arg, const char *errmsg)
  17{
  18        unsigned long res;
  19        char *ptr;
  20
  21        if (*arg) {
  22                res = strtoul(arg, &ptr, 0);
  23//FIXME: "" will be accepted too, is it correct?!
  24                if (!*ptr && res <= UINT_MAX) {
  25                        return res;
  26                }
  27        }
  28        invarg(arg, errmsg); /* does not return */
  29}
  30
  31uint32_t get_u32(char *arg, const char *errmsg)
  32{
  33        unsigned long res;
  34        char *ptr;
  35
  36        if (*arg) {
  37                res = strtoul(arg, &ptr, 0);
  38//FIXME: "" will be accepted too, is it correct?!
  39                if (!*ptr && res <= 0xFFFFFFFFUL) {
  40                        return res;
  41                }
  42        }
  43        invarg(arg, errmsg); /* does not return */
  44}
  45
  46uint16_t get_u16(char *arg, const char *errmsg)
  47{
  48        unsigned long res;
  49        char *ptr;
  50
  51        if (*arg) {
  52                res = strtoul(arg, &ptr, 0);
  53//FIXME: "" will be accepted too, is it correct?!
  54                if (!*ptr && res <= 0xFFFF) {
  55                        return res;
  56                }
  57        }
  58        invarg(arg, errmsg); /* does not return */
  59}
  60
  61int get_addr_1(inet_prefix *addr, char *name, int family)
  62{
  63        memset(addr, 0, sizeof(*addr));
  64
  65        if (strcmp(name, "default") == 0
  66         || strcmp(name, "all") == 0
  67         || strcmp(name, "any") == 0
  68        ) {
  69                addr->family = family;
  70                addr->bytelen = (family == AF_INET6 ? 16 : 4);
  71                addr->bitlen = -1;
  72                return 0;
  73        }
  74
  75        if (strchr(name, ':')) {
  76                addr->family = AF_INET6;
  77                if (family != AF_UNSPEC && family != AF_INET6)
  78                        return -1;
  79                if (inet_pton(AF_INET6, name, addr->data) <= 0)
  80                        return -1;
  81                addr->bytelen = 16;
  82                addr->bitlen = -1;
  83                return 0;
  84        }
  85
  86        addr->family = AF_INET;
  87        if (family != AF_UNSPEC && family != AF_INET)
  88                return -1;
  89        if (inet_pton(AF_INET, name, addr->data) <= 0)
  90                return -1;
  91        addr->bytelen = 4;
  92        addr->bitlen = -1;
  93        return 0;
  94}
  95
  96static int get_prefix_1(inet_prefix *dst, char *arg, int family)
  97{
  98        int err;
  99        unsigned plen;
 100        char *slash;
 101
 102        memset(dst, 0, sizeof(*dst));
 103
 104        if (strcmp(arg, "default") == 0
 105         || strcmp(arg, "all") == 0
 106         || strcmp(arg, "any") == 0
 107        ) {
 108                dst->family = family;
 109                /*dst->bytelen = 0; - done by memset */
 110                /*dst->bitlen = 0;*/
 111                return 0;
 112        }
 113
 114        slash = strchr(arg, '/');
 115        if (slash)
 116                *slash = '\0';
 117        err = get_addr_1(dst, arg, family);
 118        if (err == 0) {
 119                dst->bitlen = (dst->family == AF_INET6) ? 128 : 32;
 120                if (slash) {
 121                        inet_prefix netmask_pfx;
 122
 123                        netmask_pfx.family = AF_UNSPEC;
 124                        plen = bb_strtou(slash + 1, NULL, 0);
 125                        if ((errno || plen > dst->bitlen)
 126                         && (get_addr_1(&netmask_pfx, slash + 1, family)))
 127                                err = -1;
 128                        else if (netmask_pfx.family == AF_INET) {
 129                                /* fill in prefix length of dotted quad */
 130                                uint32_t mask = ntohl(netmask_pfx.data[0]);
 131                                uint32_t host = ~mask;
 132
 133                                /* a valid netmask must be 2^n - 1 */
 134                                if (!(host & (host + 1))) {
 135                                        for (plen = 0; mask; mask <<= 1)
 136                                                ++plen;
 137                                        if (plen <= dst->bitlen) {
 138                                                dst->bitlen = plen;
 139                                                /* dst->flags |= PREFIXLEN_SPECIFIED; */
 140                                        } else
 141                                                err = -1;
 142                                } else
 143                                        err = -1;
 144                        } else {
 145                                /* plain prefix */
 146                                dst->bitlen = plen;
 147                        }
 148                }
 149        }
 150        if (slash)
 151                *slash = '/';
 152        return err;
 153}
 154
 155int get_addr(inet_prefix *dst, char *arg, int family)
 156{
 157        if (family == AF_PACKET) {
 158                bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "address");
 159        }
 160        if (get_addr_1(dst, arg, family)) {
 161                bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "address", arg);
 162        }
 163        return 0;
 164}
 165
 166int get_prefix(inet_prefix *dst, char *arg, int family)
 167{
 168        if (family == AF_PACKET) {
 169                bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix");
 170        }
 171        if (get_prefix_1(dst, arg, family)) {
 172                bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg);
 173        }
 174        return 0;
 175}
 176
 177uint32_t get_addr32(char *name)
 178{
 179        inet_prefix addr;
 180
 181        if (get_addr_1(&addr, name, AF_INET)) {
 182                bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "IP", "address", name);
 183        }
 184        return addr.data[0];
 185}
 186
 187void incomplete_command(void)
 188{
 189        bb_error_msg_and_die("command line is not complete, try option \"help\"");
 190}
 191
 192void invarg(const char *arg, const char *opt)
 193{
 194        bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt);
 195}
 196
 197void duparg(const char *key, const char *arg)
 198{
 199        bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg);
 200}
 201
 202void duparg2(const char *key, const char *arg)
 203{
 204        bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg);
 205}
 206
 207int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits)
 208{
 209        uint32_t *a1 = a->data;
 210        uint32_t *a2 = b->data;
 211        int words = bits >> 5;
 212
 213        bits &= 0x1f;
 214
 215        if (words)
 216                if (memcmp(a1, a2, words << 2))
 217                        return -1;
 218
 219        if (bits) {
 220                uint32_t w1, w2;
 221                uint32_t mask;
 222
 223                w1 = a1[words];
 224                w2 = a2[words];
 225
 226                mask = htonl((0xffffffff) << (0x20 - bits));
 227
 228                if ((w1 ^ w2) & mask)
 229                        return 1;
 230        }
 231
 232        return 0;
 233}
 234
 235const char *rt_addr_n2a(int af,
 236                void *addr, char *buf, int buflen)
 237{
 238        switch (af) {
 239        case AF_INET:
 240        case AF_INET6:
 241                return inet_ntop(af, addr, buf, buflen);
 242        default:
 243                return "???";
 244        }
 245}
 246
 247#ifdef RESOLVE_HOSTNAMES
 248const char *format_host(int af, int len, void *addr, char *buf, int buflen)
 249{
 250        if (resolve_hosts) {
 251                struct hostent *h_ent;
 252
 253                if (len <= 0) {
 254                        switch (af) {
 255                        case AF_INET:
 256                                len = 4;
 257                                break;
 258                        case AF_INET6:
 259                                len = 16;
 260                                break;
 261                        default:;
 262                        }
 263                }
 264                if (len > 0) {
 265                        h_ent = gethostbyaddr(addr, len, af);
 266                        if (h_ent != NULL) {
 267                                safe_strncpy(buf, h_ent->h_name, buflen);
 268                                return buf;
 269                        }
 270                }
 271        }
 272        return rt_addr_n2a(af, addr, buf, buflen);
 273}
 274#endif
 275