]>
Commit | Line | Data |
---|---|---|
d085b054 | 1 | These patches add the ability to send and receive DNS messages with |
2 | edns-client-subnet options to BIND's dig utility. | |
3 | ||
4 | Example: | |
5 | ||
6 | wilmer@fiona:~/src/bind-ecs$ bin/dig/dig @ns1.google.com www.google.com +client=130.89.89.130 | |
7 | ||
8 | ; <<>> DiG 9.7.1-P2 <<>> @ns1.google.com www.google.com +client=130.89.89.130 | |
9 | ;; OPT PSEUDOSECTION: | |
10 | ; EDNS: version: 0, flags:; udp: 512 | |
11 | ; CLIENT-SUBNET: 130.89.89.130/32/21 | |
12 | ;; QUESTION SECTION: | |
13 | ;www.google.com. IN A | |
14 | ||
15 | ;; ANSWER SECTION: | |
16 | www.google.com. 604800 IN CNAME www.l.google.com. | |
17 | www.l.google.com. 300 IN A 74.125.79.104 | |
18 | www.l.google.com. 300 IN A 74.125.79.99 | |
19 | www.l.google.com. 300 IN A 74.125.79.147 | |
20 | ||
21 | Copyright 2010 Google Inc. | |
22 | Author: Wilmer van der Gaast <wilmer@google.com> | |
23 | ||
24 | ||
25 | diff -uNr bin/dig/dig.c bin/dig/dig.c | |
26 | --- bin/dig/dig.c 2010-05-13 01:42:26.000000000 +0100 | |
27 | +++ bin/dig/dig.c 2011-02-16 15:58:31.000000000 +0000 | |
28 | @@ -188,6 +188,7 @@ | |
29 | " +bufsize=### (Set EDNS0 Max UDP packet size)\n" | |
30 | " +ndots=### (Set NDOTS value)\n" | |
31 | " +edns=### (Set EDNS version)\n" | |
32 | +" +client=addr (Set edns-client-subnet option)\n" | |
33 | " +[no]search (Set whether to use searchlist)\n" | |
34 | " +[no]showsearch (Search with intermediate results)\n" | |
35 | " +[no]defname (Ditto)\n" | |
36 | @@ -804,8 +805,25 @@ | |
37 | } | |
38 | break; | |
39 | case 'l': /* cl */ | |
40 | - FULLCHECK("cl"); | |
41 | - noclass = ISC_TF(!state); | |
42 | + switch (cmd[2]) { | |
43 | + case 'i':/* client */ | |
44 | + FULLCHECK("client"); | |
45 | + if (value == NULL) | |
46 | + goto need_value; | |
47 | + if (state && lookup->edns == -1) | |
48 | + lookup->edns = 0; | |
49 | + if (parse_netprefix(&lookup->ecs_addr, | |
50 | + &lookup->ecs_len, | |
51 | + value) != ISC_R_SUCCESS) | |
52 | + fatal("Couldn't parse client"); | |
53 | + break; | |
54 | + case '\0': | |
55 | + FULLCHECK("cl"); | |
56 | + noclass = ISC_TF(!state); | |
57 | + break; | |
58 | + default: | |
59 | + goto invalid_option; | |
60 | + } | |
61 | break; | |
62 | case 'm': /* cmd */ | |
63 | FULLCHECK("cmd"); | |
64 | diff -uNr bin/dig/dighost.c bin/dig/dighost.c | |
65 | --- bin/dig/dighost.c 2010-12-09 01:05:27.000000000 +0000 | |
66 | +++ bin/dig/dighost.c 2011-02-16 15:58:31.000000000 +0000 | |
67 | @@ -96,6 +96,9 @@ | |
68 | ||
69 | #include <dig/dig.h> | |
70 | ||
71 | +/* parse_netprefix */ | |
72 | +#include <netdb.h> | |
73 | + | |
74 | #if ! defined(NS_INADDRSZ) | |
75 | #define NS_INADDRSZ 4 | |
76 | #endif | |
77 | @@ -789,6 +792,8 @@ | |
78 | looknew->new_search = ISC_FALSE; | |
79 | looknew->done_as_is = ISC_FALSE; | |
80 | looknew->need_search = ISC_FALSE; | |
81 | + looknew->ecs_addr = NULL; | |
82 | + looknew->ecs_len = 0; | |
83 | ISC_LINK_INIT(looknew, link); | |
84 | ISC_LIST_INIT(looknew->q); | |
85 | ISC_LIST_INIT(looknew->my_server_list); | |
86 | @@ -805,6 +810,7 @@ | |
87 | dig_lookup_t * | |
88 | clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { | |
89 | dig_lookup_t *looknew; | |
90 | + size_t len; | |
91 | ||
92 | debug("clone_lookup()"); | |
93 | ||
94 | @@ -865,6 +871,19 @@ | |
95 | looknew->need_search = lookold->need_search; | |
96 | looknew->done_as_is = lookold->done_as_is; | |
97 | ||
98 | + if (lookold->ecs_addr) { | |
99 | + if (lookold->ecs_addr->sa_family == AF_INET) | |
100 | + len = sizeof(struct sockaddr_in); | |
101 | + else if (lookold->ecs_addr->sa_family == AF_INET6) | |
102 | + len = sizeof(struct sockaddr_in6); | |
103 | + else | |
104 | + INSIST(0); | |
105 | + | |
106 | + looknew->ecs_addr = isc_mem_allocate(mctx, len); | |
107 | + memcpy(looknew->ecs_addr, lookold->ecs_addr, len); | |
108 | + looknew->ecs_len = lookold->ecs_len; | |
109 | + } | |
110 | + | |
111 | if (servers) | |
112 | clone_server_list(lookold->my_server_list, | |
113 | &looknew->my_server_list); | |
114 | @@ -974,6 +993,48 @@ | |
115 | return (tmp); | |
116 | } | |
117 | ||
118 | +isc_result_t | |
119 | +parse_netprefix(struct sockaddr **sa, isc_uint32_t *netmask, | |
120 | + const char *value) { | |
121 | + struct addrinfo *res, hints; | |
122 | + char *addr, *slash; | |
123 | + isc_uint32_t result; | |
124 | + | |
125 | + addr = isc_mem_strdup(mctx, value); | |
126 | + if ((slash = strchr(addr, '/'))) { | |
127 | + *slash = '\0'; | |
128 | + result = isc_parse_uint32(netmask, slash + 1, 10); | |
129 | + if (result != ISC_R_SUCCESS) { | |
130 | + isc_mem_free(mctx, addr); | |
131 | + printf("invalid %s '%s': %s\n", "prefix length", | |
132 | + value, isc_result_totext(result)); | |
133 | + return (result); | |
134 | + } | |
135 | + } else { | |
136 | + *netmask = 128; | |
137 | + } | |
138 | + | |
139 | + memset(&hints, 0, sizeof(hints)); | |
140 | + hints.ai_flags = AI_NUMERICHOST; | |
141 | + if ((result = getaddrinfo(addr, NULL, &hints, &res)) != 0) { | |
142 | + isc_mem_free(mctx, addr); | |
143 | + printf("getaddrinfo() error: %s\n", gai_strerror(result)); | |
144 | + return ISC_R_FAILURE; | |
145 | + } | |
146 | + isc_mem_free(mctx, addr); | |
147 | + | |
148 | + *sa = isc_mem_allocate(mctx, res->ai_addrlen); | |
149 | + memcpy(*sa, res->ai_addr, res->ai_addrlen); | |
150 | + | |
151 | + if (res->ai_family == AF_INET && *netmask > 32) | |
152 | + *netmask = 32; | |
153 | + else if (res->ai_family == AF_INET6 && *netmask > 128) | |
154 | + *netmask = 128; | |
155 | + | |
156 | + freeaddrinfo(res); | |
157 | + return (ISC_R_SUCCESS); | |
158 | +} | |
159 | + | |
160 | ||
161 | /* | |
162 | * Parse HMAC algorithm specification | |
163 | @@ -1361,12 +1422,15 @@ | |
164 | */ | |
165 | static void | |
166 | add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns, | |
167 | - isc_boolean_t dnssec, isc_boolean_t nsid) | |
168 | + isc_boolean_t dnssec, isc_boolean_t nsid, | |
169 | + struct sockaddr *ecs_addr, isc_uint32_t ecs_len) | |
170 | { | |
171 | dns_rdataset_t *rdataset = NULL; | |
172 | dns_rdatalist_t *rdatalist = NULL; | |
173 | dns_rdata_t *rdata = NULL; | |
174 | isc_result_t result; | |
175 | + unsigned char data[64]; | |
176 | + isc_buffer_t buf; | |
177 | ||
178 | debug("add_opt()"); | |
179 | result = dns_message_gettemprdataset(msg, &rdataset); | |
180 | @@ -1384,20 +1448,37 @@ | |
181 | rdatalist->ttl = edns << 16; | |
182 | if (dnssec) | |
183 | rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO; | |
184 | - if (nsid) { | |
185 | - isc_buffer_t *b = NULL; | |
186 | ||
187 | - result = isc_buffer_allocate(mctx, &b, 4); | |
188 | - check_result(result, "isc_buffer_allocate"); | |
189 | - isc_buffer_putuint16(b, DNS_OPT_NSID); | |
190 | - isc_buffer_putuint16(b, 0); | |
191 | - rdata->data = isc_buffer_base(b); | |
192 | - rdata->length = isc_buffer_usedlength(b); | |
193 | - dns_message_takebuffer(msg, &b); | |
194 | - } else { | |
195 | - rdata->data = NULL; | |
196 | - rdata->length = 0; | |
197 | + isc_buffer_init(&buf, data, sizeof(data)); | |
198 | + if (nsid) { | |
199 | + isc_buffer_putuint16(&buf, DNS_OPT_NSID); | |
200 | + isc_buffer_putuint16(&buf, 0); | |
201 | } | |
202 | + if (ecs_addr) { | |
203 | + size_t addrl = (ecs_len + 7) / 8; | |
204 | + | |
205 | + isc_buffer_putuint16(&buf, DNS_OPT_CLIENT_SUBNET); | |
206 | + isc_buffer_putuint16(&buf, 4 + addrl); | |
207 | + if (ecs_addr->sa_family == AF_INET) { | |
208 | + struct sockaddr_in *ad = (struct sockaddr_in *) ecs_addr; | |
209 | + isc_buffer_putuint16(&buf, 1); | |
210 | + isc_buffer_putuint8(&buf, ecs_len); | |
211 | + isc_buffer_putuint8(&buf, 0); | |
212 | + isc_buffer_putmem(&buf, (isc_uint8_t*) &ad->sin_addr, addrl); | |
213 | + } | |
214 | + else /* if (ecs_addr->sa_family == AF_INET6) */ { | |
215 | + struct sockaddr_in6 *ad = (struct sockaddr_in6 *) ecs_addr; | |
216 | + isc_buffer_putuint16(&buf, 2); | |
217 | + isc_buffer_putuint8(&buf, ecs_len); | |
218 | + isc_buffer_putuint8(&buf, 0); | |
219 | + isc_buffer_putmem(&buf, (isc_uint8_t*) &ad->sin6_addr, addrl); | |
220 | + } | |
221 | + } | |
222 | + if ((rdata->length = isc_buffer_usedlength(&buf)) > 0) | |
223 | + rdata->data = data; | |
224 | + else | |
225 | + rdata->data = NULL; | |
226 | + | |
227 | ISC_LIST_INIT(rdatalist->rdata); | |
228 | ISC_LIST_APPEND(rdatalist->rdata, rdata, link); | |
229 | dns_rdatalist_tordataset(rdatalist, rdataset); | |
230 | @@ -1546,6 +1627,9 @@ | |
231 | if (lookup->tsigctx != NULL) | |
232 | dst_context_destroy(&lookup->tsigctx); | |
233 | ||
234 | + if (lookup->ecs_addr != NULL) | |
235 | + isc_mem_free(mctx, lookup->ecs_addr); | |
236 | + | |
237 | isc_mem_free(mctx, lookup); | |
238 | } | |
239 | ||
240 | @@ -2210,7 +2294,8 @@ | |
241 | if (lookup->edns < 0) | |
242 | lookup->edns = 0; | |
243 | add_opt(lookup->sendmsg, lookup->udpsize, | |
244 | - lookup->edns, lookup->dnssec, lookup->nsid); | |
245 | + lookup->edns, lookup->dnssec, lookup->nsid, | |
246 | + lookup->ecs_addr, lookup->ecs_len); | |
247 | } | |
248 | ||
249 | result = dns_message_rendersection(lookup->sendmsg, | |
250 | diff -uNr bin/dig/include/dig/dig.h bin/dig/include/dig/dig.h | |
251 | --- bin/dig/include/dig/dig.h 2009-09-29 16:06:06.000000000 +0100 | |
252 | +++ bin/dig/include/dig/dig.h 2011-02-16 15:58:31.000000000 +0000 | |
253 | @@ -183,6 +183,8 @@ | |
254 | isc_buffer_t *querysig; | |
255 | isc_uint32_t msgcounter; | |
256 | dns_fixedname_t fdomain; | |
257 | + struct sockaddr *ecs_addr; /*% edns-client-subnet */ | |
258 | + isc_uint32_t ecs_len; | |
259 | }; | |
260 | ||
261 | /*% The dig_query structure */ | |
262 | @@ -330,6 +332,10 @@ | |
263 | parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max, | |
264 | const char *desc); | |
265 | ||
266 | +isc_result_t | |
267 | +parse_netprefix(struct sockaddr **sa, isc_uint32_t *netmask, | |
268 | + const char *value); | |
269 | + | |
270 | void | |
271 | parse_hmac(const char *hmacstr); | |
272 | ||
273 | diff -uNr lib/dns/include/dns/message.h lib/dns/include/dns/message.h | |
274 | --- lib/dns/include/dns/message.h 2009-10-26 23:47:35.000000000 +0000 | |
275 | +++ lib/dns/include/dns/message.h 2011-02-16 15:58:31.000000000 +0000 | |
276 | @@ -105,6 +105,7 @@ | |
277 | ||
278 | /*%< EDNS0 extended OPT codes */ | |
279 | #define DNS_OPT_NSID 0x0003 /*%< NSID opt code */ | |
280 | +#define DNS_OPT_CLIENT_SUBNET 0x50fa /*%< client subnet opt code */ | |
281 | ||
282 | #define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD) | |
283 | #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO) | |
284 | diff -uNr lib/dns/message.c lib/dns/message.c | |
285 | --- lib/dns/message.c 2010-06-03 06:27:59.000000000 +0100 | |
286 | +++ lib/dns/message.c 2011-02-16 15:58:31.000000000 +0000 | |
287 | @@ -3236,6 +3236,35 @@ | |
288 | ||
289 | if (optcode == DNS_OPT_NSID) { | |
290 | ADD_STRING(target, "; NSID"); | |
291 | + } else if (optcode == DNS_OPT_CLIENT_SUBNET) { | |
292 | + int i; | |
293 | + char addr[16], addr_text[64]; | |
294 | + isc_uint16_t family; | |
295 | + isc_uint8_t addrlen, addrbytes, scopelen; | |
296 | + | |
297 | + family = isc_buffer_getuint16(&optbuf); | |
298 | + addrlen = isc_buffer_getuint8(&optbuf); | |
299 | + scopelen = isc_buffer_getuint8(&optbuf); | |
300 | + addrbytes = (addrlen + 7) / 8; | |
301 | + memset(addr, 0, sizeof(addr)); | |
302 | + for (i = 0; i < addrbytes; i ++) | |
303 | + addr[i] = isc_buffer_getuint8(&optbuf); | |
304 | + | |
305 | + ADD_STRING(target, "; CLIENT-SUBNET: "); | |
306 | + if (family == 1) | |
307 | + inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text)); | |
308 | + else if (family == 2) | |
309 | + inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text)); | |
310 | + else | |
311 | + snprintf(addr_text, sizeof(addr_text), | |
312 | + "Unsupported(family=%d)", family); | |
313 | + | |
314 | + ADD_STRING(target, addr_text); | |
315 | + sprintf(addr_text, "/%d/%d", addrlen, scopelen); | |
316 | + ADD_STRING(target, addr_text); | |
317 | + | |
318 | + /* Disable the dumb byte representation below. */ | |
319 | + optlen = 0; | |
320 | } else { | |
321 | ADD_STRING(target, "; OPT="); | |
322 | sprintf(buf, "%u", optcode); |