utils.c revision 5e8bc6316b1a6c56598cdb29a737d1d670d74e69
1/* 2 * utils.c 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 * 11 * 12 * Changes: 13 * 14 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 15 */ 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <unistd.h> 20#include <syslog.h> 21#include <fcntl.h> 22#include <sys/socket.h> 23#include <netinet/in.h> 24#include <string.h> 25#include <netdb.h> 26#include <arpa/inet.h> 27#include <resolv.h> 28#include <asm/types.h> 29#include <linux/pkt_sched.h> 30 31#include "utils.h" 32 33int get_integer(int *val, const char *arg, int base) 34{ 35 long res; 36 char *ptr; 37 38 if (!arg || !*arg) 39 return -1; 40 res = strtol(arg, &ptr, base); 41 if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN) 42 return -1; 43 *val = res; 44 return 0; 45} 46 47int get_unsigned(unsigned *val, const char *arg, int base) 48{ 49 unsigned long res; 50 char *ptr; 51 52 if (!arg || !*arg) 53 return -1; 54 res = strtoul(arg, &ptr, base); 55 if (!ptr || ptr == arg || *ptr || res > UINT_MAX) 56 return -1; 57 *val = res; 58 return 0; 59} 60 61int get_u64(__u64 *val, const char *arg, int base) 62{ 63 unsigned long long res; 64 char *ptr; 65 66 if (!arg || !*arg) 67 return -1; 68 res = strtoull(arg, &ptr, base); 69 if (!ptr || ptr == arg || *ptr || res == 0xFFFFFFFFULL) 70 return -1; 71 *val = res; 72 return 0; 73} 74 75int get_u32(__u32 *val, const char *arg, int base) 76{ 77 unsigned long res; 78 char *ptr; 79 80 if (!arg || !*arg) 81 return -1; 82 res = strtoul(arg, &ptr, base); 83 if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL) 84 return -1; 85 *val = res; 86 return 0; 87} 88 89int get_u16(__u16 *val, const char *arg, int base) 90{ 91 unsigned long res; 92 char *ptr; 93 94 if (!arg || !*arg) 95 return -1; 96 res = strtoul(arg, &ptr, base); 97 if (!ptr || ptr == arg || *ptr || res > 0xFFFF) 98 return -1; 99 *val = res; 100 return 0; 101} 102 103int get_u8(__u8 *val, const char *arg, int base) 104{ 105 unsigned long res; 106 char *ptr; 107 108 if (!arg || !*arg) 109 return -1; 110 res = strtoul(arg, &ptr, base); 111 if (!ptr || ptr == arg || *ptr || res > 0xFF) 112 return -1; 113 *val = res; 114 return 0; 115} 116 117int get_s16(__s16 *val, const char *arg, int base) 118{ 119 long res; 120 char *ptr; 121 122 if (!arg || !*arg) 123 return -1; 124 res = strtol(arg, &ptr, base); 125 if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000) 126 return -1; 127 *val = res; 128 return 0; 129} 130 131int get_s8(__s8 *val, const char *arg, int base) 132{ 133 long res; 134 char *ptr; 135 136 if (!arg || !*arg) 137 return -1; 138 res = strtol(arg, &ptr, base); 139 if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80) 140 return -1; 141 *val = res; 142 return 0; 143} 144 145int get_addr_1(inet_prefix *addr, const char *name, int family) 146{ 147 const char *cp; 148 unsigned char *ap = (unsigned char*)addr->data; 149 int i; 150 151 memset(addr, 0, sizeof(*addr)); 152 153 if (strcmp(name, "default") == 0 || 154 strcmp(name, "all") == 0 || 155 strcmp(name, "any") == 0) { 156 if (family == AF_DECnet) 157 return -1; 158 addr->family = family; 159 addr->bytelen = (family == AF_INET6 ? 16 : 4); 160 addr->bitlen = -1; 161 return 0; 162 } 163 164 if (strchr(name, ':')) { 165 addr->family = AF_INET6; 166 if (family != AF_UNSPEC && family != AF_INET6) 167 return -1; 168 if (inet_pton(AF_INET6, name, addr->data) <= 0) 169 return -1; 170 addr->bytelen = 16; 171 addr->bitlen = -1; 172 return 0; 173 } 174 175 if (family == AF_DECnet) { 176 struct dn_naddr dna; 177 addr->family = AF_DECnet; 178 if (dnet_pton(AF_DECnet, name, &dna) <= 0) 179 return -1; 180 memcpy(addr->data, dna.a_addr, 2); 181 addr->bytelen = 2; 182 addr->bitlen = -1; 183 return 0; 184 } 185 186 addr->family = AF_INET; 187 if (family != AF_UNSPEC && family != AF_INET) 188 return -1; 189 addr->bytelen = 4; 190 addr->bitlen = -1; 191 for (cp=name, i=0; *cp; cp++) { 192 if (*cp <= '9' && *cp >= '0') { 193 ap[i] = 10*ap[i] + (*cp-'0'); 194 continue; 195 } 196 if (*cp == '.' && ++i <= 3) 197 continue; 198 return -1; 199 } 200 return 0; 201} 202 203int get_prefix_1(inet_prefix *dst, char *arg, int family) 204{ 205 int err; 206 unsigned plen; 207 char *slash; 208 209 memset(dst, 0, sizeof(*dst)); 210 211 if (strcmp(arg, "default") == 0 || 212 strcmp(arg, "any") == 0 || 213 strcmp(arg, "all") == 0) { 214 if (family == AF_DECnet) 215 return -1; 216 dst->family = family; 217 dst->bytelen = 0; 218 dst->bitlen = 0; 219 return 0; 220 } 221 222 slash = strchr(arg, '/'); 223 if (slash) 224 *slash = 0; 225 226 err = get_addr_1(dst, arg, family); 227 if (err == 0) { 228 switch(dst->family) { 229 case AF_INET6: 230 dst->bitlen = 128; 231 break; 232 case AF_DECnet: 233 dst->bitlen = 16; 234 break; 235 default: 236 case AF_INET: 237 dst->bitlen = 32; 238 } 239 if (slash) { 240 if (get_integer(&plen, slash+1, 0) || plen > dst->bitlen) { 241 err = -1; 242 goto done; 243 } 244 dst->bitlen = plen; 245 } 246 } 247done: 248 if (slash) 249 *slash = '/'; 250 return err; 251} 252 253int get_addr(inet_prefix *dst, const char *arg, int family) 254{ 255 if (family == AF_PACKET) { 256 fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg); 257 exit(1); 258 } 259 if (get_addr_1(dst, arg, family)) { 260 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg); 261 exit(1); 262 } 263 return 0; 264} 265 266int get_prefix(inet_prefix *dst, char *arg, int family) 267{ 268 if (family == AF_PACKET) { 269 fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg); 270 exit(1); 271 } 272 if (get_prefix_1(dst, arg, family)) { 273 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg); 274 exit(1); 275 } 276 return 0; 277} 278 279__u32 get_addr32(const char *name) 280{ 281 inet_prefix addr; 282 if (get_addr_1(&addr, name, AF_INET)) { 283 fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name); 284 exit(1); 285 } 286 return addr.data[0]; 287} 288 289void incomplete_command(void) 290{ 291 fprintf(stderr, "Command line is not complete. Try option \"help\"\n"); 292 exit(-1); 293} 294 295void missarg(const char *key) 296{ 297 fprintf(stderr, "Error: argument \"%s\" is required\n", key); 298 exit(-1); 299} 300 301void invarg(const char *msg, const char *arg) 302{ 303 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg); 304 exit(-1); 305} 306 307void duparg(const char *key, const char *arg) 308{ 309 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg); 310 exit(-1); 311} 312 313void duparg2(const char *key, const char *arg) 314{ 315 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg); 316 exit(-1); 317} 318 319int matches(const char *cmd, const char *pattern) 320{ 321 int len = strlen(cmd); 322 if (len > strlen(pattern)) 323 return -1; 324 return memcmp(pattern, cmd, len); 325} 326 327int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits) 328{ 329 __u32 *a1 = a->data; 330 __u32 *a2 = b->data; 331 int words = bits >> 0x05; 332 333 bits &= 0x1f; 334 335 if (words) 336 if (memcmp(a1, a2, words << 2)) 337 return -1; 338 339 if (bits) { 340 __u32 w1, w2; 341 __u32 mask; 342 343 w1 = a1[words]; 344 w2 = a2[words]; 345 346 mask = htonl((0xffffffff) << (0x20 - bits)); 347 348 if ((w1 ^ w2) & mask) 349 return 1; 350 } 351 352 return 0; 353} 354 355int __iproute2_hz_internal; 356 357int __get_hz(void) 358{ 359 char name[1024]; 360 int hz = 0; 361 FILE *fp; 362 363 if (getenv("HZ")) 364 return atoi(getenv("HZ")) ? : HZ; 365 366 if (getenv("PROC_NET_PSCHED")) { 367 snprintf(name, sizeof(name)-1, "%s", getenv("PROC_NET_PSCHED")); 368 } else if (getenv("PROC_ROOT")) { 369 snprintf(name, sizeof(name)-1, "%s/net/psched", getenv("PROC_ROOT")); 370 } else { 371 strcpy(name, "/proc/net/psched"); 372 } 373 fp = fopen(name, "r"); 374 375 if (fp) { 376 unsigned nom, denom; 377 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) 378 if (nom == 1000000) 379 hz = denom; 380 fclose(fp); 381 } 382 if (hz) 383 return hz; 384 return HZ; 385} 386 387int __iproute2_user_hz_internal; 388 389int __get_user_hz(void) 390{ 391 return sysconf(_SC_CLK_TCK); 392} 393 394const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen) 395{ 396 switch (af) { 397 case AF_INET: 398 case AF_INET6: 399 return inet_ntop(af, addr, buf, buflen); 400 case AF_IPX: 401 return ipx_ntop(af, addr, buf, buflen); 402 case AF_DECnet: 403 { 404 struct dn_naddr dna = { 2, { 0, 0, }}; 405 memcpy(dna.a_addr, addr, 2); 406 return dnet_ntop(af, &dna, buf, buflen); 407 } 408 default: 409 return "???"; 410 } 411} 412 413#ifdef RESOLVE_HOSTNAMES 414struct namerec 415{ 416 struct namerec *next; 417 inet_prefix addr; 418 char *name; 419}; 420 421static struct namerec *nht[256]; 422 423char *resolve_address(const char *addr, int len, int af) 424{ 425 struct namerec *n; 426 struct hostent *h_ent; 427 unsigned hash; 428 static int notfirst; 429 430 431 if (af == AF_INET6 && ((__u32*)addr)[0] == 0 && 432 ((__u32*)addr)[1] == 0 && ((__u32*)addr)[2] == htonl(0xffff)) { 433 af = AF_INET; 434 addr += 12; 435 len = 4; 436 } 437 438 hash = addr[len-1] ^ addr[len-2] ^ addr[len-3] ^ addr[len-4]; 439 440 for (n = nht[hash]; n; n = n->next) { 441 if (n->addr.family == af && 442 n->addr.bytelen == len && 443 memcmp(n->addr.data, addr, len) == 0) 444 return n->name; 445 } 446 if ((n = malloc(sizeof(*n))) == NULL) 447 return NULL; 448 n->addr.family = af; 449 n->addr.bytelen = len; 450 n->name = NULL; 451 memcpy(n->addr.data, addr, len); 452 n->next = nht[hash]; 453 nht[hash] = n; 454 if (++notfirst == 1) 455 sethostent(1); 456 fflush(stdout); 457 458 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL) 459 n->name = strdup(h_ent->h_name); 460 461 /* Even if we fail, "negative" entry is remembered. */ 462 return n->name; 463} 464#endif 465 466 467const char *format_host(int af, int len, const void *addr, 468 char *buf, int buflen) 469{ 470#ifdef RESOLVE_HOSTNAMES 471 if (resolve_hosts) { 472 char *n; 473 if (len <= 0) { 474 switch (af) { 475 case AF_INET: 476 len = 4; 477 break; 478 case AF_INET6: 479 len = 16; 480 break; 481 case AF_IPX: 482 len = 10; 483 break; 484#ifdef AF_DECnet 485 /* I see no reasons why gethostbyname 486 may not work for DECnet */ 487 case AF_DECnet: 488 len = 2; 489 break; 490#endif 491 default: ; 492 } 493 } 494 if (len > 0 && 495 (n = resolve_address(addr, len, af)) != NULL) 496 return n; 497 } 498#endif 499 return rt_addr_n2a(af, len, addr, buf, buflen); 500} 501 502 503__u8* hexstring_n2a(const __u8 *str, int len, __u8 *buf, int blen) 504{ 505 __u8 *ptr = buf; 506 int i; 507 508 for (i=0; i<len; i++) { 509 if (blen < 3) 510 break; 511 sprintf(ptr, "%02x", str[i]); 512 ptr += 2; 513 blen -= 2; 514 if (i != len-1 && blen > 1) { 515 *ptr++ = ':'; 516 blen--; 517 } 518 } 519 return buf; 520} 521 522__u8* hexstring_a2n(const __u8 *str, __u8 *buf, int blen) 523{ 524 int cnt = 0; 525 526 for (;;) { 527 unsigned acc; 528 char ch; 529 530 acc = 0; 531 532 while ((ch = *str) != ':' && ch != 0) { 533 if (ch >= '0' && ch <= '9') 534 ch -= '0'; 535 else if (ch >= 'a' && ch <= 'f') 536 ch -= 'a'-10; 537 else if (ch >= 'A' && ch <= 'F') 538 ch -= 'A'-10; 539 else 540 return NULL; 541 acc = (acc<<4) + ch; 542 str++; 543 } 544 545 if (acc > 255) 546 return NULL; 547 if (cnt < blen) { 548 buf[cnt] = acc; 549 cnt++; 550 } 551 if (ch == 0) 552 break; 553 ++str; 554 } 555 if (cnt < blen) 556 memset(buf+cnt, 0, blen-cnt); 557 return buf; 558} 559