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