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 30struct rtnl_hash_entry { 31 struct rtnl_hash_entry *next; 32 const char *name; 33 unsigned int id; 34}; 35 36static 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 61static void 62rtnl_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 94static 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 120static 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 140static int rtnl_rtprot_init; 141 142static 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 149const 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 165int 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 198static 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 206static int rtnl_rtscope_init; 207 208static 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 215const 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 234int 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 267static char *rtnl_rtrealm_tab[256] = { 268 "unknown", 269}; 270 271static int rtnl_rtrealm_init; 272 273static 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 280const 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 297int 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 330static struct rtnl_hash_entry dflt_table_entry = { .name = "default" }; 331static struct rtnl_hash_entry main_table_entry = { .name = "main" }; 332static struct rtnl_hash_entry local_table_entry = { .name = "local" }; 333 334static 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 340static int rtnl_rttable_init; 341 342static 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 381const 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 400int 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 436static char *rtnl_rtdsfield_tab[256] = { 437 "0", 438}; 439 440static int rtnl_rtdsfield_init; 441 442static 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 449const 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 466int 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 499static struct rtnl_hash_entry dflt_group_entry = { 500 .id = 0, .name = "default" 501}; 502 503static struct rtnl_hash_entry *rtnl_group_hash[256] = { 504 [0] = &dflt_group_entry, 505}; 506 507static int rtnl_group_init; 508 509static void rtnl_group_initialize(void) 510{ 511 rtnl_group_init = 1; 512 rtnl_hash_initialize(CONFDIR "/group", 513 rtnl_group_hash, 256); 514} 515 516int 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 551const 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 569static 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 593static int nl_proto_init; 594 595static 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 602const 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 619int 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