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