utils.c revision 5dfe556188df2a3b2bfe73c8bc3b3b9216171a93
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_u32(__u32 *val, const char *arg, int base) 62{ 63 unsigned long res; 64 char *ptr; 65 66 if (!arg || !*arg) 67 return -1; 68 res = strtoul(arg, &ptr, base); 69 if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL) 70 return -1; 71 *val = res; 72 return 0; 73} 74 75int get_u16(__u16 *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 > 0xFFFF) 84 return -1; 85 *val = res; 86 return 0; 87} 88 89int get_u8(__u8 *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 > 0xFF) 98 return -1; 99 *val = res; 100 return 0; 101} 102 103int get_s16(__s16 *val, const char *arg, int base) 104{ 105 long res; 106 char *ptr; 107 108 if (!arg || !*arg) 109 return -1; 110 res = strtol(arg, &ptr, base); 111 if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000) 112 return -1; 113 *val = res; 114 return 0; 115} 116 117int get_s8(__s8 *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 > 0x7F || res < -0x80) 126 return -1; 127 *val = res; 128 return 0; 129} 130 131int get_addr_1(inet_prefix *addr, const char *name, int family) 132{ 133 const char *cp; 134 unsigned char *ap = (unsigned char*)addr->data; 135 int i; 136 137 memset(addr, 0, sizeof(*addr)); 138 139 if (strcmp(name, "default") == 0 || 140 strcmp(name, "all") == 0 || 141 strcmp(name, "any") == 0) { 142 if (family == AF_DECnet) 143 return -1; 144 addr->family = family; 145 addr->bytelen = (family == AF_INET6 ? 16 : 4); 146 addr->bitlen = -1; 147 return 0; 148 } 149 150 if (strchr(name, ':')) { 151 addr->family = AF_INET6; 152 if (family != AF_UNSPEC && family != AF_INET6) 153 return -1; 154 if (inet_pton(AF_INET6, name, addr->data) <= 0) 155 return -1; 156 addr->bytelen = 16; 157 addr->bitlen = -1; 158 return 0; 159 } 160 161 if (family == AF_DECnet) { 162 struct dn_naddr dna; 163 addr->family = AF_DECnet; 164 if (dnet_pton(AF_DECnet, name, &dna) <= 0) 165 return -1; 166 memcpy(addr->data, dna.a_addr, 2); 167 addr->bytelen = 2; 168 addr->bitlen = -1; 169 return 0; 170 } 171 172 addr->family = AF_INET; 173 if (family != AF_UNSPEC && family != AF_INET) 174 return -1; 175 addr->bytelen = 4; 176 addr->bitlen = -1; 177 for (cp=name, i=0; *cp; cp++) { 178 if (*cp <= '9' && *cp >= '0') { 179 ap[i] = 10*ap[i] + (*cp-'0'); 180 continue; 181 } 182 if (*cp == '.' && ++i <= 3) 183 continue; 184 return -1; 185 } 186 return 0; 187} 188 189int get_prefix_1(inet_prefix *dst, char *arg, int family) 190{ 191 int err; 192 unsigned plen; 193 char *slash; 194 195 memset(dst, 0, sizeof(*dst)); 196 197 if (strcmp(arg, "default") == 0 || 198 strcmp(arg, "any") == 0 || 199 strcmp(arg, "all") == 0) { 200 if (family == AF_DECnet) 201 return -1; 202 dst->family = family; 203 dst->bytelen = 0; 204 dst->bitlen = 0; 205 return 0; 206 } 207 208 slash = strchr(arg, '/'); 209 if (slash) 210 *slash = 0; 211 err = get_addr_1(dst, arg, family); 212 if (err == 0) { 213 switch(dst->family) { 214 case AF_INET6: 215 dst->bitlen = 128; 216 break; 217 case AF_DECnet: 218 dst->bitlen = 16; 219 break; 220 default: 221 case AF_INET: 222 dst->bitlen = 32; 223 } 224 if (slash) { 225 if (get_integer(&plen, slash+1, 0) || plen > dst->bitlen) { 226 err = -1; 227 goto done; 228 } 229 dst->bitlen = plen; 230 } 231 } 232done: 233 if (slash) 234 *slash = '/'; 235 return err; 236} 237 238int get_addr(inet_prefix *dst, char *arg, int family) 239{ 240 if (family == AF_PACKET) { 241 fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg); 242 exit(1); 243 } 244 if (get_addr_1(dst, arg, family)) { 245 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg); 246 exit(1); 247 } 248 return 0; 249} 250 251int get_prefix(inet_prefix *dst, char *arg, int family) 252{ 253 if (family == AF_PACKET) { 254 fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg); 255 exit(1); 256 } 257 if (get_prefix_1(dst, arg, family)) { 258 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg); 259 exit(1); 260 } 261 return 0; 262} 263 264__u32 get_addr32(char *name) 265{ 266 inet_prefix addr; 267 if (get_addr_1(&addr, name, AF_INET)) { 268 fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name); 269 exit(1); 270 } 271 return addr.data[0]; 272} 273 274void incomplete_command(void) 275{ 276 fprintf(stderr, "Command line is not complete. Try option \"help\"\n"); 277 exit(-1); 278} 279 280void invarg(const char *msg, const char *arg) 281{ 282 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg); 283 exit(-1); 284} 285 286void duparg(const char *key, const char *arg) 287{ 288 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg); 289 exit(-1); 290} 291 292void duparg2(const char *key, const char *arg) 293{ 294 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg); 295 exit(-1); 296} 297 298int matches(const char *cmd, const char *pattern) 299{ 300 int len = strlen(cmd); 301 if (len > strlen(pattern)) 302 return -1; 303 return memcmp(pattern, cmd, len); 304} 305 306int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits) 307{ 308 __u32 *a1 = a->data; 309 __u32 *a2 = b->data; 310 int words = bits >> 0x05; 311 312 bits &= 0x1f; 313 314 if (words) 315 if (memcmp(a1, a2, words << 2)) 316 return -1; 317 318 if (bits) { 319 __u32 w1, w2; 320 __u32 mask; 321 322 w1 = a1[words]; 323 w2 = a2[words]; 324 325 mask = htonl((0xffffffff) << (0x20 - bits)); 326 327 if ((w1 ^ w2) & mask) 328 return 1; 329 } 330 331 return 0; 332} 333 334int __iproute2_hz_internal; 335 336int __get_hz(void) 337{ 338 char name[1024]; 339 int hz = 0; 340 FILE *fp; 341 342 if (getenv("HZ")) 343 return atoi(getenv("HZ")) ? : HZ; 344 345 if (getenv("PROC_NET_PSCHED")) { 346 snprintf(name, sizeof(name)-1, "%s", getenv("PROC_NET_PSCHED")); 347 } else if (getenv("PROC_ROOT")) { 348 snprintf(name, sizeof(name)-1, "%s/net/psched", getenv("PROC_ROOT")); 349 } else { 350 strcpy(name, "/proc/net/psched"); 351 } 352 fp = fopen(name, "r"); 353 354 if (fp) { 355 unsigned nom, denom; 356 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) 357 if (nom == 1000000) 358 hz = denom; 359 fclose(fp); 360 } 361 if (hz) 362 return hz; 363 return HZ; 364} 365 366const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen) 367{ 368 switch (af) { 369 case AF_INET: 370 case AF_INET6: 371 return inet_ntop(af, addr, buf, buflen); 372 case AF_IPX: 373 return ipx_ntop(af, addr, buf, buflen); 374 case AF_DECnet: 375 { 376 struct dn_naddr dna = { 2, { 0, 0, }}; 377 memcpy(dna.a_addr, addr, 2); 378 return dnet_ntop(af, &dna, buf, buflen); 379 } 380 default: 381 return "???"; 382 } 383} 384 385#ifdef RESOLVE_HOSTNAMES 386struct namerec 387{ 388 struct namerec *next; 389 inet_prefix addr; 390 char *name; 391}; 392 393static struct namerec *nht[256]; 394 395char *resolve_address(const char *addr, int len, int af) 396{ 397 struct namerec *n; 398 struct hostent *h_ent; 399 unsigned hash; 400 static int notfirst; 401 402 403 if (af == AF_INET6 && ((__u32*)addr)[0] == 0 && 404 ((__u32*)addr)[1] == 0 && ((__u32*)addr)[2] == htonl(0xffff)) { 405 af = AF_INET; 406 addr += 12; 407 len = 4; 408 } 409 410 hash = addr[len-1] ^ addr[len-2] ^ addr[len-3] ^ addr[len-4]; 411 412 for (n = nht[hash]; n; n = n->next) { 413 if (n->addr.family == af && 414 n->addr.bytelen == len && 415 memcmp(n->addr.data, addr, len) == 0) 416 return n->name; 417 } 418 if ((n = malloc(sizeof(*n))) == NULL) 419 return NULL; 420 n->addr.family = af; 421 n->addr.bytelen = len; 422 n->name = NULL; 423 memcpy(n->addr.data, addr, len); 424 n->next = nht[hash]; 425 nht[hash] = n; 426 if (++notfirst == 1) 427 sethostent(1); 428 fflush(stdout); 429 430 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL) 431 n->name = strdup(h_ent->h_name); 432 433 /* Even if we fail, "negative" entry is remembered. */ 434 return n->name; 435} 436#endif 437 438 439const char *format_host(int af, int len, const void *addr, 440 char *buf, int buflen) 441{ 442#ifdef RESOLVE_HOSTNAMES 443 if (resolve_hosts) { 444 char *n; 445 if (len <= 0) { 446 switch (af) { 447 case AF_INET: 448 len = 4; 449 break; 450 case AF_INET6: 451 len = 16; 452 break; 453 case AF_IPX: 454 len = 10; 455 break; 456#ifdef AF_DECnet 457 /* I see no reasons why gethostbyname 458 may not work for DECnet */ 459 case AF_DECnet: 460 len = 2; 461 break; 462#endif 463 default: ; 464 } 465 } 466 if (len > 0 && 467 (n = resolve_address(addr, len, af)) != NULL) 468 return n; 469 } 470#endif 471 return rt_addr_n2a(af, len, addr, buf, buflen); 472} 473 474 475__u8* hexstring_n2a(const __u8 *str, int len, __u8 *buf, int blen) 476{ 477 __u8 *ptr = buf; 478 int i; 479 480 for (i=0; i<len; i++) { 481 if (blen < 3) 482 break; 483 sprintf(ptr, "%02x", str[i]); 484 ptr += 2; 485 blen -= 2; 486 if (i != len-1 && blen > 1) { 487 *ptr++ = ':'; 488 blen--; 489 } 490 } 491 return buf; 492} 493 494__u8* hexstring_a2n(const __u8 *str, __u8 *buf, int blen) 495{ 496 int cnt = 0; 497 498 for (;;) { 499 unsigned acc; 500 char ch; 501 502 acc = 0; 503 504 while ((ch = *str) != ':' && ch != 0) { 505 if (ch >= '0' && ch <= '9') 506 ch -= '0'; 507 else if (ch >= 'a' && ch <= 'f') 508 ch -= 'a'-10; 509 else if (ch >= 'A' && ch <= 'F') 510 ch -= 'A'-10; 511 else 512 return NULL; 513 acc = (acc<<4) + ch; 514 str++; 515 } 516 517 if (acc > 255) 518 return NULL; 519 if (cnt < blen) { 520 buf[cnt] = acc; 521 cnt++; 522 } 523 if (ch == 0) 524 break; 525 ++str; 526 } 527 if (cnt < blen) 528 memset(buf+cnt, 0, blen-cnt); 529 return buf; 530} 531