blob: 73ce865dfdb1f981a25c20a7d1e813c7226e4a8a [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
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>
osdl.org!shemminger5dfe5562004-06-08 23:50:43 +000028#include <asm/types.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000029#include <linux/pkt_sched.h>
30
31#include "utils.h"
32
osdl.org!shemminger4094db72004-06-02 20:22:08 +000033int get_integer(int *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000034{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +000047int get_unsigned(unsigned *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000048{
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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000061int 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
osdl.org!shemminger4094db72004-06-02 20:22:08 +000075int get_u32(__u32 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000076{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +000089int get_u16(__u16 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000090{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000103int get_u8(__u8 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000104{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000117int get_s16(__s16 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000118{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000131int get_s8(__s8 *val, const char *arg, int base)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000132{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000145int get_addr_1(inet_prefix *addr, const char *name, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000146{
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000147 const char *cp;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000148 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
osdl.net!shemmingerfb9b1d02005-02-07 18:15:04 +0000203int get_prefix_1(inet_prefix *dst, char *arg, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000204{
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;
osdl.net!shemmingerfb9b1d02005-02-07 18:15:04 +0000225
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000226 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->bitlen = plen;
245 }
246 }
247done:
248 if (slash)
249 *slash = '/';
250 return err;
251}
252
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000253int get_addr(inet_prefix *dst, const char *arg, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000254{
255 if (family == AF_PACKET) {
256 fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg);
257 exit(1);
258 }
259 if (get_addr_1(dst, arg, family)) {
260 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg);
261 exit(1);
262 }
263 return 0;
264}
265
osdl.net!shemmingerfb9b1d02005-02-07 18:15:04 +0000266int get_prefix(inet_prefix *dst, char *arg, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000267{
268 if (family == AF_PACKET) {
269 fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg);
270 exit(1);
271 }
272 if (get_prefix_1(dst, arg, family)) {
273 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg);
274 exit(1);
275 }
276 return 0;
277}
278
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000279__u32 get_addr32(const char *name)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000280{
281 inet_prefix addr;
282 if (get_addr_1(&addr, name, AF_INET)) {
283 fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name);
284 exit(1);
285 }
286 return addr.data[0];
287}
288
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000289void incomplete_command(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000290{
291 fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
292 exit(-1);
293}
294
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000295void missarg(const char *key)
296{
297 fprintf(stderr, "Error: argument \"%s\" is required\n", key);
298 exit(-1);
299}
300
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000301void invarg(const char *msg, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000302{
303 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg);
304 exit(-1);
305}
306
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000307void duparg(const char *key, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000308{
309 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg);
310 exit(-1);
311}
312
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000313void duparg2(const char *key, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000314{
315 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg);
316 exit(-1);
317}
318
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000319int matches(const char *cmd, const char *pattern)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000320{
321 int len = strlen(cmd);
322 if (len > strlen(pattern))
323 return -1;
324 return memcmp(pattern, cmd, len);
325}
326
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000327int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000328{
329 __u32 *a1 = a->data;
330 __u32 *a2 = b->data;
331 int words = bits >> 0x05;
332
333 bits &= 0x1f;
334
335 if (words)
336 if (memcmp(a1, a2, words << 2))
337 return -1;
338
339 if (bits) {
340 __u32 w1, w2;
341 __u32 mask;
342
343 w1 = a1[words];
344 w2 = a2[words];
345
346 mask = htonl((0xffffffff) << (0x20 - bits));
347
348 if ((w1 ^ w2) & mask)
349 return 1;
350 }
351
352 return 0;
353}
354
355int __iproute2_hz_internal;
356
357int __get_hz(void)
358{
359 char name[1024];
360 int hz = 0;
361 FILE *fp;
362
363 if (getenv("HZ"))
364 return atoi(getenv("HZ")) ? : HZ;
365
366 if (getenv("PROC_NET_PSCHED")) {
367 snprintf(name, sizeof(name)-1, "%s", getenv("PROC_NET_PSCHED"));
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000368 } else if (getenv("PROC_ROOT")) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000369 snprintf(name, sizeof(name)-1, "%s/net/psched", getenv("PROC_ROOT"));
370 } else {
371 strcpy(name, "/proc/net/psched");
372 }
373 fp = fopen(name, "r");
374
375 if (fp) {
376 unsigned nom, denom;
377 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
378 if (nom == 1000000)
379 hz = denom;
380 fclose(fp);
381 }
382 if (hz)
383 return hz;
384 return HZ;
385}
386
net[shemminger]!shemminger5e8bc632005-03-14 18:44:54 +0000387int __iproute2_user_hz_internal;
388
389int __get_user_hz(void)
390{
391 return sysconf(_SC_CLK_TCK);
392}
393
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000394const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000395{
396 switch (af) {
397 case AF_INET:
398 case AF_INET6:
399 return inet_ntop(af, addr, buf, buflen);
400 case AF_IPX:
401 return ipx_ntop(af, addr, buf, buflen);
402 case AF_DECnet:
403 {
404 struct dn_naddr dna = { 2, { 0, 0, }};
405 memcpy(dna.a_addr, addr, 2);
406 return dnet_ntop(af, &dna, buf, buflen);
407 }
408 default:
409 return "???";
410 }
411}
412
413#ifdef RESOLVE_HOSTNAMES
414struct namerec
415{
416 struct namerec *next;
417 inet_prefix addr;
418 char *name;
419};
420
421static struct namerec *nht[256];
422
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000423char *resolve_address(const char *addr, int len, int af)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000424{
425 struct namerec *n;
426 struct hostent *h_ent;
427 unsigned hash;
428 static int notfirst;
429
430
431 if (af == AF_INET6 && ((__u32*)addr)[0] == 0 &&
432 ((__u32*)addr)[1] == 0 && ((__u32*)addr)[2] == htonl(0xffff)) {
433 af = AF_INET;
434 addr += 12;
435 len = 4;
436 }
437
438 hash = addr[len-1] ^ addr[len-2] ^ addr[len-3] ^ addr[len-4];
439
440 for (n = nht[hash]; n; n = n->next) {
441 if (n->addr.family == af &&
442 n->addr.bytelen == len &&
443 memcmp(n->addr.data, addr, len) == 0)
444 return n->name;
445 }
446 if ((n = malloc(sizeof(*n))) == NULL)
447 return NULL;
448 n->addr.family = af;
449 n->addr.bytelen = len;
450 n->name = NULL;
451 memcpy(n->addr.data, addr, len);
452 n->next = nht[hash];
453 nht[hash] = n;
454 if (++notfirst == 1)
455 sethostent(1);
456 fflush(stdout);
457
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000458 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000459 n->name = strdup(h_ent->h_name);
460
461 /* Even if we fail, "negative" entry is remembered. */
462 return n->name;
463}
464#endif
465
466
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000467const char *format_host(int af, int len, const void *addr,
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000468 char *buf, int buflen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000469{
470#ifdef RESOLVE_HOSTNAMES
471 if (resolve_hosts) {
472 char *n;
473 if (len <= 0) {
474 switch (af) {
475 case AF_INET:
476 len = 4;
477 break;
478 case AF_INET6:
479 len = 16;
480 break;
481 case AF_IPX:
482 len = 10;
483 break;
484#ifdef AF_DECnet
485 /* I see no reasons why gethostbyname
486 may not work for DECnet */
487 case AF_DECnet:
488 len = 2;
489 break;
490#endif
491 default: ;
492 }
493 }
494 if (len > 0 &&
495 (n = resolve_address(addr, len, af)) != NULL)
496 return n;
497 }
498#endif
499 return rt_addr_n2a(af, len, addr, buf, buflen);
500}
501
502
503__u8* hexstring_n2a(const __u8 *str, int len, __u8 *buf, int blen)
504{
505 __u8 *ptr = buf;
506 int i;
507
508 for (i=0; i<len; i++) {
509 if (blen < 3)
510 break;
511 sprintf(ptr, "%02x", str[i]);
512 ptr += 2;
513 blen -= 2;
514 if (i != len-1 && blen > 1) {
515 *ptr++ = ':';
516 blen--;
517 }
518 }
519 return buf;
520}
521
522__u8* hexstring_a2n(const __u8 *str, __u8 *buf, int blen)
523{
524 int cnt = 0;
525
526 for (;;) {
527 unsigned acc;
528 char ch;
529
530 acc = 0;
531
532 while ((ch = *str) != ':' && ch != 0) {
533 if (ch >= '0' && ch <= '9')
534 ch -= '0';
535 else if (ch >= 'a' && ch <= 'f')
536 ch -= 'a'-10;
537 else if (ch >= 'A' && ch <= 'F')
538 ch -= 'A'-10;
539 else
540 return NULL;
541 acc = (acc<<4) + ch;
542 str++;
543 }
544
545 if (acc > 255)
546 return NULL;
547 if (cnt < blen) {
548 buf[cnt] = acc;
549 cnt++;
550 }
551 if (ch == 0)
552 break;
553 ++str;
554 }
555 if (cnt < blen)
556 memset(buf+cnt, 0, blen-cnt);
557 return buf;
558}