OpenDNSSEC-signer  1.4.10
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  } else if (zone->adinbound->type != ADAPTER_DNS) {
285  (void)snprintf(buf, ODS_SE_MAXLINE,
286  "Error: Zone %s not configured to use DNS input adapter.\n",
287  tbd);
288  ods_writen(sockfd, buf, strlen(buf));
289  return;
290  }
291  zone->xfrd->serial_retransfer = 1;
292  xfrd_set_timer_now(zone->xfrd);
293  ods_log_debug("[%s] forward a notify", cmdh_str);
295  (uint8_t*) ODS_SE_NOTIFY_CMD, strlen(ODS_SE_NOTIFY_CMD));
296  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s being retransferred.\n", tbd);
297  ods_writen(sockfd, buf, strlen(buf));
298  ods_log_verbose("[%s] zone %s being retransferred", cmdh_str, tbd);
299  return;
300 }
301 
302 
303 static uint32_t
304 max(uint32_t a, uint32_t b)
305 {
306  return (a<b?b:a);
307 }
308 
309 
314 static void
315 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd)
316 {
317  engine_type* engine = NULL;
318  zone_type* zone = NULL;
319  ods_status status = ODS_STATUS_OK;
320  char buf[ODS_SE_MAXLINE];
321 
322  ods_log_assert(tbd);
323  ods_log_assert(cmdc);
324  ods_log_assert(cmdc->engine);
325  engine = (engine_type*) cmdc->engine;
326  ods_log_assert(engine->taskq);
327  if (ods_strcmp(tbd, "--all") == 0) {
329  schedule_flush(engine->taskq, TASK_READ);
331  engine_wakeup_workers(engine);
332  (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for "
333  "immediate re-sign.\n");
334  ods_writen(sockfd, buf, strlen(buf));
335  ods_log_verbose("[%s] all zones scheduled for immediate re-sign",
336  cmdh_str);
337  return;
338  } else {
339  char* delim1 = strchr(tbd, ' ');
340  char* delim2 = NULL;
341  int force_serial = 0;
342  uint32_t serial = 0;
343  if (delim1) {
344  char* end = NULL;
346  if (strncmp(delim1+1, "--serial ", 9) != 0) {
347  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting <zone> "
348  "--serial <nr>, got %s.\n", tbd);
349  ods_writen(sockfd, buf, strlen(buf));
350  return;
351  }
352  delim2 = strchr(delim1+1, ' ');
353  if (!delim2) {
354  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial.\n");
355  ods_writen(sockfd, buf, strlen(buf));
356  return;
357  }
358  serial = (uint32_t) strtol(delim2+1, &end, 10);
359  if (*end != '\0') {
360  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial, "
361  "got %s.\n", delim2+1);
362  ods_writen(sockfd, buf, strlen(buf));
363  return;
364  }
365  force_serial = 1;
366  *delim1 = '\0';
367  }
368  lock_basic_lock(&engine->zonelist->zl_lock);
369  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
370  LDNS_RR_CLASS_IN);
371  /* If this zone is just added, don't update (it might not have a task
372  * yet).
373  */
374  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
375  zone = NULL;
376  }
378 
379  if (!zone) {
380  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
381  tbd);
382  ods_writen(sockfd, buf, strlen(buf));
383  return;
384  }
385 
386  lock_basic_lock(&zone->zone_lock);
387  if (force_serial) {
388  ods_log_assert(zone->db);
389  if (!util_serial_gt(serial, max(zone->db->outserial,
390  zone->db->inbserial))) {
392  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to enforce "
393  "serial %u for zone %s.\n", serial, tbd);
394  ods_writen(sockfd, buf, strlen(buf));
395  return;
396  }
397  zone->db->altserial = serial;
398  zone->db->force_serial = 1;
399  }
400  status = zone_reschedule_task(zone, engine->taskq, TASK_READ);
402 
403  if (status != ODS_STATUS_OK) {
404  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
405  "task for zone %s.\n", tbd);
406  ods_writen(sockfd, buf, strlen(buf));
407  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
408  cmdh_str, zone->name, ods_status2str(status));
409  } else {
410  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for "
411  "immediate re-sign.\n", tbd);
412  ods_writen(sockfd, buf, strlen(buf));
413  ods_log_verbose("[%s] zone %s scheduled for immediate re-sign",
414  cmdh_str, tbd);
415  engine_wakeup_workers(engine);
416  }
417  }
418  return;
419 }
420 
421 
426 static void
427 unlink_backup_file(const char* filename, const char* extension)
428 {
429  char* tmpname = ods_build_path(filename, extension, 0, 1);
430  if (tmpname) {
431  ods_log_debug("[%s] unlink file %s", cmdh_str, tmpname);
432  unlink(tmpname);
433  free((void*)tmpname);
434  }
435  return;
436 }
437 
442 static void
443 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd)
444 {
445  ods_status status = ODS_STATUS_OK;
446  engine_type* engine = NULL;
447  char buf[ODS_SE_MAXLINE];
448  zone_type* zone = NULL;
449  uint32_t inbserial = 0;
450  uint32_t intserial = 0;
451  uint32_t outserial = 0;
452  ods_log_assert(tbd);
453  ods_log_assert(cmdc);
454  ods_log_assert(cmdc->engine);
455  engine = (engine_type*) cmdc->engine;
456  unlink_backup_file(tbd, ".inbound");
457  unlink_backup_file(tbd, ".backup");
458  unlink_backup_file(tbd, ".axfr");
459  unlink_backup_file(tbd, ".ixfr");
460  lock_basic_lock(&engine->zonelist->zl_lock);
461  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
462  LDNS_RR_CLASS_IN);
464  if (zone) {
465  lock_basic_lock(&zone->zone_lock);
466  inbserial = zone->db->inbserial;
467  intserial = zone->db->intserial;
468  outserial = zone->db->outserial;
469  namedb_cleanup(zone->db);
470  ixfr_cleanup(zone->ixfr);
471  signconf_cleanup(zone->signconf);
472 
473  zone->db = namedb_create((void*)zone);
474  zone->ixfr = ixfr_create((void*)zone);
475  zone->signconf = signconf_create();
476 
477  if (!zone->signconf || !zone->ixfr || !zone->db) {
478  ods_fatal_exit("[%s] unable to clear zone %s: failed to recreate"
479  "signconf, ixfr of db structure (out of memory?)", cmdh_str, tbd);
480  return;
481  }
482  /* restore serial management */
483  zone->db->inbserial = inbserial;
484  zone->db->intserial = intserial;
485  zone->db->outserial = outserial;
486  zone->db->have_serial = 1;
487 
488  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
490 
491  if (status != ODS_STATUS_OK) {
492  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
493  "task for zone %s.\n", tbd);
494  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
495  cmdh_str, zone->name, ods_status2str(status));
496  } else {
497  (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about "
498  "%s cleared", tbd?tbd:"(null)");
499  ods_log_info("[%s] internal zone information about %s cleared",
500  cmdh_str, tbd?tbd:"(null)");
501  }
502  } else {
503  (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not "
504  "found", tbd?tbd:"(null)");
505  ods_log_warning("[%s] cannot clear zone %s, zone not found",
506  cmdh_str, tbd?tbd:"(null)");
507  }
508  ods_writen(sockfd, buf, strlen(buf));
509  return;
510 }
511 
512 
517 static void
518 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc)
519 {
520  engine_type* engine = NULL;
521  char* strtime = NULL;
522  char buf[ODS_SE_MAXLINE];
523  size_t i = 0;
524  time_t now = 0;
525  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
526  task_type* task = NULL;
527  ods_log_assert(cmdc);
528  ods_log_assert(cmdc->engine);
529  engine = (engine_type*) cmdc->engine;
530  if (!engine->taskq || !engine->taskq->tasks) {
531  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no tasks scheduled.\n");
532  ods_writen(sockfd, buf, strlen(buf));
533  return;
534  }
535  /* current time */
536  now = time_now();
537  strtime = ctime(&now);
538  (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s",
539  strtime?strtime:"(null)");
540  ods_writen(sockfd, buf, strlen(buf));
541  /* current work */
543  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
544  task = engine->workers[i]->task;
545  if (task) {
546  (void)snprintf(buf, ODS_SE_MAXLINE, "Working with task %s on "
547  "zone %s\n",
548  task_what2str(engine->workers[i]->working_with),
549  task_who2str(task));
550  ods_writen(sockfd, buf, strlen(buf));
551  }
552  }
553  /* how many tasks */
554  (void)snprintf(buf, ODS_SE_MAXLINE, "\nI have %i tasks scheduled.\n",
555  (int) engine->taskq->tasks->count);
556  ods_writen(sockfd, buf, strlen(buf));
557  /* list tasks */
558  node = ldns_rbtree_first(engine->taskq->tasks);
559  while (node && node != LDNS_RBTREE_NULL) {
560  task = (task_type*) node->data;
561  for (i=0; i < ODS_SE_MAXLINE; i++) {
562  buf[i] = 0;
563  }
564  (void)task2str(task, (char*) &buf[0]);
565  ods_writen(sockfd, buf, strlen(buf));
566  node = ldns_rbtree_next(node);
567  }
569  return;
570 }
571 
572 
577 static void
578 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc)
579 {
580  engine_type* engine = NULL;
581  char buf[ODS_SE_MAXLINE];
582  ods_log_assert(cmdc);
583  ods_log_assert(cmdc->engine);
584  engine = (engine_type*) cmdc->engine;
585  ods_log_assert(engine->taskq);
587  schedule_flush(engine->taskq, TASK_NONE);
589  engine_wakeup_workers(engine);
590  (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n");
591  ods_writen(sockfd, buf, strlen(buf));
592  ods_log_verbose("[%s] all tasks scheduled immediately", cmdh_str);
593  return;
594 }
595 
596 
601 static void
602 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc)
603 {
604  engine_type* engine = NULL;
605  char buf[ODS_SE_MAXLINE];
606  ods_log_assert(cmdc);
607  ods_log_assert(cmdc->engine);
608  engine = (engine_type*) cmdc->engine;
609  ods_log_error("signer instructed to reload due to explicit command");
610  engine->need_to_reload = 1;
611  lock_basic_lock(&engine->signal_lock);
612  lock_basic_alarm(&engine->signal_cond);
613  lock_basic_unlock(&engine->signal_lock);
614  (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n");
615  ods_writen(sockfd, buf, strlen(buf));
616  return;
617 }
618 
619 
624 static void
625 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc)
626 {
627  engine_type* engine = NULL;
628  char buf[ODS_SE_MAXLINE];
629  ods_log_assert(cmdc);
630  ods_log_assert(cmdc->engine);
631  engine = (engine_type*) cmdc->engine;
632  engine->need_to_exit = 1;
633  lock_basic_lock(&engine->signal_lock);
634  lock_basic_alarm(&engine->signal_cond);
635  lock_basic_unlock(&engine->signal_lock);
636  (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE);
637  ods_writen(sockfd, buf, strlen(buf));
638  return;
639 }
640 
641 
646 static void
647 cmdhandler_handle_cmd_start(int sockfd)
648 {
649  char buf[ODS_SE_MAXLINE];
650  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n");
651  ods_writen(sockfd, buf, strlen(buf));
652  return;
653 }
654 
655 
660 static void
661 cmdhandler_handle_cmd_running(int sockfd)
662 {
663  char buf[ODS_SE_MAXLINE];
664  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n");
665  ods_writen(sockfd, buf, strlen(buf));
666  return;
667 }
668 
669 
674 static void
675 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val)
676 {
677  engine_type* engine = NULL;
678  char buf[ODS_SE_MAXLINE];
679  ods_log_assert(cmdc);
680  ods_log_assert(cmdc->engine);
681  engine = (engine_type*) cmdc->engine;
682  ods_log_assert(engine->config);
683  ods_log_init(engine->config->log_filename, engine->config->use_syslog,
684  val);
685  (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val);
686  ods_writen(sockfd, buf, strlen(buf));
687  return;
688 }
689 
690 
695 static void
696 cmdhandler_handle_cmd_error(int sockfd, const char* str)
697 {
698  char buf[ODS_SE_MAXLINE];
699  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)");
700  ods_writen(sockfd, buf, strlen(buf));
701  return;
702 }
703 
704 
709 static void
710 cmdhandler_handle_cmd_unknown(int sockfd, const char* str)
711 {
712  char buf[ODS_SE_MAXLINE];
713  (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n",
714  str?str:"(null)");
715  ods_writen(sockfd, buf, strlen(buf));
716  return;
717 }
718 
719 
738 static void
739 cmdhandler_handle_cmd(cmdhandler_type* cmdc)
740 {
741  ssize_t n = 0;
742  int sockfd = 0;
743  char buf[ODS_SE_MAXLINE];
744 
745  ods_log_assert(cmdc);
746  sockfd = cmdc->client_fd;
747 
748 again:
749  while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) {
750  /* what if this number is smaller than the number of bytes requested? */
751  buf[n-1] = '\0';
752  n--;
753  ods_log_verbose("[%s] received command %s[%i]", cmdh_str, buf, n);
754  ods_str_trim(buf);
755  n = strlen(buf);
756 
757  if (n == 4 && strncmp(buf, "help", n) == 0) {
758  ods_log_debug("[%s] help command", cmdh_str);
759  cmdhandler_handle_cmd_help(sockfd);
760  } else if (n == 5 && strncmp(buf, "zones", n) == 0) {
761  ods_log_debug("[%s] list zones command", cmdh_str);
762  cmdhandler_handle_cmd_zones(sockfd, cmdc);
763  } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) {
764  ods_log_debug("[%s] sign zone command", cmdh_str);
765  if (n == 4 || buf[4] == '\0') {
766  /* NOTE: wouldn't it be nice that we default to --all? */
767  cmdhandler_handle_cmd_error(sockfd, "sign command needs "
768  "an argument (either '--all' or a zone name)");
769  } else if (buf[4] != ' ') {
770  cmdhandler_handle_cmd_unknown(sockfd, buf);
771  } else {
772  cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]);
773  }
774  } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) {
775  ods_log_debug("[%s] clear zone command", cmdh_str);
776  if (n == 5 || buf[5] == '\0') {
777  cmdhandler_handle_cmd_error(sockfd, "clear command needs "
778  "a zone name");
779  } else if (buf[5] != ' ') {
780  cmdhandler_handle_cmd_unknown(sockfd, buf);
781  } else {
782  cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]);
783  }
784  } else if (n == 5 && strncmp(buf, "queue", n) == 0) {
785  ods_log_debug("[%s] list tasks command", cmdh_str);
786  cmdhandler_handle_cmd_queue(sockfd, cmdc);
787  } else if (n == 5 && strncmp(buf, "flush", n) == 0) {
788  ods_log_debug("[%s] flush tasks command", cmdh_str);
789  cmdhandler_handle_cmd_flush(sockfd, cmdc);
790  } else if (n >= 6 && strncmp(buf, "update", 6) == 0) {
791  ods_log_debug("[%s] update command", cmdh_str);
792  if (n == 6 || buf[6] == '\0') {
793  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
794  } else if (buf[6] != ' ') {
795  cmdhandler_handle_cmd_unknown(sockfd, buf);
796  } else {
797  cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]);
798  }
799  } else if (n == 4 && strncmp(buf, "stop", n) == 0) {
800  ods_log_debug("[%s] shutdown command", cmdh_str);
801  cmdhandler_handle_cmd_stop(sockfd, cmdc);
802  return;
803  } else if (n == 5 && strncmp(buf, "start", n) == 0) {
804  ods_log_debug("[%s] start command", cmdh_str);
805  cmdhandler_handle_cmd_start(sockfd);
806  } else if (n == 6 && strncmp(buf, "reload", n) == 0) {
807  ods_log_debug("[%s] reload command", cmdh_str);
808  cmdhandler_handle_cmd_reload(sockfd, cmdc);
809  } else if (n == 7 && strncmp(buf, "running", n) == 0) {
810  ods_log_debug("[%s] running command", cmdh_str);
811  cmdhandler_handle_cmd_running(sockfd);
812  } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) {
813  ods_log_debug("[%s] verbosity command", cmdh_str);
814  if (n == 9 || buf[9] == '\0') {
815  cmdhandler_handle_cmd_error(sockfd, "verbosity command "
816  "an argument (verbosity level)");
817  } else if (buf[9] != ' ') {
818  cmdhandler_handle_cmd_unknown(sockfd, buf);
819  } else {
820  cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10]));
821  }
822  } else if (n >= 10 && strncmp(buf, "retransfer", 10) == 0) {
823  ods_log_debug("[%s] retransfer zone command", cmdh_str);
824  if (n == 10 || buf[10] == '\0') {
825  cmdhandler_handle_cmd_error(sockfd, "retransfer command needs "
826  "an argument (a zone name)");
827  } else if (buf[10] != ' ') {
828  cmdhandler_handle_cmd_unknown(sockfd, buf);
829  } else {
830  cmdhandler_handle_cmd_retransfer(sockfd, cmdc, &buf[11]);
831  }
832  } else if (n > 0) {
833  ods_log_debug("[%s] unknown command", cmdh_str);
834  cmdhandler_handle_cmd_unknown(sockfd, buf);
835  }
836  ods_log_debug("[%s] done handling command %s[%i]", cmdh_str, buf, n);
837  (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> ");
838  ods_writen(sockfd, buf, strlen(buf));
839  }
840 
841  if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) {
842  goto again;
843  } else if (n < 0 && errno == ECONNRESET) {
844  ods_log_debug("[%s] done handling client: %s", cmdh_str,
845  strerror(errno));
846  } else if (n < 0 ) {
847  ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno));
848  }
849  return;
850 }
851 
852 
857 static void*
858 cmdhandler_accept_client(void* arg)
859 {
860  cmdhandler_type* cmdc = (cmdhandler_type*) arg;
861 
864 
865  ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd);
866  cmdhandler_handle_cmd(cmdc);
867  if (cmdc->client_fd) {
868  shutdown(cmdc->client_fd, SHUT_RDWR);
869  close(cmdc->client_fd);
870  }
871  free(cmdc);
872  count--;
873  return NULL;
874 }
875 
876 
882 cmdhandler_create(allocator_type* allocator, const char* filename)
883 {
884  cmdhandler_type* cmdh = NULL;
885  struct sockaddr_un servaddr;
886  int listenfd = 0;
887  int flags = 0;
888  int ret = 0;
889 
890  if (!allocator || !filename) {
891  return NULL;
892  }
893  /* new socket */
894  ods_log_debug("[%s] create socket %s", cmdh_str, filename);
895  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
896  if (listenfd < 0) {
897  ods_log_error("[%s] unable to create cmdhandler: "
898  "socket() failed (%s)", cmdh_str, strerror(errno));
899  return NULL;
900  }
901  /* set it to non-blocking */
902  flags = fcntl(listenfd, F_GETFL, 0);
903  if (flags < 0) {
904  ods_log_error("[%s] unable to create cmdhandler: "
905  "fcntl(F_GETFL) failed (%s)", cmdh_str, strerror(errno));
906  close(listenfd);
907  return NULL;
908  }
909  flags |= O_NONBLOCK;
910  if (fcntl(listenfd, F_SETFL, flags) < 0) {
911  ods_log_error("[%s] unable to create cmdhandler: "
912  "fcntl(F_SETFL) failed (%s)", cmdh_str, strerror(errno));
913  close(listenfd);
914  return NULL;
915  }
916  /* no surprises so far */
917  if (filename) {
918  (void)unlink(filename);
919  }
920  bzero(&servaddr, sizeof(servaddr));
921  servaddr.sun_family = AF_UNIX;
922  strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1);
923 #ifdef HAVE_SOCKADDR_SUN_LEN
924  servaddr.sun_len = strlen(servaddr.sun_path);
925 #endif
926  /* bind and listen... */
927  ret = bind(listenfd, (const struct sockaddr*) &servaddr,
928  SUN_LEN(&servaddr));
929  if (ret != 0) {
930  ods_log_error("[%s] unable to create cmdhandler: "
931  "bind() failed (%s)", cmdh_str, strerror(errno));
932  close(listenfd);
933  return NULL;
934  }
935  ret = listen(listenfd, ODS_SE_MAX_HANDLERS);
936  if (ret != 0) {
937  ods_log_error("[%s] unable to create cmdhandler: "
938  "listen() failed (%s)", cmdh_str, strerror(errno));
939  close(listenfd);
940  return NULL;
941  }
942  /* all ok */
943  cmdh = (cmdhandler_type*) allocator_alloc(allocator,
944  sizeof(cmdhandler_type));
945  if (!cmdh) {
946  ods_log_error("[%s] unable to create cmdhandler: "
947  "allocator_alloc() failed", cmdh_str);
948  close(listenfd);
949  return NULL;
950  }
951  cmdh->allocator = allocator;
952  cmdh->listen_fd = listenfd;
953  cmdh->listen_addr = servaddr;
954  cmdh->need_to_exit = 0;
955  return cmdh;
956 }
957 
958 
963 void
965 {
966  struct sockaddr_un cliaddr;
967  socklen_t clilen;
968  cmdhandler_type* cmdc = NULL;
969  engine_type* engine = NULL;
970  fd_set rset;
971  int connfd = 0;
972  int ret = 0;
973  ods_log_assert(cmdhandler);
974  ods_log_assert(cmdhandler->engine);
975  ods_log_debug("[%s] start", cmdh_str);
976  engine = (engine_type*) cmdhandler->engine;
977  ods_thread_detach(cmdhandler->thread_id);
978  FD_ZERO(&rset);
979  while (cmdhandler->need_to_exit == 0) {
980  clilen = sizeof(cliaddr);
981  FD_SET(cmdhandler->listen_fd, &rset);
982  ret = select(cmdhandler->listen_fd+1, &rset, NULL, NULL, NULL);
983  if (ret < 0) {
984  if (errno != EINTR && errno != EWOULDBLOCK) {
985  ods_log_warning("[%s] select() error: %s", cmdh_str,
986  strerror(errno));
987  }
988  continue;
989  }
990  if (FD_ISSET(cmdhandler->listen_fd, &rset)) {
991  connfd = accept(cmdhandler->listen_fd,
992  (struct sockaddr *) &cliaddr, &clilen);
993  if (connfd < 0) {
994  if (errno != EINTR && errno != EWOULDBLOCK) {
995  ods_log_warning("[%s] accept() error: %s", cmdh_str,
996  strerror(errno));
997  }
998  continue;
999  }
1000  /* client accepted, create new thread */
1001  cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type));
1002  if (!cmdc) {
1003  ods_log_crit("[%s] unable to create thread for client: "
1004  "malloc() failed", cmdh_str);
1005  cmdhandler->need_to_exit = 1;
1006  break;
1007  }
1008  cmdc->listen_fd = cmdhandler->listen_fd;
1009  cmdc->client_fd = connfd;
1010  cmdc->listen_addr = cmdhandler->listen_addr;
1011  cmdc->engine = cmdhandler->engine;
1012  cmdc->need_to_exit = cmdhandler->need_to_exit;
1013  ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client,
1014  (void*) cmdc);
1015  count++;
1016  ods_log_debug("[%s] %i clients in progress...", cmdh_str, count);
1017  }
1018  }
1019  ods_log_debug("[%s] shutdown", cmdh_str);
1020  engine = cmdhandler->engine;
1021  engine->cmdhandler_done = 1;
1022  return;
1023 }
1024 
1025 
1030 void
1032 {
1033  allocator_type* allocator = NULL;
1034  if (!cmdhandler) {
1035  return;
1036  }
1037  allocator = cmdhandler->allocator;
1038  allocator_deallocate(allocator, (void*) cmdhandler);
1039  return;
1040 }
1041 
signconf_type * signconf_create(void)
Definition: signconf.c:47
void ixfr_cleanup(ixfr_type *ixfr)
Definition: ixfr.c:320
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:173
void engine_wakeup_workers(engine_type *engine)
Definition: engine.c:444
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:771
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:882
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
adapter_mode type
Definition: adapter.h:58
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:964
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:94
void ods_str_trim(char *str)
Definition: file.c:556
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
adapter_type * adinbound
Definition: zone.h:81
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:105
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:118
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:104
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:99
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:95
void ods_log_warning(const char *format,...)
Definition: log.c:318
void cmdhandler_cleanup(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:1031
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