OpenDNSSEC-signer  2.0.4
cmdhandler.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
32 #include "daemon/cmdhandler.h"
33 #include "daemon/engine.h"
34 #include "file.h"
35 #include "str.h"
36 #include "locks.h"
37 #include "log.h"
38 #include "status.h"
39 #include "util.h"
40 
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <ldns/ldns.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <sys/select.h>
49 #include <sys/socket.h>
50 #ifdef HAVE_SYS_TYPES_H
51 # include <sys/types.h>
52 #endif
53 #include <unistd.h>
54 /* According to earlier standards: select() sys/time.h sys/types.h unistd.h */
55 #include <sys/time.h>
56 #include <sys/types.h>
57 
58 #define SE_CMDH_CMDLEN 7
59 
60 static int count = 0;
61 static char const * cmdh_str = "cmdhandler";
62 
63 
68 static void
69 cmdhandler_handle_cmd_help(int sockfd)
70 {
71  char buf[ODS_SE_MAXLINE];
72 
73  (void) snprintf(buf, ODS_SE_MAXLINE,
74  "Commands:\n"
75  "zones Show the currently known zones.\n"
76  "sign <zone> [--serial <nr>] Read zone and schedule for immediate "
77  "(re-)sign.\n"
78  " If a serial is given, that serial is used "
79  "in the output zone.\n"
80  "sign --all Read all zones and schedule all for "
81  "immediate (re-)sign.\n"
82  );
83  ods_writen(sockfd, buf, strlen(buf));
84 
85  (void) snprintf(buf, ODS_SE_MAXLINE,
86  "clear <zone> Delete the internal storage of this "
87  "zone.\n"
88  " All signatures will be regenerated "
89  "on the next re-sign.\n"
90  "queue Show the current task queue.\n"
91  "flush Execute all scheduled tasks "
92  "immediately.\n"
93  );
94  ods_writen(sockfd, buf, strlen(buf));
95 
96  (void) snprintf(buf, ODS_SE_MAXLINE,
97  "update <zone> Update this zone signer "
98  "configurations.\n"
99  "update [--all] Update zone list and all signer "
100  "configurations.\n"
101  "retransfer <zone> Retransfer the zone from the master.\n"
102  "start Start the engine.\n"
103  "running Check if the engine is running.\n"
104  "reload Reload the engine.\n"
105  "stop Stop the engine.\n"
106  "verbosity <nr> Set verbosity.\n"
107  );
108  ods_writen(sockfd, buf, strlen(buf));
109 }
110 
111 
116 static void
117 cmdhandler_handle_cmd_zones(int sockfd, cmdhandler_type* cmdc)
118 {
119  engine_type* engine = NULL;
120  char buf[ODS_SE_MAXLINE];
121  size_t i;
122  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
123  zone_type* zone = NULL;
124  ods_log_assert(cmdc);
125  ods_log_assert(cmdc->engine);
126  engine = cmdc->engine;
127  if (!engine->zonelist || !engine->zonelist->zones) {
128  (void)snprintf(buf, ODS_SE_MAXLINE, "There are no zones configured\n");
129  ods_writen(sockfd, buf, strlen(buf));
130  return;
131  }
132  /* how many zones */
133  lock_basic_lock(&engine->zonelist->zl_lock);
134  (void)snprintf(buf, ODS_SE_MAXLINE, "There are %i zones configured\n",
135  (int) engine->zonelist->zones->count);
136  ods_writen(sockfd, buf, strlen(buf));
137  /* list zones */
138  node = ldns_rbtree_first(engine->zonelist->zones);
139  while (node && node != LDNS_RBTREE_NULL) {
140  zone = (zone_type*) node->data;
141  for (i=0; i < ODS_SE_MAXLINE; i++) {
142  buf[i] = 0;
143  }
144  (void)snprintf(buf, ODS_SE_MAXLINE, "- %s\n", zone->name);
145  ods_writen(sockfd, buf, strlen(buf));
146  node = ldns_rbtree_next(node);
147  }
148  lock_basic_unlock(&engine->zonelist->zl_lock);
149 }
150 
151 
156 static void
157 cmdhandler_handle_cmd_update(int sockfd, cmdhandler_type* cmdc,
158  const char* tbd)
159 {
160  engine_type* engine = NULL;
161  char buf[ODS_SE_MAXLINE];
162  ods_status status = ODS_STATUS_OK;
163  zone_type* zone = NULL;
164  ods_status zl_changed = ODS_STATUS_OK;
165  ods_log_assert(tbd);
166  ods_log_assert(cmdc);
167  ods_log_assert(cmdc->engine);
168  engine = cmdc->engine;
169  ods_log_assert(engine->taskq);
170  if (ods_strcmp(tbd, "--all") == 0) {
171  lock_basic_lock(&engine->zonelist->zl_lock);
172  zl_changed = zonelist_update(engine->zonelist,
173  engine->config->zonelist_filename);
174  if (zl_changed == ODS_STATUS_UNCHANGED) {
175  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has not changed."
176  " Signer configurations updated.\n");
177  ods_writen(sockfd, buf, strlen(buf));
178  } else if (zl_changed == ODS_STATUS_OK) {
179  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list updated: %i "
180  "removed, %i added, %i updated.\n",
181  engine->zonelist->just_removed,
182  engine->zonelist->just_added,
183  engine->zonelist->just_updated);
184  ods_writen(sockfd, buf, strlen(buf));
185  } else {
186  lock_basic_unlock(&engine->zonelist->zl_lock);
187  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has errors.\n");
188  ods_writen(sockfd, buf, strlen(buf));
189  }
190  if (zl_changed == ODS_STATUS_OK ||
191  zl_changed == ODS_STATUS_UNCHANGED) {
192  engine->zonelist->just_removed = 0;
193  engine->zonelist->just_added = 0;
194  engine->zonelist->just_updated = 0;
195  lock_basic_unlock(&engine->zonelist->zl_lock);
200  engine_update_zones(engine, ODS_STATUS_OK);
201  }
202  } else {
203  /* look up zone */
204  lock_basic_lock(&engine->zonelist->zl_lock);
205  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
206  LDNS_RR_CLASS_IN);
207  /* If this zone is just added, don't update (it might not have a
208  * task yet) */
209  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
210  zone = NULL;
211  }
212  lock_basic_unlock(&engine->zonelist->zl_lock);
213 
214  if (!zone) {
215  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
216  tbd);
217  ods_writen(sockfd, buf, strlen(buf));
218  /* update all */
219  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
220  return;
221  }
222 
223  lock_basic_lock(&zone->zone_lock);
224  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
225  lock_basic_unlock(&zone->zone_lock);
226 
227  if (status != ODS_STATUS_OK) {
228  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
229  "task for zone %s.\n", tbd);
230  ods_writen(sockfd, buf, strlen(buf));
231  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
232  cmdh_str, zone->name, ods_status2str(status));
233  } else {
234  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s config being updated.\n",
235  tbd);
236  ods_writen(sockfd, buf, strlen(buf));
237  ods_log_verbose("[%s] zone %s scheduled for immediate update signconf",
238  cmdh_str, tbd);
239  engine_wakeup_workers(engine);
240  }
241  }
242 }
243 
244 
249 static void
250 cmdhandler_handle_cmd_retransfer(int sockfd, cmdhandler_type* cmdc, char* tbd)
251 {
252  engine_type* engine = NULL;
253  char buf[ODS_SE_MAXLINE];
254  zone_type* zone = NULL;
255  ods_log_assert(tbd);
256  ods_log_assert(cmdc);
257  ods_log_assert(cmdc->engine);
258  engine = (engine_type*) cmdc->engine;
259  ods_log_assert(engine->taskq);
260  /* look up zone */
261  lock_basic_lock(&engine->zonelist->zl_lock);
262  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
263  LDNS_RR_CLASS_IN);
264  /* If this zone is just added, don't retransfer (it might not have a
265  * task yet) */
266  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
267  zone = NULL;
268  }
269  lock_basic_unlock(&engine->zonelist->zl_lock);
270 
271  if (!zone) {
272  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
273  tbd);
274  ods_writen(sockfd, buf, strlen(buf));
275  } else if (zone->adinbound->type != ADAPTER_DNS) {
276  (void)snprintf(buf, ODS_SE_MAXLINE,
277  "Error: Zone %s not configured to use DNS input adapter.\n",
278  tbd);
279  ods_writen(sockfd, buf, strlen(buf));
280  } else {
281  zone->xfrd->serial_retransfer = 1;
282  xfrd_set_timer_now(zone->xfrd);
283  ods_log_debug("[%s] forward a notify", cmdh_str);
285  (uint8_t*) ODS_SE_NOTIFY_CMD, strlen(ODS_SE_NOTIFY_CMD));
286  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s being retransferred.\n", tbd);
287  ods_writen(sockfd, buf, strlen(buf));
288  ods_log_verbose("[%s] zone %s being retransferred", cmdh_str, tbd);
289  }
290 }
291 
292 
293 static uint32_t
294 max(uint32_t a, uint32_t b)
295 {
296  return (a<b?b:a);
297 }
298 
299 
304 static void
305 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd)
306 {
307  engine_type* engine = NULL;
308  zone_type* zone = NULL;
309  ods_status status = ODS_STATUS_OK;
310  char buf[ODS_SE_MAXLINE];
311 
312  ods_log_assert(tbd);
313  ods_log_assert(cmdc);
314  ods_log_assert(cmdc->engine);
315  engine = (engine_type*) cmdc->engine;
316  ods_log_assert(engine->taskq);
317  if (ods_strcmp(tbd, "--all") == 0) {
318  lock_basic_lock(&engine->taskq->schedule_lock);
319  schedule_flush(engine->taskq, TASK_READ);
320  lock_basic_unlock(&engine->taskq->schedule_lock);
321  engine_wakeup_workers(engine);
322  (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for "
323  "immediate re-sign.\n");
324  ods_writen(sockfd, buf, strlen(buf));
325  ods_log_verbose("[%s] all zones scheduled for immediate re-sign",
326  cmdh_str);
327  } else {
328  char* delim1 = strchr(tbd, ' ');
329  char* delim2 = NULL;
330  int force_serial = 0;
331  uint32_t serial = 0;
332  if (delim1) {
333  char* end = NULL;
335  if (strncmp(delim1+1, "--serial ", 9) != 0) {
336  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting <zone> "
337  "--serial <nr>, got %s.\n", tbd);
338  ods_writen(sockfd, buf, strlen(buf));
339  return;
340  }
341  delim2 = strchr(delim1+1, ' ');
342  if (!delim2) {
343  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial.\n");
344  ods_writen(sockfd, buf, strlen(buf));
345  return;
346  }
347  serial = (uint32_t) strtol(delim2+1, &end, 10);
348  if (*end != '\0') {
349  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial, "
350  "got %s.\n", delim2+1);
351  ods_writen(sockfd, buf, strlen(buf));
352  return;
353  }
354  force_serial = 1;
355  *delim1 = '\0';
356  }
357  lock_basic_lock(&engine->zonelist->zl_lock);
358  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
359  LDNS_RR_CLASS_IN);
360  /* If this zone is just added, don't update (it might not have a task
361  * yet).
362  */
363  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
364  zone = NULL;
365  }
366  lock_basic_unlock(&engine->zonelist->zl_lock);
367 
368  if (!zone) {
369  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
370  tbd);
371  ods_writen(sockfd, buf, strlen(buf));
372  return;
373  }
374 
375  lock_basic_lock(&zone->zone_lock);
376  if (force_serial) {
377  ods_log_assert(zone->db);
378  if (!util_serial_gt(serial, max(zone->db->outserial,
379  zone->db->inbserial))) {
380  lock_basic_unlock(&zone->zone_lock);
381  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to enforce "
382  "serial %u for zone %s.\n", serial, tbd);
383  ods_writen(sockfd, buf, strlen(buf));
384  return;
385  }
386  zone->db->altserial = serial;
387  zone->db->force_serial = 1;
388  }
389  status = zone_reschedule_task(zone, engine->taskq, TASK_READ);
390  lock_basic_unlock(&zone->zone_lock);
391 
392  if (status != ODS_STATUS_OK) {
393  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
394  "task for zone %s.\n", tbd);
395  ods_writen(sockfd, buf, strlen(buf));
396  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
397  cmdh_str, zone->name, ods_status2str(status));
398  } else {
399  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for "
400  "immediate re-sign.\n", tbd);
401  ods_writen(sockfd, buf, strlen(buf));
402  ods_log_verbose("[%s] zone %s scheduled for immediate re-sign",
403  cmdh_str, tbd);
404  engine_wakeup_workers(engine);
405  }
406  }
407 }
408 
409 
414 static void
415 unlink_backup_file(const char* filename, const char* extension)
416 {
417  char* tmpname = ods_build_path(filename, extension, 0, 1);
418  if (tmpname) {
419  ods_log_debug("[%s] unlink file %s", cmdh_str, tmpname);
420  unlink(tmpname);
421  free((void*)tmpname);
422  }
423 }
424 
429 static void
430 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd)
431 {
432  ods_status status = ODS_STATUS_OK;
433  engine_type* engine = NULL;
434  char buf[ODS_SE_MAXLINE];
435  zone_type* zone = NULL;
436  uint32_t inbserial = 0;
437  uint32_t intserial = 0;
438  uint32_t outserial = 0;
439  ods_log_assert(tbd);
440  ods_log_assert(cmdc);
441  ods_log_assert(cmdc->engine);
442  engine = (engine_type*) cmdc->engine;
443  unlink_backup_file(tbd, ".inbound");
444  unlink_backup_file(tbd, ".backup");
445  unlink_backup_file(tbd, ".axfr");
446  unlink_backup_file(tbd, ".ixfr");
447  lock_basic_lock(&engine->zonelist->zl_lock);
448  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
449  LDNS_RR_CLASS_IN);
450  lock_basic_unlock(&engine->zonelist->zl_lock);
451  if (zone) {
452  lock_basic_lock(&zone->zone_lock);
453  inbserial = zone->db->inbserial;
454  intserial = zone->db->intserial;
455  outserial = zone->db->outserial;
456  namedb_cleanup(zone->db);
457  ixfr_cleanup(zone->ixfr);
458  signconf_cleanup(zone->signconf);
459 
460  zone->db = namedb_create((void*)zone);
461  zone->ixfr = ixfr_create((void*)zone);
462  zone->signconf = signconf_create();
463 
464  if (!zone->signconf || !zone->ixfr || !zone->db) {
465  ods_fatal_exit("[%s] unable to clear zone %s: failed to recreate"
466  "signconf, ixfr of db structure (out of memory?)", cmdh_str, tbd);
467  return;
468  }
469  /* restore serial management */
470  zone->db->inbserial = inbserial;
471  zone->db->intserial = intserial;
472  zone->db->outserial = outserial;
473  zone->db->have_serial = 1;
474 
475  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
476  lock_basic_unlock(&zone->zone_lock);
477 
478  if (status != ODS_STATUS_OK) {
479  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
480  "task for zone %s.\n", tbd);
481  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
482  cmdh_str, zone->name, ods_status2str(status));
483  } else {
484  (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about "
485  "%s cleared", tbd?tbd:"(null)");
486  ods_log_info("[%s] internal zone information about %s cleared",
487  cmdh_str, tbd?tbd:"(null)");
488  }
489  } else {
490  (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not "
491  "found", tbd?tbd:"(null)");
492  ods_log_warning("[%s] cannot clear zone %s, zone not found",
493  cmdh_str, tbd?tbd:"(null)");
494  }
495  ods_writen(sockfd, buf, strlen(buf));
496 }
497 
498 
503 static void
504 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc)
505 {
506  engine_type* engine = NULL;
507  char* strtime = NULL;
508  char buf[ODS_SE_MAXLINE];
509  size_t i = 0;
510  time_t now = 0;
511  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
512  task_type* task = NULL;
513  ods_log_assert(cmdc);
514  ods_log_assert(cmdc->engine);
515  engine = (engine_type*) cmdc->engine;
516  if (!engine->taskq || !engine->taskq->tasks) {
517  (void)snprintf(buf, ODS_SE_MAXLINE, "There are no tasks scheduled.\n");
518  ods_writen(sockfd, buf, strlen(buf));
519  return;
520  }
521  /* current time */
522  now = time_now();
523  strtime = ctime(&now);
524  (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s",
525  strtime?strtime:"(null)");
526  ods_writen(sockfd, buf, strlen(buf));
527  /* current work */
528  lock_basic_lock(&engine->taskq->schedule_lock);
529  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
530  task = engine->workers[i]->task;
531  if (task) {
532  (void)snprintf(buf, ODS_SE_MAXLINE, "Working with task %s on "
533  "zone %s\n",
534  task_what2str(engine->workers[i]->working_with),
535  task_who2str(task));
536  ods_writen(sockfd, buf, strlen(buf));
537  }
538  }
539  /* how many tasks */
540  (void)snprintf(buf, ODS_SE_MAXLINE, "\nThere are %i tasks scheduled.\n",
541  (int) engine->taskq->tasks->count);
542  ods_writen(sockfd, buf, strlen(buf));
543  /* list tasks */
544  node = ldns_rbtree_first(engine->taskq->tasks);
545  while (node && node != LDNS_RBTREE_NULL) {
546  task = (task_type*) node->data;
547  for (i=0; i < ODS_SE_MAXLINE; i++) {
548  buf[i] = 0;
549  }
550  (void)task2str(task, (char*) &buf[0]);
551  ods_writen(sockfd, buf, strlen(buf));
552  node = ldns_rbtree_next(node);
553  }
554  lock_basic_unlock(&engine->taskq->schedule_lock);
555 }
556 
557 
562 static void
563 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc)
564 {
565  engine_type* engine = NULL;
566  char buf[ODS_SE_MAXLINE];
567  ods_log_assert(cmdc);
568  ods_log_assert(cmdc->engine);
569  engine = (engine_type*) cmdc->engine;
570  ods_log_assert(engine->taskq);
571  lock_basic_lock(&engine->taskq->schedule_lock);
572  schedule_flush(engine->taskq, TASK_NONE);
573  lock_basic_unlock(&engine->taskq->schedule_lock);
574  engine_wakeup_workers(engine);
575  (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n");
576  ods_writen(sockfd, buf, strlen(buf));
577  ods_log_verbose("[%s] all tasks scheduled immediately", cmdh_str);
578 }
579 
580 
585 static void
586 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc)
587 {
588  engine_type* engine = NULL;
589  char buf[ODS_SE_MAXLINE];
590  ods_log_assert(cmdc);
591  ods_log_assert(cmdc->engine);
592  engine = (engine_type*) cmdc->engine;
593  ods_log_error("signer instructed to reload due to explicit command");
594  engine->need_to_reload = 1;
595  lock_basic_lock(&engine->signal_lock);
596  lock_basic_alarm(&engine->signal_cond);
597  lock_basic_unlock(&engine->signal_lock);
598  (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n");
599  ods_writen(sockfd, buf, strlen(buf));
600 }
601 
602 
607 static void
608 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc)
609 {
610  engine_type* engine = NULL;
611  char buf[ODS_SE_MAXLINE];
612  ods_log_assert(cmdc);
613  ods_log_assert(cmdc->engine);
614  engine = (engine_type*) cmdc->engine;
615  engine->need_to_exit = 1;
616  lock_basic_lock(&engine->signal_lock);
617  lock_basic_alarm(&engine->signal_cond);
618  lock_basic_unlock(&engine->signal_lock);
619  (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE);
620  ods_writen(sockfd, buf, strlen(buf));
621 }
622 
623 
628 static void
629 cmdhandler_handle_cmd_start(int sockfd)
630 {
631  char buf[ODS_SE_MAXLINE];
632  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n");
633  ods_writen(sockfd, buf, strlen(buf));
634 }
635 
636 
641 static void
642 cmdhandler_handle_cmd_running(int sockfd)
643 {
644  char buf[ODS_SE_MAXLINE];
645  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n");
646  ods_writen(sockfd, buf, strlen(buf));
647 }
648 
649 
654 static void
655 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val)
656 {
657  engine_type* engine = NULL;
658  char buf[ODS_SE_MAXLINE];
659  ods_log_assert(cmdc);
660  ods_log_assert(cmdc->engine);
661  engine = (engine_type*) cmdc->engine;
662  ods_log_assert(engine->config);
663  ods_log_init("ods-signerd", engine->config->use_syslog, engine->config->log_filename, val);
664  (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val);
665  ods_writen(sockfd, buf, strlen(buf));
666 }
667 
668 
673 static void
674 cmdhandler_handle_cmd_error(int sockfd, const char* str)
675 {
676  char buf[ODS_SE_MAXLINE];
677  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)");
678  ods_writen(sockfd, buf, strlen(buf));
679 }
680 
681 
686 static void
687 cmdhandler_handle_cmd_unknown(int sockfd, const char* str)
688 {
689  char buf[ODS_SE_MAXLINE];
690  (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n",
691  str?str:"(null)");
692  ods_writen(sockfd, buf, strlen(buf));
693 }
694 
695 
713 static void
714 cmdhandler_handle_cmd(cmdhandler_type* cmdc)
715 {
716  ssize_t n = 0;
717  int sockfd = 0;
718  char buf[ODS_SE_MAXLINE];
719 
720  ods_log_assert(cmdc);
721  sockfd = cmdc->client_fd;
722 
723 again:
724  while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) {
725  /* what if this number is smaller than the number of bytes requested? */
726  buf[n-1] = '\0';
727  n--;
728  ods_log_verbose("[%s] received command %s[%ld]", cmdh_str, buf, (long)n);
729  ods_str_trim(buf,1);
730  n = strlen(buf);
731 
732  if (n == 4 && strncmp(buf, "help", n) == 0) {
733  ods_log_debug("[%s] help command", cmdh_str);
734  cmdhandler_handle_cmd_help(sockfd);
735  } else if (n == 5 && strncmp(buf, "zones", n) == 0) {
736  ods_log_debug("[%s] list zones command", cmdh_str);
737  cmdhandler_handle_cmd_zones(sockfd, cmdc);
738  } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) {
739  ods_log_debug("[%s] sign zone command", cmdh_str);
740  if (n == 4 || buf[4] == '\0') {
741  /* NOTE: wouldn't it be nice that we default to --all? */
742  cmdhandler_handle_cmd_error(sockfd, "sign command needs "
743  "an argument (either '--all' or a zone name)");
744  } else if (buf[4] != ' ') {
745  cmdhandler_handle_cmd_unknown(sockfd, buf);
746  } else {
747  cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]);
748  }
749  } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) {
750  ods_log_debug("[%s] clear zone command", cmdh_str);
751  if (n == 5 || buf[5] == '\0') {
752  cmdhandler_handle_cmd_error(sockfd, "clear command needs "
753  "a zone name");
754  } else if (buf[5] != ' ') {
755  cmdhandler_handle_cmd_unknown(sockfd, buf);
756  } else {
757  cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]);
758  }
759  } else if (n == 5 && strncmp(buf, "queue", n) == 0) {
760  ods_log_debug("[%s] list tasks command", cmdh_str);
761  cmdhandler_handle_cmd_queue(sockfd, cmdc);
762  } else if (n == 5 && strncmp(buf, "flush", n) == 0) {
763  ods_log_debug("[%s] flush tasks command", cmdh_str);
764  cmdhandler_handle_cmd_flush(sockfd, cmdc);
765  } else if (n >= 6 && strncmp(buf, "update", 6) == 0) {
766  ods_log_debug("[%s] update command", cmdh_str);
767  if (n == 6 || buf[6] == '\0') {
768  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
769  } else if (buf[6] != ' ') {
770  cmdhandler_handle_cmd_unknown(sockfd, buf);
771  } else {
772  cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]);
773  }
774  } else if (n == 4 && strncmp(buf, "stop", n) == 0) {
775  ods_log_debug("[%s] shutdown command", cmdh_str);
776  cmdhandler_handle_cmd_stop(sockfd, cmdc);
777  return;
778  } else if (n == 5 && strncmp(buf, "start", n) == 0) {
779  ods_log_debug("[%s] start command", cmdh_str);
780  cmdhandler_handle_cmd_start(sockfd);
781  } else if (n == 6 && strncmp(buf, "reload", n) == 0) {
782  ods_log_debug("[%s] reload command", cmdh_str);
783  cmdhandler_handle_cmd_reload(sockfd, cmdc);
784  } else if (n == 7 && strncmp(buf, "running", n) == 0) {
785  ods_log_debug("[%s] running command", cmdh_str);
786  cmdhandler_handle_cmd_running(sockfd);
787  } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) {
788  ods_log_debug("[%s] verbosity command", cmdh_str);
789  if (n == 9 || buf[9] == '\0') {
790  cmdhandler_handle_cmd_error(sockfd, "verbosity command "
791  "an argument (verbosity level)");
792  } else if (buf[9] != ' ') {
793  cmdhandler_handle_cmd_unknown(sockfd, buf);
794  } else {
795  cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10]));
796  }
797  } else if (n >= 10 && strncmp(buf, "retransfer", 10) == 0) {
798  ods_log_debug("[%s] retransfer zone command", cmdh_str);
799  if (n == 10 || buf[10] == '\0') {
800  cmdhandler_handle_cmd_error(sockfd, "retransfer command needs "
801  "an argument (a zone name)");
802  } else if (buf[10] != ' ') {
803  cmdhandler_handle_cmd_unknown(sockfd, buf);
804  } else {
805  cmdhandler_handle_cmd_retransfer(sockfd, cmdc, &buf[11]);
806  }
807  } else if (n > 0) {
808  ods_log_debug("[%s] unknown command", cmdh_str);
809  cmdhandler_handle_cmd_unknown(sockfd, buf);
810  }
811  ods_log_debug("[%s] done handling command %s[%ld]", cmdh_str, buf, (long)n);
812  (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> ");
813  ods_writen(sockfd, buf, strlen(buf));
814  }
815 
816  if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) {
817  goto again;
818  } else if (n < 0 && errno == ECONNRESET) {
819  ods_log_debug("[%s] done handling client: %s", cmdh_str,
820  strerror(errno));
821  } else if (n < 0 ) {
822  ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno));
823  }
824 }
825 
826 
831 static void*
832 cmdhandler_accept_client(void* arg)
833 {
834  cmdhandler_type* cmdc = (cmdhandler_type*) arg;
835 
836  ods_thread_blocksigs();
837  ods_thread_detach(cmdc->thread_id);
838 
839  ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd);
840  cmdhandler_handle_cmd(cmdc);
841  if (cmdc->client_fd) {
842  shutdown(cmdc->client_fd, SHUT_RDWR);
843  close(cmdc->client_fd);
844  }
845  free(cmdc);
846  count--;
847  return NULL;
848 }
849 
850 
856 cmdhandler_create(const char* filename)
857 {
858  cmdhandler_type* cmdh = NULL;
859  struct sockaddr_un servaddr;
860  int listenfd = 0;
861  int flags = 0;
862  int ret = 0;
863 
864  if (!filename) {
865  return NULL;
866  }
867  /* new socket */
868  ods_log_debug("[%s] create socket %s", cmdh_str, filename);
869  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
870  if (listenfd < 0) {
871  ods_log_error("[%s] unable to create cmdhandler: "
872  "socket() failed (%s)", cmdh_str, strerror(errno));
873  return NULL;
874  }
875  /* set it to non-blocking */
876  flags = fcntl(listenfd, F_GETFL, 0);
877  if (flags < 0) {
878  ods_log_error("[%s] unable to create cmdhandler: "
879  "fcntl(F_GETFL) failed (%s)", cmdh_str, strerror(errno));
880  close(listenfd);
881  return NULL;
882  }
883  flags |= O_NONBLOCK;
884  if (fcntl(listenfd, F_SETFL, flags) < 0) {
885  ods_log_error("[%s] unable to create cmdhandler: "
886  "fcntl(F_SETFL) failed (%s)", cmdh_str, strerror(errno));
887  close(listenfd);
888  return NULL;
889  }
890  /* no surprises so far */
891  if (filename) {
892  (void)unlink(filename);
893  }
894  bzero(&servaddr, sizeof(servaddr));
895  servaddr.sun_family = AF_UNIX;
896  strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1);
897 #ifdef HAVE_SOCKADDR_SUN_LEN
898  servaddr.sun_len = strlen(servaddr.sun_path);
899 #endif
900  /* bind and listen... */
901  ret = bind(listenfd, (const struct sockaddr*) &servaddr, sizeof(struct sockaddr_un));
902  if (ret != 0) {
903  ods_log_error("[%s] unable to create cmdhandler: "
904  "bind() failed (%s)", cmdh_str, strerror(errno));
905  close(listenfd);
906  return NULL;
907  }
908  ret = listen(listenfd, ODS_SE_MAX_HANDLERS);
909  if (ret != 0) {
910  ods_log_error("[%s] unable to create cmdhandler: "
911  "listen() failed (%s)", cmdh_str, strerror(errno));
912  close(listenfd);
913  return NULL;
914  }
915  /* all ok */
916  CHECKALLOC(cmdh = (cmdhandler_type*) malloc(sizeof(cmdhandler_type)));
917  cmdh->listen_fd = listenfd;
918  cmdh->listen_addr = servaddr;
919  cmdh->need_to_exit = 0;
920  return cmdh;
921 }
922 
923 
928 void
930 {
931  struct sockaddr_un cliaddr;
932  socklen_t clilen;
933  cmdhandler_type* cmdc = NULL;
934  engine_type* engine = NULL;
935  fd_set rset;
936  int connfd = 0;
937  int ret = 0;
938  ods_log_assert(cmdhandler);
939  ods_log_assert(cmdhandler->engine);
940  ods_log_debug("[%s] start", cmdh_str);
941  engine = cmdhandler->engine;
942  ods_thread_detach(cmdhandler->thread_id);
943  FD_ZERO(&rset);
944  while (cmdhandler->need_to_exit == 0) {
945  clilen = sizeof(cliaddr);
946  FD_SET(cmdhandler->listen_fd, &rset);
947  ret = select(cmdhandler->listen_fd+1, &rset, NULL, NULL, NULL);
948  if (ret < 0) {
949  if (errno != EINTR && errno != EWOULDBLOCK) {
950  ods_log_warning("[%s] select() error: %s", cmdh_str,
951  strerror(errno));
952  }
953  continue;
954  }
955  if (FD_ISSET(cmdhandler->listen_fd, &rset)) {
956  connfd = accept(cmdhandler->listen_fd,
957  (struct sockaddr *) &cliaddr, &clilen);
958  if (connfd < 0) {
959  if (errno != EINTR && errno != EWOULDBLOCK) {
960  ods_log_warning("[%s] accept() error: %s", cmdh_str,
961  strerror(errno));
962  }
963  continue;
964  }
965  /* client accepted, create new thread */
966  cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type));
967  if (!cmdc) {
968  ods_log_crit("[%s] unable to create thread for client: "
969  "malloc() failed", cmdh_str);
970  cmdhandler->need_to_exit = 1;
971  break;
972  }
973  cmdc->listen_fd = cmdhandler->listen_fd;
974  cmdc->client_fd = connfd;
975  cmdc->listen_addr = cmdhandler->listen_addr;
976  cmdc->engine = cmdhandler->engine;
977  cmdc->need_to_exit = cmdhandler->need_to_exit;
978  ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client,
979  (void*) cmdc);
980  count++;
981  ods_log_debug("[%s] %i clients in progress...", cmdh_str, count);
982  }
983  }
984  ods_log_debug("[%s] shutdown", cmdh_str);
985  engine = cmdhandler->engine;
986  engine->cmdhandler_done = 1;
987 }
988 
989 
994 void
996 {
997  free(cmdhandler);
998 }
999 
signconf_type * signconf_create(void)
Definition: signconf.c:47
void ixfr_cleanup(ixfr_type *ixfr)
Definition: ixfr.c:305
Definition: task.h:39
uint32_t intserial
Definition: namedb.h:54
#define ODS_SE_NOTIFY_CMD
Definition: dnshandler.h:48
zonelist_type * zonelist
Definition: engine.h:60
void engine_wakeup_workers(engine_type *engine)
Definition: engine.c:427
int just_updated
Definition: zonelist.h:48
cond_basic_type signal_cond
Definition: engine.h:78
const char * zonelist_filename
Definition: cfg.h:49
void engine_update_zones(engine_type *engine, ods_status zl_changed)
Definition: engine.c:751
void signconf_cleanup(signconf_type *sc)
Definition: signconf.c:470
void namedb_cleanup(namedb_type *db)
Definition: namedb.c:1130
ixfr_type * ixfr_create(zone_type *zone)
Definition: ixfr.c:93
const char * task_who2str(task_type *task)
Definition: task.c:137
ldns_rbtree_t * zones
Definition: zonelist.h:45
lock_basic_type zone_lock
Definition: zone.h:86
void schedule_flush(schedule_type *schedule, task_id override)
Definition: schedule.c:76
ods_thread_type thread_id
Definition: cmdhandler.h:50
uint32_t outserial
Definition: namedb.h:55
adapter_mode type
Definition: adapter.h:58
zone_zl_status zl_status
Definition: zone.h:70
int just_removed
Definition: zonelist.h:49
void cmdhandler_start(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:929
struct sockaddr_un listen_addr
Definition: cmdhandler.h:49
#define ODS_SE_MAX_HANDLERS
Definition: cmdhandler.h:45
const char * log_filename
Definition: cfg.h:50
lock_basic_type signal_lock
Definition: engine.h:79
task_type * task
Definition: worker.h:55
engineconfig_type * config
Definition: engine.h:57
namedb_type * db
Definition: zone.h:77
ixfr_type * ixfr
Definition: zone.h:78
uint32_t inbserial
Definition: namedb.h:53
int num_worker_threads
Definition: cfg.h:59
Definition: task.h:41
worker_type ** workers
Definition: engine.h:58
#define SE_CMDH_CMDLEN
Definition: cmdhandler.c:58
signconf_type * signconf
Definition: zone.h:75
engine_type * engine
Definition: cmdhandler.h:48
adapter_type * adinbound
Definition: zone.h:72
unsigned force_serial
Definition: namedb.h:60
ods_status zone_reschedule_task(zone_type *zone, schedule_type *taskq, task_id what)
Definition: zone.c:186
namedb_type * namedb_create(void *zone)
Definition: namedb.c:121
int use_syslog
Definition: cfg.h:58
ldns_rbtree_t * tasks
Definition: schedule.h:59
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:157
void xfrd_set_timer_now(xfrd_type *xfrd)
Definition: xfrd.c:454
const char * name
Definition: zone.h:67
schedule_type * taskq
Definition: engine.h:61
uint8_t serial_retransfer
Definition: xfrd.h:119
cmdhandler_type * cmdhandler_create(const char *filename)
Definition: cmdhandler.c:856
uint32_t altserial
Definition: namedb.h:56
task_id working_with
Definition: worker.h:56
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:345
char * task2str(task_type *task, char *buftask)
Definition: task.c:155
lock_basic_type schedule_lock
Definition: schedule.h:62
int need_to_exit
Definition: engine.h:74
int need_to_reload
Definition: engine.h:75
xfrd_type * xfrd
Definition: zone.h:80
void dnshandler_fwd_notify(dnshandler_type *dnshandler, uint8_t *pkt, size_t len)
Definition: dnshandler.c:240
void cmdhandler_cleanup(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:995
lock_basic_type zl_lock
Definition: zonelist.h:50
int cmdhandler_done
Definition: engine.h:67
const char * task_what2str(task_id what)
Definition: task.c:107
dnshandler_type * dnshandler
Definition: engine.h:64