#include #include #include #include #include #include "odhcpd.h" #define READ_END 0 #define WRITE_END 1 static void update_cb(struct uloop_fd *u, unsigned int events); static void update_proc_cb(struct uloop_process *c, int ret); static void update_time_cb(struct uloop_timeout *t); static int dns_start(); static int dns_update_init(); static ssize_t dns_write(const char *buf, size_t count); static struct uloop_fd update_in = { .fd = -1, .cb = update_cb }; static struct uloop_fd update_err = { .fd = -1, .cb = update_cb }; static struct uloop_process update_proc = { .cb = update_proc_cb }; static int update_pipes[3][2] = {{-1, -1}, {-1, -1}, {-1, -1}}; static struct uloop_timeout update_time = { .cb = update_time_cb }; static void update_time_cb(struct uloop_timeout *t) { const char CMD_QUIT[] = "quit\n"; syslog(LOG_ERR, "update_time"); if (update_pipes[1][WRITE_END] < 0) { return; } dns_write(CMD_QUIT, sizeof(CMD_QUIT)); } static void update_cb(struct uloop_fd *u, unsigned int events) { syslog(LOG_ERR, "update_cb: %d %d", u->fd, events); // if (events & ULOOP_READ) { char buf[512]; int len = 0; if ((len = read(u->fd, buf, sizeof(buf)-1)) > 0) { buf[len] = 0; syslog(LOG_ERR, "update_cb: read '%s'", buf); } // } syslog(LOG_ERR, "update_cb: read done"); } static void update_proc_cb(struct uloop_process *c, int ret) { syslog(LOG_ERR, "update_cb: process exit: %d", ret); uloop_timeout_cancel(&update_time); c->pid = 0; uloop_fd_delete(&update_in); update_in.fd = -1; uloop_fd_delete(&update_err); update_err.fd = -1; close(update_pipes[0][READ_END]); close(update_pipes[1][WRITE_END]); close(update_pipes[2][READ_END]); update_pipes[0][READ_END] = -1; update_pipes[1][WRITE_END] = -1; update_pipes[2][READ_END] = -1; } static ssize_t dns_write(const char *buf, size_t count) { if (update_pipes[1][WRITE_END] < 0) { if (dns_start() < 0) return -1; } uloop_timeout_set(&update_time, 10 * 1000); return write(update_pipes[1][WRITE_END], buf, count); } int dns_update_rr(const char *hostname, int family, const void *addr) { if (!config.nsupdate_domain) { return 0; } if (!hostname) { syslog(LOG_ERR, "update_cb: no hostname"); return 0; } dns_update_init(); char tmp_addr[INET6_ADDRSTRLEN]; inet_ntop(family, addr, tmp_addr, sizeof(tmp_addr)); char buf[512]=""; int res = snprintf(buf, sizeof(buf), "add %s.%s. 3600 %s %s\n", hostname, config.nsupdate_domain, family==AF_INET6?"AAAA":"A", tmp_addr); // build_nsupdate(name, 'dhcid', build_dhcid(TYPE_HWID, mac)) // build_nsupdate(name, 'dhcid', build_dhcid(TYPE_DUID, duid)) syslog(LOG_ERR, "dns_update_rr: buf=%s", buf); if (res > 0 && res < (int)sizeof(buf)) { res = dns_write(buf, strlen(buf)); syslog(LOG_ERR, "dns_update_rr: write %d %zd", res, strlen(buf)); syslog(LOG_ERR, "dns_update_rr: hostname=%s addr=%s", hostname, tmp_addr); } return 0; } int dns_update_finish() { const char CMD[] = "send\n"; int res = dns_write(CMD, strlen(CMD)); syslog(LOG_ERR, "dns_update_finish: write %d %zd", res, strlen(CMD)); return res; } int dns_reload() { return 0; } static int dns_update_init() { struct { const char *name; const char *value; } params[] = { { "key", config.nsupdate_key }, { "server", config.nsupdate_server }, { "zone", config.nsupdate_zone }, { NULL, NULL }, }; for (int i = 0; params[i].name; i++) { if (!params[i].value) continue; char buf[512]; int len = snprintf(buf, sizeof(buf), "%s %s\n", params[i].name, params[i].value); if (len < 0 || len > (int)sizeof(buf)) continue; syslog(LOG_ERR, "dns_reload: %s=%s", params[i].name, params[i].value); int res = dns_write(buf, len); syslog(LOG_ERR, "dns_reload: write %d %d", res, len); } return 0; } int dns_init() { syslog(LOG_ERR, "dns_init"); return -1; } static int dns_start() { /* if (update_pipes[0] > -1) */ /* close(update_pipes[0]); */ /* if (update_pipes[1] > -1) */ /* close(update_pipes[1]); */ for (int i = 0; i < 3; i++) { if (pipe2(update_pipes[i], 0) < 0) { syslog(LOG_ERR, "dns_init: pipe2 failed"); return -1; } } int pid = fork(); switch (pid) { case 0: /* child */ syslog(LOG_ERR, "dns_init: child"); dup2(update_pipes[0][WRITE_END], STDOUT_FILENO); dup2(update_pipes[1][READ_END], STDIN_FILENO); dup2(update_pipes[2][WRITE_END], STDERR_FILENO); close(update_pipes[0][READ_END]); close(update_pipes[1][WRITE_END]); close(update_pipes[2][READ_END]); char *argv[2] = {"/root/knsupdate.sh", NULL}; execv(argv[0], argv); syslog(LOG_ERR, "dns_init: exec error?"); return 0; case -1: /* error returned in parent. */ syslog(LOG_ERR, "dns_init: failed"); return -1; default: /* parent */ break; } syslog(LOG_ERR, "dns_init: parent '%d'", pid); update_in.fd = update_pipes[0][READ_END]; update_err.fd = update_pipes[2][READ_END]; close(update_pipes[0][WRITE_END]); close(update_pipes[1][READ_END]); close(update_pipes[2][WRITE_END]); update_pipes[0][WRITE_END] = -1; update_pipes[1][READ_END] = -1; update_pipes[2][WRITE_END] = -1; uloop_fd_add(&update_in, ULOOP_READ | ULOOP_BLOCKING); uloop_fd_add(&update_err, ULOOP_READ | ULOOP_BLOCKING); update_proc.pid = pid; uloop_process_add(&update_proc); //dns_reload(); return 0; }