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