s4 dns: Allow changing the dns operation flags in handlers
[nivanova/samba-autobuild/.git] / source4 / dns_server / dns_server.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    DNS server startup
5
6    Copyright (C) 2010 Kai Blin  <kai@samba.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "smbd/service_task.h"
24 #include "smbd/service.h"
25 #include "smbd/service_stream.h"
26 #include "smbd/process_model.h"
27 #include "lib/events/events.h"
28 #include "lib/socket/socket.h"
29 #include "lib/tsocket/tsocket.h"
30 #include "libcli/util/tstream.h"
31 #include "libcli/util/ntstatus.h"
32 #include "system/network.h"
33 #include "lib/stream/packet.h"
34 #include "lib/socket/netif.h"
35 #include "dns_server/dns_server.h"
36 #include "param/param.h"
37 #include "librpc/ndr/libndr.h"
38 #include "librpc/gen_ndr/ndr_dns.h"
39 #include "librpc/gen_ndr/ndr_dnsp.h"
40 #include <ldb.h>
41 #include "dsdb/samdb/samdb.h"
42 #include "dsdb/common/util.h"
43 #include "auth/session.h"
44 #include "lib/util/dlinklist.h"
45
46 NTSTATUS server_service_dns_init(void);
47
48 /* hold information about one dns socket */
49 struct dns_socket {
50         struct dns_server *dns;
51         struct tsocket_address *local_address;
52 };
53
54 struct dns_udp_socket {
55         struct dns_socket *dns_socket;
56         struct tdgram_context *dgram;
57         struct tevent_queue *send_queue;
58 };
59
60 /*
61   state of an open tcp connection
62 */
63 struct dns_tcp_connection {
64         /* stream connection we belong to */
65         struct stream_connection *conn;
66
67         /* the dns_server the connection belongs to */
68         struct dns_socket *dns_socket;
69
70         struct tstream_context *tstream;
71
72         struct tevent_queue *send_queue;
73 };
74
75 static void dns_tcp_terminate_connection(struct dns_tcp_connection *dnsconn, const char *reason)
76 {
77         stream_terminate_connection(dnsconn->conn, reason);
78 }
79
80 static void dns_tcp_recv(struct stream_connection *conn, uint16_t flags)
81 {
82         struct dns_tcp_connection *dnsconn = talloc_get_type(conn->private_data,
83                                                              struct dns_tcp_connection);
84         /* this should never be triggered! */
85         dns_tcp_terminate_connection(dnsconn, "dns_tcp_recv: called");
86 }
87
88 static void dns_tcp_send(struct stream_connection *conn, uint16_t flags)
89 {
90         struct dns_tcp_connection *dnsconn = talloc_get_type(conn->private_data,
91                                                              struct dns_tcp_connection);
92         /* this should never be triggered! */
93         dns_tcp_terminate_connection(dnsconn, "dns_tcp_send: called");
94 }
95
96 static NTSTATUS dns_process(struct dns_server *dns,
97                             TALLOC_CTX *mem_ctx,
98                             DATA_BLOB *in,
99                             DATA_BLOB *out)
100 {
101         enum ndr_err_code ndr_err;
102         WERROR ret;
103         struct dns_request_state *state;
104         struct dns_name_packet *in_packet;
105         struct dns_name_packet *out_packet;
106         struct dns_res_rec *answers = NULL, *nsrecs = NULL, *additional = NULL;
107         uint16_t num_answers = 0 , num_nsrecs = 0, num_additional = 0;
108
109         if (in->length < 12) {
110                 return NT_STATUS_INVALID_PARAMETER;
111         }
112
113         state = talloc_zero(mem_ctx, struct dns_request_state);
114
115         in_packet = talloc_zero(state, struct dns_name_packet);
116         /* TODO: We don't really need an out_packet. */
117         out_packet = talloc_zero(state, struct dns_name_packet);
118
119         if (in_packet == NULL) return NT_STATUS_NO_MEMORY;
120         if (out_packet == NULL) return NT_STATUS_NO_MEMORY;
121
122         dump_data(2, in->data, in->length);
123
124         ndr_err = ndr_pull_struct_blob(in, in_packet, in_packet,
125                         (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
126         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
127                 TALLOC_FREE(in_packet);
128                 DEBUG(0, ("Failed to parse packet %d!\n", ndr_err));
129                 *out = *in;
130
131                 out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */
132                 out->data[3] |= DNS_RCODE_FORMERR;
133
134                 return NT_STATUS_OK;
135         }
136         if (DEBUGLVL(2)) {
137                 NDR_PRINT_DEBUG(dns_name_packet, in_packet);
138         }
139         *out_packet = *in_packet;
140         state->flags |= in_packet->operation | DNS_FLAG_REPLY;
141
142         /* TODO: Allow setting the forwarding in smb.conf or the like */
143         state->flags |= DNS_FLAG_RECURSION_AVAIL;
144
145         switch (in_packet->operation & DNS_OPCODE) {
146         case DNS_OPCODE_QUERY:
147
148                 ret = dns_server_process_query(dns, state,
149                                                out_packet, in_packet,
150                                                &answers, &num_answers,
151                                                &nsrecs,  &num_nsrecs,
152                                                &additional, &num_additional);
153
154                 break;
155         case DNS_OPCODE_UPDATE:
156                 ret = dns_server_process_update(dns, state,
157                                                 out_packet, in_packet,
158                                                 &answers, &num_answers,
159                                                 &nsrecs,  &num_nsrecs,
160                                                 &additional, &num_additional);
161                 break;
162         default:
163                 ret = WERR_DNS_ERROR_RCODE_NOT_IMPLEMENTED;
164                 break;
165         }
166
167         if (W_ERROR_IS_OK(ret)) {
168                 out_packet->ancount = num_answers;
169                 out_packet->answers = answers;
170
171                 out_packet->nscount = num_nsrecs;
172                 out_packet->nsrecs  = nsrecs;
173
174                 out_packet->arcount = num_additional;
175                 out_packet->additional = additional;
176         } else {
177                 out_packet->operation |= werr_to_dns_err(ret);
178         }
179
180         out_packet->operation |= state->flags;
181
182         if (DEBUGLVL(2)) {
183                 NDR_PRINT_DEBUG(dns_name_packet, out_packet);
184         }
185         ndr_err = ndr_push_struct_blob(out, out_packet, out_packet,
186                         (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
187         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
188                 TALLOC_FREE(in_packet);
189                 TALLOC_FREE(out_packet);
190                 DEBUG(0, ("Failed to push packet %d!\n", ndr_err));
191                 *out = *in;
192
193                 out->data[2] |= 0x80; /* Toggle DNS_FLAG_REPLY */
194                 out->data[3] |= DNS_RCODE_SERVFAIL;
195
196                 return NT_STATUS_OK;
197         }
198
199         dump_data(2, out->data, out->length);
200         return NT_STATUS_OK;
201 }
202
203 struct dns_tcp_call {
204         struct dns_tcp_connection *dns_conn;
205         DATA_BLOB in;
206         DATA_BLOB out;
207         uint8_t out_hdr[4];
208         struct iovec out_iov[2];
209 };
210
211 static void dns_tcp_call_writev_done(struct tevent_req *subreq);
212
213 static void dns_tcp_call_loop(struct tevent_req *subreq)
214 {
215         struct dns_tcp_connection *dns_conn = tevent_req_callback_data(subreq,
216                                       struct dns_tcp_connection);
217         struct dns_tcp_call *call;
218         NTSTATUS status;
219
220         call = talloc(dns_conn, struct dns_tcp_call);
221         if (call == NULL) {
222                 dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: "
223                                 "no memory for dns_tcp_call");
224                 return;
225         }
226         call->dns_conn = dns_conn;
227
228         status = tstream_read_pdu_blob_recv(subreq,
229                                             call,
230                                             &call->in);
231         TALLOC_FREE(subreq);
232         if (!NT_STATUS_IS_OK(status)) {
233                 const char *reason;
234
235                 reason = talloc_asprintf(call, "dns_tcp_call_loop: "
236                                          "tstream_read_pdu_blob_recv() - %s",
237                                          nt_errstr(status));
238                 if (!reason) {
239                         reason = nt_errstr(status);
240                 }
241
242                 dns_tcp_terminate_connection(dns_conn, reason);
243                 return;
244         }
245
246         DEBUG(10,("Received DNS TCP packet of length %lu from %s\n",
247                  (long) call->in.length,
248                  tsocket_address_string(dns_conn->conn->remote_address, call)));
249
250         /* skip length header */
251         call->in.data += 2;
252         call->in.length -= 2;
253
254         /* Call dns */
255         status = dns_process(dns_conn->dns_socket->dns, call, &call->in, &call->out);
256         if (!NT_STATUS_IS_OK(status)) {
257                 DEBUG(0, ("dns_process returned %s\n", nt_errstr(status)));
258                 dns_tcp_terminate_connection(dns_conn,
259                                 "dns_tcp_call_loop: process function failed");
260                 return;
261         }
262
263         /* First add the length of the out buffer */
264         RSSVAL(call->out_hdr, 0, call->out.length);
265         call->out_iov[0].iov_base = (char *) call->out_hdr;
266         call->out_iov[0].iov_len = 2;
267
268         call->out_iov[1].iov_base = (char *) call->out.data;
269         call->out_iov[1].iov_len = call->out.length;
270
271         subreq = tstream_writev_queue_send(call,
272                                            dns_conn->conn->event.ctx,
273                                            dns_conn->tstream,
274                                            dns_conn->send_queue,
275                                            call->out_iov, 2);
276         if (subreq == NULL) {
277                 dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: "
278                                 "no memory for tstream_writev_queue_send");
279                 return;
280         }
281         tevent_req_set_callback(subreq, dns_tcp_call_writev_done, call);
282
283         /*
284          * The dns tcp pdu's has the length as 2 byte (initial_read_size),
285          * packet_full_request_u16 provides the pdu length then.
286          */
287         subreq = tstream_read_pdu_blob_send(dns_conn,
288                                             dns_conn->conn->event.ctx,
289                                             dns_conn->tstream,
290                                             2, /* initial_read_size */
291                                             packet_full_request_u16,
292                                             dns_conn);
293         if (subreq == NULL) {
294                 dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: "
295                                 "no memory for tstream_read_pdu_blob_send");
296                 return;
297         }
298         tevent_req_set_callback(subreq, dns_tcp_call_loop, dns_conn);
299 }
300
301 static void dns_tcp_call_writev_done(struct tevent_req *subreq)
302 {
303         struct dns_tcp_call *call = tevent_req_callback_data(subreq,
304                         struct dns_tcp_call);
305         int sys_errno;
306         int rc;
307
308         rc = tstream_writev_queue_recv(subreq, &sys_errno);
309         TALLOC_FREE(subreq);
310         if (rc == -1) {
311                 const char *reason;
312
313                 reason = talloc_asprintf(call, "dns_tcp_call_writev_done: "
314                                          "tstream_writev_queue_recv() - %d:%s",
315                                          sys_errno, strerror(sys_errno));
316                 if (!reason) {
317                         reason = "dns_tcp_call_writev_done: tstream_writev_queue_recv() failed";
318                 }
319
320                 dns_tcp_terminate_connection(call->dns_conn, reason);
321                 return;
322         }
323
324         /* We don't care about errors */
325
326         talloc_free(call);
327 }
328
329 /*
330   called when we get a new connection
331 */
332 static void dns_tcp_accept(struct stream_connection *conn)
333 {
334         struct dns_socket *dns_socket;
335         struct dns_tcp_connection *dns_conn;
336         struct tevent_req *subreq;
337         int rc;
338
339         dns_conn = talloc_zero(conn, struct dns_tcp_connection);
340         if (dns_conn == NULL) {
341                 stream_terminate_connection(conn,
342                                 "dns_tcp_accept: out of memory");
343                 return;
344         }
345
346         dns_conn->send_queue = tevent_queue_create(conn, "dns_tcp_accept");
347         if (dns_conn->send_queue == NULL) {
348                 stream_terminate_connection(conn,
349                                 "dns_tcp_accept: out of memory");
350                 return;
351         }
352
353         dns_socket = talloc_get_type(conn->private_data, struct dns_socket);
354
355         TALLOC_FREE(conn->event.fde);
356
357         rc = tstream_bsd_existing_socket(dns_conn,
358                         socket_get_fd(conn->socket),
359                         &dns_conn->tstream);
360         if (rc < 0) {
361                 stream_terminate_connection(conn,
362                                 "dns_tcp_accept: out of memory");
363                 return;
364         }
365
366         dns_conn->conn = conn;
367         dns_conn->dns_socket = dns_socket;
368         conn->private_data = dns_conn;
369
370         /*
371          * The dns tcp pdu's has the length as 2 byte (initial_read_size),
372          * packet_full_request_u16 provides the pdu length then.
373          */
374         subreq = tstream_read_pdu_blob_send(dns_conn,
375                                             dns_conn->conn->event.ctx,
376                                             dns_conn->tstream,
377                                             2, /* initial_read_size */
378                                             packet_full_request_u16,
379                                             dns_conn);
380         if (subreq == NULL) {
381                 dns_tcp_terminate_connection(dns_conn, "dns_tcp_accept: "
382                                 "no memory for tstream_read_pdu_blob_send");
383                 return;
384         }
385         tevent_req_set_callback(subreq, dns_tcp_call_loop, dns_conn);
386 }
387
388 static const struct stream_server_ops dns_tcp_stream_ops = {
389         .name                   = "dns_tcp",
390         .accept_connection      = dns_tcp_accept,
391         .recv_handler           = dns_tcp_recv,
392         .send_handler           = dns_tcp_send
393 };
394
395 struct dns_udp_call {
396         struct tsocket_address *src;
397         DATA_BLOB in;
398         DATA_BLOB out;
399 };
400
401 static void dns_udp_call_sendto_done(struct tevent_req *subreq);
402
403 static void dns_udp_call_loop(struct tevent_req *subreq)
404 {
405         struct dns_udp_socket *sock = tevent_req_callback_data(subreq,
406                                       struct dns_udp_socket);
407         struct dns_udp_call *call;
408         uint8_t *buf;
409         ssize_t len;
410         int sys_errno;
411         NTSTATUS status;
412
413         call = talloc(sock, struct dns_udp_call);
414         if (call == NULL) {
415                 talloc_free(call);
416                 goto done;
417         }
418
419         len = tdgram_recvfrom_recv(subreq, &sys_errno,
420                                    call, &buf, &call->src);
421         TALLOC_FREE(subreq);
422         if (len == -1) {
423                 talloc_free(call);
424                 goto done;
425         }
426
427         call->in.data = buf;
428         call->in.length = len;
429
430         DEBUG(10,("Received DNS UDP packet of length %lu from %s\n",
431                  (long)call->in.length,
432                  tsocket_address_string(call->src, call)));
433
434         /* Call dns_process */
435         status = dns_process(sock->dns_socket->dns, call, &call->in, &call->out);
436         if (!NT_STATUS_IS_OK(status)) {
437                 talloc_free(call);
438                 DEBUG(0, ("dns_process returned %s\n", nt_errstr(status)));
439                 goto done;
440         }
441
442         subreq = tdgram_sendto_queue_send(call,
443                                           sock->dns_socket->dns->task->event_ctx,
444                                           sock->dgram,
445                                           sock->send_queue,
446                                           call->out.data,
447                                           call->out.length,
448                                           call->src);
449         if (subreq == NULL) {
450                 talloc_free(call);
451                 goto done;
452         }
453         tevent_req_set_callback(subreq, dns_udp_call_sendto_done, call);
454
455 done:
456         subreq = tdgram_recvfrom_send(sock,
457                                       sock->dns_socket->dns->task->event_ctx,
458                                       sock->dgram);
459         if (subreq == NULL) {
460                 task_server_terminate(sock->dns_socket->dns->task,
461                                       "no memory for tdgram_recvfrom_send",
462                                       true);
463                 return;
464         }
465         tevent_req_set_callback(subreq, dns_udp_call_loop, sock);
466 }
467
468 static void dns_udp_call_sendto_done(struct tevent_req *subreq)
469 {
470         struct dns_udp_call *call = tevent_req_callback_data(subreq,
471                                        struct dns_udp_call);
472         ssize_t ret;
473         int sys_errno;
474
475         ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
476
477         /* We don't care about errors */
478
479         talloc_free(call);
480 }
481
482 /*
483   start listening on the given address
484 */
485 static NTSTATUS dns_add_socket(struct dns_server *dns,
486                                const struct model_ops *model_ops,
487                                const char *name,
488                                const char *address,
489                                uint16_t port)
490 {
491         struct dns_socket *dns_socket;
492         struct dns_udp_socket *dns_udp_socket;
493         struct tevent_req *udpsubreq;
494         NTSTATUS status;
495         int ret;
496
497         dns_socket = talloc(dns, struct dns_socket);
498         NT_STATUS_HAVE_NO_MEMORY(dns_socket);
499
500         dns_socket->dns = dns;
501
502         ret = tsocket_address_inet_from_strings(dns_socket, "ip",
503                                                 address, port,
504                                                 &dns_socket->local_address);
505         if (ret != 0) {
506                 status = map_nt_error_from_unix_common(errno);
507                 return status;
508         }
509
510         status = stream_setup_socket(dns->task,
511                                      dns->task->event_ctx,
512                                      dns->task->lp_ctx,
513                                      model_ops,
514                                      &dns_tcp_stream_ops,
515                                      "ip", address, &port,
516                                      lpcfg_socket_options(dns->task->lp_ctx),
517                                      dns_socket);
518         if (!NT_STATUS_IS_OK(status)) {
519                 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
520                          address, port, nt_errstr(status)));
521                 talloc_free(dns_socket);
522                 return status;
523         }
524
525         dns_udp_socket = talloc(dns_socket, struct dns_udp_socket);
526         NT_STATUS_HAVE_NO_MEMORY(dns_udp_socket);
527
528         dns_udp_socket->dns_socket = dns_socket;
529
530         ret = tdgram_inet_udp_socket(dns_socket->local_address,
531                                      NULL,
532                                      dns_udp_socket,
533                                      &dns_udp_socket->dgram);
534         if (ret != 0) {
535                 status = map_nt_error_from_unix_common(errno);
536                 DEBUG(0,("Failed to bind to %s:%u UDP - %s\n",
537                          address, port, nt_errstr(status)));
538                 return status;
539         }
540
541         dns_udp_socket->send_queue = tevent_queue_create(dns_udp_socket,
542                                                          "dns_udp_send_queue");
543         NT_STATUS_HAVE_NO_MEMORY(dns_udp_socket->send_queue);
544
545         udpsubreq = tdgram_recvfrom_send(dns_udp_socket,
546                                          dns->task->event_ctx,
547                                          dns_udp_socket->dgram);
548         NT_STATUS_HAVE_NO_MEMORY(udpsubreq);
549         tevent_req_set_callback(udpsubreq, dns_udp_call_loop, dns_udp_socket);
550
551         return NT_STATUS_OK;
552 }
553
554 /*
555   setup our listening sockets on the configured network interfaces
556 */
557 static NTSTATUS dns_startup_interfaces(struct dns_server *dns, struct loadparm_context *lp_ctx,
558                                        struct interface *ifaces)
559 {
560         const struct model_ops *model_ops;
561         int num_interfaces;
562         TALLOC_CTX *tmp_ctx = talloc_new(dns);
563         NTSTATUS status;
564         int i;
565
566         /* within the dns task we want to be a single process, so
567            ask for the single process model ops and pass these to the
568            stream_setup_socket() call. */
569         model_ops = process_model_startup("single");
570         if (!model_ops) {
571                 DEBUG(0,("Can't find 'single' process model_ops\n"));
572                 return NT_STATUS_INTERNAL_ERROR;
573         }
574
575         num_interfaces = iface_list_count(ifaces);
576
577         for (i=0; i<num_interfaces; i++) {
578                 const char *address = talloc_strdup(tmp_ctx, iface_list_n_ip(ifaces, i));
579
580                 status = dns_add_socket(dns, model_ops, "dns", address, DNS_SERVICE_PORT);
581                 NT_STATUS_NOT_OK_RETURN(status);
582         }
583
584         talloc_free(tmp_ctx);
585
586         return NT_STATUS_OK;
587 }
588
589 static int dns_server_sort_zones(struct ldb_message **m1, struct ldb_message **m2)
590 {
591         const char *n1, *n2;
592         size_t l1, l2;
593
594         n1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
595         n2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
596
597         l1 = strlen(n1);
598         l2 = strlen(n2);
599
600         /* If the string lengths are not equal just sort by length */
601         if (l1 != l2) {
602                 /* If m1 is the larger zone name, return it first */
603                 return l2 - l1;
604         }
605
606         /*TODO: We need to compare DNs here, we want the DomainDNSZones first */
607         return 0;
608 }
609
610 static void dns_task_init(struct task_server *task)
611 {
612         struct dns_server *dns;
613         NTSTATUS status;
614         struct interface *ifaces;
615         int ret;
616         struct ldb_result *res;
617         static const char * const attrs[] = { "name", NULL};
618         unsigned int i;
619
620         switch (lpcfg_server_role(task->lp_ctx)) {
621         case ROLE_STANDALONE:
622                 task_server_terminate(task, "dns: no DNS required in standalone configuration", false);
623                 return;
624         case ROLE_DOMAIN_MEMBER:
625                 task_server_terminate(task, "dns: no DNS required in member server configuration", false);
626                 return;
627         case ROLE_DOMAIN_CONTROLLER:
628                 /* Yes, we want a DNS */
629                 break;
630         }
631
632         load_interface_list(task, task->lp_ctx, &ifaces);
633
634         if (iface_list_count(ifaces) == 0) {
635                 task_server_terminate(task, "dns: no network interfaces configured", false);
636                 return;
637         }
638
639         task_server_set_title(task, "task[dns]");
640
641         dns = talloc_zero(task, struct dns_server);
642         if (dns == NULL) {
643                 task_server_terminate(task, "dns: out of memory", true);
644                 return;
645         }
646
647         dns->task = task;
648
649         dns->samdb = samdb_connect(dns, dns->task->event_ctx, dns->task->lp_ctx,
650                               system_session(dns->task->lp_ctx), 0);
651         if (!dns->samdb) {
652                 task_server_terminate(task, "dns: samdb_connect failed", true);
653                 return;
654         }
655
656         // TODO: this search does not work against windows
657         ret = dsdb_search(dns->samdb, dns, &res, NULL, LDB_SCOPE_SUBTREE,
658                           attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, "(objectClass=dnsZone)");
659         if (ret != LDB_SUCCESS) {
660                 task_server_terminate(task,
661                                       "dns: failed to look up root DNS zones",
662                                       true);
663                 return;
664         }
665
666         TYPESAFE_QSORT(res->msgs, res->count, dns_server_sort_zones);
667
668         for (i=0; i < res->count; i++) {
669                 struct dns_server_zone *z;
670
671                 z = talloc_zero(dns, struct dns_server_zone);
672                 if (z == NULL) {
673                 }
674
675                 z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
676                 z->dn = talloc_move(z, &res->msgs[i]->dn);
677
678                 DLIST_ADD_END(dns->zones, z, NULL);
679         }
680
681         status = dns_startup_interfaces(dns, task->lp_ctx, ifaces);
682         if (!NT_STATUS_IS_OK(status)) {
683                 task_server_terminate(task, "dns failed to setup interfaces", true);
684                 return;
685         }
686 }
687
688 NTSTATUS server_service_dns_init(void)
689 {
690         return register_server_service("dns", dns_task_init);
691 }