summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.c34
-rw-r--r--src/dhcpv4.c4
-rw-r--r--src/dhcpv6-ia.c27
-rw-r--r--src/dnsupdate.c217
-rw-r--r--src/odhcpd.c1
-rw-r--r--src/odhcpd.h9
6 files changed, 287 insertions, 5 deletions
diff --git a/src/config.c b/src/config.c
index 71b786c..dc0722e 100644
--- a/src/config.c
+++ b/src/config.c
@@ -172,6 +172,10 @@ enum {
ODHCPD_ATTR_LEASEFILE,
ODHCPD_ATTR_LEASETRIGGER,
ODHCPD_ATTR_LOGLEVEL,
+ ODHCPD_ATTR_NSUPDATE_DOMAIN,
+ ODHCPD_ATTR_NSUPDATE_KEY,
+ ODHCPD_ATTR_NSUPDATE_SERVER,
+ ODHCPD_ATTR_NSUPDATE_ZONE,
ODHCPD_ATTR_MAX
};
@@ -181,6 +185,10 @@ static const struct blobmsg_policy odhcpd_attrs[ODHCPD_ATTR_MAX] = {
[ODHCPD_ATTR_LEASEFILE] = { .name = "leasefile", .type = BLOBMSG_TYPE_STRING },
[ODHCPD_ATTR_LEASETRIGGER] = { .name = "leasetrigger", .type = BLOBMSG_TYPE_STRING },
[ODHCPD_ATTR_LOGLEVEL] = { .name = "loglevel", .type = BLOBMSG_TYPE_INT32 },
+ [ODHCPD_ATTR_NSUPDATE_DOMAIN] = { .name = "nsupdate_domain", .type = BLOBMSG_TYPE_STRING },
+ [ODHCPD_ATTR_NSUPDATE_KEY] = { .name = "nsupdate_key", .type = BLOBMSG_TYPE_STRING },
+ [ODHCPD_ATTR_NSUPDATE_SERVER] = { .name = "nsupdate_server", .type = BLOBMSG_TYPE_STRING },
+ [ODHCPD_ATTR_NSUPDATE_ZONE] = { .name = "nsupdate_zone", .type = BLOBMSG_TYPE_STRING },
};
const struct uci_blob_param_list odhcpd_attr_list = {
@@ -326,6 +334,26 @@ static void set_config(struct uci_section *s)
setlogmask(LOG_UPTO(config.log_level));
}
}
+
+ if ((c = tb[ODHCPD_ATTR_NSUPDATE_DOMAIN])) {
+ free(config.nsupdate_domain);
+ config.nsupdate_domain = strdup(blobmsg_get_string(c));
+ }
+
+ if ((c = tb[ODHCPD_ATTR_NSUPDATE_KEY])) {
+ free(config.nsupdate_key);
+ config.nsupdate_key = strdup(blobmsg_get_string(c));
+ }
+
+ if ((c = tb[ODHCPD_ATTR_NSUPDATE_SERVER])) {
+ free(config.nsupdate_server);
+ config.nsupdate_server = strdup(blobmsg_get_string(c));
+ }
+
+ if ((c = tb[ODHCPD_ATTR_NSUPDATE_ZONE])) {
+ free(config.nsupdate_zone);
+ config.nsupdate_zone = strdup(blobmsg_get_string(c));
+ }
}
static double parse_leasetime(struct blob_attr *c) {
@@ -1210,6 +1238,8 @@ void odhcpd_reload(void)
uci_unload(uci, dhcp);
uci_free_context(uci);
+
+ dns_reload();
}
static void handle_signal(int signal)
@@ -1234,6 +1264,7 @@ static struct uloop_fd reload_fd = { .fd = -1, .cb = reload_cb };
void odhcpd_run(void)
{
+ syslog(LOG_DEBUG, "odhcpd_run");
if (pipe2(reload_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {}
reload_fd.fd = reload_pipe[0];
@@ -1248,6 +1279,9 @@ void odhcpd_run(void)
sleep(1);
#endif
+ syslog(LOG_DEBUG, "pre dns_init");
+ dns_init();
+ syslog(LOG_DEBUG, "after dns_init");
odhcpd_reload();
uloop_run();
}
diff --git a/src/dhcpv4.c b/src/dhcpv4.c
index a3b0e33..4bab081 100644
--- a/src/dhcpv4.c
+++ b/src/dhcpv4.c
@@ -917,6 +917,10 @@ void dhcpv4_handle_msg(void *addr, void *data, size_t len,
ubus_bcast_dhcp_event("dhcp.ack", req->chaddr, req->hlen, &reply.yiaddr,
a ? a->hostname : NULL, iface->ifname);
#endif
+ if (msg == DHCPV4_MSG_ACK) {
+ dns_update_rr(a ? a->hostname : NULL, AF_INET, &reply.yiaddr);
+ dns_update_finish();
+ }
}
static bool dhcpv4_insert_assignment(struct list_head *list, struct dhcp_assignment *a,
diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c
index e8255b5..af0b367 100644
--- a/src/dhcpv6-ia.c
+++ b/src/dhcpv6-ia.c
@@ -453,12 +453,26 @@ void dhcpv6_ia_write_statefile(void)
}
}
-static void __apply_lease(struct dhcp_assignment *a,
+static void __apply_lease_na(struct dhcp_assignment *a,
struct odhcpd_ipaddr *addrs, ssize_t addr_len, bool add)
{
- if (a->flags & OAF_DHCPV6_NA)
- return;
+ for (ssize_t i = 0; i < addr_len; ++i) {
+ struct in6_addr addr;
+ /* if (ADDR_MATCH_PIO_FILTER(&addrs[i], a->iface)) */
+ /* continue; */
+
+ addr = addrs[i].addr.in6;
+ addr.s6_addr32[2] = htonl(a->assigned_host_id >> 32);
+ addr.s6_addr32[3] = htonl(a->assigned_host_id & UINT32_MAX);
+ dns_update_rr(a->hostname, AF_INET6, &addr);
+ }
+ dns_update_finish();
+}
+
+static void __apply_lease_pd(struct dhcp_assignment *a,
+ struct odhcpd_ipaddr *addrs, ssize_t addr_len, bool add)
+{
for (ssize_t i = 0; i < addr_len; ++i) {
struct in6_addr prefix;
@@ -479,7 +493,10 @@ static void apply_lease(struct dhcp_assignment *a, bool add)
struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
ssize_t addrlen = (a->managed) ? a->managed_size : (ssize_t)iface->addr6_len;
- __apply_lease(a, addrs, addrlen, add);
+ if (a->flags & OAF_DHCPV6_NA)
+ __apply_lease_na(a, addrs, addrlen, add);
+ else
+ __apply_lease_pd(a, addrs, addrlen, add);
}
/* Set border assignment size based on the IPv6 address prefixes */
@@ -774,7 +791,7 @@ static void handle_addrlist_change(struct netevent_handler_info *info)
list_for_each_entry(c, &iface->ia_assignments, head) {
if ((c->flags & OAF_DHCPV6_PD) && !(iface->ra_flags & ND_RA_FLAG_MANAGED)
&& (c->flags & OAF_BOUND))
- __apply_lease(c, info->addrs_old.addrs,
+ __apply_lease_pd(c, info->addrs_old.addrs,
info->addrs_old.len, false);
}
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;
+}
diff --git a/src/odhcpd.c b/src/odhcpd.c
index 9797507..3ab172f 100644
--- a/src/odhcpd.c
+++ b/src/odhcpd.c
@@ -130,6 +130,7 @@ int main(int argc, char **argv)
return 4;
#endif
+ syslog(LOG_ERR, "pre odhcpd_run");
odhcpd_run();
return 0;
}
diff --git a/src/odhcpd.h b/src/odhcpd.h
index ff7e105..4cdf5a4 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -149,6 +149,10 @@ struct config {
char *dhcp_cb;
char *dhcp_statefile;
int log_level;
+ char *nsupdate_domain;
+ char *nsupdate_key;
+ char *nsupdate_server;
+ char *nsupdate_zone;
};
@@ -446,4 +450,9 @@ int router_setup_interface(struct interface *iface, bool enable);
int dhcpv6_setup_interface(struct interface *iface, bool enable);
int ndp_setup_interface(struct interface *iface, bool enable);
+int dns_init();
+int dns_update_rr(const char *hostname, int family, const void *addr);
+int dns_update_finish();
+int dns_reload();
+
void odhcpd_reload(void);