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 
     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 
     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
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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