OpenDNSSEC-signer  1.4.6
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 "shared/allocator.h"
35 #include "shared/file.h"
36 #include "shared/locks.h"
37 #include "shared/log.h"
38 #include "shared/status.h"
39 #include "shared/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 #ifndef SUN_LEN
61 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
62 #endif
63 
64 static int count = 0;
65 static char* cmdh_str = "cmdhandler";
66 
67 
72 static void
73 cmdhandler_handle_cmd_help(int sockfd)
74 {
75  char buf[ODS_SE_MAXLINE];
76 
77  (void) snprintf(buf, ODS_SE_MAXLINE,
78  "Commands:\n"
79  "zones Show the currently known zones.\n"
80  "sign <zone> [--serial <nr>] Read zone and schedule for immediate "
81  "(re-)sign.\n"
82  " If a serial is given, that serial is used "
83  "in the output zone.\n"
84  "sign --all Read all zones and schedule all for "
85  "immediate (re-)sign.\n"
86  );
87  ods_writen(sockfd, buf, strlen(buf));
88 
89  (void) snprintf(buf, ODS_SE_MAXLINE,
90  "clear <zone> Delete the internal storage of this "
91  "zone.\n"
92  " All signatures will be regenerated "
93  "on the next re-sign.\n"
94  "queue Show the current task queue.\n"
95  "flush Execute all scheduled tasks "
96  "immediately.\n"
97  );
98  ods_writen(sockfd, buf, strlen(buf));
99 
100  (void) snprintf(buf, ODS_SE_MAXLINE,
101  "update <zone> Update this zone signer "
102  "configurations.\n"
103  "update [--all] Update zone list and all signer "
104  "configurations.\n"
105  "retransfer <zone> Retransfer the zone from the master.\n"
106  "start Start the engine.\n"
107  "running Check if the engine is running.\n"
108  "reload Reload the engine.\n"
109  "stop Stop the engine.\n"
110  "verbosity <nr> Set verbosity.\n"
111  );
112  ods_writen(sockfd, buf, strlen(buf));
113  return;
114 }
115 
116 
121 static void
122 cmdhandler_handle_cmd_zones(int sockfd, cmdhandler_type* cmdc)
123 {
124  engine_type* engine = NULL;
125  char buf[ODS_SE_MAXLINE];
126  size_t i;
127  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
128  zone_type* zone = NULL;
129  ods_log_assert(cmdc);
130  ods_log_assert(cmdc->engine);
131  engine = (engine_type*) cmdc->engine;
132  if (!engine->zonelist || !engine->zonelist->zones) {
133  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no zones configured\n");
134  ods_writen(sockfd, buf, strlen(buf));
135  return;
136  }
137  /* how many zones */
138  lock_basic_lock(&engine->zonelist->zl_lock);
139  (void)snprintf(buf, ODS_SE_MAXLINE, "I have %i zones configured\n",
140  (int) engine->zonelist->zones->count);
141  ods_writen(sockfd, buf, strlen(buf));
142  /* list zones */
143  node = ldns_rbtree_first(engine->zonelist->zones);
144  while (node && node != LDNS_RBTREE_NULL) {
145  zone = (zone_type*) node->data;
146  for (i=0; i < ODS_SE_MAXLINE; i++) {
147  buf[i] = 0;
148  }
149  (void)snprintf(buf, ODS_SE_MAXLINE, "- %s\n", zone->name);
150  ods_writen(sockfd, buf, strlen(buf));
151  node = ldns_rbtree_next(node);
152  }
154  return;
155 }
156 
157 
162 static void
163 cmdhandler_handle_cmd_update(int sockfd, cmdhandler_type* cmdc,
164  const char* tbd)
165 {
166  engine_type* engine = NULL;
167  char buf[ODS_SE_MAXLINE];
168  ods_status status = ODS_STATUS_OK;
169  zone_type* zone = NULL;
170  ods_status zl_changed = ODS_STATUS_OK;
171  ods_log_assert(tbd);
172  ods_log_assert(cmdc);
173  ods_log_assert(cmdc->engine);
174  engine = (engine_type*) cmdc->engine;
175  ods_log_assert(engine->taskq);
176  if (ods_strcmp(tbd, "--all") == 0) {
177  lock_basic_lock(&engine->zonelist->zl_lock);
178  zl_changed = zonelist_update(engine->zonelist,
179  engine->config->zonelist_filename);
180  if (zl_changed == ODS_STATUS_UNCHANGED) {
181  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has not changed."
182  " Signer configurations updated.\n");
183  ods_writen(sockfd, buf, strlen(buf));
184  } else if (zl_changed == ODS_STATUS_OK) {
185  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list updated: %i "
186  "removed, %i added, %i updated.\n",
187  engine->zonelist->just_removed,
188  engine->zonelist->just_added,
189  engine->zonelist->just_updated);
190  ods_writen(sockfd, buf, strlen(buf));
191  } else {
193  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has errors.\n");
194  ods_writen(sockfd, buf, strlen(buf));
195  }
196  if (zl_changed == ODS_STATUS_OK ||
197  zl_changed == ODS_STATUS_UNCHANGED) {
198  engine->zonelist->just_removed = 0;
199  engine->zonelist->just_added = 0;
200  engine->zonelist->just_updated = 0;
207  }
208  return;
209  } else {
210  /* look up zone */
211  lock_basic_lock(&engine->zonelist->zl_lock);
212  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
213  LDNS_RR_CLASS_IN);
214  /* If this zone is just added, don't update (it might not have a
215  * task yet) */
216  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
217  zone = NULL;
218  }
220 
221  if (!zone) {
222  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
223  tbd);
224  ods_writen(sockfd, buf, strlen(buf));
225  /* update all */
226  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
227  return;
228  }
229 
230  lock_basic_lock(&zone->zone_lock);
231  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
233 
234  if (status != ODS_STATUS_OK) {
235  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
236  "task for zone %s.\n", tbd);
237  ods_writen(sockfd, buf, strlen(buf));
238  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
239  cmdh_str, zone->name, ods_status2str(status));
240  } else {
241  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s config being updated.\n",
242  tbd);
243  ods_writen(sockfd, buf, strlen(buf));
244  ods_log_verbose("[%s] zone %s scheduled for immediate update signconf",
245  cmdh_str, tbd);
246  engine_wakeup_workers(engine);
247  }
248  }
249  return;
250 }
251 
252 
257 static void
258 cmdhandler_handle_cmd_retransfer(int sockfd, cmdhandler_type* cmdc, char* tbd)
259 {
260  engine_type* engine = NULL;
261  char buf[ODS_SE_MAXLINE];
262  zone_type* zone = NULL;
263  ods_log_assert(tbd);
264  ods_log_assert(cmdc);
265  ods_log_assert(cmdc->engine);
266  engine = (engine_type*) cmdc->engine;
267  ods_log_assert(engine->taskq);
268  /* look up zone */
269  lock_basic_lock(&engine->zonelist->zl_lock);
270  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
271  LDNS_RR_CLASS_IN);
272  /* If this zone is just added, don't retransfer (it might not have a
273  * task yet) */
274  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
275  zone = NULL;
276  }
278 
279  if (!zone) {
280  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
281  tbd);
282  ods_writen(sockfd, buf, strlen(buf));
283  return;
284  }
285  zone->xfrd->serial_retransfer = 1;
286  xfrd_set_timer_now(zone->xfrd);
287  ods_log_debug("[%s] forward a notify", cmdh_str);
289  (uint8_t*) ODS_SE_NOTIFY_CMD, strlen(ODS_SE_NOTIFY_CMD));
290  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s being retransferred.\n", tbd);
291  ods_writen(sockfd, buf, strlen(buf));
292  ods_log_verbose("[%s] zone %s being retransferred", cmdh_str, tbd);
293  return;
294 }
295 
296 
297 static uint32_t
298 max(uint32_t a, uint32_t b)
299 {
300  return (a<b?b:a);
301 }
302 
303 
308 static void
309 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd)
310 {
311  engine_type* engine = NULL;
312  zone_type* zone = NULL;
313  ods_status status = ODS_STATUS_OK;
314  char buf[ODS_SE_MAXLINE];
315 
316  ods_log_assert(tbd);
317  ods_log_assert(cmdc);
318  ods_log_assert(cmdc->engine);
319  engine = (engine_type*) cmdc->engine;
320  ods_log_assert(engine->taskq);
321  if (ods_strcmp(tbd, "--all") == 0) {
323  schedule_flush(engine->taskq, TASK_READ);
325  engine_wakeup_workers(engine);
326  (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for "
327  "immediate re-sign.\n");
328  ods_writen(sockfd, buf, strlen(buf));
329  ods_log_verbose("[%s] all zones scheduled for immediate re-sign",
330  cmdh_str);
331  return;
332  } else {
333  char* delim1 = strchr(tbd, ' ');
334  char* delim2 = NULL;
335  int force_serial = 0;
336  uint32_t serial = 0;
337  if (delim1) {
338  char* end = NULL;
340  if (strncmp(delim1+1, "--serial ", 9) != 0) {
341  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting <zone> "
342  "--serial <nr>, got %s.\n", tbd);
343  ods_writen(sockfd, buf, strlen(buf));
344  return;
345  }
346  delim2 = strchr(delim1+1, ' ');
347  if (!delim2) {
348  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial.\n");
349  ods_writen(sockfd, buf, strlen(buf));
350  return;
351  }
352  serial = (uint32_t) strtol(delim2+1, &end, 10);
353  if (*end != '\0') {
354  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial, "
355  "got %s.\n", delim2+1);
356  ods_writen(sockfd, buf, strlen(buf));
357  return;
358  }
359  force_serial = 1;
360  *delim1 = '\0';
361  }
362  lock_basic_lock(&engine->zonelist->zl_lock);
363  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
364  LDNS_RR_CLASS_IN);
365  /* If this zone is just added, don't update (it might not have a task
366  * yet).
367  */
368  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
369  zone = NULL;
370  }
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);
381  if (force_serial) {
382  ods_log_assert(zone->db);
383  if (!util_serial_gt(serial, max(zone->db->outserial,
384  zone->db->inbserial))) {
386  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to enforce "
387  "serial %u for zone %s.\n", serial, tbd);
388  ods_writen(sockfd, buf, strlen(buf));
389  return;
390  }
391  zone->db->altserial = serial;
392  zone->db->force_serial = 1;
393  }
394  status = zone_reschedule_task(zone, engine->taskq, TASK_READ);
396 
397  if (status != ODS_STATUS_OK) {
398  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
399  "task for zone %s.\n", tbd);
400  ods_writen(sockfd, buf, strlen(buf));
401  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
402  cmdh_str, zone->name, ods_status2str(status));
403  } else {
404  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for "
405  "immediate re-sign.\n", tbd);
406  ods_writen(sockfd, buf, strlen(buf));
407  ods_log_verbose("[%s] zone %s scheduled for immediate re-sign",
408  cmdh_str, tbd);
409  engine_wakeup_workers(engine);
410  }
411  }
412  return;
413 }
414 
415 
420 static void
421 unlink_backup_file(const char* filename, const char* extension)
422 {
423  char* tmpname = ods_build_path(filename, extension, 0, 1);
424  if (tmpname) {
425  ods_log_debug("[%s] unlink file %s", cmdh_str, tmpname);
426  unlink(tmpname);
427  free((void*)tmpname);
428  }
429  return;
430 }
431 
436 static void
437 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd)
438 {
439  ods_status status = ODS_STATUS_OK;
440  engine_type* engine = NULL;
441  char buf[ODS_SE_MAXLINE];
442  zone_type* zone = NULL;
443  uint32_t inbserial = 0;
444  uint32_t intserial = 0;
445  uint32_t outserial = 0;
446  ods_log_assert(tbd);
447  ods_log_assert(cmdc);
448  ods_log_assert(cmdc->engine);
449  engine = (engine_type*) cmdc->engine;
450  unlink_backup_file(tbd, ".inbound");
451  unlink_backup_file(tbd, ".backup");
452  unlink_backup_file(tbd, ".axfr");
453  unlink_backup_file(tbd, ".ixfr");
454  lock_basic_lock(&engine->zonelist->zl_lock);
455  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
456  LDNS_RR_CLASS_IN);
458  if (zone) {
459  lock_basic_lock(&zone->zone_lock);
460  inbserial = zone->db->inbserial;
461  intserial = zone->db->intserial;
462  outserial = zone->db->outserial;
463  namedb_cleanup(zone->db);
464  ixfr_cleanup(zone->ixfr);
465  signconf_cleanup(zone->signconf);
466 
467  zone->db = namedb_create((void*)zone);
468  zone->ixfr = ixfr_create((void*)zone);
469  zone->signconf = signconf_create();
470 
471  if (!zone->signconf || !zone->ixfr || !zone->db) {
472  ods_fatal_exit("[%s] unable to clear zone %s: failed to recreate"
473  "signconf, ixfr of db structure (out of memory?)", cmdh_str, tbd);
474  return;
475  }
476  /* restore serial management */
477  zone->db->inbserial = inbserial;
478  zone->db->intserial = intserial;
479  zone->db->outserial = outserial;
480  zone->db->have_serial = 1;
481 
482  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
484 
485  if (status != ODS_STATUS_OK) {
486  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
487  "task for zone %s.\n", tbd);
488  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
489  cmdh_str, zone->name, ods_status2str(status));
490  } else {
491  (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about "
492  "%s cleared", tbd?tbd:"(null)");
493  ods_log_info("[%s] internal zone information about %s cleared",
494  cmdh_str, tbd?tbd:"(null)");
495  }
496  } else {
497  (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not "
498  "found", tbd?tbd:"(null)");
499  ods_log_warning("[%s] cannot clear zone %s, zone not found",
500  cmdh_str, tbd?tbd:"(null)");
501  }
502  ods_writen(sockfd, buf, strlen(buf));
503  return;
504 }
505 
506 
511 static void
512 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc)
513 {
514  engine_type* engine = NULL;
515  char* strtime = NULL;
516  char buf[ODS_SE_MAXLINE];
517  size_t i = 0;
518  time_t now = 0;
519  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
520  task_type* task = NULL;
521  ods_log_assert(cmdc);
522  ods_log_assert(cmdc->engine);
523  engine = (engine_type*) cmdc->engine;
524  if (!engine->taskq || !engine->taskq->tasks) {
525  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no tasks scheduled.\n");
526  ods_writen(sockfd, buf, strlen(buf));
527  return;
528  }
529  /* current time */
530  now = time_now();
531  strtime = ctime(&now);
532  (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s",
533  strtime?strtime:"(null)");
534  ods_writen(sockfd, buf, strlen(buf));
535  /* current work */
537  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
538  task = engine->workers[i]->task;
539  if (task) {
540  (void)snprintf(buf, ODS_SE_MAXLINE, "Working with task %s on "
541  "zone %s\n",
542  task_what2str(engine->workers[i]->working_with),
543  task_who2str(task));
544  ods_writen(sockfd, buf, strlen(buf));
545  }
546  }
547  /* how many tasks */
548  (void)snprintf(buf, ODS_SE_MAXLINE, "\nI have %i tasks scheduled.\n",
549  (int) engine->taskq->tasks->count);
550  ods_writen(sockfd, buf, strlen(buf));
551  /* list tasks */
552  node = ldns_rbtree_first(engine->taskq->tasks);
553  while (node && node != LDNS_RBTREE_NULL) {
554  task = (task_type*) node->data;
555  for (i=0; i < ODS_SE_MAXLINE; i++) {
556  buf[i] = 0;
557  }
558  (void)task2str(task, (char*) &buf[0]);
559  ods_writen(sockfd, buf, strlen(buf));
560  node = ldns_rbtree_next(node);
561  }
563  return;
564 }
565 
566 
571 static void
572 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc)
573 {
574  engine_type* engine = NULL;
575  char buf[ODS_SE_MAXLINE];
576  ods_log_assert(cmdc);
577  ods_log_assert(cmdc->engine);
578  engine = (engine_type*) cmdc->engine;
579  ods_log_assert(engine->taskq);
581  schedule_flush(engine->taskq, TASK_NONE);
583  engine_wakeup_workers(engine);
584  (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n");
585  ods_writen(sockfd, buf, strlen(buf));
586  ods_log_verbose("[%s] all tasks scheduled immediately", cmdh_str);
587  return;
588 }
589 
590 
595 static void
596 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc)
597 {
598  engine_type* engine = NULL;
599  char buf[ODS_SE_MAXLINE];
600  ods_log_assert(cmdc);
601  ods_log_assert(cmdc->engine);
602  engine = (engine_type*) cmdc->engine;
603  engine->need_to_reload = 1;
604  lock_basic_lock(&engine->signal_lock);
605  lock_basic_alarm(&engine->signal_cond);
606  lock_basic_unlock(&engine->signal_lock);
607  (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n");
608  ods_writen(sockfd, buf, strlen(buf));
609  return;
610 }
611 
612 
617 static void
618 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc)
619 {
620  engine_type* engine = NULL;
621  char buf[ODS_SE_MAXLINE];
622  ods_log_assert(cmdc);
623  ods_log_assert(cmdc->engine);
624  engine = (engine_type*) cmdc->engine;
625  engine->need_to_exit = 1;
626  lock_basic_lock(&engine->signal_lock);
627  lock_basic_alarm(&engine->signal_cond);
628  lock_basic_unlock(&engine->signal_lock);
629  (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE);
630  ods_writen(sockfd, buf, strlen(buf));
631  return;
632 }
633 
634 
639 static void
640 cmdhandler_handle_cmd_start(int sockfd)
641 {
642  char buf[ODS_SE_MAXLINE];
643  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n");
644  ods_writen(sockfd, buf, strlen(buf));
645  return;
646 }
647 
648 
653 static void
654 cmdhandler_handle_cmd_running(int sockfd)
655 {
656  char buf[ODS_SE_MAXLINE];
657  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n");
658  ods_writen(sockfd, buf, strlen(buf));
659  return;
660 }
661 
662 
667 static void
668 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val)
669 {
670  engine_type* engine = NULL;
671  char buf[ODS_SE_MAXLINE];
672  ods_log_assert(cmdc);
673  ods_log_assert(cmdc->engine);
674  engine = (engine_type*) cmdc->engine;
675  ods_log_assert(engine->config);
676  ods_log_init(engine->config->log_filename, engine->config->use_syslog,
677  val);
678  (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val);
679  ods_writen(sockfd, buf, strlen(buf));
680  return;
681 }
682 
683 
688 static void
689 cmdhandler_handle_cmd_error(int sockfd, const char* str)
690 {
691  char buf[ODS_SE_MAXLINE];
692  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)");
693  ods_writen(sockfd, buf, strlen(buf));
694  return;
695 }
696 
697 
702 static void
703 cmdhandler_handle_cmd_unknown(int sockfd, const char* str)
704 {
705  char buf[ODS_SE_MAXLINE];
706  (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n",
707  str?str:"(null)");
708  ods_writen(sockfd, buf, strlen(buf));
709  return;
710 }
711 
712 
731 static void
732 cmdhandler_handle_cmd(cmdhandler_type* cmdc)
733 {
734  ssize_t n = 0;
735  int sockfd = 0;
736  char buf[ODS_SE_MAXLINE];
737 
738  ods_log_assert(cmdc);
739  sockfd = cmdc->client_fd;
740 
741 again:
742  while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) {
743  /* what if this number is smaller than the number of bytes requested? */
744  buf[n-1] = '\0';
745  n--;
746  ods_log_verbose("[%s] received command %s[%i]", cmdh_str, buf, n);
747  ods_str_trim(buf);
748  n = strlen(buf);
749 
750  if (n == 4 && strncmp(buf, "help", n) == 0) {
751  ods_log_debug("[%s] help command", cmdh_str);
752  cmdhandler_handle_cmd_help(sockfd);
753  } else if (n == 5 && strncmp(buf, "zones", n) == 0) {
754  ods_log_debug("[%s] list zones command", cmdh_str);
755  cmdhandler_handle_cmd_zones(sockfd, cmdc);
756  } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) {
757  ods_log_debug("[%s] sign zone command", cmdh_str);
758  if (n == 4 || buf[4] == '\0') {
759  /* NOTE: wouldn't it be nice that we default to --all? */
760  cmdhandler_handle_cmd_error(sockfd, "sign command needs "
761  "an argument (either '--all' or a zone name)");
762  } else if (buf[4] != ' ') {
763  cmdhandler_handle_cmd_unknown(sockfd, buf);
764  } else {
765  cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]);
766  }
767  } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) {
768  ods_log_debug("[%s] clear zone command", cmdh_str);
769  if (n == 5 || buf[5] == '\0') {
770  cmdhandler_handle_cmd_error(sockfd, "clear command needs "
771  "a zone name");
772  } else if (buf[5] != ' ') {
773  cmdhandler_handle_cmd_unknown(sockfd, buf);
774  } else {
775  cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]);
776  }
777  } else if (n == 5 && strncmp(buf, "queue", n) == 0) {
778  ods_log_debug("[%s] list tasks command", cmdh_str);
779  cmdhandler_handle_cmd_queue(sockfd, cmdc);
780  } else if (n == 5 && strncmp(buf, "flush", n) == 0) {
781  ods_log_debug("[%s] flush tasks command", cmdh_str);
782  cmdhandler_handle_cmd_flush(sockfd, cmdc);
783  } else if (n >= 6 && strncmp(buf, "update", 6) == 0) {
784  ods_log_debug("[%s] update command", cmdh_str);
785  if (n == 6 || buf[6] == '\0') {
786  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
787  } else if (buf[6] != ' ') {
788  cmdhandler_handle_cmd_unknown(sockfd, buf);
789  } else {
790  cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]);
791  }
792  } else if (n == 4 && strncmp(buf, "stop", n) == 0) {
793  ods_log_debug("[%s] shutdown command", cmdh_str);
794  cmdhandler_handle_cmd_stop(sockfd, cmdc);
795  return;
796  } else if (n == 5 && strncmp(buf, "start", n) == 0) {
797  ods_log_debug("[%s] start command", cmdh_str);
798  cmdhandler_handle_cmd_start(sockfd);
799  } else if (n == 6 && strncmp(buf, "reload", n) == 0) {
800  ods_log_debug("[%s] reload command", cmdh_str);
801  cmdhandler_handle_cmd_reload(sockfd, cmdc);
802  } else if (n == 7 && strncmp(buf, "running", n) == 0) {
803  ods_log_debug("[%s] running command", cmdh_str);
804  cmdhandler_handle_cmd_running(sockfd);
805  } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) {
806  ods_log_debug("[%s] verbosity command", cmdh_str);
807  if (n == 9 || buf[9] == '\0') {
808  cmdhandler_handle_cmd_error(sockfd, "verbosity command "
809  "an argument (verbosity level)");
810  } else if (buf[9] != ' ') {
811  cmdhandler_handle_cmd_unknown(sockfd, buf);
812  } else {
813  cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10]));
814  }
815  } else if (n >= 10 && strncmp(buf, "retransfer", 10) == 0) {
816  ods_log_debug("[%s] retransfer zone command", cmdh_str);
817  if (n == 10 || buf[10] == '\0') {
818  cmdhandler_handle_cmd_error(sockfd, "retransfer command needs "
819  "an argument (a zone name)");
820  } else if (buf[10] != ' ') {
821  cmdhandler_handle_cmd_unknown(sockfd, buf);
822  } else {
823  cmdhandler_handle_cmd_retransfer(sockfd, cmdc, &buf[11]);
824  }
825  } else if (n > 0) {
826  ods_log_debug("[%s] unknown command", cmdh_str);
827  cmdhandler_handle_cmd_unknown(sockfd, buf);
828  }
829  ods_log_debug("[%s] done handling command %s[%i]", cmdh_str, buf, n);
830  (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> ");
831  ods_writen(sockfd, buf, strlen(buf));
832  }
833 
834  if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) {
835  goto again;
836  } else if (n < 0 && errno == ECONNRESET) {
837  ods_log_debug("[%s] done handling client: %s", cmdh_str,
838  strerror(errno));
839  } else if (n < 0 ) {
840  ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno));
841  }
842  return;
843 }
844 
845 
850 static void*
851 cmdhandler_accept_client(void* arg)
852 {
853  cmdhandler_type* cmdc = (cmdhandler_type*) arg;
854 
857 
858  ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd);
859  cmdhandler_handle_cmd(cmdc);
860  if (cmdc->client_fd) {
861  shutdown(cmdc->client_fd, SHUT_RDWR);
862  close(cmdc->client_fd);
863  }
864  free(cmdc);
865  count--;
866  return NULL;
867 }
868 
869 
875 cmdhandler_create(allocator_type* allocator, const char* filename)
876 {
877  cmdhandler_type* cmdh = NULL;
878  struct sockaddr_un servaddr;
879  int listenfd = 0;
880  int flags = 0;
881  int ret = 0;
882 
883  if (!allocator || !filename) {
884  return NULL;
885  }
886  /* new socket */
887  ods_log_debug("[%s] create socket %s", cmdh_str, filename);
888  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
889  if (listenfd < 0) {
890  ods_log_error("[%s] unable to create cmdhandler: "
891  "socket() failed (%s)", cmdh_str, strerror(errno));
892  return NULL;
893  }
894  /* set it to non-blocking */
895  flags = fcntl(listenfd, F_GETFL, 0);
896  if (flags < 0) {
897  ods_log_error("[%s] unable to create cmdhandler: "
898  "fcntl(F_GETFL) failed (%s)", cmdh_str, strerror(errno));
899  close(listenfd);
900  return NULL;
901  }
902  flags |= O_NONBLOCK;
903  if (fcntl(listenfd, F_SETFL, flags) < 0) {
904  ods_log_error("[%s] unable to create cmdhandler: "
905  "fcntl(F_SETFL) failed (%s)", cmdh_str, strerror(errno));
906  close(listenfd);
907  return NULL;
908  }
909  /* no surprises so far */
910  if (filename) {
911  (void)unlink(filename);
912  }
913  bzero(&servaddr, sizeof(servaddr));
914  servaddr.sun_family = AF_UNIX;
915  strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1);
916 #ifdef HAVE_SOCKADDR_SUN_LEN
917  servaddr.sun_len = strlen(servaddr.sun_path);
918 #endif
919  /* bind and listen... */
920  ret = bind(listenfd, (const struct sockaddr*) &servaddr,
921  SUN_LEN(&servaddr));
922  if (ret != 0) {
923  ods_log_error("[%s] unable to create cmdhandler: "
924  "bind() failed (%s)", cmdh_str, strerror(errno));
925  close(listenfd);
926  return NULL;
927  }
928  ret = listen(listenfd, ODS_SE_MAX_HANDLERS);
929  if (ret != 0) {
930  ods_log_error("[%s] unable to create cmdhandler: "
931  "listen() failed (%s)", cmdh_str, strerror(errno));
932  close(listenfd);
933  return NULL;
934  }
935  /* all ok */
936  cmdh = (cmdhandler_type*) allocator_alloc(allocator,
937  sizeof(cmdhandler_type));
938  if (!cmdh) {
939  ods_log_error("[%s] unable to create cmdhandler: "
940  "allocator_alloc() failed", cmdh_str);
941  close(listenfd);
942  return NULL;
943  }
944  cmdh->allocator = allocator;
945  cmdh->listen_fd = listenfd;
946  cmdh->listen_addr = servaddr;
947  cmdh->need_to_exit = 0;
948  return cmdh;
949 }
950 
951 
956 void
958 {
959  struct sockaddr_un cliaddr;
960  socklen_t clilen;
961  cmdhandler_type* cmdc = NULL;
962  engine_type* engine = NULL;
963  fd_set rset;
964  int connfd = 0;
965  int ret = 0;
966  ods_log_assert(cmdhandler);
967  ods_log_assert(cmdhandler->engine);
968  ods_log_debug("[%s] start", cmdh_str);
969  engine = (engine_type*) cmdhandler->engine;
970  ods_thread_detach(cmdhandler->thread_id);
971  FD_ZERO(&rset);
972  while (cmdhandler->need_to_exit == 0) {
973  clilen = sizeof(cliaddr);
974  FD_SET(cmdhandler->listen_fd, &rset);
975  ret = select(cmdhandler->listen_fd+1, &rset, NULL, NULL, NULL);
976  if (ret < 0) {
977  if (errno != EINTR && errno != EWOULDBLOCK) {
978  ods_log_warning("[%s] select() error: %s", cmdh_str,
979  strerror(errno));
980  }
981  continue;
982  }
983  if (FD_ISSET(cmdhandler->listen_fd, &rset)) {
984  connfd = accept(cmdhandler->listen_fd,
985  (struct sockaddr *) &cliaddr, &clilen);
986  if (connfd < 0) {
987  if (errno != EINTR && errno != EWOULDBLOCK) {
988  ods_log_warning("[%s] accept() error: %s", cmdh_str,
989  strerror(errno));
990  }
991  continue;
992  }
993  /* client accepted, create new thread */
994  cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type));
995  if (!cmdc) {
996  ods_log_crit("[%s] unable to create thread for client: "
997  "malloc() failed", cmdh_str);
998  cmdhandler->need_to_exit = 1;
999  break;
1000  }
1001  cmdc->listen_fd = cmdhandler->listen_fd;
1002  cmdc->client_fd = connfd;
1003  cmdc->listen_addr = cmdhandler->listen_addr;
1004  cmdc->engine = cmdhandler->engine;
1005  cmdc->need_to_exit = cmdhandler->need_to_exit;
1006  ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client,
1007  (void*) cmdc);
1008  count++;
1009  ods_log_debug("[%s] %i clients in progress...", cmdh_str, count);
1010  }
1011  }
1012  ods_log_debug("[%s] shutdown", cmdh_str);
1013  engine = cmdhandler->engine;
1014  engine->cmdhandler_done = 1;
1015  return;
1016 }
1017 
1018 
1023 void
1025 {
1026  allocator_type* allocator = NULL;
1027  if (!cmdhandler) {
1028  return;
1029  }
1030  allocator = cmdhandler->allocator;
1031  allocator_deallocate(allocator, (void*) cmdhandler);
1032  return;
1033 }
1034 
signconf_type * signconf_create(void)
Definition: signconf.c:47
void ixfr_cleanup(ixfr_type *ixfr)
Definition: ixfr.c:309
Definition: task.h:41
uint32_t intserial
Definition: namedb.h:52
#define ODS_SE_NOTIFY_CMD
Definition: dnshandler.h:46
zonelist_type * zonelist
Definition: engine.h:60
void ods_thread_blocksigs(void)
Definition: locks.c:148
void engine_wakeup_workers(engine_type *engine)
Definition: engine.c:454
void ods_log_debug(const char *format,...)
Definition: log.c:270
int just_updated
Definition: zonelist.h:53
cond_basic_type signal_cond
Definition: engine.h:78
#define SUN_LEN(su)
Definition: cmdhandler.c:61
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:66
const char * zonelist_filename
Definition: cfg.h:52
void engine_update_zones(engine_type *engine, ods_status zl_changed)
Definition: engine.c:789
void signconf_cleanup(signconf_type *sc)
Definition: signconf.c:564
void namedb_cleanup(namedb_type *db)
Definition: namedb.c:1154
cmdhandler_type * cmdhandler_create(allocator_type *allocator, const char *filename)
Definition: cmdhandler.c:875
void ods_fatal_exit(const char *format,...)
Definition: log.c:382
unsigned have_serial
Definition: namedb.h:59
void ods_log_info(const char *format,...)
Definition: log.c:302
const char * task_who2str(task_type *task)
Definition: task.c:176
ldns_rbtree_t * zones
Definition: zonelist.h:50
enum ods_enum_status ods_status
Definition: status.h:90
lock_basic_type zone_lock
Definition: zone.h:95
void schedule_flush(schedule_type *schedule, task_id override)
Definition: schedule.c:81
ods_thread_type thread_id
Definition: cmdhandler.h:48
void ods_log_error(const char *format,...)
Definition: log.c:334
uint32_t outserial
Definition: namedb.h:53
const char * ods_status2str(ods_status status)
Definition: status.c:111
zone_zl_status zl_status
Definition: zone.h:79
int ods_strcmp(const char *s1, const char *s2)
Definition: file.c:320
int just_removed
Definition: zonelist.h:54
void cmdhandler_start(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:957
struct sockaddr_un listen_addr
Definition: cmdhandler.h:47
int util_serial_gt(uint32_t serial_new, uint32_t serial_old)
Definition: util.c:72
#define ODS_SE_MAX_HANDLERS
Definition: cmdhandler.h:41
void ods_log_crit(const char *format,...)
Definition: log.c:350
const char * log_filename
Definition: cfg.h:53
lock_basic_type signal_lock
Definition: engine.h:79
task_type * task
Definition: worker.h:54
#define lock_basic_lock(lock)
Definition: locks.h:91
void ods_str_trim(char *str)
Definition: file.c:554
engineconfig_type * config
Definition: engine.h:57
namedb_type * db
Definition: zone.h:86
ixfr_type * ixfr
Definition: zone.h:87
uint32_t inbserial
Definition: namedb.h:51
int num_worker_threads
Definition: cfg.h:62
Definition: task.h:43
worker_type ** workers
Definition: engine.h:58
#define SE_CMDH_CMDLEN
Definition: cmdhandler.c:58
signconf_type * signconf
Definition: zone.h:84
ssize_t ods_writen(int fd, const void *vptr, size_t n)
Definition: file.c:265
allocator_type * allocator
Definition: cmdhandler.h:45
unsigned force_serial
Definition: namedb.h:58
ods_status zone_reschedule_task(zone_type *zone, schedule_type *taskq, task_id what)
Definition: zone.c:187
namedb_type * namedb_create(void *zone)
Definition: namedb.c:124
char * ods_build_path(const char *file, const char *suffix, int dir, int no_slash)
Definition: file.c:125
#define ods_thread_detach(thr)
Definition: locks.h:102
int use_syslog
Definition: cfg.h:61
void ods_log_verbose(const char *format,...)
Definition: log.c:286
ldns_rbtree_t * tasks
Definition: schedule.h:60
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:161
void xfrd_set_timer_now(xfrd_type *xfrd)
Definition: xfrd.c:472
const char * name
Definition: zone.h:76
schedule_type * taskq
Definition: engine.h:61
uint8_t serial_retransfer
Definition: xfrd.h:113
uint32_t altserial
Definition: namedb.h:54
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:135
task_id working_with
Definition: worker.h:55
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:350
char * task2str(task_type *task, char *buftask)
Definition: task.c:194
lock_basic_type schedule_lock
Definition: schedule.h:63
int need_to_exit
Definition: engine.h:74
#define ods_log_assert(x)
Definition: log.h:154
#define ods_thread_create(thr, func, arg)
Definition: locks.h:101
void ods_log_init(const char *filename, int use_syslog, int verbosity)
Definition: log.c:81
int need_to_reload
Definition: engine.h:75
xfrd_type * xfrd
Definition: zone.h:89
ixfr_type * ixfr_create(void *zone)
Definition: ixfr.c:100
#define lock_basic_alarm(cond)
Definition: locks.h:96
void dnshandler_fwd_notify(dnshandler_type *dnshandler, uint8_t *pkt, size_t len)
Definition: dnshandler.c:247
#define lock_basic_unlock(lock)
Definition: locks.h:92
void ods_log_warning(const char *format,...)
Definition: log.c:318
void cmdhandler_cleanup(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:1024
lock_basic_type zl_lock
Definition: zonelist.h:55
int cmdhandler_done
Definition: engine.h:67
const char * task_what2str(task_id what)
Definition: task.c:146
time_t time_now(void)
Definition: duration.c:513
dnshandler_type * dnshandler
Definition: engine.h:64