]> git.proxmox.com Git - mirror_iproute2.git/blob - lib/rt_names.c
Merge branch 'master' into net-next
[mirror_iproute2.git] / lib / rt_names.c
1 /*
2 * rt_names.c rtnetlink names DB.
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 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <string.h>
17 #include <sys/time.h>
18 #include <sys/socket.h>
19 #include <dirent.h>
20 #include <limits.h>
21
22 #include <asm/types.h>
23 #include <linux/rtnetlink.h>
24
25 #include "rt_names.h"
26 #include "utils.h"
27
28 #define NAME_MAX_LEN 512
29
30 struct rtnl_hash_entry {
31 struct rtnl_hash_entry *next;
32 const char *name;
33 unsigned int id;
34 };
35
36 static int fread_id_name(FILE *fp, int *id, char *namebuf)
37 {
38 char buf[NAME_MAX_LEN];
39
40 while (fgets(buf, sizeof(buf), fp)) {
41 char *p = buf;
42
43 while (*p == ' ' || *p == '\t')
44 p++;
45
46 if (*p == '#' || *p == '\n' || *p == 0)
47 continue;
48
49 if (sscanf(p, "0x%x %s\n", id, namebuf) != 2 &&
50 sscanf(p, "0x%x %s #", id, namebuf) != 2 &&
51 sscanf(p, "%d %s\n", id, namebuf) != 2 &&
52 sscanf(p, "%d %s #", id, namebuf) != 2) {
53 strcpy(namebuf, p);
54 return -1;
55 }
56 return 1;
57 }
58 return 0;
59 }
60
61 static void
62 rtnl_hash_initialize(const char *file, struct rtnl_hash_entry **hash, int size)
63 {
64 struct rtnl_hash_entry *entry;
65 FILE *fp;
66 int id;
67 char namebuf[NAME_MAX_LEN] = {0};
68 int ret;
69
70 fp = fopen(file, "r");
71 if (!fp)
72 return;
73
74 while ((ret = fread_id_name(fp, &id, &namebuf[0]))) {
75 if (ret == -1) {
76 fprintf(stderr, "Database %s is corrupted at %s\n",
77 file, namebuf);
78 fclose(fp);
79 return;
80 }
81
82 if (id < 0)
83 continue;
84
85 entry = malloc(sizeof(*entry));
86 entry->id = id;
87 entry->name = strdup(namebuf);
88 entry->next = hash[id & (size - 1)];
89 hash[id & (size - 1)] = entry;
90 }
91 fclose(fp);
92 }
93
94 static void rtnl_tab_initialize(const char *file, char **tab, int size)
95 {
96 FILE *fp;
97 int id;
98 char namebuf[NAME_MAX_LEN] = {0};
99 int ret;
100
101 fp = fopen(file, "r");
102 if (!fp)
103 return;
104
105 while ((ret = fread_id_name(fp, &id, &namebuf[0]))) {
106 if (ret == -1) {
107 fprintf(stderr, "Database %s is corrupted at %s\n",
108 file, namebuf);
109 fclose(fp);
110 return;
111 }
112 if (id < 0 || id > size)
113 continue;
114
115 tab[id] = strdup(namebuf);
116 }
117 fclose(fp);
118 }
119
120 static char *rtnl_rtprot_tab[256] = {
121 [RTPROT_UNSPEC] = "unspec",
122 [RTPROT_REDIRECT] = "redirect",
123 [RTPROT_KERNEL] = "kernel",
124 [RTPROT_BOOT] = "boot",
125 [RTPROT_STATIC] = "static",
126
127 [RTPROT_GATED] = "gated",
128 [RTPROT_RA] = "ra",
129 [RTPROT_MRT] = "mrt",
130 [RTPROT_ZEBRA] = "zebra",
131 [RTPROT_BIRD] = "bird",
132 [RTPROT_BABEL] = "babel",
133 [RTPROT_DNROUTED] = "dnrouted",
134 [RTPROT_XORP] = "xorp",
135 [RTPROT_NTK] = "ntk",
136 [RTPROT_DHCP] = "dhcp",
137 };
138
139
140 static int rtnl_rtprot_init;
141
142 static void rtnl_rtprot_initialize(void)
143 {
144 struct dirent *de;
145 DIR *d;
146
147 rtnl_rtprot_init = 1;
148 rtnl_tab_initialize(CONFDIR "/rt_protos",
149 rtnl_rtprot_tab, 256);
150
151 d = opendir(CONFDIR "/rt_protos.d");
152 if (!d)
153 return;
154
155 while ((de = readdir(d)) != NULL) {
156 char path[PATH_MAX];
157 size_t len;
158
159 if (*de->d_name == '.')
160 continue;
161
162 /* only consider filenames ending in '.conf' */
163 len = strlen(de->d_name);
164 if (len <= 5)
165 continue;
166 if (strcmp(de->d_name + len - 5, ".conf"))
167 continue;
168
169 snprintf(path, sizeof(path), CONFDIR "/rt_protos.d/%s",
170 de->d_name);
171 rtnl_tab_initialize(path, rtnl_rtprot_tab, 256);
172 }
173 closedir(d);
174 }
175
176 const char *rtnl_rtprot_n2a(int id, char *buf, int len)
177 {
178 if (id < 0 || id >= 256) {
179 snprintf(buf, len, "%u", id);
180 return buf;
181 }
182 if (!rtnl_rtprot_tab[id]) {
183 if (!rtnl_rtprot_init)
184 rtnl_rtprot_initialize();
185 }
186 if (rtnl_rtprot_tab[id])
187 return rtnl_rtprot_tab[id];
188 snprintf(buf, len, "%u", id);
189 return buf;
190 }
191
192 int rtnl_rtprot_a2n(__u32 *id, const char *arg)
193 {
194 static char *cache;
195 static unsigned long res;
196 char *end;
197 int i;
198
199 if (cache && strcmp(cache, arg) == 0) {
200 *id = res;
201 return 0;
202 }
203
204 if (!rtnl_rtprot_init)
205 rtnl_rtprot_initialize();
206
207 for (i = 0; i < 256; i++) {
208 if (rtnl_rtprot_tab[i] &&
209 strcmp(rtnl_rtprot_tab[i], arg) == 0) {
210 cache = rtnl_rtprot_tab[i];
211 res = i;
212 *id = res;
213 return 0;
214 }
215 }
216
217 res = strtoul(arg, &end, 0);
218 if (!end || end == arg || *end || res > 255)
219 return -1;
220 *id = res;
221 return 0;
222 }
223
224
225 static char *rtnl_rtscope_tab[256] = {
226 [RT_SCOPE_UNIVERSE] = "global",
227 [RT_SCOPE_NOWHERE] = "nowhere",
228 [RT_SCOPE_HOST] = "host",
229 [RT_SCOPE_LINK] = "link",
230 [RT_SCOPE_SITE] = "site",
231 };
232
233 static int rtnl_rtscope_init;
234
235 static void rtnl_rtscope_initialize(void)
236 {
237 rtnl_rtscope_init = 1;
238 rtnl_tab_initialize(CONFDIR "/rt_scopes",
239 rtnl_rtscope_tab, 256);
240 }
241
242 const char *rtnl_rtscope_n2a(int id, char *buf, int len)
243 {
244 if (id < 0 || id >= 256) {
245 snprintf(buf, len, "%d", id);
246 return buf;
247 }
248
249 if (!rtnl_rtscope_tab[id]) {
250 if (!rtnl_rtscope_init)
251 rtnl_rtscope_initialize();
252 }
253
254 if (rtnl_rtscope_tab[id])
255 return rtnl_rtscope_tab[id];
256
257 snprintf(buf, len, "%d", id);
258 return buf;
259 }
260
261 int rtnl_rtscope_a2n(__u32 *id, const char *arg)
262 {
263 static const char *cache;
264 static unsigned long res;
265 char *end;
266 int i;
267
268 if (cache && strcmp(cache, arg) == 0) {
269 *id = res;
270 return 0;
271 }
272
273 if (!rtnl_rtscope_init)
274 rtnl_rtscope_initialize();
275
276 for (i = 0; i < 256; i++) {
277 if (rtnl_rtscope_tab[i] &&
278 strcmp(rtnl_rtscope_tab[i], arg) == 0) {
279 cache = rtnl_rtscope_tab[i];
280 res = i;
281 *id = res;
282 return 0;
283 }
284 }
285
286 res = strtoul(arg, &end, 0);
287 if (!end || end == arg || *end || res > 255)
288 return -1;
289 *id = res;
290 return 0;
291 }
292
293
294 static char *rtnl_rtrealm_tab[256] = {
295 "unknown",
296 };
297
298 static int rtnl_rtrealm_init;
299
300 static void rtnl_rtrealm_initialize(void)
301 {
302 rtnl_rtrealm_init = 1;
303 rtnl_tab_initialize(CONFDIR "/rt_realms",
304 rtnl_rtrealm_tab, 256);
305 }
306
307 const char *rtnl_rtrealm_n2a(int id, char *buf, int len)
308 {
309 if (id < 0 || id >= 256) {
310 snprintf(buf, len, "%d", id);
311 return buf;
312 }
313 if (!rtnl_rtrealm_tab[id]) {
314 if (!rtnl_rtrealm_init)
315 rtnl_rtrealm_initialize();
316 }
317 if (rtnl_rtrealm_tab[id])
318 return rtnl_rtrealm_tab[id];
319 snprintf(buf, len, "%d", id);
320 return buf;
321 }
322
323
324 int rtnl_rtrealm_a2n(__u32 *id, const char *arg)
325 {
326 static char *cache;
327 static unsigned long res;
328 char *end;
329 int i;
330
331 if (cache && strcmp(cache, arg) == 0) {
332 *id = res;
333 return 0;
334 }
335
336 if (!rtnl_rtrealm_init)
337 rtnl_rtrealm_initialize();
338
339 for (i = 0; i < 256; i++) {
340 if (rtnl_rtrealm_tab[i] &&
341 strcmp(rtnl_rtrealm_tab[i], arg) == 0) {
342 cache = rtnl_rtrealm_tab[i];
343 res = i;
344 *id = res;
345 return 0;
346 }
347 }
348
349 res = strtoul(arg, &end, 0);
350 if (!end || end == arg || *end || res > 255)
351 return -1;
352 *id = res;
353 return 0;
354 }
355
356
357 static struct rtnl_hash_entry dflt_table_entry = { .name = "default" };
358 static struct rtnl_hash_entry main_table_entry = { .name = "main" };
359 static struct rtnl_hash_entry local_table_entry = { .name = "local" };
360
361 static struct rtnl_hash_entry *rtnl_rttable_hash[256] = {
362 [RT_TABLE_DEFAULT] = &dflt_table_entry,
363 [RT_TABLE_MAIN] = &main_table_entry,
364 [RT_TABLE_LOCAL] = &local_table_entry,
365 };
366
367 static int rtnl_rttable_init;
368
369 static void rtnl_rttable_initialize(void)
370 {
371 struct dirent *de;
372 DIR *d;
373 int i;
374
375 rtnl_rttable_init = 1;
376 for (i = 0; i < 256; i++) {
377 if (rtnl_rttable_hash[i])
378 rtnl_rttable_hash[i]->id = i;
379 }
380 rtnl_hash_initialize(CONFDIR "/rt_tables",
381 rtnl_rttable_hash, 256);
382
383 d = opendir(CONFDIR "/rt_tables.d");
384 if (!d)
385 return;
386
387 while ((de = readdir(d)) != NULL) {
388 char path[PATH_MAX];
389 size_t len;
390
391 if (*de->d_name == '.')
392 continue;
393
394 /* only consider filenames ending in '.conf' */
395 len = strlen(de->d_name);
396 if (len <= 5)
397 continue;
398 if (strcmp(de->d_name + len - 5, ".conf"))
399 continue;
400
401 snprintf(path, sizeof(path),
402 CONFDIR "/rt_tables.d/%s", de->d_name);
403 rtnl_hash_initialize(path, rtnl_rttable_hash, 256);
404 }
405 closedir(d);
406 }
407
408 const char *rtnl_rttable_n2a(__u32 id, char *buf, int len)
409 {
410 struct rtnl_hash_entry *entry;
411
412 if (!rtnl_rttable_init)
413 rtnl_rttable_initialize();
414 entry = rtnl_rttable_hash[id & 255];
415 while (entry && entry->id != id)
416 entry = entry->next;
417 if (entry)
418 return entry->name;
419 snprintf(buf, len, "%u", id);
420 return buf;
421 }
422
423 int rtnl_rttable_a2n(__u32 *id, const char *arg)
424 {
425 static const char *cache;
426 static unsigned long res;
427 struct rtnl_hash_entry *entry;
428 char *end;
429 unsigned long i;
430
431 if (cache && strcmp(cache, arg) == 0) {
432 *id = res;
433 return 0;
434 }
435
436 if (!rtnl_rttable_init)
437 rtnl_rttable_initialize();
438
439 for (i = 0; i < 256; i++) {
440 entry = rtnl_rttable_hash[i];
441 while (entry && strcmp(entry->name, arg))
442 entry = entry->next;
443 if (entry) {
444 cache = entry->name;
445 res = entry->id;
446 *id = res;
447 return 0;
448 }
449 }
450
451 i = strtoul(arg, &end, 0);
452 if (!end || end == arg || *end || i > RT_TABLE_MAX)
453 return -1;
454 *id = i;
455 return 0;
456 }
457
458
459 static char *rtnl_rtdsfield_tab[256] = {
460 "0",
461 };
462
463 static int rtnl_rtdsfield_init;
464
465 static void rtnl_rtdsfield_initialize(void)
466 {
467 rtnl_rtdsfield_init = 1;
468 rtnl_tab_initialize(CONFDIR "/rt_dsfield",
469 rtnl_rtdsfield_tab, 256);
470 }
471
472 const char *rtnl_dsfield_n2a(int id, char *buf, int len)
473 {
474 if (id < 0 || id >= 256) {
475 snprintf(buf, len, "%d", id);
476 return buf;
477 }
478 if (!rtnl_rtdsfield_tab[id]) {
479 if (!rtnl_rtdsfield_init)
480 rtnl_rtdsfield_initialize();
481 }
482 if (rtnl_rtdsfield_tab[id])
483 return rtnl_rtdsfield_tab[id];
484 snprintf(buf, len, "0x%02x", id);
485 return buf;
486 }
487
488
489 int rtnl_dsfield_a2n(__u32 *id, const char *arg)
490 {
491 static char *cache;
492 static unsigned long res;
493 char *end;
494 int i;
495
496 if (cache && strcmp(cache, arg) == 0) {
497 *id = res;
498 return 0;
499 }
500
501 if (!rtnl_rtdsfield_init)
502 rtnl_rtdsfield_initialize();
503
504 for (i = 0; i < 256; i++) {
505 if (rtnl_rtdsfield_tab[i] &&
506 strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
507 cache = rtnl_rtdsfield_tab[i];
508 res = i;
509 *id = res;
510 return 0;
511 }
512 }
513
514 res = strtoul(arg, &end, 16);
515 if (!end || end == arg || *end || res > 255)
516 return -1;
517 *id = res;
518 return 0;
519 }
520
521
522 static struct rtnl_hash_entry dflt_group_entry = {
523 .id = 0, .name = "default"
524 };
525
526 static struct rtnl_hash_entry *rtnl_group_hash[256] = {
527 [0] = &dflt_group_entry,
528 };
529
530 static int rtnl_group_init;
531
532 static void rtnl_group_initialize(void)
533 {
534 rtnl_group_init = 1;
535 rtnl_hash_initialize(CONFDIR "/group",
536 rtnl_group_hash, 256);
537 }
538
539 int rtnl_group_a2n(int *id, const char *arg)
540 {
541 static const char *cache;
542 static unsigned long res;
543 struct rtnl_hash_entry *entry;
544 char *end;
545 int i;
546
547 if (cache && strcmp(cache, arg) == 0) {
548 *id = res;
549 return 0;
550 }
551
552 if (!rtnl_group_init)
553 rtnl_group_initialize();
554
555 for (i = 0; i < 256; i++) {
556 entry = rtnl_group_hash[i];
557 while (entry && strcmp(entry->name, arg))
558 entry = entry->next;
559 if (entry) {
560 cache = entry->name;
561 res = entry->id;
562 *id = res;
563 return 0;
564 }
565 }
566
567 i = strtol(arg, &end, 0);
568 if (!end || end == arg || *end || i < 0)
569 return -1;
570 *id = i;
571 return 0;
572 }
573
574 const char *rtnl_group_n2a(int id, char *buf, int len)
575 {
576 struct rtnl_hash_entry *entry;
577 int i;
578
579 if (!rtnl_group_init)
580 rtnl_group_initialize();
581
582 for (i = 0; i < 256; i++) {
583 entry = rtnl_group_hash[i];
584
585 while (entry) {
586 if (entry->id == id)
587 return entry->name;
588 entry = entry->next;
589 }
590 }
591
592 snprintf(buf, len, "%d", id);
593 return buf;
594 }
595
596 static char *nl_proto_tab[256] = {
597 [NETLINK_ROUTE] = "rtnl",
598 [NETLINK_UNUSED] = "unused",
599 [NETLINK_USERSOCK] = "usersock",
600 [NETLINK_FIREWALL] = "fw",
601 [NETLINK_SOCK_DIAG] = "tcpdiag",
602 [NETLINK_NFLOG] = "nflog",
603 [NETLINK_XFRM] = "xfrm",
604 [NETLINK_SELINUX] = "selinux",
605 [NETLINK_ISCSI] = "iscsi",
606 [NETLINK_AUDIT] = "audit",
607 [NETLINK_FIB_LOOKUP] = "fiblookup",
608 [NETLINK_CONNECTOR] = "connector",
609 [NETLINK_NETFILTER] = "nft",
610 [NETLINK_IP6_FW] = "ip6fw",
611 [NETLINK_DNRTMSG] = "dec-rt",
612 [NETLINK_KOBJECT_UEVENT] = "uevent",
613 [NETLINK_GENERIC] = "genl",
614 [NETLINK_SCSITRANSPORT] = "scsi-trans",
615 [NETLINK_ECRYPTFS] = "ecryptfs",
616 [NETLINK_RDMA] = "rdma",
617 [NETLINK_CRYPTO] = "crypto",
618 };
619
620 static int nl_proto_init;
621
622 static void nl_proto_initialize(void)
623 {
624 nl_proto_init = 1;
625 rtnl_tab_initialize(CONFDIR "/nl_protos",
626 nl_proto_tab, 256);
627 }
628
629 const char *nl_proto_n2a(int id, char *buf, int len)
630 {
631 if (id < 0 || id >= 256) {
632 snprintf(buf, len, "%u", id);
633 return buf;
634 }
635
636 if (!nl_proto_init)
637 nl_proto_initialize();
638
639 if (nl_proto_tab[id])
640 return nl_proto_tab[id];
641
642 snprintf(buf, len, "%u", id);
643 return buf;
644 }
645
646 int nl_proto_a2n(__u32 *id, const char *arg)
647 {
648 static char *cache;
649 static unsigned long res;
650 char *end;
651 int i;
652
653 if (cache && strcmp(cache, arg) == 0) {
654 *id = res;
655 return 0;
656 }
657
658 if (!nl_proto_init)
659 nl_proto_initialize();
660
661 for (i = 0; i < 256; i++) {
662 if (nl_proto_tab[i] &&
663 strcmp(nl_proto_tab[i], arg) == 0) {
664 cache = nl_proto_tab[i];
665 res = i;
666 *id = res;
667 return 0;
668 }
669 }
670
671 res = strtoul(arg, &end, 0);
672 if (!end || end == arg || *end || res > 255)
673 return -1;
674 *id = res;
675 return 0;
676 }