1 /**************************************************************************************************
2 	$Id: alias.c,v 1.15 2006/01/18 20:46:46 bboy Exp $
3 
4 	Copyright (C) 2002-2005  Don Moore <bboy@bboy.net>
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 2 of the License, or
9 	(at Your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with this program; if not, write to the Free Software
18 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 **************************************************************************************************/
20 
21 #include "named.h"
22 
23 /* Make this nonzero to enable debugging for this source file */
24 #define	DEBUG_ALIAS	1
25 
26 
27 #if ALIAS_ENABLED
28 /**************************************************************************************************
29 	FIND_ALIAS
30 	Find an ALIAS or A record for the alias.
31 	Returns the RR or NULL if not found.
32 **************************************************************************************************/
33 MYDNS_RR *
find_alias(TASK * t,char * fqdn)34 find_alias(TASK *t, char *fqdn)
35 {
36 	register MYDNS_SOA *soa;
37 	register MYDNS_RR *rr;
38 	register char *label;
39 	char name[DNS_MAXNAMELEN+1];
40 
41 	/* Load the SOA for the alias name. */
42 	memset(name, 0, sizeof(name));
43 	if (!(soa = find_soa(t, fqdn, name)))
44 		return (NULL);
45 
46 	/* Examine each label in the name, one at a time; look for relevant records */
47 	for (label = name; ; label++)
48 	{
49 		if (label == name || *label == '.')
50 		{
51 			if (label[0] == '.' && label[1]) label++;		/* Advance past leading dot */
52 #if DEBUG_ENABLED && DEBUG_ALIAS
53 			Debug("%s: label=`%s'", desctask(t), label);
54 #endif
55 
56 			/* Do an exact match if the label is the first in the list */
57 			if (label == name)
58 			{
59 #if DEBUG_ENABLED && DEBUG_ALIAS
60 				Debug("%s: trying exact match `%s'", desctask(t), label);
61 #endif
62 				if ((rr = find_rr(t, soa, DNS_QTYPE_A, label)))
63 					return (rr);
64 			}
65 
66 			/* No exact match. If the label isn't empty, replace the first part
67 				of the label with `*' and check for wildcard matches. */
68 			if (*label)
69 			{
70 				uchar wclabel[DNS_MAXNAMELEN+1], *c;
71 
72 				/* Generate wildcarded label, i.e. `*.example' or maybe just `*'. */
73 				if (!(c = strchr(label, '.')))
74 					wclabel[0] = '*', wclabel[1] = '\0';
75 				else
76 					wclabel[0] = '*', strncpy(wclabel+1, c, sizeof(wclabel)-2);
77 
78 #if DEBUG_ENABLED && DEBUG_ALIAS
79 				Debug("%s: trying wildcard `%s'", desctask(t), wclabel);
80 #endif
81 				if ((rr = find_rr(t, soa, DNS_QTYPE_A, wclabel)))
82 					return (rr);
83 			}
84 		}
85 		if (!*label)
86 			break;
87 	}
88 	return (NULL);
89 }
90 /*--- find_alias() ------------------------------------------------------------------------------*/
91 
92 
93 /**************************************************************************************************
94 	ALIAS_RECURSE
95 	If the task has a matching ALIAS record, recurse into it.
96 	Returns the number of records added.
97 **************************************************************************************************/
98 int
alias_recurse(TASK * t,datasection_t section,char * fqdn,MYDNS_SOA * soa,char * label,MYDNS_RR * alias)99 alias_recurse(TASK *t, datasection_t section, char *fqdn, MYDNS_SOA *soa, char *label, MYDNS_RR *alias)
100 {
101 	uint32_t aliases[MAX_ALIAS_LEVEL];
102 	char name[DNS_MAXNAMELEN+1];
103 	register MYDNS_RR *rr;
104 	register int depth, n;
105 
106 	if (LASTCHAR(alias->data) != '.')
107 		snprintf(name, sizeof(name), "%s.%s", alias->data, soa->origin);
108 	else
109 		strncpy(name, alias->data, sizeof(name)-1);
110 
111 	for (depth = 0; depth < MAX_ALIAS_LEVEL; depth++)
112 	{
113 #if DEBUG_ENABLED && DEBUG_ALIAS
114 		Debug("%s: ALIAS -> `%s'", desctask(t), name);
115 #endif
116 		/* Are there any alias records? */
117 		if ((rr = find_alias(t, name)))
118 		{
119 			/* We need an A record that is not an alias to end the chain. */
120 			if (rr->alias == 0)
121 			{
122 				/* Override the id and name, because rrlist_add() checks for duplicates and we might have several records aliased to one */
123 				rr->id = alias->id;
124 				strcpy(rr->name, alias->name);
125 				rrlist_add(t, section, DNS_RRTYPE_RR, (void *)rr, fqdn);
126 				t->sort_level++;
127 				mydns_rr_free(rr);
128 				return (1);
129 			}
130 
131 			/* Append origin if needed */
132 			int len = strlen(rr->data);
133 			if (len > 0 && rr->data[len - 1] != '.') {
134 				strcat(rr->data, ".");
135 				strncat(rr->data, soa->origin, sizeof(rr->name) - len - 1);
136 			}
137 
138 			/* Check aliases list; if we are looping, stop. Otherwise add this to the list. */
139 			for (n = 0; n < depth; n++)
140 				if (aliases[n] == rr->id)
141 				{
142 					/* ALIAS loop: We aren't going to find an A record, so we're done. */
143 					Verbose("%s: %s: %s (depth %d)", desctask(t), _("ALIAS loop detected"), fqdn, depth);
144 					mydns_rr_free(rr);
145 					return (0);
146 				}
147 			aliases[depth] = rr->id;
148 
149 			/* Continue search with new alias. */
150 			strncpy(name, rr->data, sizeof(name)-1);
151 			mydns_rr_free(rr);
152 		}
153 		else
154 		{
155 			Verbose("%s: %s: %s -> %s", desctask(t), _("ALIAS chain is broken"), fqdn, name);
156 			return (0);
157 		}
158 	}
159 	Verbose("%s: %s: %s -> %s (depth %d)", desctask(t), _("max ALIAS depth exceeded"), fqdn, alias->data, depth);
160 	return (0);
161 }
162 /*--- alias_recurse() ---------------------------------------------------------------------------*/
163 
164 #endif /* ALIAS_ENABLED */
165 
166 /* vi:set ts=3: */
167