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