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