OpenDNSSEC-signer  1.3.16
cmdhandler.c
Go to the documentation of this file.
1 /*
2  * $Id: cmdhandler.c 7295 2013-09-11 10:18:25Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "daemon/cmdhandler.h"
35 #include "daemon/engine.h"
36 #include "scheduler/schedule.h"
37 #include "scheduler/task.h"
38 #include "shared/allocator.h"
39 #include "shared/file.h"
40 #include "shared/hsm.h"
41 #include "shared/locks.h"
42 #include "shared/log.h"
43 #include "shared/status.h"
44 #include "shared/util.h"
45 
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <ldns/ldns.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <sys/select.h>
54 #include <sys/socket.h>
55 #ifdef HAVE_SYS_TYPES_H
56 # include <sys/types.h>
57 #endif
58 #include <unistd.h>
59 /* According to earlier standards: select() sys/time.h sys/types.h unistd.h */
60 #include <sys/time.h>
61 #include <sys/types.h>
62 
63 #define SE_CMDH_CMDLEN 7
64 
65 #ifndef SUN_LEN
66 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
67 #endif
68 
69 static int count = 0;
70 static char* cmdh_str = "cmdhandler";
71 
72 
77 static void
78 cmdhandler_handle_cmd_help(int sockfd)
79 {
80  char buf[ODS_SE_MAXLINE];
81 
82  (void) snprintf(buf, ODS_SE_MAXLINE,
83  "Commands:\n"
84  "zones show the currently known zones.\n"
85  "sign <zone> [--serial <nr>] read zone and schedule for immediate "
86  "(re-)sign.\n"
87  " If a serial is given, that serial is used "
88  "in the output zone.\n"
89  "sign --all read all zones and schedule all for "
90  "immediate (re-)sign.\n"
91  "clear <zone> delete the internal storage of this zone.\n"
92  " All signatures will be regenerated on the "
93  "next re-sign.\n"
94  );
95  ods_writen(sockfd, buf, strlen(buf));
96 
97  (void) snprintf(buf, ODS_SE_MAXLINE,
98  "queue show the current task queue.\n"
99  "debug-locks show locking information (for debugging "
100  "purposes).\n"
101  "flush execute all scheduled tasks immediately.\n"
102  "update <zone> update this zone signer configurations.\n"
103  "update [--all] update zone list and all signer "
104  "configurations.\n"
105  "start start the engine.\n"
106  "running check if the engine is running.\n"
107  "reload reload the engine.\n"
108  );
109  ods_writen(sockfd, buf, strlen(buf));
110 
111  (void) snprintf(buf, ODS_SE_MAXLINE,
112  "stop stop the engine.\n"
113  "verbosity <nr> set verbosity.\n"
114  );
115  ods_writen(sockfd, buf, strlen(buf));
116  return;
117 }
118 
119 
124 static void
125 cmdhandler_handle_cmd_zones(int sockfd, cmdhandler_type* cmdc)
126 {
127  char buf[ODS_SE_MAXLINE];
128  size_t i;
129  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
130  zone_type* zone = NULL;
131 
132  ods_log_assert(cmdc);
133  ods_log_assert(cmdc->engine);
134  if (!cmdc->engine->zonelist || !cmdc->engine->zonelist->zones) {
135  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no zones configured\n");
136  ods_writen(sockfd, buf, strlen(buf));
137  return;
138  }
139 
142  /* how many zones */
143  (void)snprintf(buf, ODS_SE_MAXLINE, "I have %i zones configured\n",
144  (int) cmdc->engine->zonelist->zones->count);
145  ods_writen(sockfd, buf, strlen(buf));
146 
147  /* list zones */
148  node = ldns_rbtree_first(cmdc->engine->zonelist->zones);
149  while (node && node != LDNS_RBTREE_NULL) {
150  zone = (zone_type*) node->data;
151  for (i=0; i < ODS_SE_MAXLINE; i++) {
152  buf[i] = 0;
153  }
154  (void)snprintf(buf, ODS_SE_MAXLINE, "- %s\n", zone->name);
155  ods_writen(sockfd, buf, strlen(buf));
156  node = ldns_rbtree_next(node);
157  }
158  cmdc->engine->zonelist->zl_locked = 0;
160  return;
161 }
162 
163 
168 static void
169 cmdhandler_handle_cmd_update(int sockfd, cmdhandler_type* cmdc,
170  const char* tbd)
171 {
172  char buf[ODS_SE_MAXLINE];
173  ods_status status = ODS_STATUS_OK;
174  zone_type* zone = NULL;
175  task_type* task = NULL;
176  int zl_changed = 0;
177 
178  ods_log_assert(tbd);
179  ods_log_assert(cmdc);
180  ods_log_assert(cmdc->engine);
181  ods_log_assert(cmdc->engine->taskq);
182 
183  if (ods_strcmp(tbd, "--all") == 0) {
186  zl_changed = zonelist_update(cmdc->engine->zonelist,
188  if (zl_changed == ODS_STATUS_UNCHANGED) {
189  cmdc->engine->zonelist->zl_locked = 0;
191  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has not changed."
192  " Signer configurations updated.\n");
193  ods_writen(sockfd, buf, strlen(buf));
194 
196  ods_log_debug("[%s] signer configurations updated", cmdh_str);
197  } else if (zl_changed == ODS_STATUS_OK) {
198  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list updated: %i "
199  "removed, %i added, %i updated.\n",
200  cmdc->engine->zonelist->just_removed,
201  cmdc->engine->zonelist->just_added,
202  cmdc->engine->zonelist->just_updated);
203  ods_writen(sockfd, buf, strlen(buf));
204 
205  cmdc->engine->zonelist->just_removed = 0;
206  cmdc->engine->zonelist->just_added = 0;
207  cmdc->engine->zonelist->just_updated = 0;
208  cmdc->engine->zonelist->zl_locked = 0;
210 
211  ods_log_debug("[%s] commit zone list changes", cmdh_str);
213  ods_log_debug("[%s] signer configurations updated", cmdh_str);
214  } else {
215  cmdc->engine->zonelist->zl_locked = 0;
217  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has errors.\n");
218  ods_writen(sockfd, buf, strlen(buf));
219  }
220  return;
221  } else {
222  /* look up zone */
225  zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
226  LDNS_RR_CLASS_IN);
227  /* If this zone is just added, don't update (it might not have a
228  * task yet) */
229  if (zone && zone->just_added) {
230  zone = NULL;
231  }
232  cmdc->engine->zonelist->zl_locked = 0;
234  if (!zone) {
235  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
236  tbd);
237  ods_writen(sockfd, buf, strlen(buf));
238  /* update all */
239  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
240  return;
241  }
242 
243  lock_basic_lock(&zone->zone_lock);
245  ods_log_assert(zone->task);
246 
249  task = unschedule_task(cmdc->engine->taskq, (task_type*) zone->task);
250  if (task != NULL) {
251  ods_log_debug("[%s] reschedule task for zone %s", cmdh_str,
252  zone->name);
253  if (task->what != TASK_SIGNCONF) {
254  task->halted = task->what;
255  task->interrupt = TASK_SIGNCONF;
256  }
257  task->what = TASK_SIGNCONF;
258  task->when = time_now();
259  status = schedule_task(cmdc->engine->taskq, task, 0);
260  zone->task = task;
261  } else {
262  /* task not queued, being worked on? */
263  ods_log_verbose("[%s] worker busy with zone %s, will update "
264  "signconf as soon as possible", cmdh_str, zone->name);
265  task = (task_type*) zone->task;
266  task->interrupt = TASK_SIGNCONF;
267  /* task->halted set by worker */
268  }
269  cmdc->engine->taskq->schedule_locked = 0;
271 
272  zone->zone_locked = 0;
274 
275  if (status != ODS_STATUS_OK) {
276  ods_log_crit("[%s] cannot schedule task for zone %s: %s",
277  cmdh_str, zone->name, ods_status2str(status));
278  task_cleanup(task);
279  zone->task = NULL;
280  } else {
282  }
283 
284  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s config being updated.\n",
285  tbd);
286  ods_writen(sockfd, buf, strlen(buf));
287  }
288  return;
289 }
290 
291 
292 static uint32_t
293 max(uint32_t a, uint32_t b)
294 {
295  return (a<b?b:a);
296 }
297 
298 
303 static void
304 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd)
305 {
306  zone_type* zone = NULL;
307  task_type* task = NULL;
308  ods_status status = ODS_STATUS_OK;
309  char buf[ODS_SE_MAXLINE];
310 
311  ods_log_assert(tbd);
312  ods_log_assert(cmdc);
313  ods_log_assert(cmdc->engine);
314  ods_log_assert(cmdc->engine->taskq);
315 
316  if (ods_strcmp(tbd, "--all") == 0) {
320  cmdc->engine->taskq->schedule_locked = 0;
323  (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for "
324  "immediate re-sign.\n");
325  ods_writen(sockfd, buf, strlen(buf));
326  ods_log_verbose("[%s] all zones scheduled for immediate re-sign",
327  cmdh_str);
328  return;
329  } else {
330  char* delim1 = strchr(tbd, ' ');
331  char* delim2 = NULL;
332  int force_serial = 0;
333  uint32_t serial = 0;
334  if (delim1) {
335  char* end = NULL;
337  if (strncmp(delim1+1, "--serial ", 9) != 0) {
338  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting <zone> "
339  "--serial <nr>, got %s.\n", tbd);
340  ods_writen(sockfd, buf, strlen(buf));
341  return;
342  }
343  delim2 = strchr(delim1+1, ' ');
344  if (!delim2) {
345  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial.\n");
346  ods_writen(sockfd, buf, strlen(buf));
347  return;
348  }
349  serial = (uint32_t) strtol(delim2+1, &end, 10);
350  if (*end != '\0') {
351  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial, "
352  "got %s.\n", delim2+1);
353  ods_writen(sockfd, buf, strlen(buf));
354  return;
355  }
356  force_serial = 1;
357  *delim1 = '\0';
358  }
359 
362  zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
363  LDNS_RR_CLASS_IN);
364  /* If this zone is just added, don't update (it might not have a task
365  * yet).
366  */
367  if (zone && zone->just_added) {
368  zone = NULL;
369  }
370  cmdc->engine->zonelist->zl_locked = 0;
372 
373  if (!zone) {
374  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
375  tbd);
376  ods_writen(sockfd, buf, strlen(buf));
377  return;
378  }
379 
380  lock_basic_lock(&zone->zone_lock);
382  ods_log_assert(zone->task);
383  if (force_serial) {
384  ods_log_assert(zone->zonedata);
385  if (!DNS_SERIAL_GT(serial, max(zone->zonedata->outbound_serial,
386  zone->zonedata->inbound_serial))) {
388  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to enforce "
389  "serial %u for zone %s.\n", serial, tbd);
390  ods_writen(sockfd, buf, strlen(buf));
391  return;
392  }
393  zone->zonedata->enforced_serial = serial;
394  zone->zonedata->force_serial = 1;
395  }
398  task = unschedule_task(cmdc->engine->taskq, (task_type*) zone->task);
399  if (task != NULL) {
400  ods_log_debug("[%s] reschedule task for zone %s", cmdh_str,
401  zone->name);
402  if (task->what != TASK_READ) {
403  task->halted = task->what;
404  task->interrupt = TASK_READ;
405  }
406  task->what = TASK_READ;
407  task->when = time_now();
408  status = schedule_task(cmdc->engine->taskq, task, 0);
409  } else {
410  /* task now queued, being worked on? */
411  ods_log_verbose("[%s] worker busy with zone %s, will read "
412  "zone input as soon as possible", cmdh_str, zone->name);
413  task = (task_type*) zone->task;
414  task->interrupt = TASK_READ;
415  /* task->halted set by worker */
416  }
417  cmdc->engine->taskq->schedule_locked = 0;
419 
420  zone->task = task;
421  zone->zone_locked = 0;
423 
424  if (status != ODS_STATUS_OK) {
425  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Cannot schedule task for "
426  "zone %s.\n", tbd);
427  ods_writen(sockfd, buf, strlen(buf));
428  ods_log_crit("[%s] cannot schedule task for zone %s: %s",
429  cmdh_str, zone->name, ods_status2str(status));
430  task_cleanup(task);
431  zone->task = NULL;
432  } else {
433  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for immediate "
434  "re-sign.\n", tbd);
435  ods_writen(sockfd, buf, strlen(buf));
436  ods_log_verbose("[%s] zone %s scheduled for immediate re-sign",
437  cmdh_str, tbd);
439  }
440  }
441  return;
442 }
443 
444 
449 static void
450 unlink_backup_file(const char* filename, const char* extension)
451 {
452  char* tmpname = ods_build_path(filename, extension, 0, 1);
453  ods_log_debug("[%s] unlink file %s", cmdh_str, tmpname);
454  unlink(tmpname);
455  free((void*)tmpname);
456  return;
457 }
458 
463 static void
464 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd)
465 {
466  char buf[ODS_SE_MAXLINE];
467  zone_type* zone = NULL;
468  task_type* task = NULL;
469  uint32_t inbound_serial = 0;
470  uint32_t internal_serial = 0;
471  uint32_t outbound_serial = 0;
472  ods_status status = ODS_STATUS_OK;
473 
474  ods_log_assert(tbd);
475  ods_log_assert(cmdc);
476  ods_log_assert(cmdc->engine);
477 
478  unlink_backup_file(tbd, ".inbound");
479  unlink_backup_file(tbd, ".backup");
480 
483  zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd,
484  LDNS_RR_CLASS_IN);
485  cmdc->engine->zonelist->zl_locked = 0;
487  if (zone) {
488  lock_basic_lock(&zone->zone_lock);
490  inbound_serial = zone->zonedata->inbound_serial;
491  internal_serial = zone->zonedata->internal_serial;
492  outbound_serial = zone->zonedata->outbound_serial;
493  zonedata_cleanup(zone->zonedata);
494  zone->zonedata = NULL;
495  zone->zonedata = zonedata_create(zone->allocator);
496  zone->zonedata->initialized = 1;
497  zone->zonedata->inbound_serial = inbound_serial;
498  zone->zonedata->internal_serial = internal_serial;
499  zone->zonedata->outbound_serial = outbound_serial;
500 
505  lhsm_check_connection((void*)cmdc->engine);
506  status = zone_publish_dnskeys(zone, 1);
507  if (status == ODS_STATUS_OK) {
508  status = zone_prepare_nsec3(zone, 1);
509  } else {
510  ods_log_warning("[%s] unable to restore DNSKEY RRset for zone %s,"
511  " reloading signconf", cmdh_str, zone->name);
512  }
513  if (status == ODS_STATUS_OK) {
514  status = zonedata_commit(zone->zonedata);
515  } else {
516  ods_log_warning("[%s] unable to restore NSEC3PARAM RRset for "
517  " zone %s, reloading signconf", cmdh_str, zone->name);
518  }
519 
520  task = (task_type*) zone->task;
521  task->what = TASK_READ;
522  if (status != ODS_STATUS_OK) {
523  ods_log_warning("[%s] unable to restore DNSKEY/NSEC3PARAM RRset "
524  " for zone %s, reloading signconf", cmdh_str, zone->name);
525  task->what = TASK_SIGNCONF;
526  }
527  zone->zone_locked = 0;
529 
530  (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about "
531  "%s cleared", tbd?tbd:"(null)");
532  ods_log_info("[%s] internal zone information about %s cleared",
533  cmdh_str, tbd?tbd:"(null)");
534  } else {
535  (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not "
536  "found", tbd?tbd:"(null)");
537  ods_log_warning("[%s] cannot clear zone %s, zone not found",
538  cmdh_str, tbd?tbd:"(null)");
539  }
540 
541  ods_writen(sockfd, buf, strlen(buf));
542  return;
543 }
544 
545 
550 static void
551 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc)
552 {
553  char* strtime = NULL;
554  char buf[ODS_SE_MAXLINE];
555  size_t i = 0;
556  time_t now = 0;
557  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
558  task_type* task = NULL;
559 
560  ods_log_assert(cmdc);
561  ods_log_assert(cmdc->engine);
562  if (!cmdc->engine->taskq || !cmdc->engine->taskq->tasks) {
563  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no tasks scheduled.\n");
564  ods_writen(sockfd, buf, strlen(buf));
565  return;
566  }
567 
570  /* time */
571  now = time_now();
572  strtime = ctime(&now);
573  (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s",
574  strtime?strtime:"(null)");
575  ods_writen(sockfd, buf, strlen(buf));
576 
577  /* current work */
578  for (i=0; i < (size_t) cmdc->engine->config->num_worker_threads; i++) {
579  task = cmdc->engine->workers[i]->task;
580  if (task) {
581  (void)snprintf(buf, ODS_SE_MAXLINE, "Working with task %s on "
582  "zone %s\n",
584  task_who2str(task->who));
585  ods_writen(sockfd, buf, strlen(buf));
586  }
587  }
588 
589  /* how many tasks */
590  (void)snprintf(buf, ODS_SE_MAXLINE, "\nI have %i tasks scheduled.\n",
591  (int) cmdc->engine->taskq->tasks->count);
592  ods_writen(sockfd, buf, strlen(buf));
593 
594  /* list tasks */
595  node = ldns_rbtree_first(cmdc->engine->taskq->tasks);
596  while (node && node != LDNS_RBTREE_NULL) {
597  task = (task_type*) node->data;
598  for (i=0; i < ODS_SE_MAXLINE; i++) {
599  buf[i] = 0;
600  }
601  (void)task2str(task, (char*) &buf[0]);
602  ods_writen(sockfd, buf, strlen(buf));
603  node = ldns_rbtree_next(node);
604  }
605  cmdc->engine->taskq->schedule_locked = 0;
607  return;
608 }
609 
610 
615 static void
616 cmdhandler_handle_cmd_debuglocks(int sockfd, cmdhandler_type* cmdc)
617 {
618  char* strtime = NULL;
619  char buf[ODS_SE_MAXLINE];
620  size_t i = 0;
621  time_t now = 0;
622  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
623  zone_type* zone = NULL;
624 
625  ods_log_assert(cmdc);
626  ods_log_assert(cmdc->engine);
627  ods_log_assert(cmdc->engine->taskq);
628  /* time */
629  now = time_now();
630  strtime = ctime(&now);
631  (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s",
632  strtime?strtime:"(null)");
633  ods_writen(sockfd, buf, strlen(buf));
634  /* general */
635  (void)snprintf(buf, ODS_SE_MAXLINE, "- signal is %s[%i]\n",
636  cmdc->engine->signal_locked?"locked":"unlocked",
637  cmdc->engine->signal_locked);
638  ods_writen(sockfd, buf, strlen(buf));
639  (void)snprintf(buf, ODS_SE_MAXLINE, "- zone list is %s[%i]\n",
640  cmdc->engine->zonelist->zl_locked?"locked":"unlocked",
641  cmdc->engine->zonelist->zl_locked);
642  ods_writen(sockfd, buf, strlen(buf));
643  (void)snprintf(buf, ODS_SE_MAXLINE, "- task schedule is %s[%i]\n",
644  cmdc->engine->taskq->schedule_locked?"locked":"unlocked",
645  cmdc->engine->taskq->schedule_locked);
646  ods_writen(sockfd, buf, strlen(buf));
647  (void)snprintf(buf, ODS_SE_MAXLINE, "- rrset queue is %s[%i]\n",
648  cmdc->engine->signq->q_locked?"locked":"unlocked",
649  cmdc->engine->signq->q_locked);
650  ods_writen(sockfd, buf, strlen(buf));
651  /* workers */
652  for (i=0; i < (size_t) cmdc->engine->config->num_worker_threads; i++) {
653  (void)snprintf(buf, ODS_SE_MAXLINE, "- worker[%i] is %s[%i]\n",
654  cmdc->engine->workers[i]->thread_num,
655  cmdc->engine->workers[i]->worker_locked?"locked":"unlocked",
656  cmdc->engine->workers[i]->worker_locked);
657  ods_writen(sockfd, buf, strlen(buf));
658  }
659  /* drudgers */
660  for (i=0; i < (size_t) cmdc->engine->config->num_signer_threads; i++) {
661  (void)snprintf(buf, ODS_SE_MAXLINE, "- drudger[%i] is %s[%i]\n",
662  cmdc->engine->drudgers[i]->thread_num,
663  cmdc->engine->drudgers[i]->worker_locked?"locked":"unlocked",
664  cmdc->engine->drudgers[i]->worker_locked);
665  ods_writen(sockfd, buf, strlen(buf));
666  }
667  /* zones */
669  node = ldns_rbtree_first(cmdc->engine->zonelist->zones);
670  while (node && node != LDNS_RBTREE_NULL) {
671  zone = (zone_type*) node->data;
672  memset(buf, 0, ODS_SE_MAXLINE);
673  (void)snprintf(buf, ODS_SE_MAXLINE, "- %s is %s[%i], stats is %s[%i]\n",
674  zone->name,
675  zone->zone_locked?"locked":"unlocked",
676  zone->zone_locked,
677  zone->stats->stats_locked?"locked":"unlocked",
678  zone->stats->stats_locked);
679  ods_writen(sockfd, buf, strlen(buf));
680  node = ldns_rbtree_next(node);
681  }
683  return;
684 }
685 
686 
691 static void
692 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc)
693 {
694  char buf[ODS_SE_MAXLINE];
695 
696  ods_log_assert(cmdc);
697  ods_log_assert(cmdc->engine);
698  ods_log_assert(cmdc->engine->taskq);
699 
703  cmdc->engine->taskq->schedule_locked = 0;
705 
707 
708  (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n");
709  ods_writen(sockfd, buf, strlen(buf));
710  ods_log_verbose("[%s] all tasks scheduled immediately", cmdh_str);
711  return;
712 }
713 
714 
719 static void
720 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc)
721 {
722  char buf[ODS_SE_MAXLINE];
723 
724  ods_log_assert(cmdc);
725  ods_log_assert(cmdc->engine);
726 
727  cmdc->engine->need_to_reload = 1;
728 
732  cmdc->engine->signal_locked = 0;
734 
735  (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n");
736  ods_writen(sockfd, buf, strlen(buf));
737  return;
738 }
739 
740 
745 static void
746 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc)
747 {
748  char buf[ODS_SE_MAXLINE];
749 
750  ods_log_assert(cmdc);
751  ods_log_assert(cmdc->engine);
752 
753  cmdc->engine->need_to_exit = 1;
754 
758  cmdc->engine->signal_locked = 0;
760 
761  (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE);
762  ods_writen(sockfd, buf, strlen(buf));
763  return;
764 }
765 
766 
771 static void
772 cmdhandler_handle_cmd_start(int sockfd)
773 {
774  char buf[ODS_SE_MAXLINE];
775 
776  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n");
777  ods_writen(sockfd, buf, strlen(buf));
778  return;
779 }
780 
781 
786 static void
787 cmdhandler_handle_cmd_running(int sockfd)
788 {
789  char buf[ODS_SE_MAXLINE];
790 
791  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n");
792  ods_writen(sockfd, buf, strlen(buf));
793  return;
794 }
795 
796 
801 static void
802 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val)
803 {
804  char buf[ODS_SE_MAXLINE];
805 
806  ods_log_assert(cmdc);
807  ods_log_assert(cmdc->engine);
808  ods_log_assert(cmdc->engine->config);
809 
811  cmdc->engine->config->use_syslog, val);
812 
813  (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val);
814  ods_writen(sockfd, buf, strlen(buf));
815 }
816 
817 
822 static void
823 cmdhandler_handle_cmd_error(int sockfd, const char* str)
824 {
825  char buf[ODS_SE_MAXLINE];
826  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)");
827  ods_writen(sockfd, buf, strlen(buf));
828  return;
829 }
830 
831 
836 static void
837 cmdhandler_handle_cmd_unknown(int sockfd, const char* str)
838 {
839  char buf[ODS_SE_MAXLINE];
840  (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n",
841  str?str:"(null)");
842  ods_writen(sockfd, buf, strlen(buf));
843  return;
844 }
845 
846 
865 static void
866 cmdhandler_handle_cmd(cmdhandler_type* cmdc)
867 {
868  ssize_t n = 0;
869  int sockfd = 0;
870  char buf[ODS_SE_MAXLINE];
871 
872  ods_log_assert(cmdc);
873  sockfd = cmdc->client_fd;
874 
875 again:
876  while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) {
877  buf[n-1] = '\0';
878  n--;
879  if (n <= 0) {
880  return;
881  }
882  ods_log_verbose("[%s] received command %s[%i]", cmdh_str, buf, n);
883 
884  if (n == 4 && strncmp(buf, "help", n) == 0) {
885  ods_log_debug("[%s] help command", cmdh_str);
886  cmdhandler_handle_cmd_help(sockfd);
887  } else if (n == 5 && strncmp(buf, "zones", n) == 0) {
888  ods_log_debug("[%s] list zones command", cmdh_str);
889  cmdhandler_handle_cmd_zones(sockfd, cmdc);
890  } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) {
891  ods_log_debug("[%s] sign zone command", cmdh_str);
892  if (buf[4] == '\0') {
893  /* NOTE: wouldn't it be nice that we default to --all? */
894  cmdhandler_handle_cmd_error(sockfd, "sign command needs "
895  "an argument (either '--all' or a zone name)");
896  } else if (buf[4] != ' ') {
897  cmdhandler_handle_cmd_unknown(sockfd, buf);
898  } else {
899  cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]);
900  }
901  } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) {
902  ods_log_debug("[%s] clear zone command", cmdh_str);
903  if (buf[5] == '\0') {
904  cmdhandler_handle_cmd_error(sockfd, "clear command needs "
905  "a zone name");
906  } else if (buf[5] != ' ') {
907  cmdhandler_handle_cmd_unknown(sockfd, buf);
908  } else {
909  cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]);
910  }
911  } else if (n == 5 && strncmp(buf, "queue", n) == 0) {
912  ods_log_debug("[%s] list tasks command", cmdh_str);
913  cmdhandler_handle_cmd_queue(sockfd, cmdc);
914  } else if (n == 11 && strncmp(buf, "debug-locks", n) == 0) {
915  ods_log_debug("[%s] debug locks command", cmdh_str);
916  cmdhandler_handle_cmd_debuglocks(sockfd, cmdc);
917  } else if (n == 5 && strncmp(buf, "flush", n) == 0) {
918  ods_log_debug("[%s] flush tasks command", cmdh_str);
919  cmdhandler_handle_cmd_flush(sockfd, cmdc);
920  } else if (n >= 6 && strncmp(buf, "update", 6) == 0) {
921  ods_log_debug("[%s] update command", cmdh_str);
922  if (buf[6] == '\0') {
923  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
924  } else if (buf[6] != ' ') {
925  cmdhandler_handle_cmd_unknown(sockfd, buf);
926  } else {
927  cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]);
928  }
929  } else if (n == 4 && strncmp(buf, "stop", n) == 0) {
930  ods_log_debug("[%s] shutdown command", cmdh_str);
931  cmdhandler_handle_cmd_stop(sockfd, cmdc);
932  return;
933  } else if (n == 5 && strncmp(buf, "start", n) == 0) {
934  ods_log_debug("[%s] start command", cmdh_str);
935  cmdhandler_handle_cmd_start(sockfd);
936  } else if (n == 6 && strncmp(buf, "reload", n) == 0) {
937  ods_log_debug("[%s] reload command", cmdh_str);
938  cmdhandler_handle_cmd_reload(sockfd, cmdc);
939  } else if (n == 7 && strncmp(buf, "running", n) == 0) {
940  ods_log_debug("[%s] running command", cmdh_str);
941  cmdhandler_handle_cmd_running(sockfd);
942  } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) {
943  ods_log_debug("[%s] verbosity command", cmdh_str);
944  if (buf[9] == '\0') {
945  cmdhandler_handle_cmd_error(sockfd, "verbosity command "
946  "an argument (verbosity level)");
947  } else if (buf[9] != ' ') {
948  cmdhandler_handle_cmd_unknown(sockfd, buf);
949  } else {
950  cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10]));
951  }
952  } else {
953  ods_log_debug("[%s] unknown command", cmdh_str);
954  cmdhandler_handle_cmd_unknown(sockfd, buf);
955  }
956 
957  ods_log_debug("[%s] done handling command %s[%i]", cmdh_str, buf, n);
958  (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> ");
959  ods_writen(sockfd, buf, strlen(buf));
960  }
961 
962  if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) {
963  goto again;
964  } else if (n < 0 && errno == ECONNRESET) {
965  ods_log_debug("[%s] done handling client: %s", cmdh_str,
966  strerror(errno));
967  } else if (n < 0 ) {
968  ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno));
969  }
970  return;
971 }
972 
973 
978 static void*
979 cmdhandler_accept_client(void* arg)
980 {
981  cmdhandler_type* cmdc = (cmdhandler_type*) arg;
982 
985 
986  ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd);
987  cmdhandler_handle_cmd(cmdc);
988  if (cmdc->client_fd) {
989  shutdown(cmdc->client_fd, SHUT_RDWR);
990  close(cmdc->client_fd);
991  }
992  free(cmdc);
993  count--;
994  return NULL;
995 }
996 
997 
1003 cmdhandler_create(allocator_type* allocator, const char* filename)
1004 {
1005  cmdhandler_type* cmdh = NULL;
1006  struct sockaddr_un servaddr;
1007  int listenfd = 0;
1008  int flags = 0;
1009  int ret = 0;
1010 
1011  if (!allocator) {
1012  ods_log_error("[%s] unable to create: no allocator", cmdh_str);
1013  return NULL;
1014  }
1015  ods_log_assert(allocator);
1016 
1017  if (!filename) {
1018  ods_log_error("[%s] unable to create: no socket filename", cmdh_str);
1019  return NULL;
1020  }
1021  ods_log_assert(filename);
1022  ods_log_debug("[%s] create socket %s", cmdh_str, filename);
1023 
1024  /* new socket */
1025  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
1026  if (listenfd <= 0) {
1027  ods_log_error("[%s] unable to create, socket() failed: %s", cmdh_str,
1028  strerror(errno));
1029  return NULL;
1030  }
1031  /* set it to non-blocking */
1032  flags = fcntl(listenfd, F_GETFL, 0);
1033  if (flags < 0) {
1034  ods_log_error("[%s] unable to create, fcntl(F_GETFL) failed: %s",
1035  cmdh_str, strerror(errno));
1036  close(listenfd);
1037  return NULL;
1038  }
1039  flags |= O_NONBLOCK;
1040  if (fcntl(listenfd, F_SETFL, flags) < 0) {
1041  ods_log_error("[%s] unable to create, fcntl(F_SETFL) failed: %s",
1042  cmdh_str, strerror(errno));
1043  close(listenfd);
1044  return NULL;
1045  }
1046 
1047  /* no surprises */
1048  if (filename) {
1049  unlink(filename);
1050  }
1051  bzero(&servaddr, sizeof(servaddr));
1052  servaddr.sun_family = AF_UNIX;
1053  strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1);
1054 
1055  /* bind and listen... */
1056  ret = bind(listenfd, (const struct sockaddr*) &servaddr,
1057  SUN_LEN(&servaddr));
1058  if (ret != 0) {
1059  ods_log_error("[%s] unable to create, bind() failed: %s", cmdh_str,
1060  strerror(errno));
1061  close(listenfd);
1062  return NULL;
1063  }
1064  ret = listen(listenfd, ODS_SE_MAX_HANDLERS);
1065  if (ret != 0) {
1066  ods_log_error("[%s] unable to create, listen() failed: %s", cmdh_str,
1067  strerror(errno));
1068  close(listenfd);
1069  return NULL;
1070  }
1071 
1072  /* all ok */
1073  cmdh = (cmdhandler_type*) allocator_alloc(allocator,
1074  sizeof(cmdhandler_type));
1075  if (!cmdh) {
1076  close(listenfd);
1077  return NULL;
1078  }
1079  cmdh->allocator = allocator;
1080  cmdh->listen_fd = listenfd;
1081  cmdh->listen_addr = servaddr;
1082  cmdh->need_to_exit = 0;
1083  return cmdh;
1084 }
1085 
1086 
1091 void
1093 {
1094  struct sockaddr_un cliaddr;
1095  socklen_t clilen;
1096  cmdhandler_type* cmdc = NULL;
1097  engine_type* engine = NULL;
1098  fd_set rset;
1099  int connfd = 0;
1100  int ret = 0;
1101 
1102  ods_log_assert(cmdhandler);
1103  ods_log_assert(cmdhandler->engine);
1104  ods_log_debug("[%s] start", cmdh_str);
1105 
1106  engine = cmdhandler->engine;
1107  ods_thread_detach(cmdhandler->thread_id);
1108  FD_ZERO(&rset);
1109  while (cmdhandler->need_to_exit == 0) {
1110  clilen = sizeof(cliaddr);
1111  FD_SET(cmdhandler->listen_fd, &rset);
1112  ret = select(cmdhandler->listen_fd+1, &rset, NULL, NULL, NULL);
1113  if (ret < 0) {
1114  if (errno != EINTR && errno != EWOULDBLOCK) {
1115  ods_log_warning("[%s] select() error: %s", cmdh_str,
1116  strerror(errno));
1117  }
1118  continue;
1119  }
1120  if (FD_ISSET(cmdhandler->listen_fd, &rset)) {
1121  connfd = accept(cmdhandler->listen_fd,
1122  (struct sockaddr *) &cliaddr, &clilen);
1123  if (connfd < 0) {
1124  if (errno != EINTR && errno != EWOULDBLOCK) {
1125  ods_log_warning("[%s] accept error: %s", cmdh_str,
1126  strerror(errno));
1127  }
1128  continue;
1129  }
1130  /* client accepted, create new thread */
1131  cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type));
1132  if (!cmdc) {
1133  ods_log_crit("[%s] unable to create thread for client: "
1134  "malloc failed", cmdh_str);
1135  cmdhandler->need_to_exit = 1;
1136  break;
1137  }
1138  cmdc->listen_fd = cmdhandler->listen_fd;
1139  cmdc->client_fd = connfd;
1140  cmdc->listen_addr = cmdhandler->listen_addr;
1141  cmdc->engine = cmdhandler->engine;
1142  cmdc->need_to_exit = cmdhandler->need_to_exit;
1143  ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client,
1144  (void*) cmdc);
1145  count++;
1146  ods_log_debug("[%s] %i clients in progress...", cmdh_str, count);
1147  }
1148  }
1149 
1150  ods_log_debug("[%s] done", cmdh_str);
1151  engine = cmdhandler->engine;
1152  engine->cmdhandler_done = 1;
1153  return;
1154 }
1155 
1156 
1161 void
1163 {
1164  allocator_type* allocator;
1165  if (!cmdhandler) {
1166  return;
1167  }
1168  allocator = cmdhandler->allocator;
1169  allocator_deallocate(allocator, (void*) cmdhandler);
1170  return;
1171 }
1172 
uint32_t outbound_serial
Definition: zonedata.h:68
int num_signer_threads
Definition: cfg.h:67
Definition: task.h:43
void zonedata_cleanup(zonedata_type *zd)
Definition: zonedata.c:1564
#define DNS_SERIAL_GT(a, b)
Definition: util.h:52
#define LOCKED_ZL_CMD_UPDATE
Definition: locks.h:56
zonelist_type * zonelist
Definition: engine.h:60
void ods_thread_blocksigs(void)
Definition: locks.c:150
void engine_wakeup_workers(engine_type *engine)
Definition: engine.c:381
int force_serial
Definition: zonedata.h:64
#define LOCKED_ZONE_CMD_SIGN
Definition: locks.h:77
void ods_log_debug(const char *format,...)
Definition: log.c:285
time_t when
Definition: task.h:62
uint32_t internal_serial
Definition: zonedata.h:67
int just_updated
Definition: zonelist.h:55
cond_basic_type signal_cond
Definition: engine.h:76
task_id interrupt
Definition: task.h:60
int schedule_locked
Definition: schedule.h:66
#define SUN_LEN(su)
Definition: cmdhandler.c:66
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:67
const char * zonelist_filename
Definition: cfg.h:54
void lhsm_check_connection(void *engine)
Definition: hsm.c:114
cmdhandler_type * cmdhandler_create(allocator_type *allocator, const char *filename)
Definition: cmdhandler.c:1003
struct engine_struct * engine
Definition: cmdhandler.h:51
zonedata_type * zonedata_create(allocator_type *allocator)
Definition: zonedata.c:165
#define LOCKED_ZL_CMD_CLEAR
Definition: locks.h:59
ods_status schedule_task(schedule_type *schedule, task_type *task, int log)
Definition: schedule.c:154
void ods_log_info(const char *format,...)
Definition: log.c:317
ldns_rbtree_t * zones
Definition: zonelist.h:52
enum ods_enum_status ods_status
Definition: status.h:64
lock_basic_type zone_lock
Definition: zone.h:93
int worker_locked
Definition: worker.h:70
#define LOCKED_SCHEDULE_CMD_SIGN_ALL
Definition: locks.h:62
ods_status zone_publish_dnskeys(zone_type *zone, int recover)
Definition: zone.c:510
void schedule_flush(schedule_type *schedule, task_id override)
Definition: schedule.c:84
ods_thread_type thread_id
Definition: cmdhandler.h:53
void ods_log_error(const char *format,...)
Definition: log.c:349
#define LOCKED_SCHEDULE_CMD_FLUSH
Definition: locks.h:64
const char * ods_status2str(ods_status status)
Definition: status.c:84
int ods_strcmp(const char *s1, const char *s2)
Definition: file.c:317
int just_removed
Definition: zonelist.h:56
void cmdhandler_start(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:1092
void engine_update_zones(engine_type *engine)
Definition: engine.c:812
int q_locked
Definition: fifoq.h:70
struct sockaddr_un listen_addr
Definition: cmdhandler.h:52
#define LOCKED_ZL_CMD_UPDATE_ALL
Definition: locks.h:57
uint32_t enforced_serial
Definition: zonedata.h:69
#define ODS_SE_MAX_HANDLERS
Definition: cmdhandler.h:43
void ods_log_crit(const char *format,...)
Definition: log.c:365
const char * log_filename
Definition: cfg.h:56
lock_basic_type signal_lock
Definition: engine.h:77
task_type * task
Definition: worker.h:58
#define LOCKED_SCHEDULE_CMD_QUEUE
Definition: locks.h:63
#define lock_basic_lock(lock)
Definition: locks.h:154
engineconfig_type * config
Definition: engine.h:57
#define LOCKED_SIGNAL_CMD_RELOAD
Definition: locks.h:53
int num_worker_threads
Definition: cfg.h:66
Definition: task.h:45
#define LOCKED_ZL_CMD_SIGN
Definition: locks.h:58
worker_type ** workers
Definition: engine.h:58
#define SE_CMDH_CMDLEN
Definition: cmdhandler.c:63
worker_type ** drudgers
Definition: engine.h:59
task_id halted
Definition: task.h:61
ssize_t ods_writen(int fd, const void *vptr, size_t n)
Definition: file.c:259
allocator_type * allocator
Definition: cmdhandler.h:50
void task_cleanup(task_type *task)
Definition: task.c:169
const char * who
Definition: task.h:65
task_type * unschedule_task(schedule_type *schedule, task_type *task)
Definition: schedule.c:204
int zone_locked
Definition: zone.h:94
allocator_type * allocator
Definition: zone.h:58
const char * task_what2str(int what)
Definition: task.c:222
#define LOCKED_ZONE_CMD_CLEAR
Definition: locks.h:78
char * ods_build_path(const char *file, const char *suffix, int dir, int no_slash)
Definition: file.c:128
#define ods_thread_detach(thr)
Definition: locks.h:165
const char * task_who2str(const char *who)
Definition: task.c:259
int use_syslog
Definition: cfg.h:64
void ods_log_verbose(const char *format,...)
Definition: log.c:301
#define LOCKED_SCHEDULE_CMD_SIGN
Definition: locks.h:61
task_id what
Definition: task.h:59
ldns_rbtree_t * tasks
Definition: schedule.h:62
int thread_num
Definition: worker.h:55
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:181
#define LOCKED_ZONE_CMD_UPDATE
Definition: locks.h:76
uint32_t inbound_serial
Definition: zonedata.h:66
const char * name
Definition: zone.h:67
ods_status zonedata_commit(zonedata_type *zd)
Definition: zonedata.c:687
schedule_type * taskq
Definition: engine.h:61
ods_status zone_prepare_nsec3(zone_type *zone, int recover)
Definition: zone.c:616
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:136
int stats_locked
Definition: stats.h:70
task_id working_with
Definition: worker.h:59
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:371
char * task2str(task_type *task, char *buftask)
Definition: task.c:273
lock_basic_type schedule_lock
Definition: schedule.h:65
int need_to_exit
Definition: engine.h:72
void * task
Definition: zone.h:88
fifoq_type * signq
Definition: engine.h:62
int signal_locked
Definition: engine.h:78
zonedata_type * zonedata
Definition: zone.h:85
#define ods_log_assert(x)
Definition: log.h:141
#define ods_thread_create(thr, func, arg)
Definition: locks.h:164
void ods_log_init(const char *filename, int use_syslog, int verbosity)
Definition: log.c:96
int just_added
Definition: zone.h:70
int need_to_reload
Definition: engine.h:73
#define lock_basic_alarm(cond)
Definition: locks.h:159
#define lock_basic_unlock(lock)
Definition: locks.h:155
void ods_log_warning(const char *format,...)
Definition: log.c:333
#define LOCKED_SCHEDULE_CMD_UPDATE
Definition: locks.h:60
#define LOCKED_SIGNAL_CMD_STOP
Definition: locks.h:54
void cmdhandler_cleanup(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:1162
lock_basic_type zl_lock
Definition: zonelist.h:57
int cmdhandler_done
Definition: engine.h:64
time_t time_now(void)
Definition: duration.c:479
stats_type * stats
Definition: zone.h:91
#define LOCKED_ZL_CMD_ZONES
Definition: locks.h:55