utils.c revision f082b64fb40b467bc1f9e5d245114aae4e256d5c
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->flags |= PREFIXLEN_SPECIFIED; 245 dst->bitlen = plen; 246 } 247 } 248done: 249 if (slash) 250 *slash = '/'; 251 return err; 252} 253 254int get_addr(inet_prefix *dst, const char *arg, int family) 255{ 256 if (family == AF_PACKET) { 257 fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg); 258 exit(1); 259 } 260 if (get_addr_1(dst, arg, family)) { 261 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg); 262 exit(1); 263 } 264 return 0; 265} 266 267int get_prefix(inet_prefix *dst, char *arg, int family) 268{ 269 if (family == AF_PACKET) { 270 fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg); 271 exit(1); 272 } 273 if (get_prefix_1(dst, arg, family)) { 274 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg); 275 exit(1); 276 } 277 return 0; 278} 279 280__u32 get_addr32(const char *name) 281{ 282 inet_prefix addr; 283 if (get_addr_1(&addr, name, AF_INET)) { 284 fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name); 285 exit(1); 286 } 287 return addr.data[0]; 288} 289 290void incomplete_command(void) 291{ 292 fprintf(stderr, "Command line is not complete. Try option \"help\"\n"); 293 exit(-1); 294} 295 296void missarg(const char *key) 297{ 298 fprintf(stderr, "Error: argument \"%s\" is required\n", key); 299 exit(-1); 300} 301 302void invarg(const char *msg, const char *arg) 303{ 304 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg); 305 exit(-1); 306} 307 308void duparg(const char *key, const char *arg) 309{ 310 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg); 311 exit(-1); 312} 313 314void duparg2(const char *key, const char *arg) 315{ 316 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg); 317 exit(-1); 318} 319 320int matches(const char *cmd, const char *pattern) 321{ 322 int len = strlen(cmd); 323 if (len > strlen(pattern)) 324 return -1; 325 return memcmp(pattern, cmd, len); 326} 327 328int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits) 329{ 330 __u32 *a1 = a->data; 331 __u32 *a2 = b->data; 332 int words = bits >> 0x05; 333 334 bits &= 0x1f; 335 336 if (words) 337 if (memcmp(a1, a2, words << 2)) 338 return -1; 339 340 if (bits) { 341 __u32 w1, w2; 342 __u32 mask; 343 344 w1 = a1[words]; 345 w2 = a2[words]; 346 347 mask = htonl((0xffffffff) << (0x20 - bits)); 348 349 if ((w1 ^ w2) & mask) 350 return 1; 351 } 352 353 return 0; 354} 355 356int __iproute2_hz_internal; 357 358int __get_hz(void) 359{ 360 char name[1024]; 361 int hz = 0; 362 FILE *fp; 363 364 if (getenv("HZ")) 365 return atoi(getenv("HZ")) ? : HZ; 366 367 if (getenv("PROC_NET_PSCHED")) { 368 snprintf(name, sizeof(name)-1, "%s", getenv("PROC_NET_PSCHED")); 369 } else if (getenv("PROC_ROOT")) { 370 snprintf(name, sizeof(name)-1, "%s/net/psched", getenv("PROC_ROOT")); 371 } else { 372 strcpy(name, "/proc/net/psched"); 373 } 374 fp = fopen(name, "r"); 375 376 if (fp) { 377 unsigned nom, denom; 378 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) 379 if (nom == 1000000) 380 hz = denom; 381 fclose(fp); 382 } 383 if (hz) 384 return hz; 385 return HZ; 386} 387 388int __iproute2_user_hz_internal; 389 390int __get_user_hz(void) 391{ 392 return sysconf(_SC_CLK_TCK); 393} 394 395const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen) 396{ 397 switch (af) { 398 case AF_INET: 399 case AF_INET6: 400 return inet_ntop(af, addr, buf, buflen); 401 case AF_IPX: 402 return ipx_ntop(af, addr, buf, buflen); 403 case AF_DECnet: 404 { 405 struct dn_naddr dna = { 2, { 0, 0, }}; 406 memcpy(dna.a_addr, addr, 2); 407 return dnet_ntop(af, &dna, buf, buflen); 408 } 409 default: 410 return "???"; 411 } 412} 413 414#ifdef RESOLVE_HOSTNAMES 415struct namerec 416{ 417 struct namerec *next; 418 inet_prefix addr; 419 char *name; 420}; 421 422static struct namerec *nht[256]; 423 424char *resolve_address(const char *addr, int len, int af) 425{ 426 struct namerec *n; 427 struct hostent *h_ent; 428 unsigned hash; 429 static int notfirst; 430 431 432 if (af == AF_INET6 && ((__u32*)addr)[0] == 0 && 433 ((__u32*)addr)[1] == 0 && ((__u32*)addr)[2] == htonl(0xffff)) { 434 af = AF_INET; 435 addr += 12; 436 len = 4; 437 } 438 439 hash = addr[len-1] ^ addr[len-2] ^ addr[len-3] ^ addr[len-4]; 440 441 for (n = nht[hash]; n; n = n->next) { 442 if (n->addr.family == af && 443 n->addr.bytelen == len && 444 memcmp(n->addr.data, addr, len) == 0) 445 return n->name; 446 } 447 if ((n = malloc(sizeof(*n))) == NULL) 448 return NULL; 449 n->addr.family = af; 450 n->addr.bytelen = len; 451 n->name = NULL; 452 memcpy(n->addr.data, addr, len); 453 n->next = nht[hash]; 454 nht[hash] = n; 455 if (++notfirst == 1) 456 sethostent(1); 457 fflush(stdout); 458 459 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL) 460 n->name = strdup(h_ent->h_name); 461 462 /* Even if we fail, "negative" entry is remembered. */ 463 return n->name; 464} 465#endif 466 467 468const char *format_host(int af, int len, const void *addr, 469 char *buf, int buflen) 470{ 471#ifdef RESOLVE_HOSTNAMES 472 if (resolve_hosts) { 473 char *n; 474 if (len <= 0) { 475 switch (af) { 476 case AF_INET: 477 len = 4; 478 break; 479 case AF_INET6: 480 len = 16; 481 break; 482 case AF_IPX: 483 len = 10; 484 break; 485#ifdef AF_DECnet 486 /* I see no reasons why gethostbyname 487 may not work for DECnet */ 488 case AF_DECnet: 489 len = 2; 490 break; 491#endif 492 default: ; 493 } 494 } 495 if (len > 0 && 496 (n = resolve_address(addr, len, af)) != NULL) 497 return n; 498 } 499#endif 500 return rt_addr_n2a(af, len, addr, buf, buflen); 501} 502 503 504__u8* hexstring_n2a(const __u8 *str, int len, __u8 *buf, int blen) 505{ 506 __u8 *ptr = buf; 507 int i; 508 509 for (i=0; i<len; i++) { 510 if (blen < 3) 511 break; 512 sprintf(ptr, "%02x", str[i]); 513 ptr += 2; 514 blen -= 2; 515 if (i != len-1 && blen > 1) { 516 *ptr++ = ':'; 517 blen--; 518 } 519 } 520 return buf; 521} 522 523__u8* hexstring_a2n(const __u8 *str, __u8 *buf, int blen) 524{ 525 int cnt = 0; 526 527 for (;;) { 528 unsigned acc; 529 char ch; 530 531 acc = 0; 532 533 while ((ch = *str) != ':' && ch != 0) { 534 if (ch >= '0' && ch <= '9') 535 ch -= '0'; 536 else if (ch >= 'a' && ch <= 'f') 537 ch -= 'a'-10; 538 else if (ch >= 'A' && ch <= 'F') 539 ch -= 'A'-10; 540 else 541 return NULL; 542 acc = (acc<<4) + ch; 543 str++; 544 } 545 546 if (acc > 255) 547 return NULL; 548 if (cnt < blen) { 549 buf[cnt] = acc; 550 cnt++; 551 } 552 if (ch == 0) 553 break; 554 ++str; 555 } 556 if (cnt < blen) 557 memset(buf+cnt, 0, blen-cnt); 558 return buf; 559} 560