]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - lib/utils.c
7834b7aa8a62dbfd556fc10d8cff96aeff0c0eb8
[lisovros/iproute2_canprio.git] / lib / utils.c
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
33 int 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
47 int 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
61 int 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
75 int 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
89 int 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
103 int 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
117 int 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
131 int 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
189 int 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         }
232 done:
233         if (slash)
234                 *slash = '/';
235         return err;
236 }
237
238 int 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
251 int 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
274 void incomplete_command(void)
275 {
276         fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
277         exit(-1);
278 }
279
280 void 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
286 void 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
292 void 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
298 int 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
306 int 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
334 int __iproute2_hz_internal;
335
336 int __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
366 const 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
386 struct namerec
387 {
388         struct namerec *next;
389         inet_prefix addr;
390         char        *name;
391 };
392
393 static struct namerec *nht[256];
394
395 char *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
439 const 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 }