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 const char *name;
483
484 if (id < 0 || id >= 256) {
485 snprintf(buf, len, "%d", id);
486 return buf;
487 }
488 if (!numeric) {
489 name = rtnl_dsfield_get_name(id);
490 if (name != NULL)
491 return name;
492 }
493 snprintf(buf, len, "0x%02x", id);
494 return buf;
495}
496
497const char *rtnl_dsfield_get_name(int id)
498{
499 if (id < 0 || id >= 256)
500 return NULL;
501 if (!rtnl_rtdsfield_tab[id]) {
502 if (!rtnl_rtdsfield_init)
503 rtnl_rtdsfield_initialize();
504 }
505 return rtnl_rtdsfield_tab[id];
506}
507
508
509int rtnl_dsfield_a2n(__u32 *id, const char *arg)
510{
511 static char *cache;
512 static unsigned long res;
513 char *end;
514 int i;
515
516 if (cache && strcmp(cache, arg) == 0) {
517 *id = res;
518 return 0;
519 }
520
521 if (!rtnl_rtdsfield_init)
522 rtnl_rtdsfield_initialize();
523
524 for (i = 0; i < 256; i++) {
525 if (rtnl_rtdsfield_tab[i] &&
526 strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
527 cache = rtnl_rtdsfield_tab[i];
528 res = i;
529 *id = res;
530 return 0;
531 }
532 }
533
534 res = strtoul(arg, &end, 16);
535 if (!end || end == arg || *end || res > 255)
536 return -1;
537 *id = res;
538 return 0;
539}
540
541
542static struct rtnl_hash_entry dflt_group_entry = {
543 .id = 0, .name = "default"
544};
545
546static struct rtnl_hash_entry *rtnl_group_hash[256] = {
547 [0] = &dflt_group_entry,
548};
549
550static int rtnl_group_init;
551
552static void rtnl_group_initialize(void)
553{
554 rtnl_group_init = 1;
555 rtnl_hash_initialize(CONFDIR "/group",
556 rtnl_group_hash, 256);
557}
558
559int rtnl_group_a2n(int *id, const char *arg)
560{
561 static const char *cache;
562 static unsigned long res;
563 struct rtnl_hash_entry *entry;
564 char *end;
565 int i;
566
567 if (cache && strcmp(cache, arg) == 0) {
568 *id = res;
569 return 0;
570 }
571
572 if (!rtnl_group_init)
573 rtnl_group_initialize();
574
575 for (i = 0; i < 256; i++) {
576 entry = rtnl_group_hash[i];
577 while (entry && strcmp(entry->name, arg))
578 entry = entry->next;
579 if (entry) {
580 cache = entry->name;
581 res = entry->id;
582 *id = res;
583 return 0;
584 }
585 }
586
587 i = strtol(arg, &end, 0);
588 if (!end || end == arg || *end || i < 0)
589 return -1;
590 *id = i;
591 return 0;
592}
593
594const char *rtnl_group_n2a(int id, char *buf, int len)
595{
596 struct rtnl_hash_entry *entry;
597 int i;
598
599 if (!rtnl_group_init)
600 rtnl_group_initialize();
601
602 for (i = 0; !numeric && i < 256; i++) {
603 entry = rtnl_group_hash[i];
604
605 while (entry) {
606 if (entry->id == id)
607 return entry->name;
608 entry = entry->next;
609 }
610 }
611
612 snprintf(buf, len, "%d", id);
613 return buf;
614}
615
616static char *nl_proto_tab[256] = {
617 [NETLINK_ROUTE] = "rtnl",
618 [NETLINK_UNUSED] = "unused",
619 [NETLINK_USERSOCK] = "usersock",
620 [NETLINK_FIREWALL] = "fw",
621 [NETLINK_SOCK_DIAG] = "tcpdiag",
622 [NETLINK_NFLOG] = "nflog",
623 [NETLINK_XFRM] = "xfrm",
624 [NETLINK_SELINUX] = "selinux",
625 [NETLINK_ISCSI] = "iscsi",
626 [NETLINK_AUDIT] = "audit",
627 [NETLINK_FIB_LOOKUP] = "fiblookup",
628 [NETLINK_CONNECTOR] = "connector",
629 [NETLINK_NETFILTER] = "nft",
630 [NETLINK_IP6_FW] = "ip6fw",
631 [NETLINK_DNRTMSG] = "dec-rt",
632 [NETLINK_KOBJECT_UEVENT] = "uevent",
633 [NETLINK_GENERIC] = "genl",
634 [NETLINK_SCSITRANSPORT] = "scsi-trans",
635 [NETLINK_ECRYPTFS] = "ecryptfs",
636 [NETLINK_RDMA] = "rdma",
637 [NETLINK_CRYPTO] = "crypto",
638};
639
640static int nl_proto_init;
641
642static void nl_proto_initialize(void)
643{
644 nl_proto_init = 1;
645 rtnl_tab_initialize(CONFDIR "/nl_protos",
646 nl_proto_tab, 256);
647}
648
649const char *nl_proto_n2a(int id, char *buf, int len)
650{
651 if (id < 0 || id >= 256 || numeric) {
652 snprintf(buf, len, "%d", id);
653 return buf;
654 }
655
656 if (!nl_proto_init)
657 nl_proto_initialize();
658
659 if (nl_proto_tab[id])
660 return nl_proto_tab[id];
661
662 snprintf(buf, len, "%u", id);
663 return buf;
664}
665
666int nl_proto_a2n(__u32 *id, const char *arg)
667{
668 static char *cache;
669 static unsigned long res;
670 char *end;
671 int i;
672
673 if (cache && strcmp(cache, arg) == 0) {
674 *id = res;
675 return 0;
676 }
677
678 if (!nl_proto_init)
679 nl_proto_initialize();
680
681 for (i = 0; i < 256; i++) {
682 if (nl_proto_tab[i] &&
683 strcmp(nl_proto_tab[i], arg) == 0) {
684 cache = nl_proto_tab[i];
685 res = i;
686 *id = res;
687 return 0;
688 }
689 }
690
691 res = strtoul(arg, &end, 0);
692 if (!end || end == arg || *end || res > 255)
693 return -1;
694 *id = res;
695 return 0;
696}
697
698#define PROTODOWN_REASON_NUM_BITS 32
699static char *protodown_reason_tab[PROTODOWN_REASON_NUM_BITS] = {
700};
701
702static int protodown_reason_init;
703
704static void protodown_reason_initialize(void)
705{
706 struct dirent *de;
707 DIR *d;
708
709 protodown_reason_init = 1;
710
711 d = opendir(CONFDIR "/protodown_reasons.d");
712 if (!d)
713 return;
714
715 while ((de = readdir(d)) != NULL) {
716 char path[PATH_MAX];
717 size_t len;
718
719 if (*de->d_name == '.')
720 continue;
721
722
723 len = strlen(de->d_name);
724 if (len <= 5)
725 continue;
726 if (strcmp(de->d_name + len - 5, ".conf"))
727 continue;
728
729 snprintf(path, sizeof(path), CONFDIR "/protodown_reasons.d/%s",
730 de->d_name);
731 rtnl_tab_initialize(path, protodown_reason_tab,
732 PROTODOWN_REASON_NUM_BITS);
733 }
734 closedir(d);
735}
736
737int protodown_reason_n2a(int id, char *buf, int len)
738{
739 if (id < 0 || id >= PROTODOWN_REASON_NUM_BITS)
740 return -1;
741
742 if (numeric) {
743 snprintf(buf, len, "%d", id);
744 return 0;
745 }
746
747 if (!protodown_reason_init)
748 protodown_reason_initialize();
749
750 if (protodown_reason_tab[id])
751 snprintf(buf, len, "%s", protodown_reason_tab[id]);
752 else
753 snprintf(buf, len, "%d", id);
754
755 return 0;
756}
757
758int protodown_reason_a2n(__u32 *id, const char *arg)
759{
760 static char *cache;
761 static unsigned long res;
762 char *end;
763 int i;
764
765 if (cache && strcmp(cache, arg) == 0) {
766 *id = res;
767 return 0;
768 }
769
770 if (!protodown_reason_init)
771 protodown_reason_initialize();
772
773 for (i = 0; i < PROTODOWN_REASON_NUM_BITS; i++) {
774 if (protodown_reason_tab[i] &&
775 strcmp(protodown_reason_tab[i], arg) == 0) {
776 cache = protodown_reason_tab[i];
777 res = i;
778 *id = res;
779 return 0;
780 }
781 }
782
783 res = strtoul(arg, &end, 0);
784 if (!end || end == arg || *end || res >= PROTODOWN_REASON_NUM_BITS)
785 return -1;
786 *id = res;
787 return 0;
788}
789