]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/dnsmasq/0081-Handle-domain-names-with-.-or-000-within-labels.patch
Merge remote-tracking branch 'mfischer/python' into next
[people/pmueller/ipfire-2.x.git] / src / patches / dnsmasq / 0081-Handle-domain-names-with-.-or-000-within-labels.patch
1 From cbe379ad6b52a538a4416a7cd992817e5637ccf9 Mon Sep 17 00:00:00 2001
2 From: Simon Kelley <simon@thekelleys.org.uk>
3 Date: Tue, 21 Apr 2015 22:57:06 +0100
4 Subject: [PATCH 81/98] Handle domain names with '.' or /000 within labels.
5
6 Only in DNSSEC mode, where we might need to validate or store
7 such names. In none-DNSSEC mode, simply don't cache these, as before.
8 ---
9 src/dns-protocol.h | 4 ++++
10 src/dnsmasq.c | 15 +++++++++++++--
11 src/dnssec.c | 40 +++++++++++++++++++++++++++++++---------
12 src/rfc1035.c | 16 +++++++++++++++-
13 src/util.c | 9 ++++++++-
14 5 files changed, 71 insertions(+), 13 deletions(-)
15
16 diff --git a/src/dns-protocol.h b/src/dns-protocol.h
17 index 16fade33d98c..7f5d686bb150 100644
18 --- a/src/dns-protocol.h
19 +++ b/src/dns-protocol.h
20 @@ -142,3 +142,7 @@ struct dns_header {
21
22 #define ADD_RDLEN(header, pp, plen, len) \
23 (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
24 +
25 +/* Escape character in our presentation format for names.
26 + Cannot be '.' or /000 and must be !isprint() */
27 +#define NAME_ESCAPE 1
28 diff --git a/src/dnsmasq.c b/src/dnsmasq.c
29 index 20b15c05103a..19a6428b09e8 100644
30 --- a/src/dnsmasq.c
31 +++ b/src/dnsmasq.c
32 @@ -102,8 +102,19 @@ int main (int argc, char **argv)
33 #ifdef HAVE_DNSSEC
34 if (option_bool(OPT_DNSSEC_VALID))
35 {
36 - daemon->keyname = safe_malloc(MAXDNAME);
37 - daemon->workspacename = safe_malloc(MAXDNAME);
38 + /* Note that both /000 and '.' are allowed within labels. These get
39 + represented in presentation format using NAME_ESCAPE as an escape
40 + character when in DNSSEC mode.
41 + In theory, if all the characters in a name were /000 or
42 + '.' or NAME_ESCAPE then all would have to be escaped, so the
43 + presentation format would be twice as long as the spec.
44 +
45 + daemon->namebuff was previously allocated by the option-reading
46 + code before we knew if we're in DNSSEC mode, so reallocate here. */
47 + free(daemon->namebuff);
48 + daemon->namebuff = safe_malloc(MAXDNAME * 2);
49 + daemon->keyname = safe_malloc(MAXDNAME * 2);
50 + daemon->workspacename = safe_malloc(MAXDNAME * 2);
51 }
52 #endif
53
54 diff --git a/src/dnssec.c b/src/dnssec.c
55 index 05e0983cb251..c116a7b5f6f4 100644
56 --- a/src/dnssec.c
57 +++ b/src/dnssec.c
58 @@ -321,10 +321,18 @@ static int verify(struct blockdata *key_data, unsigned int key_len, unsigned cha
59 thus generating names in canonical form.
60 Calling to_wire followed by from_wire is almost an identity,
61 except that the UC remains mapped to LC.
62 +
63 + Note that both /000 and '.' are allowed within labels. These get
64 + represented in presentation format using NAME_ESCAPE as an escape
65 + character. In theory, if all the characters in a name were /000 or
66 + '.' or NAME_ESCAPE then all would have to be escaped, so the
67 + presentation format would be twice as long as the spec (1024).
68 + The buffers are all delcared as 2049 (allowing for the trailing zero)
69 + for this reason.
70 */
71 static int to_wire(char *name)
72 {
73 - unsigned char *l, *p, term;
74 + unsigned char *l, *p, *q, term;
75 int len;
76
77 for (l = (unsigned char*)name; *l != 0; l = p)
78 @@ -332,7 +340,10 @@ static int to_wire(char *name)
79 for (p = l; *p != '.' && *p != 0; p++)
80 if (*p >= 'A' && *p <= 'Z')
81 *p = *p - 'A' + 'a';
82 -
83 + else if (*p == NAME_ESCAPE)
84 + for (q = p; *q; q++)
85 + *q = *(q+1);
86 +
87 term = *p;
88
89 if ((len = p - l) != 0)
90 @@ -351,13 +362,23 @@ static int to_wire(char *name)
91 /* Note: no compression allowed in input. */
92 static void from_wire(char *name)
93 {
94 - unsigned char *l;
95 + unsigned char *l, *p, *last;
96 int len;
97 -
98 +
99 + for (last = (unsigned char *)name; *last != 0; last += *last+1);
100 +
101 for (l = (unsigned char *)name; *l != 0; l += len+1)
102 {
103 len = *l;
104 memmove(l, l+1, len);
105 + for (p = l; p < l + len; p++)
106 + if (*p == '.' || *p == 0 || *p == NAME_ESCAPE)
107 + {
108 + memmove(p+1, p, 1 + last - p);
109 + len++;
110 + *p++ = NAME_ESCAPE;
111 + }
112 +
113 l[len] = '.';
114 }
115
116 @@ -645,7 +666,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
117 if (left1 != 0)
118 memmove(buff1, buff1 + len1 - left1, left1);
119
120 - if ((len1 = get_rdata(header, plen, end1, buff1 + left1, MAXDNAME - left1, &p1, &dp1)) == 0)
121 + if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
122 {
123 quit = 1;
124 len1 = end1 - p1;
125 @@ -656,7 +677,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
126 if (left2 != 0)
127 memmove(buff2, buff2 + len2 - left2, left2);
128
129 - if ((len2 = get_rdata(header, plen, end2, buff2 + left2, MAXDNAME - left2, &p2, &dp2)) == 0)
130 + if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
131 {
132 quit = 1;
133 len2 = end2 - p2;
134 @@ -902,10 +923,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
135
136 end = p + rdlen;
137
138 - /* canonicalise rdata and calculate length of same, use name buffer as workspace */
139 + /* canonicalise rdata and calculate length of same, use name buffer as workspace.
140 + Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
141 cp = p;
142 dp = rr_desc;
143 - for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)) != 0; len += seg);
144 + for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
145 len += end - cp;
146 len = htons(len);
147 hash->update(ctx, 2, (unsigned char *)&len);
148 @@ -913,7 +935,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
149 /* Now canonicalise again and digest. */
150 cp = p;
151 dp = rr_desc;
152 - while ((seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)))
153 + while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
154 hash->update(ctx, seg, (unsigned char *)name);
155 if (cp != end)
156 hash->update(ctx, end - cp, cp);
157 diff --git a/src/rfc1035.c b/src/rfc1035.c
158 index a995ab50d74a..19fecc818c06 100644
159 --- a/src/rfc1035.c
160 +++ b/src/rfc1035.c
161 @@ -128,6 +128,15 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
162 if (isExtract)
163 {
164 unsigned char c = *p;
165 +#ifdef HAVE_DNSSEC
166 + if (option_bool(OPT_DNSSEC_VALID))
167 + {
168 + if (c == 0 || c == '.' || c == NAME_ESCAPE)
169 + *cp++ = NAME_ESCAPE;
170 + *cp++ = c;
171 + }
172 + else
173 +#endif
174 if (c != 0 && c != '.')
175 *cp++ = c;
176 else
177 @@ -144,9 +153,14 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
178 cp++;
179 if (c1 >= 'A' && c1 <= 'Z')
180 c1 += 'a' - 'A';
181 +#ifdef HAVE_DNSSEC
182 + if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
183 + c1 = *cp++;
184 +#endif
185 +
186 if (c2 >= 'A' && c2 <= 'Z')
187 c2 += 'a' - 'A';
188 -
189 +
190 if (c1 != c2)
191 retvalue = 2;
192 }
193 diff --git a/src/util.c b/src/util.c
194 index 648bc4d4b428..0c1a48b4700a 100644
195 --- a/src/util.c
196 +++ b/src/util.c
197 @@ -226,7 +226,14 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
198 {
199 unsigned char *cp = p++;
200 for (j = 0; *sval && (*sval != '.'); sval++, j++)
201 - *p++ = *sval;
202 + {
203 +#ifdef HAVE_DNSSEC
204 + if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
205 + *p++ = *(++sval);
206 + else
207 +#endif
208 + *p++ = *sval;
209 + }
210 *cp = j;
211 if (*sval)
212 sval++;
213 --
214 2.1.0
215