OpenDNSSEC-signer  1.4.8.2
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  engine->need_to_reload = 1;
610  lock_basic_lock(&engine->signal_lock);
611  lock_basic_alarm(&engine->signal_cond);
612  lock_basic_unlock(&engine->signal_lock);
613  (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n");
614  ods_writen(sockfd, buf, strlen(buf));
615  return;
616 }
617 
618 
623 static void
624 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc)
625 {
626  engine_type* engine = NULL;
627  char buf[ODS_SE_MAXLINE];
628  ods_log_assert(cmdc);
629  ods_log_assert(cmdc->engine);
630  engine = (engine_type*) cmdc->engine;
631  engine->need_to_exit = 1;
632  lock_basic_lock(&engine->signal_lock);
633  lock_basic_alarm(&engine->signal_cond);
634  lock_basic_unlock(&engine->signal_lock);
635  (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE);
636  ods_writen(sockfd, buf, strlen(buf));
637  return;
638 }
639 
640 
645 static void
646 cmdhandler_handle_cmd_start(int sockfd)
647 {
648  char buf[ODS_SE_MAXLINE];
649  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n");
650  ods_writen(sockfd, buf, strlen(buf));
651  return;
652 }
653 
654 
659 static void
660 cmdhandler_handle_cmd_running(int sockfd)
661 {
662  char buf[ODS_SE_MAXLINE];
663  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n");
664  ods_writen(sockfd, buf, strlen(buf));
665  return;
666 }
667 
668 
673 static void
674 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val)
675 {
676  engine_type* engine = NULL;
677  char buf[ODS_SE_MAXLINE];
678  ods_log_assert(cmdc);
679  ods_log_assert(cmdc->engine);
680  engine = (engine_type*) cmdc->engine;
681  ods_log_assert(engine->config);
682  ods_log_init(engine->config->log_filename, engine->config->use_syslog,
683  val);
684  (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val);
685  ods_writen(sockfd, buf, strlen(buf));
686  return;
687 }
688 
689 
694 static void
695 cmdhandler_handle_cmd_error(int sockfd, const char* str)
696 {
697  char buf[ODS_SE_MAXLINE];
698  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)");
699  ods_writen(sockfd, buf, strlen(buf));
700  return;
701 }
702 
703 
708 static void
709 cmdhandler_handle_cmd_unknown(int sockfd, const char* str)
710 {
711  char buf[ODS_SE_MAXLINE];
712  (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n",
713  str?str:"(null)");
714  ods_writen(sockfd, buf, strlen(buf));
715  return;
716 }
717 
718 
737 static void
738 cmdhandler_handle_cmd(cmdhandler_type* cmdc)
739 {
740  ssize_t n = 0;
741  int sockfd = 0;
742  char buf[ODS_SE_MAXLINE];
743 
744  ods_log_assert(cmdc);
745  sockfd = cmdc->client_fd;
746 
747 again:
748  while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) {
749  /* what if this number is smaller than the number of bytes requested? */
750  buf[n-1] = '\0';
751  n--;
752  ods_log_verbose("[%s] received command %s[%i]", cmdh_str, buf, n);
753  ods_str_trim(buf);
754  n = strlen(buf);
755 
756  if (n == 4 && strncmp(buf, "help", n) == 0) {
757  ods_log_debug("[%s] help command", cmdh_str);
758  cmdhandler_handle_cmd_help(sockfd);
759  } else if (n == 5 && strncmp(buf, "zones", n) == 0) {
760  ods_log_debug("[%s] list zones command", cmdh_str);
761  cmdhandler_handle_cmd_zones(sockfd, cmdc);
762  } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) {
763  ods_log_debug("[%s] sign zone command", cmdh_str);
764  if (n == 4 || buf[4] == '\0') {
765  /* NOTE: wouldn't it be nice that we default to --all? */
766  cmdhandler_handle_cmd_error(sockfd, "sign command needs "
767  "an argument (either '--all' or a zone name)");
768  } else if (buf[4] != ' ') {
769  cmdhandler_handle_cmd_unknown(sockfd, buf);
770  } else {
771  cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]);
772  }
773  } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) {
774  ods_log_debug("[%s] clear zone command", cmdh_str);
775  if (n == 5 || buf[5] == '\0') {
776  cmdhandler_handle_cmd_error(sockfd, "clear command needs "
777  "a zone name");
778  } else if (buf[5] != ' ') {
779  cmdhandler_handle_cmd_unknown(sockfd, buf);
780  } else {
781  cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]);
782  }
783  } else if (n == 5 && strncmp(buf, "queue", n) == 0) {
784  ods_log_debug("[%s] list tasks command", cmdh_str);
785  cmdhandler_handle_cmd_queue(sockfd, cmdc);
786  } else if (n == 5 && strncmp(buf, "flush", n) == 0) {
787  ods_log_debug("[%s] flush tasks command", cmdh_str);
788  cmdhandler_handle_cmd_flush(sockfd, cmdc);
789  } else if (n >= 6 && strncmp(buf, "update", 6) == 0) {
790  ods_log_debug("[%s] update command", cmdh_str);
791  if (n == 6 || buf[6] == '\0') {
792  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
793  } else if (buf[6] != ' ') {
794  cmdhandler_handle_cmd_unknown(sockfd, buf);
795  } else {
796  cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]);
797  }
798  } else if (n == 4 && strncmp(buf, "stop", n) == 0) {
799  ods_log_debug("[%s] shutdown command", cmdh_str);
800  cmdhandler_handle_cmd_stop(sockfd, cmdc);
801  return;
802  } else if (n == 5 && strncmp(buf, "start", n) == 0) {
803  ods_log_debug("[%s] start command", cmdh_str);
804  cmdhandler_handle_cmd_start(sockfd);
805  } else if (n == 6 && strncmp(buf, "reload", n) == 0) {
806  ods_log_debug("[%s] reload command", cmdh_str);
807  cmdhandler_handle_cmd_reload(sockfd, cmdc);
808  } else if (n == 7 && strncmp(buf, "running", n) == 0) {
809  ods_log_debug("[%s] running command", cmdh_str);
810  cmdhandler_handle_cmd_running(sockfd);
811  } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) {
812  ods_log_debug("[%s] verbosity command", cmdh_str);
813  if (n == 9 || buf[9] == '\0') {
814  cmdhandler_handle_cmd_error(sockfd, "verbosity command "
815  "an argument (verbosity level)");
816  } else if (buf[9] != ' ') {
817  cmdhandler_handle_cmd_unknown(sockfd, buf);
818  } else {
819  cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10]));
820  }
821  } else if (n >= 10 && strncmp(buf, "retransfer", 10) == 0) {
822  ods_log_debug("[%s] retransfer zone command", cmdh_str);
823  if (n == 10 || buf[10] == '\0') {
824  cmdhandler_handle_cmd_error(sockfd, "retransfer command needs "
825  "an argument (a zone name)");
826  } else if (buf[10] != ' ') {
827  cmdhandler_handle_cmd_unknown(sockfd, buf);
828  } else {
829  cmdhandler_handle_cmd_retransfer(sockfd, cmdc, &buf[11]);
830  }
831  } else if (n > 0) {
832  ods_log_debug("[%s] unknown command", cmdh_str);
833  cmdhandler_handle_cmd_unknown(sockfd, buf);
834  }
835  ods_log_debug("[%s] done handling command %s[%i]", cmdh_str, buf, n);
836  (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> ");
837  ods_writen(sockfd, buf, strlen(buf));
838  }
839 
840  if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) {
841  goto again;
842  } else if (n < 0 && errno == ECONNRESET) {
843  ods_log_debug("[%s] done handling client: %s", cmdh_str,
844  strerror(errno));
845  } else if (n < 0 ) {
846  ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno));
847  }
848  return;
849 }
850 
851 
856 static void*
857 cmdhandler_accept_client(void* arg)
858 {
859  cmdhandler_type* cmdc = (cmdhandler_type*) arg;
860 
863 
864  ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd);
865  cmdhandler_handle_cmd(cmdc);
866  if (cmdc->client_fd) {
867  shutdown(cmdc->client_fd, SHUT_RDWR);
868  close(cmdc->client_fd);
869  }
870  free(cmdc);
871  count--;
872  return NULL;
873 }
874 
875 
881 cmdhandler_create(allocator_type* allocator, const char* filename)
882 {
883  cmdhandler_type* cmdh = NULL;
884  struct sockaddr_un servaddr;
885  int listenfd = 0;
886  int flags = 0;
887  int ret = 0;
888 
889  if (!allocator || !filename) {
890  return NULL;
891  }
892  /* new socket */
893  ods_log_debug("[%s] create socket %s", cmdh_str, filename);
894  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
895  if (listenfd < 0) {
896  ods_log_error("[%s] unable to create cmdhandler: "
897  "socket() failed (%s)", cmdh_str, strerror(errno));
898  return NULL;
899  }
900  /* set it to non-blocking */
901  flags = fcntl(listenfd, F_GETFL, 0);
902  if (flags < 0) {
903  ods_log_error("[%s] unable to create cmdhandler: "
904  "fcntl(F_GETFL) failed (%s)", cmdh_str, strerror(errno));
905  close(listenfd);
906  return NULL;
907  }
908  flags |= O_NONBLOCK;
909  if (fcntl(listenfd, F_SETFL, flags) < 0) {
910  ods_log_error("[%s] unable to create cmdhandler: "
911  "fcntl(F_SETFL) failed (%s)", cmdh_str, strerror(errno));
912  close(listenfd);
913  return NULL;
914  }
915  /* no surprises so far */
916  if (filename) {
917  (void)unlink(filename);
918  }
919  bzero(&servaddr, sizeof(servaddr));
920  servaddr.sun_family = AF_UNIX;
921  strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1);
922 #ifdef HAVE_SOCKADDR_SUN_LEN
923  servaddr.sun_len = strlen(servaddr.sun_path);
924 #endif
925  /* bind and listen... */
926  ret = bind(listenfd, (const struct sockaddr*) &servaddr,
927  SUN_LEN(&servaddr));
928  if (ret != 0) {
929  ods_log_error("[%s] unable to create cmdhandler: "
930  "bind() failed (%s)", cmdh_str, strerror(errno));
931  close(listenfd);
932  return NULL;
933  }
934  ret = listen(listenfd, ODS_SE_MAX_HANDLERS);
935  if (ret != 0) {
936  ods_log_error("[%s] unable to create cmdhandler: "
937  "listen() failed (%s)", cmdh_str, strerror(errno));
938  close(listenfd);
939  return NULL;
940  }
941  /* all ok */
942  cmdh = (cmdhandler_type*) allocator_alloc(allocator,
943  sizeof(cmdhandler_type));
944  if (!cmdh) {
945  ods_log_error("[%s] unable to create cmdhandler: "
946  "allocator_alloc() failed", cmdh_str);
947  close(listenfd);
948  return NULL;
949  }
950  cmdh->allocator = allocator;
951  cmdh->listen_fd = listenfd;
952  cmdh->listen_addr = servaddr;
953  cmdh->need_to_exit = 0;
954  return cmdh;
955 }
956 
957 
962 void
964 {
965  struct sockaddr_un cliaddr;
966  socklen_t clilen;
967  cmdhandler_type* cmdc = NULL;
968  engine_type* engine = NULL;
969  fd_set rset;
970  int connfd = 0;
971  int ret = 0;
972  ods_log_assert(cmdhandler);
973  ods_log_assert(cmdhandler->engine);
974  ods_log_debug("[%s] start", cmdh_str);
975  engine = (engine_type*) cmdhandler->engine;
976  ods_thread_detach(cmdhandler->thread_id);
977  FD_ZERO(&rset);
978  while (cmdhandler->need_to_exit == 0) {
979  clilen = sizeof(cliaddr);
980  FD_SET(cmdhandler->listen_fd, &rset);
981  ret = select(cmdhandler->listen_fd+1, &rset, NULL, NULL, NULL);
982  if (ret < 0) {
983  if (errno != EINTR && errno != EWOULDBLOCK) {
984  ods_log_warning("[%s] select() error: %s", cmdh_str,
985  strerror(errno));
986  }
987  continue;
988  }
989  if (FD_ISSET(cmdhandler->listen_fd, &rset)) {
990  connfd = accept(cmdhandler->listen_fd,
991  (struct sockaddr *) &cliaddr, &clilen);
992  if (connfd < 0) {
993  if (errno != EINTR && errno != EWOULDBLOCK) {
994  ods_log_warning("[%s] accept() error: %s", cmdh_str,
995  strerror(errno));
996  }
997  continue;
998  }
999  /* client accepted, create new thread */
1000  cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type));
1001  if (!cmdc) {
1002  ods_log_crit("[%s] unable to create thread for client: "
1003  "malloc() failed", cmdh_str);
1004  cmdhandler->need_to_exit = 1;
1005  break;
1006  }
1007  cmdc->listen_fd = cmdhandler->listen_fd;
1008  cmdc->client_fd = connfd;
1009  cmdc->listen_addr = cmdhandler->listen_addr;
1010  cmdc->engine = cmdhandler->engine;
1011  cmdc->need_to_exit = cmdhandler->need_to_exit;
1012  ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client,
1013  (void*) cmdc);
1014  count++;
1015  ods_log_debug("[%s] %i clients in progress...", cmdh_str, count);
1016  }
1017  }
1018  ods_log_debug("[%s] shutdown", cmdh_str);
1019  engine = cmdhandler->engine;
1020  engine->cmdhandler_done = 1;
1021  return;
1022 }
1023 
1024 
1029 void
1031 {
1032  allocator_type* allocator = NULL;
1033  if (!cmdhandler) {
1034  return;
1035  }
1036  allocator = cmdhandler->allocator;
1037  allocator_deallocate(allocator, (void*) cmdhandler);
1038  return;
1039 }
1040 
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:173
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:881
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:963
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: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: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:1030
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