s4 dns: Add a boilerplate DNS server implementation
[garming/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 "system/network.h"
32 #include "lib/stream/packet.h"
33 #include "lib/socket/netif.h"
34 #include "dns_server/dns_server.h"
35 #include "param/param.h"
36
37 /* hold information about one dns socket */
38 struct dns_socket {
39         struct dns_server *dns;
40         struct tsocket_address *local_address;
41 };
42
43 struct dns_udp_socket {
44         struct dns_socket *dns_socket;
45         struct tdgram_context *dgram;
46         struct tevent_queue *send_queue;
47 };
48
49 /*
50   state of an open tcp connection
51 */
52 struct dns_tcp_connection {
53         /* stream connection we belong to */
54         struct stream_connection *conn;
55
56         /* the dns_server the connection belongs to */
57         struct dns_socket *dns_socket;
58
59         struct tstream_context *tstream;
60
61         struct tevent_queue *send_queue;
62 };
63
64 static void dns_tcp_terminate_connection(struct dns_tcp_connection *dnsconn, const char *reason)
65 {
66         stream_terminate_connection(dnsconn->conn, reason);
67 }
68
69 static void dns_tcp_recv(struct stream_connection *conn, uint16_t flags)
70 {
71         struct dns_tcp_connection *dnsconn = talloc_get_type(conn->private_data,
72                                                              struct dns_tcp_connection);
73         /* this should never be triggered! */
74         dns_tcp_terminate_connection(dnsconn, "dns_tcp_recv: called");
75 }
76
77 static void dns_tcp_send(struct stream_connection *conn, uint16_t flags)
78 {
79         struct dns_tcp_connection *dnsconn = talloc_get_type(conn->private_data,
80                                                              struct dns_tcp_connection);
81         /* this should never be triggered! */
82         dns_tcp_terminate_connection(dnsconn, "dns_tcp_send: called");
83 }
84
85 bool dns_process(struct dns_server *dns,
86                  TALLOC_CTX *mem_ctx,
87                  DATA_BLOB *in,
88                  DATA_BLOB *out)
89 {
90         DEBUG(0, ("FIXME: actually process DNS packet here\n"));
91         return true;
92 }
93
94 struct dns_tcp_call {
95         struct dns_tcp_connection *dns_conn;
96         DATA_BLOB in;
97         DATA_BLOB out;
98         uint8_t out_hdr[4];
99         struct iovec out_iov[2];
100 };
101
102 static void dns_tcp_call_writev_done(struct tevent_req *subreq);
103
104 static void dns_tcp_call_loop(struct tevent_req *subreq)
105 {
106         struct dns_tcp_connection *dns_conn = tevent_req_callback_data(subreq,
107                                       struct dns_tcp_connection);
108         struct dns_tcp_call *call;
109         NTSTATUS status;
110         bool ok;
111
112         call = talloc(dns_conn, struct dns_tcp_call);
113         if (call == NULL) {
114                 dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: "
115                                 "no memory for dns_tcp_call");
116                 return;
117         }
118         call->dns_conn = dns_conn;
119
120         status = tstream_read_pdu_blob_recv(subreq,
121                                             call,
122                                             &call->in);
123         TALLOC_FREE(subreq);
124         if (!NT_STATUS_IS_OK(status)) {
125                 const char *reason;
126
127                 reason = talloc_asprintf(call, "dns_tcp_call_loop: "
128                                          "tstream_read_pdu_blob_recv() - %s",
129                                          nt_errstr(status));
130                 if (!reason) {
131                         reason = nt_errstr(status);
132                 }
133
134                 dns_tcp_terminate_connection(dns_conn, reason);
135                 return;
136         }
137
138         DEBUG(10,("Received krb5 TCP packet of length %lu from %s\n",
139                  (long) call->in.length,
140                  tsocket_address_string(dns_conn->conn->remote_address, call)));
141
142         /* skip length header */
143         call->in.data +=4;
144         call->in.length -= 4;
145
146         /* Call dns */
147         ok = dns_process(dns_conn->dns_socket->dns, call, &call->in, &call->out);
148         if (!ok) {
149                 dns_tcp_terminate_connection(dns_conn,
150                                 "dns_tcp_call_loop: process function failed");
151                 return;
152         }
153
154         /* First add the length of the out buffer */
155         RSIVAL(call->out_hdr, 0, call->out.length);
156         call->out_iov[0].iov_base = (char *) call->out_hdr;
157         call->out_iov[0].iov_len = 4;
158
159         call->out_iov[1].iov_base = (char *) call->out.data;
160         call->out_iov[1].iov_len = call->out.length;
161
162         subreq = tstream_writev_queue_send(call,
163                                            dns_conn->conn->event.ctx,
164                                            dns_conn->tstream,
165                                            dns_conn->send_queue,
166                                            call->out_iov, 2);
167         if (subreq == NULL) {
168                 dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: "
169                                 "no memory for tstream_writev_queue_send");
170                 return;
171         }
172         tevent_req_set_callback(subreq, dns_tcp_call_writev_done, call);
173
174         /*
175          * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
176          * packet_full_request_u32 provides the pdu length then.
177          */
178         subreq = tstream_read_pdu_blob_send(dns_conn,
179                                             dns_conn->conn->event.ctx,
180                                             dns_conn->tstream,
181                                             4, /* initial_read_size */
182                                             packet_full_request_u32,
183                                             dns_conn);
184         if (subreq == NULL) {
185                 dns_tcp_terminate_connection(dns_conn, "dns_tcp_call_loop: "
186                                 "no memory for tstream_read_pdu_blob_send");
187                 return;
188         }
189         tevent_req_set_callback(subreq, dns_tcp_call_loop, dns_conn);
190 }
191
192 static void dns_tcp_call_writev_done(struct tevent_req *subreq)
193 {
194         struct dns_tcp_call *call = tevent_req_callback_data(subreq,
195                         struct dns_tcp_call);
196         int sys_errno;
197         int rc;
198
199         rc = tstream_writev_queue_recv(subreq, &sys_errno);
200         TALLOC_FREE(subreq);
201         if (rc == -1) {
202                 const char *reason;
203
204                 reason = talloc_asprintf(call, "dns_tcp_call_writev_done: "
205                                          "tstream_writev_queue_recv() - %d:%s",
206                                          sys_errno, strerror(sys_errno));
207                 if (!reason) {
208                         reason = "dns_tcp_call_writev_done: tstream_writev_queue_recv() failed";
209                 }
210
211                 dns_tcp_terminate_connection(call->dns_conn, reason);
212                 return;
213         }
214
215         /* We don't care about errors */
216
217         talloc_free(call);
218 }
219
220 /*
221   called when we get a new connection
222 */
223 static void dns_tcp_accept(struct stream_connection *conn)
224 {
225         struct dns_socket *dns_socket;
226         struct dns_tcp_connection *dns_conn;
227         struct tevent_req *subreq;
228         int rc;
229
230         dns_conn = talloc_zero(conn, struct dns_tcp_connection);
231         if (dns_conn == NULL) {
232                 stream_terminate_connection(conn,
233                                 "dns_tcp_accept: out of memory");
234                 return;
235         }
236
237         dns_conn->send_queue = tevent_queue_create(conn, "dns_tcp_accept");
238         if (dns_conn->send_queue == NULL) {
239                 stream_terminate_connection(conn,
240                                 "dns_tcp_accept: out of memory");
241                 return;
242         }
243
244         dns_socket = talloc_get_type(conn->private_data, struct dns_socket);
245
246         TALLOC_FREE(conn->event.fde);
247
248         rc = tstream_bsd_existing_socket(dns_conn,
249                         socket_get_fd(conn->socket),
250                         &dns_conn->tstream);
251         if (rc < 0) {
252                 stream_terminate_connection(conn,
253                                 "dns_tcp_accept: out of memory");
254                 return;
255         }
256
257         dns_conn->conn = conn;
258         dns_conn->dns_socket = dns_socket;
259         conn->private_data = dns_conn;
260
261         /*
262          * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
263          * packet_full_request_u32 provides the pdu length then.
264          */
265         subreq = tstream_read_pdu_blob_send(dns_conn,
266                                             dns_conn->conn->event.ctx,
267                                             dns_conn->tstream,
268                                             4, /* initial_read_size */
269                                             packet_full_request_u32,
270                                             dns_conn);
271         if (subreq == NULL) {
272                 dns_tcp_terminate_connection(dns_conn, "dns_tcp_accept: "
273                                 "no memory for tstream_read_pdu_blob_send");
274                 return;
275         }
276         tevent_req_set_callback(subreq, dns_tcp_call_loop, dns_conn);
277 }
278
279 static const struct stream_server_ops dns_tcp_stream_ops = {
280         .name                   = "dns_tcp",
281         .accept_connection      = dns_tcp_accept,
282         .recv_handler           = dns_tcp_recv,
283         .send_handler           = dns_tcp_send
284 };
285
286 struct dns_udp_call {
287         struct tsocket_address *src;
288         DATA_BLOB in;
289         DATA_BLOB out;
290 };
291
292 static void dns_udp_call_sendto_done(struct tevent_req *subreq);
293
294 static void dns_udp_call_loop(struct tevent_req *subreq)
295 {
296         struct dns_udp_socket *sock = tevent_req_callback_data(subreq,
297                                       struct dns_udp_socket);
298         struct dns_udp_call *call;
299         uint8_t *buf;
300         ssize_t len;
301         int sys_errno;
302         bool ok;
303
304         call = talloc(sock, struct dns_udp_call);
305         if (call == NULL) {
306                 talloc_free(call);
307                 goto done;
308         }
309
310         len = tdgram_recvfrom_recv(subreq, &sys_errno,
311                                    call, &buf, &call->src);
312         TALLOC_FREE(subreq);
313         if (len == -1) {
314                 talloc_free(call);
315                 goto done;
316         }
317
318         call->in.data = buf;
319         call->in.length = len;
320
321         DEBUG(10,("Received krb5 UDP packet of length %lu from %s\n",
322                  (long)call->in.length,
323                  tsocket_address_string(call->src, call)));
324
325         /* Call krb5 */
326         ok = dns_process(sock->dns_socket->dns, call, &call->in, &call->out);
327         if (!ok) {
328                 talloc_free(call);
329                 goto done;
330         }
331
332         subreq = tdgram_sendto_queue_send(call,
333                                           sock->dns_socket->dns->task->event_ctx,
334                                           sock->dgram,
335                                           sock->send_queue,
336                                           call->out.data,
337                                           call->out.length,
338                                           call->src);
339         if (subreq == NULL) {
340                 talloc_free(call);
341                 goto done;
342         }
343         tevent_req_set_callback(subreq, dns_udp_call_sendto_done, call);
344
345 done:
346         subreq = tdgram_recvfrom_send(sock,
347                                       sock->dns_socket->dns->task->event_ctx,
348                                       sock->dgram);
349         if (subreq == NULL) {
350                 task_server_terminate(sock->dns_socket->dns->task,
351                                       "no memory for tdgram_recvfrom_send",
352                                       true);
353                 return;
354         }
355         tevent_req_set_callback(subreq, dns_udp_call_loop, sock);
356 }
357
358 static void dns_udp_call_sendto_done(struct tevent_req *subreq)
359 {
360         struct dns_udp_call *call = tevent_req_callback_data(subreq,
361                                        struct dns_udp_call);
362         ssize_t ret;
363         int sys_errno;
364
365         ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
366
367         /* We don't care about errors */
368
369         talloc_free(call);
370 }
371
372 /*
373   start listening on the given address
374 */
375 static NTSTATUS dns_add_socket(struct dns_server *dns,
376                                const struct model_ops *model_ops,
377                                const char *name,
378                                const char *address,
379                                uint16_t port)
380 {
381         struct dns_socket *dns_socket;
382         struct dns_udp_socket *dns_udp_socket;
383         struct tevent_req *udpsubreq;
384         NTSTATUS status;
385         int ret;
386
387         dns_socket = talloc(dns, struct dns_socket);
388         NT_STATUS_HAVE_NO_MEMORY(dns_socket);
389
390         dns_socket->dns = dns;
391
392         ret = tsocket_address_inet_from_strings(dns_socket, "ip",
393                                                 address, port,
394                                                 &dns_socket->local_address);
395         if (ret != 0) {
396                 status = map_nt_error_from_unix(errno);
397                 return status;
398         }
399
400         status = stream_setup_socket(dns->task->event_ctx,
401                                      dns->task->lp_ctx,
402                                      model_ops,
403                                      &dns_tcp_stream_ops,
404                                      "ip", address, &port,
405                                      lpcfg_socket_options(dns->task->lp_ctx),
406                                      dns_socket);
407         if (!NT_STATUS_IS_OK(status)) {
408                 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
409                          address, port, nt_errstr(status)));
410                 talloc_free(dns_socket);
411                 return status;
412         }
413
414         dns_udp_socket = talloc(dns_socket, struct dns_udp_socket);
415         NT_STATUS_HAVE_NO_MEMORY(dns_udp_socket);
416
417         dns_udp_socket->dns_socket = dns_socket;
418
419         ret = tdgram_inet_udp_socket(dns_socket->local_address,
420                                      NULL,
421                                      dns_udp_socket,
422                                      &dns_udp_socket->dgram);
423         if (ret != 0) {
424                 status = map_nt_error_from_unix(errno);
425                 DEBUG(0,("Failed to bind to %s:%u UDP - %s\n",
426                          address, port, nt_errstr(status)));
427                 return status;
428         }
429
430         dns_udp_socket->send_queue = tevent_queue_create(dns_udp_socket,
431                                                          "dns_udp_send_queue");
432         NT_STATUS_HAVE_NO_MEMORY(dns_udp_socket->send_queue);
433
434         udpsubreq = tdgram_recvfrom_send(dns_udp_socket,
435                                          dns->task->event_ctx,
436                                          dns_udp_socket->dgram);
437         NT_STATUS_HAVE_NO_MEMORY(udpsubreq);
438         tevent_req_set_callback(udpsubreq, dns_udp_call_loop, dns_udp_socket);
439
440         return NT_STATUS_OK;
441 }
442
443 /*
444   setup our listening sockets on the configured network interfaces
445 */
446 static NTSTATUS dns_startup_interfaces(struct dns_server *dns, struct loadparm_context *lp_ctx,
447                                        struct interface *ifaces)
448 {
449         const struct model_ops *model_ops;
450         int num_interfaces;
451         TALLOC_CTX *tmp_ctx = talloc_new(dns);
452         NTSTATUS status;
453         int i;
454
455         /* within the dns task we want to be a single process, so
456            ask for the single process model ops and pass these to the
457            stream_setup_socket() call. */
458         model_ops = process_model_startup(dns->task->event_ctx, "single");
459         if (!model_ops) {
460                 DEBUG(0,("Can't find 'single' process model_ops\n"));
461                 return NT_STATUS_INTERNAL_ERROR;
462         }
463
464         num_interfaces = iface_count(ifaces);
465
466         for (i=0; i<num_interfaces; i++) {
467                 const char *address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
468
469                 status = dns_add_socket(dns, model_ops, "dns", address, DNS_SERVICE_PORT);
470                 NT_STATUS_NOT_OK_RETURN(status);
471         }
472
473         talloc_free(tmp_ctx);
474
475         return NT_STATUS_OK;
476 }
477 static void dns_task_init(struct task_server *task)
478 {
479         struct dns_server *dns;
480         NTSTATUS status;
481         struct interface *ifaces;
482
483         switch (lpcfg_server_role(task->lp_ctx)) {
484         case ROLE_STANDALONE:
485                 task_server_terminate(task, "dns: no DNS required in standalone configuration", false);
486                 return;
487         case ROLE_DOMAIN_MEMBER:
488                 task_server_terminate(task, "dns: no DNS required in member server configuration", false);
489                 return;
490         case ROLE_DOMAIN_CONTROLLER:
491                 /* Yes, we want a DNS */
492                 break;
493         }
494
495         load_interfaces(task, lpcfg_interfaces(task->lp_ctx), &ifaces);
496
497         if (iface_count(ifaces) == 0) {
498                 task_server_terminate(task, "dns: no network interfaces configured", false);
499                 return;
500         }
501
502         task_server_set_title(task, "task[dns]");
503
504         dns = talloc(task, struct dns_server);
505         if (dns == NULL) {
506                 task_server_terminate(task, "dns: out of memory", true);
507                 return;
508         }
509
510         dns->task = task;
511
512         status = dns_startup_interfaces(dns, task->lp_ctx, ifaces);
513         if (!NT_STATUS_IS_OK(status)) {
514                 task_server_terminate(task, "dns failed to setup interfaces", true);
515                 return;
516         }
517 }
518
519 NTSTATUS server_service_dns_init(void)
520 {
521         return register_server_service("dns", dns_task_init);
522 }