• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
fread_id_name(FILE * fp,int * id,char * namebuf)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
rtnl_hash_initialize(const char * file,struct rtnl_hash_entry ** hash,int size)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 
rtnl_tab_initialize(const char * file,char ** tab,int size)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]   = "none",
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 
rtnl_rtprot_initialize(void)142 static void rtnl_rtprot_initialize(void)
143 {
144 	rtnl_rtprot_init = 1;
145 	rtnl_tab_initialize(CONFDIR "/rt_protos",
146 			    rtnl_rtprot_tab, 256);
147 }
148 
rtnl_rtprot_n2a(int id,char * buf,int len)149 const char *rtnl_rtprot_n2a(int id, char *buf, int len)
150 {
151 	if (id < 0 || id >= 256) {
152 		snprintf(buf, len, "%u", id);
153 		return buf;
154 	}
155 	if (!rtnl_rtprot_tab[id]) {
156 		if (!rtnl_rtprot_init)
157 			rtnl_rtprot_initialize();
158 	}
159 	if (rtnl_rtprot_tab[id])
160 		return rtnl_rtprot_tab[id];
161 	snprintf(buf, len, "%u", id);
162 	return buf;
163 }
164 
rtnl_rtprot_a2n(__u32 * id,const char * arg)165 int rtnl_rtprot_a2n(__u32 *id, const char *arg)
166 {
167 	static char *cache;
168 	static unsigned long res;
169 	char *end;
170 	int i;
171 
172 	if (cache && strcmp(cache, arg) == 0) {
173 		*id = res;
174 		return 0;
175 	}
176 
177 	if (!rtnl_rtprot_init)
178 		rtnl_rtprot_initialize();
179 
180 	for (i = 0; i < 256; i++) {
181 		if (rtnl_rtprot_tab[i] &&
182 		    strcmp(rtnl_rtprot_tab[i], arg) == 0) {
183 			cache = rtnl_rtprot_tab[i];
184 			res = i;
185 			*id = res;
186 			return 0;
187 		}
188 	}
189 
190 	res = strtoul(arg, &end, 0);
191 	if (!end || end == arg || *end || res > 255)
192 		return -1;
193 	*id = res;
194 	return 0;
195 }
196 
197 
198 static char *rtnl_rtscope_tab[256] = {
199 	[RT_SCOPE_UNIVERSE]	= "global",
200 	[RT_SCOPE_NOWHERE]	= "nowhere",
201 	[RT_SCOPE_HOST]		= "host",
202 	[RT_SCOPE_LINK]		= "link",
203 	[RT_SCOPE_SITE]		= "site",
204 };
205 
206 static int rtnl_rtscope_init;
207 
rtnl_rtscope_initialize(void)208 static void rtnl_rtscope_initialize(void)
209 {
210 	rtnl_rtscope_init = 1;
211 	rtnl_tab_initialize(CONFDIR "/rt_scopes",
212 			    rtnl_rtscope_tab, 256);
213 }
214 
rtnl_rtscope_n2a(int id,char * buf,int len)215 const char *rtnl_rtscope_n2a(int id, char *buf, int len)
216 {
217 	if (id < 0 || id >= 256) {
218 		snprintf(buf, len, "%d", id);
219 		return buf;
220 	}
221 
222 	if (!rtnl_rtscope_tab[id]) {
223 		if (!rtnl_rtscope_init)
224 			rtnl_rtscope_initialize();
225 	}
226 
227 	if (rtnl_rtscope_tab[id])
228 		return rtnl_rtscope_tab[id];
229 
230 	snprintf(buf, len, "%d", id);
231 	return buf;
232 }
233 
rtnl_rtscope_a2n(__u32 * id,const char * arg)234 int rtnl_rtscope_a2n(__u32 *id, const char *arg)
235 {
236 	static const char *cache;
237 	static unsigned long res;
238 	char *end;
239 	int i;
240 
241 	if (cache && strcmp(cache, arg) == 0) {
242 		*id = res;
243 		return 0;
244 	}
245 
246 	if (!rtnl_rtscope_init)
247 		rtnl_rtscope_initialize();
248 
249 	for (i = 0; i < 256; i++) {
250 		if (rtnl_rtscope_tab[i] &&
251 		    strcmp(rtnl_rtscope_tab[i], arg) == 0) {
252 			cache = rtnl_rtscope_tab[i];
253 			res = i;
254 			*id = res;
255 			return 0;
256 		}
257 	}
258 
259 	res = strtoul(arg, &end, 0);
260 	if (!end || end == arg || *end || res > 255)
261 		return -1;
262 	*id = res;
263 	return 0;
264 }
265 
266 
267 static char *rtnl_rtrealm_tab[256] = {
268 	"unknown",
269 };
270 
271 static int rtnl_rtrealm_init;
272 
rtnl_rtrealm_initialize(void)273 static void rtnl_rtrealm_initialize(void)
274 {
275 	rtnl_rtrealm_init = 1;
276 	rtnl_tab_initialize(CONFDIR "/rt_realms",
277 			    rtnl_rtrealm_tab, 256);
278 }
279 
rtnl_rtrealm_n2a(int id,char * buf,int len)280 const char *rtnl_rtrealm_n2a(int id, char *buf, int len)
281 {
282 	if (id < 0 || id >= 256) {
283 		snprintf(buf, len, "%d", id);
284 		return buf;
285 	}
286 	if (!rtnl_rtrealm_tab[id]) {
287 		if (!rtnl_rtrealm_init)
288 			rtnl_rtrealm_initialize();
289 	}
290 	if (rtnl_rtrealm_tab[id])
291 		return rtnl_rtrealm_tab[id];
292 	snprintf(buf, len, "%d", id);
293 	return buf;
294 }
295 
296 
rtnl_rtrealm_a2n(__u32 * id,const char * arg)297 int rtnl_rtrealm_a2n(__u32 *id, const char *arg)
298 {
299 	static char *cache;
300 	static unsigned long res;
301 	char *end;
302 	int i;
303 
304 	if (cache && strcmp(cache, arg) == 0) {
305 		*id = res;
306 		return 0;
307 	}
308 
309 	if (!rtnl_rtrealm_init)
310 		rtnl_rtrealm_initialize();
311 
312 	for (i = 0; i < 256; i++) {
313 		if (rtnl_rtrealm_tab[i] &&
314 		    strcmp(rtnl_rtrealm_tab[i], arg) == 0) {
315 			cache = rtnl_rtrealm_tab[i];
316 			res = i;
317 			*id = res;
318 			return 0;
319 		}
320 	}
321 
322 	res = strtoul(arg, &end, 0);
323 	if (!end || end == arg || *end || res > 255)
324 		return -1;
325 	*id = res;
326 	return 0;
327 }
328 
329 
330 static struct rtnl_hash_entry dflt_table_entry  = { .name = "default" };
331 static struct rtnl_hash_entry main_table_entry  = { .name = "main" };
332 static struct rtnl_hash_entry local_table_entry = { .name = "local" };
333 
334 static struct rtnl_hash_entry *rtnl_rttable_hash[256] = {
335 	[RT_TABLE_DEFAULT] = &dflt_table_entry,
336 	[RT_TABLE_MAIN]    = &main_table_entry,
337 	[RT_TABLE_LOCAL]   = &local_table_entry,
338 };
339 
340 static int rtnl_rttable_init;
341 
rtnl_rttable_initialize(void)342 static void rtnl_rttable_initialize(void)
343 {
344 	struct dirent *de;
345 	DIR *d;
346 	int i;
347 
348 	rtnl_rttable_init = 1;
349 	for (i = 0; i < 256; i++) {
350 		if (rtnl_rttable_hash[i])
351 			rtnl_rttable_hash[i]->id = i;
352 	}
353 	rtnl_hash_initialize(CONFDIR "/rt_tables",
354 			     rtnl_rttable_hash, 256);
355 
356 	d = opendir(CONFDIR "/rt_tables.d");
357 	if (!d)
358 		return;
359 
360 	while ((de = readdir(d)) != NULL) {
361 		char path[PATH_MAX];
362 		size_t len;
363 
364 		if (*de->d_name == '.')
365 			continue;
366 
367 		/* only consider filenames ending in '.conf' */
368 		len = strlen(de->d_name);
369 		if (len <= 5)
370 			continue;
371 		if (strcmp(de->d_name + len - 5, ".conf"))
372 			continue;
373 
374 		snprintf(path, sizeof(path),
375 			 CONFDIR "/rt_tables.d/%s", de->d_name);
376 		rtnl_hash_initialize(path, rtnl_rttable_hash, 256);
377 	}
378 	closedir(d);
379 }
380 
rtnl_rttable_n2a(__u32 id,char * buf,int len)381 const char *rtnl_rttable_n2a(__u32 id, char *buf, int len)
382 {
383 	struct rtnl_hash_entry *entry;
384 
385 	if (id > RT_TABLE_MAX) {
386 		snprintf(buf, len, "%u", id);
387 		return buf;
388 	}
389 	if (!rtnl_rttable_init)
390 		rtnl_rttable_initialize();
391 	entry = rtnl_rttable_hash[id & 255];
392 	while (entry && entry->id != id)
393 		entry = entry->next;
394 	if (entry)
395 		return entry->name;
396 	snprintf(buf, len, "%u", id);
397 	return buf;
398 }
399 
rtnl_rttable_a2n(__u32 * id,const char * arg)400 int rtnl_rttable_a2n(__u32 *id, const char *arg)
401 {
402 	static const char *cache;
403 	static unsigned long res;
404 	struct rtnl_hash_entry *entry;
405 	char *end;
406 	__u32 i;
407 
408 	if (cache && strcmp(cache, arg) == 0) {
409 		*id = res;
410 		return 0;
411 	}
412 
413 	if (!rtnl_rttable_init)
414 		rtnl_rttable_initialize();
415 
416 	for (i = 0; i < 256; i++) {
417 		entry = rtnl_rttable_hash[i];
418 		while (entry && strcmp(entry->name, arg))
419 			entry = entry->next;
420 		if (entry) {
421 			cache = entry->name;
422 			res = entry->id;
423 			*id = res;
424 			return 0;
425 		}
426 	}
427 
428 	i = strtoul(arg, &end, 0);
429 	if (!end || end == arg || *end || i > RT_TABLE_MAX)
430 		return -1;
431 	*id = i;
432 	return 0;
433 }
434 
435 
436 static char *rtnl_rtdsfield_tab[256] = {
437 	"0",
438 };
439 
440 static int rtnl_rtdsfield_init;
441 
rtnl_rtdsfield_initialize(void)442 static void rtnl_rtdsfield_initialize(void)
443 {
444 	rtnl_rtdsfield_init = 1;
445 	rtnl_tab_initialize(CONFDIR "/rt_dsfield",
446 			    rtnl_rtdsfield_tab, 256);
447 }
448 
rtnl_dsfield_n2a(int id,char * buf,int len)449 const char *rtnl_dsfield_n2a(int id, char *buf, int len)
450 {
451 	if (id < 0 || id >= 256) {
452 		snprintf(buf, len, "%d", id);
453 		return buf;
454 	}
455 	if (!rtnl_rtdsfield_tab[id]) {
456 		if (!rtnl_rtdsfield_init)
457 			rtnl_rtdsfield_initialize();
458 	}
459 	if (rtnl_rtdsfield_tab[id])
460 		return rtnl_rtdsfield_tab[id];
461 	snprintf(buf, len, "0x%02x", id);
462 	return buf;
463 }
464 
465 
rtnl_dsfield_a2n(__u32 * id,const char * arg)466 int rtnl_dsfield_a2n(__u32 *id, const char *arg)
467 {
468 	static char *cache;
469 	static unsigned long res;
470 	char *end;
471 	int i;
472 
473 	if (cache && strcmp(cache, arg) == 0) {
474 		*id = res;
475 		return 0;
476 	}
477 
478 	if (!rtnl_rtdsfield_init)
479 		rtnl_rtdsfield_initialize();
480 
481 	for (i = 0; i < 256; i++) {
482 		if (rtnl_rtdsfield_tab[i] &&
483 		    strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
484 			cache = rtnl_rtdsfield_tab[i];
485 			res = i;
486 			*id = res;
487 			return 0;
488 		}
489 	}
490 
491 	res = strtoul(arg, &end, 16);
492 	if (!end || end == arg || *end || res > 255)
493 		return -1;
494 	*id = res;
495 	return 0;
496 }
497 
498 
499 static struct rtnl_hash_entry dflt_group_entry = {
500 	.id = 0, .name = "default"
501 };
502 
503 static struct rtnl_hash_entry *rtnl_group_hash[256] = {
504 	[0] = &dflt_group_entry,
505 };
506 
507 static int rtnl_group_init;
508 
rtnl_group_initialize(void)509 static void rtnl_group_initialize(void)
510 {
511 	rtnl_group_init = 1;
512 	rtnl_hash_initialize(CONFDIR "/group",
513 			     rtnl_group_hash, 256);
514 }
515 
rtnl_group_a2n(int * id,const char * arg)516 int rtnl_group_a2n(int *id, const char *arg)
517 {
518 	static const char *cache;
519 	static unsigned long res;
520 	struct rtnl_hash_entry *entry;
521 	char *end;
522 	int i;
523 
524 	if (cache && strcmp(cache, arg) == 0) {
525 		*id = res;
526 		return 0;
527 	}
528 
529 	if (!rtnl_group_init)
530 		rtnl_group_initialize();
531 
532 	for (i = 0; i < 256; i++) {
533 		entry = rtnl_group_hash[i];
534 		while (entry && strcmp(entry->name, arg))
535 			entry = entry->next;
536 		if (entry) {
537 			cache = entry->name;
538 			res = entry->id;
539 			*id = res;
540 			return 0;
541 		}
542 	}
543 
544 	i = strtol(arg, &end, 0);
545 	if (!end || end == arg || *end || i < 0)
546 		return -1;
547 	*id = i;
548 	return 0;
549 }
550 
rtnl_group_n2a(int id,char * buf,int len)551 const char *rtnl_group_n2a(int id, char *buf, int len)
552 {
553 	struct rtnl_hash_entry *entry;
554 	int i;
555 
556 	if (!rtnl_group_init)
557 		rtnl_group_initialize();
558 
559 	for (i = 0; i < 256; i++) {
560 		entry = rtnl_group_hash[i];
561 		if (entry && entry->id == id)
562 			return entry->name;
563 	}
564 
565 	snprintf(buf, len, "%d", id);
566 	return buf;
567 }
568 
569 static char *nl_proto_tab[256] = {
570 	[NETLINK_ROUTE]          = "rtnl",
571 	[NETLINK_UNUSED]         = "unused",
572 	[NETLINK_USERSOCK]       = "usersock",
573 	[NETLINK_FIREWALL]       = "fw",
574 	[NETLINK_SOCK_DIAG]      = "tcpdiag",
575 	[NETLINK_NFLOG]          = "nflog",
576 	[NETLINK_XFRM]           = "xfrm",
577 	[NETLINK_SELINUX]        = "selinux",
578 	[NETLINK_ISCSI]          = "iscsi",
579 	[NETLINK_AUDIT]          = "audit",
580 	[NETLINK_FIB_LOOKUP]     = "fiblookup",
581 	[NETLINK_CONNECTOR]      = "connector",
582 	[NETLINK_NETFILTER]      = "nft",
583 	[NETLINK_IP6_FW]         = "ip6fw",
584 	[NETLINK_DNRTMSG]        = "dec-rt",
585 	[NETLINK_KOBJECT_UEVENT] = "uevent",
586 	[NETLINK_GENERIC]        = "genl",
587 	[NETLINK_SCSITRANSPORT]  = "scsi-trans",
588 	[NETLINK_ECRYPTFS]       = "ecryptfs",
589 	[NETLINK_RDMA]           = "rdma",
590 	[NETLINK_CRYPTO]         = "crypto",
591 };
592 
593 static int nl_proto_init;
594 
nl_proto_initialize(void)595 static void nl_proto_initialize(void)
596 {
597 	nl_proto_init = 1;
598 	rtnl_tab_initialize(CONFDIR "/nl_protos",
599 			    nl_proto_tab, 256);
600 }
601 
nl_proto_n2a(int id,char * buf,int len)602 const char *nl_proto_n2a(int id, char *buf, int len)
603 {
604 	if (id < 0 || id >= 256) {
605 		snprintf(buf, len, "%u", id);
606 		return buf;
607 	}
608 
609 	if (!nl_proto_init)
610 		nl_proto_initialize();
611 
612 	if (nl_proto_tab[id])
613 		return nl_proto_tab[id];
614 
615 	snprintf(buf, len, "%u", id);
616 	return buf;
617 }
618 
nl_proto_a2n(__u32 * id,const char * arg)619 int nl_proto_a2n(__u32 *id, const char *arg)
620 {
621 	static char *cache;
622 	static unsigned long res;
623 	char *end;
624 	int i;
625 
626 	if (cache && strcmp(cache, arg) == 0) {
627 		*id = res;
628 		return 0;
629 	}
630 
631 	if (!nl_proto_init)
632 		nl_proto_initialize();
633 
634 	for (i = 0; i < 256; i++) {
635 		if (nl_proto_tab[i] &&
636 		    strcmp(nl_proto_tab[i], arg) == 0) {
637 			cache = nl_proto_tab[i];
638 			res = i;
639 			*id = res;
640 			return 0;
641 		}
642 	}
643 
644 	res = strtoul(arg, &end, 0);
645 	if (!end || end == arg || *end || res > 255)
646 		return -1;
647 	*id = res;
648 	return 0;
649 }
650