conf_remote_t conf_remote_txn( conf_t *conf, knot_db_txn_t *txn, conf_val_t *id, size_t index) { assert(id != NULL && id->item != NULL); assert(id->item->type == YP_TSTR || (id->item->type == YP_TREF && id->item->var.r.ref->var.g.id->type == YP_TSTR)); conf_remote_t out = { { AF_UNSPEC } }; conf_val_t rundir_val = conf_get_txn(conf, txn, C_SRV, C_RUNDIR); char *rundir = conf_abs_path(&rundir_val, NULL); // Get indexed remote address. conf_val_t val = conf_id_get_txn(conf, txn, C_RMT, C_ADDR, id); for (size_t i = 0; val.code == KNOT_EOK && i < index; i++) { if (i == 0) { conf_val(&val); } conf_val_next(&val); } // Index overflow causes empty socket. out.addr = conf_addr(&val, rundir); // Get outgoing address if family matches (optional). val = conf_id_get_txn(conf, txn, C_RMT, C_VIA, id); while (val.code == KNOT_EOK) { struct sockaddr_storage via = conf_addr(&val, rundir); if (via.ss_family == out.addr.ss_family) { out.via = conf_addr(&val, rundir); break; } conf_val_next(&val); } // Get TSIG key (optional). conf_val_t key_id = conf_id_get_txn(conf, txn, C_RMT, C_KEY, id); if (key_id.code == KNOT_EOK) { out.key.name = (knot_dname_t *)conf_dname(&key_id); val = conf_id_get_txn(conf, txn, C_KEY, C_ALG, &key_id); out.key.algorithm = conf_opt(&val); val = conf_id_get_txn(conf, txn, C_KEY, C_SECRET, &key_id); out.key.secret.data = (uint8_t *)conf_bin(&val, &out.key.secret.size); } free(rundir); return out; }
/*! \brief Event loop listening for signals and remote commands. */ static void event_loop(server_t *server) { uint8_t buf[KNOT_WIRE_MAX_PKTSIZE]; size_t buflen = sizeof(buf); /* Read control socket configuration. */ conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN); conf_val_t rundir_val = conf_get(conf(), C_SRV, C_RUNDIR); char *rundir = conf_abs_path(&rundir_val, NULL); struct sockaddr_storage addr = conf_addr(&listen_val, rundir); free(rundir); /* Bind to control interface (error logging is inside the function. */ int remote = remote_bind(&addr); sigset_t empty; (void)sigemptyset(&empty); /* Run event loop. */ for (;;) { int ret = remote_poll(remote, &empty); /* Events. */ if (ret > 0) { ret = remote_process(server, &addr, remote, buf, buflen); if (ret == KNOT_CTL_STOP) { break; } } /* Interrupts. */ if (sig_req_stop) { break; } if (sig_req_reload) { sig_req_reload = false; server_reload(server, conf()->filename); } } server_stop(server); /* Close remote control interface. */ remote_unbind(&addr, remote); /* Wait for server to finish. */ server_wait(server); }
static char* get_filename( conf_t *conf, knot_db_txn_t *txn, const knot_dname_t *zone, const char *name) { assert(name); const char *end = name + strlen(name); char out[1024] = ""; do { // Search for a formatter. const char *pos = strchr(name, '%'); // If no formatter, copy the rest of the name. if (pos == NULL) { if (strlcat(out, name, sizeof(out)) >= sizeof(out)) { CONF_LOG_ZONE(LOG_WARNING, zone, "too long zonefile name"); return NULL; } break; } // Copy constant block. char *block = strndup(name, pos - name); if (block == NULL || strlcat(out, block, sizeof(out)) >= sizeof(out)) { CONF_LOG_ZONE(LOG_WARNING, zone, "too long zonefile name"); return NULL; } free(block); // Move name pointer behind the formatter. name = pos + 2; char buff[512] = ""; uint8_t idx1, idx2; bool failed = false; const char type = *(pos + 1); switch (type) { case '%': strlcat(buff, "%", sizeof(buff)); break; case 'c': if (get_index(&name, end, &idx1, &idx2) != KNOT_EOK || str_char(zone, buff, sizeof(buff), idx1, idx2) != KNOT_EOK) { failed = true; } break; case 'l': if (get_index(&name, end, &idx1, NULL) != KNOT_EOK || str_label(zone, buff, sizeof(buff), idx1) != KNOT_EOK) { failed = true; } break; case 's': if (str_zone(zone, buff, sizeof(buff)) != KNOT_EOK) { failed = true; } break; case '\0': CONF_LOG_ZONE(LOG_WARNING, zone, "ignoring missing " "trailing zonefile formatter"); continue; default: CONF_LOG_ZONE(LOG_WARNING, zone, "ignoring zonefile " "formatter '%%%c'", type); continue; } if (failed) { CONF_LOG_ZONE(LOG_WARNING, zone, "failed to process " "zonefile formatter '%%%c'", type); return NULL; } if (strlcat(out, buff, sizeof(out)) >= sizeof(out)) { CONF_LOG_ZONE(LOG_WARNING, zone, "too long zonefile name"); return NULL; } } while (name < end); // Use storage prefix if not absolute path. if (out[0] == '/') { return strdup(out); } else { conf_val_t val = conf_zone_get_txn(conf, txn, C_STORAGE, zone); char *storage = conf_abs_path(&val, NULL); if (storage == NULL) { return NULL; } char *abs = sprintf_alloc("%s/%s", storage, out); free(storage); return abs; } }