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 
21 #include <asm/types.h>
22 #include <linux/rtnetlink.h>
23 
24 #include "rt_names.h"
25 
26 #ifndef CONFDIR
27 #define CONFDIR "/etc/iproute2"
28 #endif
29 
30 struct rtnl_hash_entry {
31 	struct rtnl_hash_entry *next;
32 	char *			name;
33 	unsigned int		id;
34 };
35 
36 static void
rtnl_hash_initialize(char * file,struct rtnl_hash_entry ** hash,int size)37 rtnl_hash_initialize(char *file, struct rtnl_hash_entry **hash, int size)
38 {
39 	struct rtnl_hash_entry *entry;
40 	char buf[512];
41 	FILE *fp;
42 
43 	fp = fopen(file, "r");
44 	if (!fp)
45 		return;
46 	while (fgets(buf, sizeof(buf), fp)) {
47 		char *p = buf;
48 		int id;
49 		char namebuf[512];
50 
51 		while (*p == ' ' || *p == '\t')
52 			p++;
53 		if (*p == '#' || *p == '\n' || *p == 0)
54 			continue;
55 		if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 &&
56 		    sscanf(p, "0x%x %s #", &id, namebuf) != 2 &&
57 		    sscanf(p, "%d %s\n", &id, namebuf) != 2 &&
58 		    sscanf(p, "%d %s #", &id, namebuf) != 2) {
59 			fprintf(stderr, "Database %s is corrupted at %s\n",
60 				file, p);
61 			fclose(fp);
62 			return;
63 		}
64 
65 		if (id<0)
66 			continue;
67 		entry = malloc(sizeof(*entry));
68 		entry->id   = id;
69 		entry->name = strdup(namebuf);
70 		entry->next = hash[id & (size - 1)];
71 		hash[id & (size - 1)] = entry;
72 	}
73 	fclose(fp);
74 }
75 
rtnl_tab_initialize(char * file,char ** tab,int size)76 static void rtnl_tab_initialize(char *file, char **tab, int size)
77 {
78 	char buf[512];
79 	FILE *fp;
80 
81 	fp = fopen(file, "r");
82 	if (!fp)
83 		return;
84 	while (fgets(buf, sizeof(buf), fp)) {
85 		char *p = buf;
86 		int id;
87 		char namebuf[512];
88 
89 		while (*p == ' ' || *p == '\t')
90 			p++;
91 		if (*p == '#' || *p == '\n' || *p == 0)
92 			continue;
93 		if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 &&
94 		    sscanf(p, "0x%x %s #", &id, namebuf) != 2 &&
95 		    sscanf(p, "%d %s\n", &id, namebuf) != 2 &&
96 		    sscanf(p, "%d %s #", &id, namebuf) != 2) {
97 			fprintf(stderr, "Database %s is corrupted at %s\n",
98 				file, p);
99 			fclose(fp);
100 			return;
101 		}
102 
103 		if (id<0 || id>size)
104 			continue;
105 
106 		tab[id] = strdup(namebuf);
107 	}
108 	fclose(fp);
109 }
110 
111 static char * rtnl_rtprot_tab[256] = {
112 	[RTPROT_UNSPEC] = "none",
113 	[RTPROT_REDIRECT] ="redirect",
114 	[RTPROT_KERNEL] = "kernel",
115 	[RTPROT_BOOT] = "boot",
116 	[RTPROT_STATIC] = "static",
117 
118 	[RTPROT_GATED] = "gated",
119 	[RTPROT_RA] = "ra",
120 	[RTPROT_MRT] =	"mrt",
121 	[RTPROT_ZEBRA] ="zebra",
122 	[RTPROT_BIRD] = "bird",
123 	[RTPROT_DNROUTED] = "dnrouted",
124 	[RTPROT_XORP] = "xorp",
125 	[RTPROT_NTK] = "ntk",
126 	[RTPROT_DHCP] = "dhcp",
127 };
128 
129 
130 
131 static int rtnl_rtprot_init;
132 
rtnl_rtprot_initialize(void)133 static void rtnl_rtprot_initialize(void)
134 {
135 	rtnl_rtprot_init = 1;
136 	rtnl_tab_initialize(CONFDIR "/rt_protos",
137 			    rtnl_rtprot_tab, 256);
138 }
139 
rtnl_rtprot_n2a(int id,char * buf,int len)140 char * rtnl_rtprot_n2a(int id, char *buf, int len)
141 {
142 	if (id<0 || id>=256) {
143 		snprintf(buf, len, "%d", id);
144 		return buf;
145 	}
146 	if (!rtnl_rtprot_tab[id]) {
147 		if (!rtnl_rtprot_init)
148 			rtnl_rtprot_initialize();
149 	}
150 	if (rtnl_rtprot_tab[id])
151 		return rtnl_rtprot_tab[id];
152 	snprintf(buf, len, "%d", id);
153 	return buf;
154 }
155 
rtnl_rtprot_a2n(__u32 * id,char * arg)156 int rtnl_rtprot_a2n(__u32 *id, char *arg)
157 {
158 	static char *cache = NULL;
159 	static unsigned long res;
160 	char *end;
161 	int i;
162 
163 	if (cache && strcmp(cache, arg) == 0) {
164 		*id = res;
165 		return 0;
166 	}
167 
168 	if (!rtnl_rtprot_init)
169 		rtnl_rtprot_initialize();
170 
171 	for (i=0; i<256; i++) {
172 		if (rtnl_rtprot_tab[i] &&
173 		    strcmp(rtnl_rtprot_tab[i], arg) == 0) {
174 			cache = rtnl_rtprot_tab[i];
175 			res = i;
176 			*id = res;
177 			return 0;
178 		}
179 	}
180 
181 	res = strtoul(arg, &end, 0);
182 	if (!end || end == arg || *end || res > 255)
183 		return -1;
184 	*id = res;
185 	return 0;
186 }
187 
188 
189 
190 static char * rtnl_rtscope_tab[256] = {
191 	"global",
192 };
193 
194 static int rtnl_rtscope_init;
195 
rtnl_rtscope_initialize(void)196 static void rtnl_rtscope_initialize(void)
197 {
198 	rtnl_rtscope_init = 1;
199 	rtnl_rtscope_tab[255] = "nowhere";
200 	rtnl_rtscope_tab[254] = "host";
201 	rtnl_rtscope_tab[253] = "link";
202 	rtnl_rtscope_tab[200] = "site";
203 	rtnl_tab_initialize(CONFDIR "/rt_scopes",
204 			    rtnl_rtscope_tab, 256);
205 }
206 
rtnl_rtscope_n2a(int id,char * buf,int len)207 char * rtnl_rtscope_n2a(int id, char *buf, int len)
208 {
209 	if (id<0 || id>=256) {
210 		snprintf(buf, len, "%d", id);
211 		return buf;
212 	}
213 	if (!rtnl_rtscope_tab[id]) {
214 		if (!rtnl_rtscope_init)
215 			rtnl_rtscope_initialize();
216 	}
217 	if (rtnl_rtscope_tab[id])
218 		return rtnl_rtscope_tab[id];
219 	snprintf(buf, len, "%d", id);
220 	return buf;
221 }
222 
rtnl_rtscope_a2n(__u32 * id,char * arg)223 int rtnl_rtscope_a2n(__u32 *id, char *arg)
224 {
225 	static char *cache = NULL;
226 	static unsigned long res;
227 	char *end;
228 	int i;
229 
230 	if (cache && strcmp(cache, arg) == 0) {
231 		*id = res;
232 		return 0;
233 	}
234 
235 	if (!rtnl_rtscope_init)
236 		rtnl_rtscope_initialize();
237 
238 	for (i=0; i<256; i++) {
239 		if (rtnl_rtscope_tab[i] &&
240 		    strcmp(rtnl_rtscope_tab[i], arg) == 0) {
241 			cache = rtnl_rtscope_tab[i];
242 			res = i;
243 			*id = res;
244 			return 0;
245 		}
246 	}
247 
248 	res = strtoul(arg, &end, 0);
249 	if (!end || end == arg || *end || res > 255)
250 		return -1;
251 	*id = res;
252 	return 0;
253 }
254 
255 
256 
257 static char * rtnl_rtrealm_tab[256] = {
258 	"unknown",
259 };
260 
261 static int rtnl_rtrealm_init;
262 
rtnl_rtrealm_initialize(void)263 static void rtnl_rtrealm_initialize(void)
264 {
265 	rtnl_rtrealm_init = 1;
266 	rtnl_tab_initialize(CONFDIR "/rt_realms",
267 			    rtnl_rtrealm_tab, 256);
268 }
269 
rtnl_rtrealm_n2a(int id,char * buf,int len)270 char * rtnl_rtrealm_n2a(int id, char *buf, int len)
271 {
272 	if (id<0 || id>=256) {
273 		snprintf(buf, len, "%d", id);
274 		return buf;
275 	}
276 	if (!rtnl_rtrealm_tab[id]) {
277 		if (!rtnl_rtrealm_init)
278 			rtnl_rtrealm_initialize();
279 	}
280 	if (rtnl_rtrealm_tab[id])
281 		return rtnl_rtrealm_tab[id];
282 	snprintf(buf, len, "%d", id);
283 	return buf;
284 }
285 
286 
rtnl_rtrealm_a2n(__u32 * id,char * arg)287 int rtnl_rtrealm_a2n(__u32 *id, char *arg)
288 {
289 	static char *cache = NULL;
290 	static unsigned long res;
291 	char *end;
292 	int i;
293 
294 	if (cache && strcmp(cache, arg) == 0) {
295 		*id = res;
296 		return 0;
297 	}
298 
299 	if (!rtnl_rtrealm_init)
300 		rtnl_rtrealm_initialize();
301 
302 	for (i=0; i<256; i++) {
303 		if (rtnl_rtrealm_tab[i] &&
304 		    strcmp(rtnl_rtrealm_tab[i], arg) == 0) {
305 			cache = rtnl_rtrealm_tab[i];
306 			res = i;
307 			*id = res;
308 			return 0;
309 		}
310 	}
311 
312 	res = strtoul(arg, &end, 0);
313 	if (!end || end == arg || *end || res > 255)
314 		return -1;
315 	*id = res;
316 	return 0;
317 }
318 
319 
320 static struct rtnl_hash_entry dflt_table_entry  = { .id = 253, .name = "default" };
321 static struct rtnl_hash_entry main_table_entry  = { .id = 254, .name = "main" };
322 static struct rtnl_hash_entry local_table_entry = { .id = 255, .name = "local" };
323 
324 static struct rtnl_hash_entry * rtnl_rttable_hash[256] = {
325 	[253] = &dflt_table_entry,
326 	[254] = &main_table_entry,
327 	[255] = &local_table_entry,
328 };
329 
330 static int rtnl_rttable_init;
331 
rtnl_rttable_initialize(void)332 static void rtnl_rttable_initialize(void)
333 {
334 	rtnl_rttable_init = 1;
335 	rtnl_hash_initialize(CONFDIR "/rt_tables",
336 			     rtnl_rttable_hash, 256);
337 }
338 
rtnl_rttable_n2a(__u32 id,char * buf,int len)339 char * rtnl_rttable_n2a(__u32 id, char *buf, int len)
340 {
341 	struct rtnl_hash_entry *entry;
342 
343 	if (id > RT_TABLE_MAX) {
344 		snprintf(buf, len, "%u", id);
345 		return buf;
346 	}
347 	if (!rtnl_rttable_init)
348 		rtnl_rttable_initialize();
349 	entry = rtnl_rttable_hash[id & 255];
350 	while (entry && entry->id != id)
351 		entry = entry->next;
352 	if (entry)
353 		return entry->name;
354 	snprintf(buf, len, "%u", id);
355 	return buf;
356 }
357 
rtnl_rttable_a2n(__u32 * id,char * arg)358 int rtnl_rttable_a2n(__u32 *id, char *arg)
359 {
360 	static char *cache = NULL;
361 	static unsigned long res;
362 	struct rtnl_hash_entry *entry;
363 	char *end;
364 	__u32 i;
365 
366 	if (cache && strcmp(cache, arg) == 0) {
367 		*id = res;
368 		return 0;
369 	}
370 
371 	if (!rtnl_rttable_init)
372 		rtnl_rttable_initialize();
373 
374 	for (i=0; i<256; i++) {
375 		entry = rtnl_rttable_hash[i];
376 		while (entry && strcmp(entry->name, arg))
377 			entry = entry->next;
378 		if (entry) {
379 			cache = entry->name;
380 			res = entry->id;
381 			*id = res;
382 			return 0;
383 		}
384 	}
385 
386 	i = strtoul(arg, &end, 0);
387 	if (!end || end == arg || *end || i > RT_TABLE_MAX)
388 		return -1;
389 	*id = i;
390 	return 0;
391 }
392 
393 
394 static char * rtnl_rtdsfield_tab[256] = {
395 	"0",
396 };
397 
398 static int rtnl_rtdsfield_init;
399 
rtnl_rtdsfield_initialize(void)400 static void rtnl_rtdsfield_initialize(void)
401 {
402 	rtnl_rtdsfield_init = 1;
403 	rtnl_tab_initialize(CONFDIR "/rt_dsfield",
404 			    rtnl_rtdsfield_tab, 256);
405 }
406 
rtnl_dsfield_n2a(int id,char * buf,int len)407 char * rtnl_dsfield_n2a(int id, char *buf, int len)
408 {
409 	if (id<0 || id>=256) {
410 		snprintf(buf, len, "%d", id);
411 		return buf;
412 	}
413 	if (!rtnl_rtdsfield_tab[id]) {
414 		if (!rtnl_rtdsfield_init)
415 			rtnl_rtdsfield_initialize();
416 	}
417 	if (rtnl_rtdsfield_tab[id])
418 		return rtnl_rtdsfield_tab[id];
419 	snprintf(buf, len, "0x%02x", id);
420 	return buf;
421 }
422 
423 
rtnl_dsfield_a2n(__u32 * id,char * arg)424 int rtnl_dsfield_a2n(__u32 *id, char *arg)
425 {
426 	static char *cache = NULL;
427 	static unsigned long res;
428 	char *end;
429 	int i;
430 
431 	if (cache && strcmp(cache, arg) == 0) {
432 		*id = res;
433 		return 0;
434 	}
435 
436 	if (!rtnl_rtdsfield_init)
437 		rtnl_rtdsfield_initialize();
438 
439 	for (i=0; i<256; i++) {
440 		if (rtnl_rtdsfield_tab[i] &&
441 		    strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
442 			cache = rtnl_rtdsfield_tab[i];
443 			res = i;
444 			*id = res;
445 			return 0;
446 		}
447 	}
448 
449 	res = strtoul(arg, &end, 16);
450 	if (!end || end == arg || *end || res > 255)
451 		return -1;
452 	*id = res;
453 	return 0;
454 }
455 
456 
457 static struct rtnl_hash_entry dflt_group_entry  = { .id = 0, .name = "default" };
458 
459 static struct rtnl_hash_entry * rtnl_group_hash[256] = {
460 	[0] = &dflt_group_entry,
461 };
462 
463 static int rtnl_group_init;
464 
rtnl_group_initialize(void)465 static void rtnl_group_initialize(void)
466 {
467 	rtnl_group_init = 1;
468 	rtnl_hash_initialize("/etc/iproute2/group",
469 			     rtnl_group_hash, 256);
470 }
471 
rtnl_group_a2n(int * id,char * arg)472 int rtnl_group_a2n(int *id, char *arg)
473 {
474 	static char *cache = NULL;
475 	static unsigned long res;
476 	struct rtnl_hash_entry *entry;
477 	char *end;
478 	int i;
479 
480 	if (cache && strcmp(cache, arg) == 0) {
481 		*id = res;
482 		return 0;
483 	}
484 
485 	if (!rtnl_group_init)
486 		rtnl_group_initialize();
487 
488 	for (i=0; i<256; i++) {
489 		entry = rtnl_group_hash[i];
490 		while (entry && strcmp(entry->name, arg))
491 			entry = entry->next;
492 		if (entry) {
493 			cache = entry->name;
494 			res = entry->id;
495 			*id = res;
496 			return 0;
497 		}
498 	}
499 
500 	i = strtol(arg, &end, 0);
501 	if (!end || end == arg || *end || i < 0)
502 		return -1;
503 	*id = i;
504 	return 0;
505 }
506