blob: df8795a2845daba2ab21f2cca21ca8ee7ec26cd1 [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 }
net[shemminger]!shemmingerf082b642005-03-30 18:16:10 +0000244 dst->flags |= PREFIXLEN_SPECIFIED;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000245 dst->bitlen = plen;
246 }
247 }
248done:
249 if (slash)
250 *slash = '/';
251 return err;
252}
253
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000254int get_addr(inet_prefix *dst, const char *arg, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000255{
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
osdl.net!shemmingerfb9b1d02005-02-07 18:15:04 +0000267int get_prefix(inet_prefix *dst, char *arg, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000268{
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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000280__u32 get_addr32(const char *name)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000281{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000290void incomplete_command(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000291{
292 fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
293 exit(-1);
294}
295
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000296void missarg(const char *key)
297{
298 fprintf(stderr, "Error: argument \"%s\" is required\n", key);
299 exit(-1);
300}
301
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000302void invarg(const char *msg, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000303{
304 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg);
305 exit(-1);
306}
307
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000308void duparg(const char *key, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000309{
310 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg);
311 exit(-1);
312}
313
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000314void duparg2(const char *key, const char *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000315{
316 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg);
317 exit(-1);
318}
319
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000320int matches(const char *cmd, const char *pattern)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000321{
322 int len = strlen(cmd);
323 if (len > strlen(pattern))
324 return -1;
325 return memcmp(pattern, cmd, len);
326}
327
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000328int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000329{
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"));
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000369 } else if (getenv("PROC_ROOT")) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000370 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
net[shemminger]!shemminger5e8bc632005-03-14 18:44:54 +0000388int __iproute2_user_hz_internal;
389
390int __get_user_hz(void)
391{
392 return sysconf(_SC_CLK_TCK);
393}
394
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000395const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000396{
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
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000424char *resolve_address(const char *addr, int len, int af)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000425{
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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000459 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000460 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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000468const char *format_host(int af, int len, const void *addr,
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000469 char *buf, int buflen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000470{
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}