Home | History | Annotate | Download | only in lib
      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 (at) 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 
     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
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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