summaryrefslogtreecommitdiffhomepage
path: root/src/dnsupdate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dnsupdate.c')
-rw-r--r--src/dnsupdate.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/dnsupdate.c b/src/dnsupdate.c
new file mode 100644
index 0000000..e8550a6
--- /dev/null
+++ b/src/dnsupdate.c
@@ -0,0 +1,217 @@
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <libubox/uloop.h>
+#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;
+}