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#include <time.h> 31#include <sys/time.h> 32 33 34#include "utils.h" 35 36int get_integer(int *val, const char *arg, int base) 37{ 38 long res; 39 char *ptr; 40 41 if (!arg || !*arg) 42 return -1; 43 res = strtol(arg, &ptr, base); 44 if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN) 45 return -1; 46 *val = res; 47 return 0; 48} 49 50int get_unsigned(unsigned *val, const char *arg, int base) 51{ 52 unsigned long res; 53 char *ptr; 54 55 if (!arg || !*arg) 56 return -1; 57 res = strtoul(arg, &ptr, base); 58 if (!ptr || ptr == arg || *ptr || res > UINT_MAX) 59 return -1; 60 *val = res; 61 return 0; 62} 63 64int get_u64(__u64 *val, const char *arg, int base) 65{ 66 unsigned long long res; 67 char *ptr; 68 69 if (!arg || !*arg) 70 return -1; 71 res = strtoull(arg, &ptr, base); 72 if (!ptr || ptr == arg || *ptr || res == 0xFFFFFFFFULL) 73 return -1; 74 *val = res; 75 return 0; 76} 77 78int get_u32(__u32 *val, const char *arg, int base) 79{ 80 unsigned long res; 81 char *ptr; 82 83 if (!arg || !*arg) 84 return -1; 85 res = strtoul(arg, &ptr, base); 86 if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL) 87 return -1; 88 *val = res; 89 return 0; 90} 91 92int get_u16(__u16 *val, const char *arg, int base) 93{ 94 unsigned long res; 95 char *ptr; 96 97 if (!arg || !*arg) 98 return -1; 99 res = strtoul(arg, &ptr, base); 100 if (!ptr || ptr == arg || *ptr || res > 0xFFFF) 101 return -1; 102 *val = res; 103 return 0; 104} 105 106int get_u8(__u8 *val, const char *arg, int base) 107{ 108 unsigned long res; 109 char *ptr; 110 111 if (!arg || !*arg) 112 return -1; 113 res = strtoul(arg, &ptr, base); 114 if (!ptr || ptr == arg || *ptr || res > 0xFF) 115 return -1; 116 *val = res; 117 return 0; 118} 119 120int get_s16(__s16 *val, const char *arg, int base) 121{ 122 long res; 123 char *ptr; 124 125 if (!arg || !*arg) 126 return -1; 127 res = strtol(arg, &ptr, base); 128 if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000) 129 return -1; 130 *val = res; 131 return 0; 132} 133 134int get_s8(__s8 *val, const char *arg, int base) 135{ 136 long res; 137 char *ptr; 138 139 if (!arg || !*arg) 140 return -1; 141 res = strtol(arg, &ptr, base); 142 if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80) 143 return -1; 144 *val = res; 145 return 0; 146} 147 148int get_addr_1(inet_prefix *addr, const char *name, int family) 149{ 150 const char *cp; 151 unsigned char *ap = (unsigned char*)addr->data; 152 int i; 153 154 memset(addr, 0, sizeof(*addr)); 155 156 if (strcmp(name, "default") == 0 || 157 strcmp(name, "all") == 0 || 158 strcmp(name, "any") == 0) { 159 if (family == AF_DECnet) 160 return -1; 161 addr->family = family; 162 addr->bytelen = (family == AF_INET6 ? 16 : 4); 163 addr->bitlen = -1; 164 return 0; 165 } 166 167 if (strchr(name, ':')) { 168 addr->family = AF_INET6; 169 if (family != AF_UNSPEC && family != AF_INET6) 170 return -1; 171 if (inet_pton(AF_INET6, name, addr->data) <= 0) 172 return -1; 173 addr->bytelen = 16; 174 addr->bitlen = -1; 175 return 0; 176 } 177 178#if 0 /* Foxconn removed pling 07/26/2007 */ 179 if (family == AF_DECnet) { 180 struct dn_naddr dna; 181 addr->family = AF_DECnet; 182 if (dnet_pton(AF_DECnet, name, &dna) <= 0) 183 return -1; 184 memcpy(addr->data, dna.a_addr, 2); 185 addr->bytelen = 2; 186 addr->bitlen = -1; 187 return 0; 188 } 189#endif 190 191 addr->family = AF_INET; 192 if (family != AF_UNSPEC && family != AF_INET) 193 return -1; 194 addr->bytelen = 4; 195 addr->bitlen = -1; 196 for (cp=name, i=0; *cp; cp++) { 197 if (*cp <= '9' && *cp >= '0') { 198 ap[i] = 10*ap[i] + (*cp-'0'); 199 continue; 200 } 201 if (*cp == '.' && ++i <= 3) 202 continue; 203 return -1; 204 } 205 return 0; 206} 207 208int get_prefix_1(inet_prefix *dst, char *arg, int family) 209{ 210 int err; 211 unsigned plen; 212 char *slash; 213 214 memset(dst, 0, sizeof(*dst)); 215 216 if (strcmp(arg, "default") == 0 || 217 strcmp(arg, "any") == 0 || 218 strcmp(arg, "all") == 0) { 219 if (family == AF_DECnet) 220 return -1; 221 dst->family = family; 222 dst->bytelen = 0; 223 dst->bitlen = 0; 224 return 0; 225 } 226 227 slash = strchr(arg, '/'); 228 if (slash) 229 *slash = 0; 230 231 err = get_addr_1(dst, arg, family); 232 if (err == 0) { 233 switch(dst->family) { 234 case AF_INET6: 235 dst->bitlen = 128; 236 break; 237 case AF_DECnet: 238 dst->bitlen = 16; 239 break; 240 default: 241 case AF_INET: 242 dst->bitlen = 32; 243 } 244 if (slash) { 245 if (get_unsigned(&plen, slash+1, 0) || plen > dst->bitlen) { 246 err = -1; 247 goto done; 248 } 249 dst->flags |= PREFIXLEN_SPECIFIED; 250 dst->bitlen = plen; 251 } 252 } 253done: 254 if (slash) 255 *slash = '/'; 256 return err; 257} 258 259int get_addr(inet_prefix *dst, const char *arg, int family) 260{ 261 if (family == AF_PACKET) { 262 fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg); 263 exit(1); 264 } 265 if (get_addr_1(dst, arg, family)) { 266 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg); 267 exit(1); 268 } 269 return 0; 270} 271 272int get_prefix(inet_prefix *dst, char *arg, int family) 273{ 274 if (family == AF_PACKET) { 275 fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg); 276 exit(1); 277 } 278 if (get_prefix_1(dst, arg, family)) { 279 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg); 280 exit(1); 281 } 282 return 0; 283} 284 285__u32 get_addr32(const char *name) 286{ 287 inet_prefix addr; 288 if (get_addr_1(&addr, name, AF_INET)) { 289 fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name); 290 exit(1); 291 } 292 return addr.data[0]; 293} 294 295void incomplete_command(void) 296{ 297 fprintf(stderr, "Command line is not complete. Try option \"help\"\n"); 298 exit(-1); 299} 300 301void missarg(const char *key) 302{ 303 fprintf(stderr, "Error: argument \"%s\" is required\n", key); 304 exit(-1); 305} 306 307void invarg(const char *msg, const char *arg) 308{ 309 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg); 310 exit(-1); 311} 312 313void duparg(const char *key, const char *arg) 314{ 315 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg); 316 exit(-1); 317} 318 319void duparg2(const char *key, const char *arg) 320{ 321 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg); 322 exit(-1); 323} 324 325int matches(const char *cmd, const char *pattern) 326{ 327 int len = strlen(cmd); 328 if (len > strlen(pattern)) 329 return -1; 330 return memcmp(pattern, cmd, len); 331} 332 333int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits) 334{ 335 __u32 *a1 = a->data; 336 __u32 *a2 = b->data; 337 int words = bits >> 0x05; 338 339 bits &= 0x1f; 340 341 if (words) 342 if (memcmp(a1, a2, words << 2)) 343 return -1; 344 345 if (bits) { 346 __u32 w1, w2; 347 __u32 mask; 348 349 w1 = a1[words]; 350 w2 = a2[words]; 351 352 mask = htonl((0xffffffff) << (0x20 - bits)); 353 354 if ((w1 ^ w2) & mask) 355 return 1; 356 } 357 358 return 0; 359} 360 361int __iproute2_hz_internal; 362 363int __get_hz(void) 364{ 365 char name[1024]; 366 int hz = 0; 367 FILE *fp; 368 369 if (getenv("HZ")) 370 return atoi(getenv("HZ")) ? : HZ; 371 372 if (getenv("PROC_NET_PSCHED")) { 373 snprintf(name, sizeof(name)-1, "%s", getenv("PROC_NET_PSCHED")); 374 } else if (getenv("PROC_ROOT")) { 375 snprintf(name, sizeof(name)-1, "%s/net/psched", getenv("PROC_ROOT")); 376 } else { 377 strcpy(name, "/proc/net/psched"); 378 } 379 fp = fopen(name, "r"); 380 381 if (fp) { 382 unsigned nom, denom; 383 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) 384 if (nom == 1000000) 385 hz = denom; 386 fclose(fp); 387 } 388 if (hz) 389 return hz; 390 return HZ; 391} 392 393int __iproute2_user_hz_internal; 394 395int __get_user_hz(void) 396{ 397 return sysconf(_SC_CLK_TCK); 398} 399 400const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen) 401{ 402 switch (af) { 403 case AF_INET: 404 case AF_INET6: 405 return inet_ntop(af, addr, buf, buflen); 406#if 0 /* Foxconn removed pling 07/26/2007 */ 407 case AF_IPX: 408 return ipx_ntop(af, addr, buf, buflen); 409 case AF_DECnet: 410 { 411 struct dn_naddr dna = { 2, { 0, 0, }}; 412 memcpy(dna.a_addr, addr, 2); 413 return dnet_ntop(af, &dna, buf, buflen); 414 } 415#endif 416 default: 417 return "???"; 418 } 419} 420 421#ifdef RESOLVE_HOSTNAMES 422struct namerec 423{ 424 struct namerec *next; 425 inet_prefix addr; 426 char *name; 427}; 428 429static struct namerec *nht[256]; 430 431char *resolve_address(const char *addr, int len, int af) 432{ 433 struct namerec *n; 434 struct hostent *h_ent; 435 unsigned hash; 436 static int notfirst; 437 438 439 if (af == AF_INET6 && ((__u32*)addr)[0] == 0 && 440 ((__u32*)addr)[1] == 0 && ((__u32*)addr)[2] == htonl(0xffff)) { 441 af = AF_INET; 442 addr += 12; 443 len = 4; 444 } 445 446 hash = addr[len-1] ^ addr[len-2] ^ addr[len-3] ^ addr[len-4]; 447 448 for (n = nht[hash]; n; n = n->next) { 449 if (n->addr.family == af && 450 n->addr.bytelen == len && 451 memcmp(n->addr.data, addr, len) == 0) 452 return n->name; 453 } 454 if ((n = malloc(sizeof(*n))) == NULL) 455 return NULL; 456 n->addr.family = af; 457 n->addr.bytelen = len; 458 n->name = NULL; 459 memcpy(n->addr.data, addr, len); 460 n->next = nht[hash]; 461 nht[hash] = n; 462 if (++notfirst == 1) 463 sethostent(1); 464 fflush(stdout); 465 466 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL) 467 n->name = strdup(h_ent->h_name); 468 469 /* Even if we fail, "negative" entry is remembered. */ 470 return n->name; 471} 472#endif 473 474 475const char *format_host(int af, int len, const void *addr, 476 char *buf, int buflen) 477{ 478#ifdef RESOLVE_HOSTNAMES 479 if (resolve_hosts) { 480 char *n; 481 if (len <= 0) { 482 switch (af) { 483 case AF_INET: 484 len = 4; 485 break; 486 case AF_INET6: 487 len = 16; 488 break; 489 case AF_IPX: 490 len = 10; 491 break; 492#ifdef AF_DECnet 493 /* I see no reasons why gethostbyname 494 may not work for DECnet */ 495 case AF_DECnet: 496 len = 2; 497 break; 498#endif 499 default: ; 500 } 501 } 502 if (len > 0 && 503 (n = resolve_address(addr, len, af)) != NULL) 504 return n; 505 } 506#endif 507 return rt_addr_n2a(af, len, addr, buf, buflen); 508} 509 510 511char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen) 512{ 513 char *ptr = buf; 514 int i; 515 516 for (i=0; i<len; i++) { 517 if (blen < 3) 518 break; 519 sprintf(ptr, "%02x", str[i]); 520 ptr += 2; 521 blen -= 2; 522 if (i != len-1 && blen > 1) { 523 *ptr++ = ':'; 524 blen--; 525 } 526 } 527 return buf; 528} 529 530__u8* hexstring_a2n(const char *str, __u8 *buf, int blen) 531{ 532 int cnt = 0; 533 534 for (;;) { 535 unsigned acc; 536 char ch; 537 538 acc = 0; 539 540 while ((ch = *str) != ':' && ch != 0) { 541 if (ch >= '0' && ch <= '9') 542 ch -= '0'; 543 else if (ch >= 'a' && ch <= 'f') 544 ch -= 'a'-10; 545 else if (ch >= 'A' && ch <= 'F') 546 ch -= 'A'-10; 547 else 548 return NULL; 549 acc = (acc<<4) + ch; 550 str++; 551 } 552 553 if (acc > 255) 554 return NULL; 555 if (cnt < blen) { 556 buf[cnt] = acc; 557 cnt++; 558 } 559 if (ch == 0) 560 break; 561 ++str; 562 } 563 if (cnt < blen) 564 memset(buf+cnt, 0, blen-cnt); 565 return buf; 566} 567 568int print_timestamp(FILE *fp) 569{ 570 struct timeval tv; 571 char *tstr; 572 573 memset(&tv, 0, sizeof(tv)); 574 gettimeofday(&tv, NULL); 575 576 tstr = asctime(localtime(&tv.tv_sec)); 577 tstr[strlen(tstr)-1] = 0; 578 fprintf(fp, "Timestamp: %s %lu usec\n", tstr, tv.tv_usec); 579 return 0; 580} 581 582int cmdlineno; 583 584/* Like glibc getline but handle continuation lines and comments */ 585size_t getcmdline(char **linep, size_t *lenp, FILE *in) 586{ 587 size_t cc; 588 char *cp; 589 590 if ((cc = getline(linep, lenp, in)) < 0) 591 return cc; /* eof or error */ 592 ++cmdlineno; 593 594 cp = strchr(*linep, '#'); 595 if (cp) 596 *cp = '\0'; 597 598 while ((cp = strstr(*linep, "\\\n")) != NULL) { 599 char *line1 = NULL; 600 size_t len1 = 0; 601 size_t cc1; 602 603 if ((cc1 = getline(&line1, &len1, in)) < 0) { 604 fprintf(stderr, "Missing continuation line\n"); 605 return cc1; 606 } 607 608 ++cmdlineno; 609 *cp = 0; 610 611 cp = strchr(line1, '#'); 612 if (cp) 613 *cp = '\0'; 614 615 *linep = realloc(*linep, strlen(*linep) + strlen(line1) + 1); 616 if (!*linep) { 617 fprintf(stderr, "Out of memory\n"); 618 return -1; 619 } 620 cc += cc1 - 2; 621 strcat(*linep, line1); 622 free(line1); 623 } 624 return cc; 625} 626 627/* split command line into argument vector */ 628int makeargs(char *line, char *argv[], int maxargs) 629{ 630 static const char ws[] = " \t\r\n"; 631 char *cp; 632 int argc = 0; 633 634 for (cp = strtok(line, ws); cp; cp = strtok(NULL, ws)) { 635 if (argc >= (maxargs - 1)) { 636 fprintf(stderr, "Too many arguments to command\n"); 637 exit(1); 638 } 639 argv[argc++] = cp; 640 } 641 argv[argc] = NULL; 642 643 return argc; 644} 645