1 /*****************************************************************
2 **
3 **	@(#) scope.c -- SCOPE SECTION and prefix matching functions
4 **
5 **	Copyright (c) Oct 2015, Holger Zuleger HZNET. All rights reserved.
6 **
7 **	This software is open source.
8 **
9 *****************************************************************/
10 # include <stdio.h>
11 # include <string.h>
12 # include <stdlib.h>
13 # include <unistd.h>	/* for link(), unlink() */
14 # include <ctype.h>
15 # include <sys/types.h>
16 # include <sys/stat.h>
17 # include <time.h>
18 # include <utime.h>
19 # include <assert.h>
20 # include <errno.h>
21 # include <fcntl.h>
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25 # include "misc.h"
26 # include "ip6.h"
27 # include "hostid.h"
28 #define extern
29 # include "scope.h"
30 #undef extern
31 # include "gen6dns.h"
32 
33 /* List of prefixes from the command line */
34 static	prfx_t	prfxlist[MAXPREFIXES];
35 static	int	nprfx;			/* no of entries in prfx[] */
36 
37 /* List of scopes out of SCOPE SECTION */
38 static	scope_t	scopelist[MAXSCOPES];
39 static	int	nscope;			/* no of entries in scopelist[] */
40 
41 static	int	scopeset[MAXSCOPES];
42 
43 static	int	namefromstr (char *to, int tolen, const char *from);
44 
45 /*****************************************************************
46 **	prfxput ()
47 **	puts a prefix into the prefix list
48 *****************************************************************/
prfxput(const ip6_t * prfx,int to_del)49 int	prfxput (const ip6_t *prfx, int	to_del)
50 {
51 	ip6_t	*new;
52 	int	i;
53 
54 	if ( nprfx >= MAXPREFIXES )
55 		fatal ("maximum number of prefixes (%d) reached\n", MAXPREFIXES);
56 
57 	new = NULL;
58 	if ( prfx )
59 	{
60 		for ( i = 0; i <nprfx; i++ )
61 		{
62 			if ( ip6cmp (prfx, prfxlist[i].prfx) == 0 )
63 			{
64 				error ("duplicate ipv6 prefix (%s), skipped\n");
65 				return nprfx;
66 			}
67 		}
68 		if ( (new = ip6copy (NULL, prfx)) == NULL )
69 			fatal ("%s:%d prfxput(): out of memory\n", __FILE__, __LINE__);
70 	}
71 	prfxlist[nprfx].prfx = new;
72 	prfxlist[nprfx].del = to_del;
73 	prfxlist[nprfx].scope = NULL;
74 
75 	return ++nprfx;
76 }
77 
78 /*****************************************************************
79 **	prfxdel ()
80 **	removes a prefix from the prefix list
81 *****************************************************************/
prfxdel(int n)82 int	prfxdel (int n)
83 {
84 	if ( nprfx <= 0 )
85 		return 0;
86 	if ( n >= 0 && n < nprfx )
87 	{
88 		prfxlist[n].prfx = prfxlist[nprfx].prfx;
89 		prfxlist[n].del = prfxlist[nprfx].del;
90 		prfxlist[n].scope = prfxlist[nprfx].scope;
91 	}
92 	return --nprfx;
93 }
94 
95 /*****************************************************************
96 **	prfxget ()
97 **	returns a prefix from the prefix list
98 *****************************************************************/
prfxget(int n)99 prfx_t	*prfxget (int n)
100 {
101 	if ( n >= 0 && n < nprfx )
102 		return &prfxlist[n];
103 
104 	return NULL;
105 }
106 
107 /* Next functions loop through the prefix lsit */
108 static	int	prfxcnt;
109 /*****************************************************************
110 **	prfxstart ()
111 *****************************************************************/
prfxstart()112 prfx_t	*prfxstart ()
113 {
114 
115 	return prfxget (prfxcnt = 0);
116 }
117 
118 /*****************************************************************
119 **	prfxnext ()
120 *****************************************************************/
prfxnext()121 prfx_t	*prfxnext ()
122 {
123 	return prfxget (++prfxcnt);
124 }
125 
126 
127 /*****************************************************************
128 **	Scope functions starting here
129 *****************************************************************/
130 
131 #define	isequal(a, b)	((a == NULL && b == NULL) || (a && b && strcmp (a, b) == 0) )
132 /*****************************************************************
133 **	scopeput ()
134 *****************************************************************/
scopeput(const char * name,const char * view,const char * domain,ip6_t * prfx)135 int	scopeput (const char *name, const char *view, const char *domain, ip6_t *prfx)
136 {
137 	prfx_t	*prf;
138 	ip6_t	*new;
139 	int	i;
140 	const	char	*p;
141 
142 	assert ( name != NULL );
143 	assert ( view != NULL );
144 	assert ( domain != NULL );
145 
146 	if ( nscope >= MAXSCOPES )
147 		fatal ("maximum number of scopes (%d) reached\n", MAXSCOPES);
148 
149 	snprintf (scopelist[nscope].name, sizeof (scopelist[0].name), "%s", name);
150 
151 	/* Is viewname set ? */
152 	if ( *view && *view != '*' && strcmp (view, "none") != 0 && (p = strdup (view)) != NULL )
153 		scopelist[nscope].view = p;
154 	else
155 		scopelist[nscope].view = NULL;
156 
157 	/* Is domain name set ? */
158 	if ( *domain && (p = strdup (domain)) != NULL )
159 		scopelist[nscope].domain = p;
160 	else
161 		scopelist[nscope].domain = NULL;
162 
163 	if ( (new = ip6copy (NULL, prfx)) == NULL )
164 		fatal ("%s:%d scopeput(): out of memory\n", __FILE__, __LINE__);
165 	scopelist[nscope].matchprfx = new;
166 
167 	scopelist[nscope].unique_scopeid = nscope;
168 
169 	/* mark this scope as duplicate if there is another one with the same view and domain */
170 	for ( i = 0; i < nscope; i++ )
171 	{
172 		if ( isequal (scopelist[i].view, scopelist[nscope].view) &&
173 		     isequal (scopelist[i].domain, scopelist[nscope].domain) )
174 		{
175 			scopelist[nscope].unique_scopeid = scopelist[i].unique_scopeid;
176 			break;
177 		}
178 	}
179 
180 	/* lookup a prefix in prefixlist matching this scope */
181 	prf = prfxstart();
182 	while ( prf )
183 	{
184 		if ( prf->scope == NULL &&	/* entry do not have a scope */
185 		     ip6match (prf->prfx, scopelist[nscope].matchprfx) > 0 )
186 			prf->scope = &scopelist[nscope];
187 		prf = prfxnext();
188 	}
189 
190 	return ++nscope;
191 }
192 
193 /*****************************************************************
194 **	scopeget ()
195 *****************************************************************/
scopeget(const char * scope)196 scope_t	*scopeget (const char *scope)
197 {
198 	int	i;
199 
200 	for ( i = 0; i < nscope; i++ )
201 	{
202 // fprintf (stderr, "\"%s\" == \"%s\"? => %p\n", scope, snet[i].name, &snet[i].sid);
203 		if ( strcmp (scope, scopelist[i].name) == 0 )
204 			return &scopelist[i];
205 	}
206 
207 	return NULL;
208 }
209 
210 /*****************************************************************
211 **	parsescopeline ()
212 *****************************************************************/
parsescopeline(const char * line,int delim)213 int	parsescopeline (const char * line, int delim)
214 {
215 	const	char	*p;
216 	int	len;
217 	char	name[15+1];
218 	char	view[254+1];
219 	char	domain[254+1];
220 	ip6_t	prfx;
221 
222 	assert ( line != NULL );
223 
224 	p = skipdelim (line, delim);
225 	p += namefromstr (name, sizeof name, p);
226 	if ( !isdelim (*p, delim) )
227 	{
228 		error ("parsescopeline(): illegal scopename found near \"%.10s ...\"\n", p);
229 		return 0;
230 	}
231 
232 	p = skipdelim (p, delim);
233 	p += namefromstr (view, sizeof view, p);
234 	if ( !isdelim (*p, delim) )
235 	{
236 		error ("parsescopeline(): illegal viewname found near \"%.10s ...\"\n", p);
237 		return 0;
238 	}
239 
240 	p = skipdelim (p, delim);
241 	p += namefromstr (domain, sizeof(domain), p);
242 	if ( !isdelim (*p, delim) )
243 	{
244 		error ("parsescopeline(): illegal domain found near \"%.10s ...\"\n", p);
245 		return 0;
246 	}
247 
248 	p = skipdelim (p, delim);
249 	p += ip6fromstr (&prfx, p);
250 	if ( !(ip6isset (&prfx) && ip6getsbit (&prfx) == 0 && ip6getebit (&prfx) <= 64) )
251 	{
252 		error ("parsescopeline(): no matching prefix found near \"%.10s ...\"\n", p);
253 		return 0;
254 	}
255 
256 	len = strlen (domain);
257 	if ( len > 0 && domain[len-1] != '.' )
258 #if defined(ADD_DEF_ORIGIN) && ADD_DEF_ORIGIN == 1
259 		snprintf (&domain[len], sizeof (domain) - (len), ".%s", parm.origin);
260 #else
261 		error ("Missing dot at the end of domain \"%s\" (in scope definition \"%s\")!\n", domain, name);
262 #endif
263 
264 	scopeput (name, view, domain, &prfx);
265 
266 	return 1;
267 }
268 
scopeset_clear(void)269 void	scopeset_clear (void)
270 {
271 	int	i;
272 
273 	for ( i = 0; i < MAXSCOPES; i++ )
274 		scopeset[i] = 0;
275 }
276 
scopeset_set(int n)277 int	scopeset_set (int n)
278 {
279 	int	prevval;
280 
281 	prevval = 0;
282 	if ( n >= 0 && n < MAXSCOPES )
283 	{
284 		prevval = scopeset[n];
285 		scopeset[n] = 1;
286 	}
287 	return prevval;
288 }
289 
scopeset_get(int n)290 int	scopeset_get (int n)
291 {
292 	if ( n >= 0 && n < MAXSCOPES )
293 		return scopeset[n];
294 	return -1;
295 }
296 
297 /*****************************************************************
298 **	dumpscope ()
299 *****************************************************************/
dumpscope(FILE * out)300 void	dumpscope (FILE *out)
301 {
302 	int	i;
303 	char	str[63+1];
304 
305 	assert ( out != NULL );
306 
307 	fprintf (out, "\n%%%%SCOPE SECTION (%d elements)\n", nscope);
308 
309 	for ( i = 0; i < nscope; i++ )
310 	{
311 		fprintf (out, "%s\t", scopelist[i].name);
312 		fprintf (out, "%s\t", scopelist[i].view && scopelist[i].view[0] ? scopelist[i].view: "none");
313 		fprintf (out, "%s\t", scopelist[i].domain ? scopelist[i].domain: "");
314 		ip6tostr (str, sizeof str, scopelist[i].matchprfx);
315 		fprintf (out, "%s\t", str);
316 		fprintf (out, "; unique_scopeid %d", scopelist[i].unique_scopeid);
317 		fprintf (out, "\n");
318 	}
319 	fprintf (out, "%%%%END\n\n");
320 }
321 
322 /*****************************************************************
323 **	dumpprefixlist ()
324 *****************************************************************/
dumpprefixlist(FILE * out)325 void	dumpprefixlist (FILE *out)
326 {
327 	int	i;
328 	char	str[63+1];
329 
330 	assert ( out != NULL );
331 
332 	fprintf (out, "\n%%%%The current (command line) prefix list \n");
333 
334 	for ( i = 0; i < nprfx; i++ )
335 	{
336 		if ( prfxlist[i].prfx )
337 			ip6tostr (str, sizeof str, prfxlist[i].prfx);
338 		else if ( prfxlist[i].del )
339 			strcpy (str, "ALL");
340 		else	/* should never happen */
341 			fatal ("NULL prefix with add action in prefixlist; Use of -p w/o argument!");
342 		fprintf (out, "%s\t", str);
343 		fprintf (out, "%s\t", prfxlist[i].del ? "to_del": "to_add");
344 		fprintf (out, "[%s]\t", prfxlist[i].scope->name);
345 		fprintf (out, "\n");
346 	}
347 	fprintf (out, "%%%%END\n\n");
348 }
349 
350 # define	isnamechar(c)	(isalpha (c) || isdigit (c) || (c) == '-' || (c) == '_' || (c) == '.')
namefromstr(char * to,int tolen,const char * from)351 static	int	namefromstr (char *to, int tolen, const char *from)
352 {
353 	int	i;
354 	const	char	*p;
355 
356 	assert ( to != NULL );
357 
358 	if ( from == NULL )
359 		return 0;
360 
361 	i = 0;
362 	p = from;
363 	if ( isalpha (*p) || *p == '_' )
364 	{
365 		while ( *p && i < tolen && isnamechar (*p) )
366 			to[i++] = *p++;
367 	}
368 	else if ( *p == '*' )	/* "wildcard" for an empty field */
369 		p++;
370 	to[i] = '\0';
371 
372 	return p - from;
373 }
374