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        if (family != AF_UNSPEC && family != AF_INET)
  87                return -1;
  88
  89        /* Try to parse it as IPv4 */
  90        addr->family = AF_INET;
  91#if 0 /* Doesn't handle e.g. "10.10", for example, "ip r l root 10.10/16" */
  92        if (inet_pton(AF_INET, name, addr->data) <= 0)
  93                return -1;
  94#else
  95        {
  96                unsigned i = 0;
  97                unsigned n = 0;
  98                const char *cp = name - 1;
  99                while (*++cp) {
 100                        if ((unsigned char)(*cp - '0') <= 9) {
 101                                n = 10 * n + (unsigned char)(*cp - '0');
 102                                if (n >= 256)
 103                                        return -1;
 104                                ((uint8_t*)addr->data)[i] = n;
 105                                continue;
 106                        }
 107                        if (*cp == '.' && ++i <= 3) {
 108                                n = 0;
 109                                continue;
 110                        }
 111                        return -1;
 112                }
 113        }
 114#endif
 115        addr->bytelen = 4;
 116        addr->bitlen = -1;
 117
 118        return 0;
 119}
 120
 121static void get_prefix_1(inet_prefix *dst, char *arg, int family)
 122{
 123        char *slash;
 124
 125        memset(dst, 0, sizeof(*dst));
 126
 127        if (strcmp(arg, "default") == 0
 128         || strcmp(arg, "all") == 0
 129         || strcmp(arg, "any") == 0
 130        ) {
 131                dst->family = family;
 132                /*dst->bytelen = 0; - done by memset */
 133                /*dst->bitlen = 0;*/
 134                return;
 135        }
 136
 137        slash = strchr(arg, '/');
 138        if (slash)
 139                *slash = '\0';
 140
 141        if (get_addr_1(dst, arg, family) == 0) {
 142                dst->bitlen = (dst->family == AF_INET6) ? 128 : 32;
 143                if (slash) {
 144                        unsigned plen;
 145                        inet_prefix netmask_pfx;
 146
 147                        netmask_pfx.family = AF_UNSPEC;
 148                        plen = bb_strtou(slash + 1, NULL, 0);
 149                        if ((errno || plen > dst->bitlen)
 150                         && get_addr_1(&netmask_pfx, slash + 1, family) != 0
 151                        ) {
 152                                goto bad;
 153                        }
 154                        if (netmask_pfx.family == AF_INET) {
 155                                /* fill in prefix length of dotted quad */
 156                                uint32_t mask = ntohl(netmask_pfx.data[0]);
 157                                uint32_t host = ~mask;
 158
 159                                /* a valid netmask must be 2^n - 1 */
 160                                if (host & (host + 1))
 161                                        goto bad;
 162
 163                                for (plen = 0; mask; mask <<= 1)
 164                                        ++plen;
 165                                if (plen > dst->bitlen)
 166                                        goto bad;
 167                                /* dst->flags |= PREFIXLEN_SPECIFIED; */
 168                        }
 169                        dst->bitlen = plen;
 170                }
 171        }
 172
 173        if (slash)
 174                *slash = '/';
 175        return;
 176 bad:
 177        bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg);
 178}
 179
 180int get_addr(inet_prefix *dst, char *arg, int family)
 181{
 182        if (family == AF_PACKET) {
 183                bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "address");
 184        }
 185        if (get_addr_1(dst, arg, family)) {
 186                bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "address", arg);
 187        }
 188        return 0;
 189}
 190
 191void get_prefix(inet_prefix *dst, char *arg, int family)
 192{
 193        if (family == AF_PACKET) {
 194                bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix");
 195        }
 196        get_prefix_1(dst, arg, family);
 197}
 198
 199uint32_t get_addr32(char *name)
 200{
 201        inet_prefix addr;
 202
 203        if (get_addr_1(&addr, name, AF_INET)) {
 204                bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "IP", "address", name);
 205        }
 206        return addr.data[0];
 207}
 208
 209void incomplete_command(void)
 210{
 211        bb_error_msg_and_die("command line is not complete, try option \"help\"");
 212}
 213
 214void invarg(const char *arg, const char *opt)
 215{
 216        bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt);
 217}
 218
 219void duparg(const char *key, const char *arg)
 220{
 221        bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg);
 222}
 223
 224void duparg2(const char *key, const char *arg)
 225{
 226        bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg);
 227}
 228
 229int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
 230{
 231        const uint32_t *a1 = a->data;
 232        const uint32_t *a2 = b->data;
 233        int words = bits >> 5;
 234
 235        bits &= 0x1f;
 236
 237        if (words)
 238                if (memcmp(a1, a2, words << 2))
 239                        return -1;
 240
 241        if (bits) {
 242                uint32_t w1, w2;
 243                uint32_t mask;
 244
 245                w1 = a1[words];
 246                w2 = a2[words];
 247
 248                mask = htonl((0xffffffff) << (0x20 - bits));
 249
 250                if ((w1 ^ w2) & mask)
 251                        return 1;
 252        }
 253
 254        return 0;
 255}
 256
 257const char *rt_addr_n2a(int af,
 258                void *addr, char *buf, int buflen)
 259{
 260        switch (af) {
 261        case AF_INET:
 262        case AF_INET6:
 263                return inet_ntop(af, addr, buf, buflen);
 264        default:
 265                return "???";
 266        }
 267}
 268
 269#ifdef RESOLVE_HOSTNAMES
 270const char *format_host(int af, int len, void *addr, char *buf, int buflen)
 271{
 272        if (resolve_hosts) {
 273                struct hostent *h_ent;
 274
 275                if (len <= 0) {
 276                        switch (af) {
 277                        case AF_INET:
 278                                len = 4;
 279                                break;
 280                        case AF_INET6:
 281                                len = 16;
 282                                break;
 283                        default:;
 284                        }
 285                }
 286                if (len > 0) {
 287                        h_ent = gethostbyaddr(addr, len, af);
 288                        if (h_ent != NULL) {
 289                                safe_strncpy(buf, h_ent->h_name, buflen);
 290                                return buf;
 291                        }
 292                }
 293        }
 294        return rt_addr_n2a(af, addr, buf, buflen);
 295}
 296#endif
 297