]> git.proxmox.com Git - mirror_iproute2.git/blame - lib/utils.c
Initial revision
[mirror_iproute2.git] / lib / utils.c
CommitLineData
aba5acdf
SH
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>
5dfe5561 28#include <asm/types.h>
aba5acdf
SH
29#include <linux/pkt_sched.h>
30
31#include "utils.h"
32
4094db72 33int get_integer(int *val, const char *arg, int base)
aba5acdf
SH
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
4094db72 47int get_unsigned(unsigned *val, const char *arg, int base)
aba5acdf
SH
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
4094db72 61int get_u32(__u32 *val, const char *arg, int base)
aba5acdf
SH
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
4094db72 75int get_u16(__u16 *val, const char *arg, int base)
aba5acdf
SH
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
4094db72 89int get_u8(__u8 *val, const char *arg, int base)
aba5acdf
SH
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
4094db72 103int get_s16(__s16 *val, const char *arg, int base)
aba5acdf
SH
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
4094db72 117int get_s8(__s8 *val, const char *arg, int base)
aba5acdf
SH
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
4094db72 131int get_addr_1(inet_prefix *addr, const char *name, int family)
aba5acdf 132{
4094db72 133 const char *cp;
aba5acdf
SH
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
4094db72 274void incomplete_command(void)
aba5acdf
SH
275{
276 fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
277 exit(-1);
278}
279
4094db72 280void invarg(const char *msg, const char *arg)
aba5acdf
SH
281{
282 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg);
283 exit(-1);
284}
285
4094db72 286void duparg(const char *key, const char *arg)
aba5acdf
SH
287{
288 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg);
289 exit(-1);
290}
291
4094db72 292void duparg2(const char *key, const char *arg)
aba5acdf
SH
293{
294 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg);
295 exit(-1);
296}
297
4094db72 298int matches(const char *cmd, const char *pattern)
aba5acdf
SH
299{
300 int len = strlen(cmd);
301 if (len > strlen(pattern))
302 return -1;
303 return memcmp(pattern, cmd, len);
304}
305
4094db72 306int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
aba5acdf
SH
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
4094db72 366const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen)
aba5acdf
SH
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
4094db72 395char *resolve_address(const char *addr, int len, int af)
aba5acdf
SH
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
4094db72 430 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL)
aba5acdf
SH
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
4094db72
SH
439const char *format_host(int af, int len, const void *addr,
440 char *buf, int buflen)
aba5acdf
SH
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}