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
30struct rtnl_hash_entry {
31	struct rtnl_hash_entry *next;
32	char *			name;
33	unsigned int		id;
34};
35
36static void
37rtnl_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
76static 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
111static 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
131static int rtnl_rtprot_init;
132
133static 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
140char * 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
156int 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
190static char * rtnl_rtscope_tab[256] = {
191	"global",
192};
193
194static int rtnl_rtscope_init;
195
196static 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
207char * 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
223int 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
257static char * rtnl_rtrealm_tab[256] = {
258	"unknown",
259};
260
261static int rtnl_rtrealm_init;
262
263static 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
270char * 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
287int 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
320static struct rtnl_hash_entry dflt_table_entry  = { .id = 253, .name = "default" };
321static struct rtnl_hash_entry main_table_entry  = { .id = 254, .name = "main" };
322static struct rtnl_hash_entry local_table_entry = { .id = 255, .name = "local" };
323
324static 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
330static int rtnl_rttable_init;
331
332static 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
339char * 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
358int 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
394static char * rtnl_rtdsfield_tab[256] = {
395	"0",
396};
397
398static int rtnl_rtdsfield_init;
399
400static 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
407char * 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
424int 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
457static struct rtnl_hash_entry dflt_group_entry  = { .id = 0, .name = "default" };
458
459static struct rtnl_hash_entry * rtnl_group_hash[256] = {
460	[0] = &dflt_group_entry,
461};
462
463static int rtnl_group_init;
464
465static 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
472int 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