/[Apache-SVN]/httpd/sandbox/mod_domain/mod_dns.c
ViewVC logotype

Contents of /httpd/sandbox/mod_domain/mod_dns.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 651932 - (show annotations) (download)
Sun Apr 27 12:12:46 2008 UTC (16 years, 3 months ago) by issac
File MIME type: text/plain
File size: 27121 byte(s)
Add hook for dns_create_request which passes both dns_message_t and request_rec (the latter is needed to add filters)

Fix DNSAddMX to work inside virtualhosts properly
1 /* Copyright 1999-2007 The Apache Software Foundation or its licensors, as
2 * applicable.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Original Copyright (c) Netmask.IT!® 2006-2007
19 *
20 * DNS Protocol module for Apache 2.x
21 */
22
23
24 /* TODO LIST:
25 ** filters for compression (RFC 1035)
26 ** output truncation filter (limit UDP to 512 + set TC bit)
27 ** forward queries (*via tcp / * via udp with retransmission policy)
28 ** support AXFR queries for slaves to update from us
29 ** How should we update the scoreboard? we use many logical reads/writes
30 ** query cache via mod_cache with special key_generator
31 ** Error support dns_die()
32 ** IPV6 Support?
33 ** Wildcard virtualhosts will return 0.0.0.0 as the IP. What do we do with this?
34 */
35
36 #include "mod_dns.h"
37
38 static server_rec *base_server;
39
40 APR_HOOK_STRUCT(
41 APR_HOOK_LINK(post_read_request)
42 APR_HOOK_LINK(create_request)
43 APR_HOOK_LINK(handler)
44 )
45
46 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(dns, DNS, int, post_read_request,
47 (dns_message_t *dns),
48 (dns),
49 OK, DECLINED)
50
51 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(dns, DNS, int, create_request,
52 (request_rec *r, dns_message_t *dns),
53 (r, dns),
54 OK, DECLINED)
55
56 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(dns, DNS, int, handler,
57 (request_rec *r),
58 (r), DECLINED)
59
60 /** Be nice and export so other modules can remove it if they really want */
61 DNS_DECLARE_DATA ap_filter_rec_t* dns_buffered_write_response_filter_handle;
62 DNS_DECLARE_DATA ap_filter_rec_t* dns_buffered_write_proto_filter_handle;
63 DNS_DECLARE_DATA ap_filter_rec_t* dns_output_protocol_filter_handle;
64 DNS_DECLARE_DATA ap_filter_rec_t* dns_tcp_length_filter_handle;
65
66 /** This isn't exported by core, so we need to redo ourselves... */
67 DNS_DECLARE(int) dns_invoke_filter_init(ap_filter_t *filters)
68 {
69 while (filters) {
70 if (filters->frec->filter_init_func) {
71 int result = filters->frec->filter_init_func(filters);
72 if (result != OK) {
73 return result;
74 }
75 }
76 filters = filters->next;
77 }
78 return OK;
79 }
80
81 DNS_DECLARE(request_rec *) dns_create_request(dns_message_t *dns) {
82 request_rec *r;
83 apr_pool_t *p;
84
85 apr_pool_create(&p, dns->pool);
86 apr_pool_tag(p, "request");
87 r = apr_pcalloc(p, sizeof(*r));
88 r->pool = p;
89 r->connection = dns->conn;
90 r->server = dns->conn->base_server;
91
92 r->user = NULL;
93 r->ap_auth_type = NULL;
94 r->next = NULL;
95 r->prev = NULL;
96 r->main = NULL;
97
98 r->allowed_methods = ap_make_method_list(p, 2);
99
100 r->headers_in = apr_table_make(r->pool, 1);
101 r->subprocess_env = apr_table_make(r->pool, 1);
102 r->headers_out = apr_table_make(r->pool, 1);
103 r->err_headers_out = apr_table_make(r->pool, 1);
104 r->notes = apr_table_make(r->pool, 5);
105
106 r->request_config = ap_create_request_config(r->pool);
107 /* Must be set before we run create request hook */
108
109 r->proto_output_filters = dns->filters_out;
110 r->output_filters = r->proto_output_filters;
111 r->proto_input_filters = dns->filters_in;
112 r->input_filters = r->proto_input_filters;
113 r->per_dir_config = r->server->lookup_defaults;
114
115 r->sent_bodyct = 0; /* bytect isn't for body */
116
117 r->read_body = REQUEST_NO_BODY;
118 r->handler = NULL;
119
120 r->status = HTTP_OK; /* Until we get a request */
121 r->status_line = NULL;
122 r->the_request = NULL;
123
124 /* Begin by presuming any module can make its own path_info assumptions,
125 * until some module interjects and changes the value.
126 */
127 r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
128
129 ap_set_module_config(r->request_config, &dns_module, dns);
130 /** Cheat here and add our buffered write filter before anyone
131 * else gets in the way */
132 ap_add_output_filter_handle(dns_buffered_write_response_filter_handle, NULL,
133 r, dns->conn);
134
135 /** Let other modules do what they need now */
136 ap_run_create_request(r);
137 dns_run_create_request(r, dns);
138 return r;
139 }
140
141 /** Our buffered output filter */
142 typedef struct {
143 apr_bucket_brigade *bb;
144 int seen_eos;
145 } dns_buffered_write_filter_ctx;
146
147 static apr_status_t dns_buffered_write_filter(ap_filter_t *f,
148 apr_bucket_brigade *bb)
149 {
150 dns_buffered_write_filter_ctx *ctx = f->ctx;
151 apr_bucket *b;
152 apr_off_t len = 0;
153 apr_status_t rv;
154
155 if (ctx == NULL) {
156 f->ctx = ctx = apr_palloc(f->r->pool, sizeof(*ctx));
157 ctx->bb = apr_brigade_create(f->r->pool,
158 f->r->connection->bucket_alloc);
159 ctx->seen_eos = 0;
160 }
161
162 if (ctx->seen_eos)
163 return APR_SUCCESS;
164
165 rv = APR_SUCCESS;
166
167 /** Buffer until we get a EOS or FLUSH */
168 for (b = APR_BRIGADE_FIRST(bb);
169 b != APR_BRIGADE_SENTINEL(bb) && !APR_BRIGADE_EMPTY(bb);
170 b = APR_BUCKET_NEXT(b))
171 {
172 APR_BUCKET_REMOVE(b);
173 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
174 apr_brigade_length(ctx->bb, 1, &len);
175 if ((APR_BUCKET_IS_EOS(b) || APR_BUCKET_IS_FLUSH(b)) ||
176 (len > APR_BUCKET_BUFF_SIZE))
177 {
178 rv = ap_pass_brigade(f->next, ctx->bb);
179 apr_brigade_cleanup(ctx->bb);
180 if (APR_BUCKET_IS_EOS(b))
181 ctx->seen_eos = 1;
182 }
183 }
184
185 /** Give an empty brigade back */
186 apr_brigade_cleanup(bb);
187
188 /** if we got the EOS before the brigade ended, replace the unsent data */
189 if (ctx->seen_eos) {
190 APR_BRIGADE_CONCAT(bb, ctx->bb);
191 apr_brigade_destroy(ctx->bb);
192 }
193
194 return rv;
195 }
196
197 /** Our protocol output filter */
198 static apr_status_t dns_output_protocol_filter(ap_filter_t *f,
199 apr_bucket_brigade *bb)
200 {
201
202 dns_message_t *dns;
203 apr_bucket *b;
204 apr_size_t len = 0;
205 apr_status_t rv;
206 dns_rr_t *rr, *tmp_rr;
207 const char *data;
208 char *response;
209 apr_bucket_brigade *bb_out;
210
211 /*if (AP_BUCKET_IS_ERROR(e)) {
212 ap_bucket_error *eb = e->data;
213
214 ap_die(eb->status, r);
215 return AP_FILTER_ERROR;
216 }*/
217 /** Get our DNS message */
218 dns = (dns_message_t *)ap_get_module_config(f->r->request_config,
219 &dns_module);
220
221 if (!(dns)) {
222 ap_remove_output_filter(f);
223 return ap_pass_brigade(f->next, bb);
224 }
225
226 rv = APR_SUCCESS;
227
228 /** We can't flush and EOS means end of answer; we send content onward
229 * when we've got all of our answers */
230 for (b = APR_BRIGADE_FIRST(bb);
231 b != APR_BRIGADE_SENTINEL(bb) && !APR_BRIGADE_EMPTY(bb);
232 b = APR_BUCKET_NEXT(b))
233 {
234 if (BUCKET_IS_DNS_RR(b)) {
235 /** Got an RR */
236 if (BUCKET_IS_DNS_ANSWER(b)) {
237 rr = apr_array_push(dns->answer);
238 dns->header->ancount++;
239 }
240 else if (BUCKET_IS_DNS_AUTHORITY(b)) {
241 rr = apr_array_push(dns->authority);
242 dns->header->nscount++;
243 }
244 else if (BUCKET_IS_DNS_ADDITIONAL(b)) {
245 rr = apr_array_push(dns->additional);
246 dns->header->arcount++;
247 }
248 else
249 rr = NULL;
250
251 rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
252 /** This is a waste of memory, but unserialize (correctly)
253 * allocates a new rr, and apr_array_push will lose it's
254 * pointer... Since we can't play with the array's
255 * pointers (why not?) we copy the block of memory */
256 dns_rr_unserialize(f->r->pool, data, &tmp_rr);
257 memcpy(rr, tmp_rr, sizeof(*rr));
258 apr_bucket_delete(b);
259 /** Handle errors */
260
261 continue;
262 }
263
264 if (APR_BUCKET_IS_EOS(b)) {
265 /** End of query - ignore everything after this */
266 apr_brigade_cleanup(bb);
267 dns->answered++;
268 break;
269 }
270
271 if (APR_BUCKET_IS_FLUSH(b)) {
272 /** We can't flush before we've assembled the response - sorry */
273 apr_bucket_delete(b);
274 continue;
275 }
276
277 /** Handle error buckets */
278
279 /** We don't know what to do with anything else... */
280 apr_bucket_delete(b);
281 }
282
283 if (dns->answered == dns->header->qdcount) {
284 /** We've assembled a response - send it out */
285 bb_out = apr_brigade_create(dns->pool, dns->conn->bucket_alloc);
286 rv = dns_write_response(dns, &response, &len);
287 b = apr_bucket_heap_create(response, len, free,
288 bb_out->bucket_alloc);
289 APR_BRIGADE_INSERT_TAIL(bb_out, b);
290 /** Add flush (UDP needs this push) */
291 b = apr_bucket_flush_create(bb_out->bucket_alloc);
292 APR_BRIGADE_INSERT_TAIL(bb_out, b);
293 /** Add EOS */
294 b = apr_bucket_eos_create(bb_out->bucket_alloc);
295 APR_BRIGADE_INSERT_TAIL(bb_out, b);
296 /** Send it on its merry way */
297 rv = ap_pass_brigade(f->next, bb_out);
298 /** Core-output will destroy this brigade for us */
299 }
300 return rv;
301 }
302
303 /** TCP set-length filter - we cheat now by assuming one brigade holds
304 * everything; it almost certainly does, but that's besides the point */
305 static apr_status_t dns_tcp_length_filter(ap_filter_t *f,
306 apr_bucket_brigade *bb)
307 {
308 apr_bucket *b;
309 apr_uint16_t len = 0;
310 apr_status_t rv;
311 int sd_type;
312
313 /** If we have a TCP connection, we'll need to write length */
314 apr_socket_type_get(ap_get_module_config(f->r->connection->conn_config,
315 &core_module),
316 &sd_type);
317 if (sd_type == SOCK_STREAM) {
318 apr_brigade_length(bb, 1, (apr_off_t *)&len);
319 len = htons(len);
320
321 b = apr_bucket_transient_create((const char *)&len, 2, bb->bucket_alloc);
322 APR_BRIGADE_INSERT_HEAD(bb, b);
323 }
324
325 rv = ap_pass_brigade(f->next, bb);
326
327 /** We've done our work (and don't want to risk screwing more up) */
328 ap_remove_output_filter(f);
329
330 return rv;
331 }
332
333 static void finalize_response(request_rec *r) {
334 apr_bucket_brigade *bb;
335 apr_bucket *b;
336
337 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
338 b = apr_bucket_eos_create(bb->bucket_alloc);
339 APR_BRIGADE_INSERT_TAIL(bb, b);
340 ap_pass_brigade(r->output_filters, bb);
341 apr_brigade_destroy(bb);
342 }
343
344 static int process_dns_connection(conn_rec *c)
345 {
346 dns_module_config_t *conf;
347 dns_message_t *dns;
348 dns_query_t *q;
349 request_rec *r;
350 server_rec *s = c->base_server;
351 apr_status_t rv;
352 int access_status;
353 int i;
354
355 conf = (dns_module_config_t *)ap_get_module_config(s->module_config,
356 &dns_module);
357 if (!conf) {
358 /* We're not configured. Something's very wrong. Abort. */
359 return DECLINED;
360 }
361
362 if (!conf->enabled) {
363 /* We're configured, but disabled */
364 return DECLINED;
365 }
366 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0,c, "I got a connection!");
367
368 dns = dns_read_message_header(c);
369
370 if (!(dns)) {
371 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, "[mod_dns] Unable to read "
372 "DNS message header. Aborting.");
373 return OK;
374 }
375
376 dns_run_post_read_request(dns);
377 for (i=0;i<dns->header->qdcount;i++) {
378 q = NULL;
379 r = NULL;
380 rv = dns_read_request(dns, &r, &q);
381 if (rv != APR_SUCCESS) {
382 /* Set header->rcode to error and abort */
383 /* dns_die should read remaining bytes from socket,
384 * set error in dns_header_t, write response, and return
385 */
386 } else {
387 /** Allow mod_cache to act as our resolver cache */
388 access_status = ap_run_quick_handler(r, 0);
389 if (access_status == DECLINED) {
390 access_status = ap_process_request_internal(r);
391 if (access_status != OK) {
392 /** Handle me */
393 }
394 /** Invoke handler (return response) */
395 access_status = dns_invoke_filter_init(r->output_filters);
396 if (access_status != OK)
397 /** Log, but continue */
398 ap_log_rerror(APLOG_MARK, APLOG_WARNING, access_status,
399 r, "[mod_dns] Error initializing "
400 "output filters for %s",
401 r->the_request);
402
403 /** Run handler - only DNS registered handlers
404 * to avoid default-handler */
405 access_status = dns_run_handler(r);
406 finalize_response(r);
407
408 if (access_status == DECLINED) {
409 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
410 "[mod_dns] handler not found for method \"%s\"",
411 r->handler, r->method);
412 /** die */
413 }
414 }
415 if (access_status == DONE) {
416 /* e.g., something not in storage like TRACE */
417 access_status = OK;
418 }
419
420 if (access_status != OK) {
421 /** Return error (dns_die)*/
422 } else {
423 /** Cleanup */
424 }
425
426 /* FIXME:
427 * Suppose that the logging causes a DNS lookup to occur, which may
428 * have a high latency. If we hold off on this packet, then it'll
429 * appear like the link is stalled when really it's the application
430 * that's stalled.
431 * Since we can't send packets until all queries in the message
432 * are answered, we should add the request_rec to a list and
433 * batch-log them later
434 */
435 ap_run_log_transaction(r);
436 }
437 }
438 /** Flush response */
439 /** Log + cleanup */
440 return OK;
441 }
442
443 /* -------------------------------------------------------------- */
444 /* Default handlers */
445
446 static server_rec *matches_aliases(server_rec *s, const char *host)
447 {
448 int i;
449 apr_array_header_t *names;
450
451 while (s) {
452 /* match ServerName */
453 if (!strcasecmp(host, s->server_hostname)) {
454 return s;
455 }
456
457 /* search all the aliases from ServerAlias directive */
458 names = s->names;
459 if (names) {
460 char **name = (char **) names->elts;
461 for (i = 0; i < names->nelts; ++i) {
462 if(!name[i]) continue;
463 if (!strcasecmp(host, name[i]))
464 return s;
465 }
466 }
467 names = s->wild_names;
468 if (names) {
469 char **name = (char **) names->elts;
470 for (i = 0; i < names->nelts; ++i) {
471 if(!name[i]) continue;
472 if (!ap_strcasecmp_match(host, name[i]))
473 return s;
474 }
475 }
476 s = s->next;
477 }
478 return NULL;
479 }
480
481 static int dns_default_handler(request_rec *r) {
482 dns_rr_t* rr;
483 dns_rdata_a_t *a;
484 server_rec *s;
485 char *name;
486
487 if (strcasecmp(r->handler, DNS_MAGIC_TYPE))
488 return DECLINED;
489 if (strcasecmp(r->method, "A"))
490 return DECLINED;
491 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
492 "Running A/CNAME lookup for host %s", r->hostname);
493
494 if ((s = matches_aliases(base_server, r->hostname)) == NULL)
495 return DECLINED;
496
497 name = (char *)r->hostname;
498 if (strcasecmp(s->server_hostname, r->hostname)) {
499 dns_rdata_cname_t *cname;
500 /** Add CNAME */
501 cname = apr_palloc(r->pool, sizeof(*cname));
502 cname->cname = apr_pstrdup(r->pool, s->server_hostname);
503 rr = dns_create_rr(r, r->hostname, DNS_TYPE_CNAME, DNS_CLASS_IN, 0);
504 rr->rdata->rdata = cname;
505 dns_add_rr_answer(r, rr);
506 name = s->server_hostname;
507 }
508 /** Add A */
509 a = apr_pcalloc(r->pool, sizeof(*a));
510 a->address = inet_addr(inet_ntoa(*((struct in_addr *)s->addrs->host_addr->ipaddr_ptr)));
511 /** We get network address in network order; since serialize expects it in
512 * host order, switch here.*/
513 a->address = ntohl(a->address);
514 rr = dns_create_rr(r, name, DNS_TYPE_A, DNS_CLASS_IN, 0);
515 rr->rdata->rdata = a;
516 dns_add_rr_answer(r, rr);
517 return OK;
518 }
519
520 static int dns_mx_handler(request_rec *r) {
521 dns_module_config_t *conf;
522 dns_rr_t* rr;
523 dns_rdata_mx_t *mx;
524 apr_array_header_t *mxs;
525 server_rec *s;
526 char *name;
527
528 if (strcasecmp(r->handler, DNS_MAGIC_TYPE))
529 return DECLINED;
530 if (strcasecmp(r->method, "MX"))
531 return DECLINED;
532
533 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
534 "Running MX lookup for host %s", r->hostname);
535
536 if ((s = matches_aliases(base_server, r->hostname)) == NULL)
537 return DECLINED;
538
539 name = (char *)r->hostname;
540 if (strcasecmp(s->server_hostname, r->hostname))
541 return DECLINED; /* Require exact match here */
542
543 conf =
544 (dns_module_config_t *)ap_get_module_config(s->module_config,
545 &dns_module);
546
547 if (!(conf->mx))
548 return DECLINED;
549
550 mxs = apr_array_copy(r->pool, conf->mx);
551
552 while (!(apr_is_empty_array(mxs))) {
553 mx = apr_array_pop(mxs);
554 rr = dns_create_rr(r, r->hostname, DNS_TYPE_MX, DNS_CLASS_IN, 0);
555 rr->rdata->rdata = mx;
556 dns_add_rr_answer(r, rr);
557 }
558 return OK;
559 }
560
561 static int ap_create_request_handler(request_rec *r) {
562 dns_message_t *dns;
563
564 dns = (dns_message_t *)ap_get_module_config(r->request_config,
565 &dns_module);
566
567 if (!(dns))
568 return DECLINED;
569
570 ap_add_output_filter_handle(dns_output_protocol_filter_handle, NULL,
571 r, dns->conn);
572 /* ap_add_output_filter_handle(dns_buffered_write_proto_filter_handle, NULL,
573 r, dns->conn);*/
574 ap_add_output_filter_handle(dns_tcp_length_filter_handle, NULL,
575 r, dns->conn);
576
577 /** Don't care what this is, as long as it's not OK, We do it to prevent
578 * default HTTP protocol handlers from registering */
579 return DECLINED * 2;
580 }
581
582 static int dns_post_read_request(dns_message_t *dns) {
583 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, dns->conn,
584 "I got %d queries in the message", dns->header->qdcount);
585 return OK;
586 }
587
588 static int dns_post_config(apr_pool_t *p, apr_pool_t *plog,
589 apr_pool_t *ptemp, server_rec *s)
590 {
591 base_server = s;
592 dns_register_rr((dns_rdata_t *)&dns_rdata_a, DNS_TYPE_A);
593 dns_register_rr((dns_rdata_t *)&dns_rdata_cname, DNS_TYPE_CNAME);
594 dns_register_rr((dns_rdata_t *)&dns_rdata_mx, DNS_TYPE_MX);
595 return OK;
596 }
597
598
599
600 /* -------------------------------------------------------------- */
601 /* Setup configurable data */
602
603 static void *create_dns_config(apr_pool_t *p, server_rec *s)
604 {
605 dns_module_config_t *ps = apr_pcalloc(p, sizeof(*ps));
606 ps->enabled = 0;
607 ps->enabled_set = 0;
608 ps->default_ttl = DEFAULT_DEFAULT_TTL;
609 ps->default_ttl_set = 0;
610 ps->mx = NULL;
611 return ps;
612 }
613
614 static void *merge_dns_config(apr_pool_t *p, void *basev, void *overridesv)
615 {
616 dns_module_config_t *ps = apr_pcalloc(p, sizeof(*ps));
617 dns_module_config_t *base = (dns_module_config_t *) basev;
618 dns_module_config_t *overrides = (dns_module_config_t *) overridesv;
619
620 ps->enabled =
621 (overrides->enabled_set == 0)
622 ? base->enabled
623 : overrides->enabled;
624 ps->default_ttl =
625 (overrides->default_ttl_set == 0)
626 ? base->default_ttl
627 : overrides->default_ttl;
628
629 if (base->mx || overrides->mx) {
630 if (base->mx)
631 ps->mx = base->mx;
632 if (overrides->mx)
633 if (ps->mx) {
634 apr_array_cat(ps->mx, overrides->mx);
635 } else {
636 ps->mx = overrides->mx;
637 }
638 }
639
640
641 return ps;
642 }
643
644 static const char *set_dns_enabled(cmd_parms *parms, void *dummy, int flag)
645 {
646 dns_module_config_t *conf;
647
648 const char *err = ap_check_cmd_context(parms,
649 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
650 if (err) {
651 return err;
652 }
653
654 conf =
655 (dns_module_config_t *)ap_get_module_config(parms->server->module_config,
656 &dns_module);
657 conf->enabled = flag;
658 conf->enabled_set = 1;
659 return NULL;
660 }
661
662 static const char *set_dns_default_ttl(cmd_parms *parms, void *dummy,
663 const char *arg)
664 {
665 dns_module_config_t *conf;
666
667 const char *err = ap_check_cmd_context(parms, GLOBAL_ONLY);
668 if (err) {
669 return err;
670 }
671
672 conf =
673 (dns_module_config_t *)ap_get_module_config(parms->server->module_config,
674 &dns_module);
675 conf->default_ttl = (apr_size_t) atol(arg);
676 conf->default_ttl_set = 1;
677 return NULL;
678 }
679
680 static const char *set_dns_add_mx(cmd_parms *parms, void *dummy,
681 const char *preference, const char *exchange)
682 {
683 dns_module_config_t *conf;
684 dns_rdata_mx_t *mx;
685
686 const char *err = ap_check_cmd_context(parms,
687 NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
688 if (err) {
689 return err;
690 }
691
692 conf =
693 (dns_module_config_t *)ap_get_module_config(parms->server->module_config,
694 &dns_module);
695
696 if (!(conf->mx)) {
697 conf->mx = apr_array_make(parms->pool, 2, sizeof(dns_rdata_mx_t));
698 if (!(conf->mx))
699 return "Could not allocate list of MXs for virtualhost";
700 }
701
702 mx = apr_array_push(conf->mx);
703 if (!(mx))
704 return "Could not allocate MX";
705 mx->preference = (apr_uint16_t)apr_atoi64(preference);
706 mx->exchange = apr_pstrdup(parms->pool, exchange);
707
708 return NULL;
709 }
710
711 static const command_rec dns_cmds[] =
712 {
713 AP_INIT_FLAG("DNSEnabled", set_dns_enabled, NULL, RSRC_CONF,
714 "Enable the DNS server on this VirtualHost."),
715 AP_INIT_TAKE1("DNSDefaultTTL", set_dns_default_ttl, NULL, RSRC_CONF,
716 "Sets the default TTL used for all DNS replies (defaults"
717 "to 30 days"),
718 AP_INIT_TAKE2("DNSAddMX", set_dns_add_mx, NULL, RSRC_CONF,
719 "Adds an MX record to the current domain"),
720 {NULL}
721 };
722
723 static void register_hooks(apr_pool_t *p)
724 {
725 ap_hook_post_config(dns_post_config, NULL, NULL, APR_HOOK_MIDDLE);
726 ap_hook_process_connection(process_dns_connection, NULL, NULL, APR_HOOK_FIRST);
727 /** FIXME: We hook REALLY_LAST - 1 to prevent default HTTP protocol
728 * handlers to be installed for the request, but there ought to be a
729 * better way... */
730 ap_hook_create_request(ap_create_request_handler, NULL, NULL,
731 APR_HOOK_REALLY_LAST - 1);
732 dns_hook_post_read_request(dns_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
733 /** Although we don't take care of everything, hook after last so 3rd party
734 * handlers are always before us */
735 dns_hook_handler(dns_mx_handler, NULL, NULL, APR_HOOK_LAST + 4);
736 dns_hook_handler(dns_default_handler, NULL, NULL, APR_HOOK_LAST + 5);
737 /* Put buffered output filter as close as possible to front */
738 dns_buffered_write_response_filter_handle =
739 ap_register_output_filter_protocol("DNS_BUFFERED_WRITE",
740 dns_buffered_write_filter, NULL,
741 AP_FTYPE_RESOURCE, 0);
742 dns_output_protocol_filter_handle =
743 ap_register_output_filter_protocol("DNS_OUTPUT_PROTOCOL",
744 dns_output_protocol_filter, NULL,
745 AP_FTYPE_PROTOCOL,
746 AP_FILTER_PROTO_CHANGE +
747 AP_FILTER_PROTO_CHANGE_LENGTH +
748 AP_FILTER_PROTO_NO_BYTERANGE);
749 dns_buffered_write_proto_filter_handle =
750 ap_register_output_filter_protocol("DNS_BUFFERED_WRITE",
751 dns_buffered_write_filter, NULL,
752 AP_FTYPE_PROTOCOL, 0);
753 dns_tcp_length_filter_handle =
754 ap_register_output_filter_protocol("DNS_TCP_LENGTH",
755 dns_tcp_length_filter, NULL,
756 AP_FTYPE_PROTOCOL,
757 AP_FILTER_PROTO_CHANGE +
758 AP_FILTER_PROTO_CHANGE_LENGTH +
759 AP_FILTER_PROTO_NO_BYTERANGE);
760 }
761
762 /* Dispatch list for API hooks */
763 module AP_MODULE_DECLARE_DATA dns_module = {
764 STANDARD20_MODULE_STUFF,
765 NULL, /* create per-dir config structures */
766 NULL, /* merge per-dir config structures */
767 create_dns_config, /* create per-server config structures */
768 merge_dns_config, /* merge per-server config structures */
769 dns_cmds, /* table of config file commands */
770 register_hooks /* register hooks */
771 };

infrastructure at apache.org
ViewVC Help
Powered by ViewVC 1.1.26