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 31struct rtnl_hash_entry { 32 struct rtnl_hash_entry *next; 33 const char *name; 34 unsigned int id; 35}; 36 37static 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 62static void 63rtnl_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 95static 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 121static 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 141static int rtnl_rtprot_init; 142 143static 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 177const 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 193int 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 226static 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 234static int rtnl_rtscope_init; 235 236static 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 243const 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 262int 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 295static char *rtnl_rtrealm_tab[256] = { 296 "unknown", 297}; 298 299static int rtnl_rtrealm_init; 300 301static 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 308const 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 325int 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 358static struct rtnl_hash_entry dflt_table_entry = { .name = "default" }; 359static struct rtnl_hash_entry main_table_entry = { .name = "main" }; 360static struct rtnl_hash_entry local_table_entry = { .name = "local" }; 361 362static 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 368static int rtnl_rttable_init; 369 370static 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 409const 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 424int 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 460static char *rtnl_rtdsfield_tab[256] = { 461 "0", 462}; 463 464static int rtnl_rtdsfield_init; 465 466static 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 473const 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 490int 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 523static struct rtnl_hash_entry dflt_group_entry = { 524 .id = 0, .name = "default" 525}; 526 527static struct rtnl_hash_entry *rtnl_group_hash[256] = { 528 [0] = &dflt_group_entry, 529}; 530 531static int rtnl_group_init; 532 533static void rtnl_group_initialize(void) 534{ 535 rtnl_group_init = 1; 536 rtnl_hash_initialize(CONFDIR "/group", 537 rtnl_group_hash, 256); 538} 539 540int 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 575const 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 597static 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 621static int nl_proto_init; 622 623static 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 630const 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 647int 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