aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS12
-rw-r--r--doc/nssync.88
-rw-r--r--doc/nssync.texi7
-rw-r--r--src/Makefile.am1
-rw-r--r--src/config.c5
-rw-r--r--src/iflist.c93
-rw-r--r--src/nssync.c7
-rw-r--r--src/nssync.h14
-rw-r--r--src/output.c109
9 files changed, 231 insertions, 25 deletions
diff --git a/NEWS b/NEWS
index b392847..0a2ae0d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-NSsync NEWS -- history of user-visible changes. 2014-06-27
+NSsync NEWS -- history of user-visible changes. 2014-12-01
Copyright (C) 2011, 2012, 2014 Sergey Poznyakoff
See the end of file for copying conditions.
@@ -6,6 +6,16 @@ Please send nssync bug reports to <gray+nssync@gnu.org.ua>
Version 1.1.90 (Git)
+* check-ns
+
+This new configuration statement controls which zones are served by
+nssync. If set to true, nssync will check the list of NS servers
+prior to creating a zone file. The file will be created only if IPv4
+address of one of the servers matches one of the IP addresses of the
+host on which nssync is run.
+
+* Fix coredump if mysql is not in slave mode and slave status is requested
+
Version 1.1, 2012-03-27
diff --git a/doc/nssync.8 b/doc/nssync.8
index 1f62a88..6ea3121 100644
--- a/doc/nssync.8
+++ b/doc/nssync.8
@@ -13,7 +13,7 @@
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with Nssync. If not, see <http://www.gnu.org/licenses/>.
-.TH NSSYNC "8" "June 27, 2014" "NSSYNC" ""
+.TH NSSYNC "8" "December 1, 2014" "NSSYNC" ""
.SH NAME
\fBnssync\fR \- A DNS Zone File Maintenance Utility
@@ -141,6 +141,12 @@ Give a short usage message.
.SH CONFIGURATION FILE
.SS General Settings
.TP
+\fBcheck\-ns\fR \fIBOOL\fR;
+If set to \fBtrue\fR, \fBnssync\fR will check the list of NS
+servers prior to creating a zone file. The file will be created only
+if IPv4 address of one of the servers matches one of the IP addresses
+of the host on which \fBnssync\fR is run.
+.TP
\fBpidfile\fR \fIFILE\fR;
At startup, check if \fIFILE\fR already exists and is owned by an existing
process. Exit if so. Use this statement to avoid accidentally
diff --git a/doc/nssync.texi b/doc/nssync.texi
index 8c1a784..ed3099b 100644
--- a/doc/nssync.texi
+++ b/doc/nssync.texi
@@ -206,6 +206,13 @@ Sets the name for the temporary directory. This is a directory where
point to an existing directory.
@end deffn
+@deffn {Configuration} check-ns @var{bool}
+If set to @code{true}, @command{nssync} will check the list of NS
+servers prior to creating a zone file. The file will be created only
+if IPv4 address of one of the servers matches one of the IP addresses
+of the host on which @command{nssync} is run.
+@end deffn
+
@deffn {Configuration} named-conf @var{file}
Defines the full pathname of the @command{named} configuration file.
Default is @file{/etc/named.conf}.
diff --git a/src/Makefile.am b/src/Makefile.am
index 8fab7c0..00509e8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,6 +18,7 @@ sbin_PROGRAMS = nssync
nssync_SOURCES = \
bindcf.c\
config.c\
+ iflist.c\
nssync.c\
nssync.h\
output.c\
diff --git a/src/config.c b/src/config.c
index 07e684a..6f51a46 100644
--- a/src/config.c
+++ b/src/config.c
@@ -156,6 +156,11 @@ static struct grecs_keyword nssync_kw[] = {
{ "reload-command",
NULL, "Command to reload the nameserver",
grecs_type_string, GRECS_DFLT, &reload_command },
+
+ { "check-ns",
+ NULL,
+ "Synchronize only if this host is listed as one of the nameservers",
+ grecs_type_bool, GRECS_DFLT, &check_ns },
{ "sync", N_("tag: string"), N_("Define a synchronization block"),
grecs_type_section, GRECS_DFLT, NULL, 0, cb_sync, NULL, sync_kw },
diff --git a/src/iflist.c b/src/iflist.c
new file mode 100644
index 0000000..a7d0a1d
--- /dev/null
+++ b/src/iflist.c
@@ -0,0 +1,93 @@
+/* This file is part of NSsync
+ Copyright (C) 2011, 2014 Sergey Poznyakoff
+
+ NSsync is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ NSsync is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NSsync. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "nssync.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+
+struct sockaddr_in *hostaddr;
+size_t addr_count;
+
+void
+get_host_addresses()
+{
+#ifdef SIOCGIFADDR
+ struct if_nameindex *idx;
+ size_t i, j;
+ struct ifreq ifr;
+ int fd;
+
+ idx = if_nameindex();
+ if (!idx) {
+ error("can't get list of interfaces: %s", strerror(errno));
+ exit(EX_UNAVAILABLE);
+ }
+
+
+ for (addr_count = 0; idx[addr_count].if_index > 0; addr_count++)
+ ;
+
+ if (addr_count) {
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ error("can't open socket: %s", strerror(errno));
+ exit(EX_UNAVAILABLE);
+ }
+
+ hostaddr = grecs_calloc(addr_count, sizeof(hostaddr[0]));
+ for (i = j = 0; i < addr_count; i++) {
+ size_t len = strlen(idx[i].if_name);
+ if (len >= sizeof(ifr.ifr_name)) {
+ error("interface name too long: %s",
+ idx[i].if_name);
+ continue;
+ }
+ strcpy(ifr.ifr_name, idx[i].if_name);
+ if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) {
+ error("ioctl failed for %s: %s",
+ idx[i].if_name, strerror(errno));
+ continue;
+ }
+ memcpy(&hostaddr[j], &ifr.ifr_addr,
+ sizeof(struct sockaddr_in));
+ ++j;
+ }
+ addr_count = j;
+ close(fd);
+ }
+
+ if_freenameindex(idx);
+#else
+ error("check-ns is not supported on this host");
+ exit(EX_UNAVAILABLE);
+#endif
+}
+
+int
+is_my_sockaddr(struct sockaddr_in *s)
+{
+ size_t i;
+
+ for (i = 0; i < addr_count; i++)
+ if (memcmp(hostaddr + i, s, sizeof(*s)) == 0)
+ return 1;
+ return 0;
+}
diff --git a/src/nssync.c b/src/nssync.c
index 8ea95d3..dcc3592 100644
--- a/src/nssync.c
+++ b/src/nssync.c
@@ -31,6 +31,7 @@ char *reload_command = "/usr/sbin/rndc reload";
char *compare_command = "cmp $oldfile $newfile > /dev/null";
unsigned error_count;
unsigned changed_zones;
+int check_ns;
#include "cmdline.h"
@@ -425,13 +426,17 @@ int
main(int argc, char **argv)
{
struct grecs_list_entry *ep;
-
+
config_init();
parse_options(argc, argv);
if (preprocess_only)
exit(grecs_preproc_run(config_file, grecs_preprocessor) ?
EX_CONFIG : 0);
config_parse();
+
+ if (check_ns)
+ get_host_addresses();
+
sql_connect();
check_pidfile();
diff --git a/src/nssync.h b/src/nssync.h
index fc7ef0c..69149e8 100644
--- a/src/nssync.h
+++ b/src/nssync.h
@@ -37,6 +37,7 @@ extern char *pidfile;
extern char *tempdir;
extern char *compare_command;
extern char *reload_command;
+extern int check_ns;
extern unsigned changed_zones;
@@ -88,6 +89,16 @@ int sql_do_query(const char *query,
int (*fun)(MYSQL_ROW, unsigned, void*), void *data);
int sql_get_slave_status(char **pfile, char **poff);
+void get_host_addresses(void);
+struct sockaddr_in;
+int is_my_sockaddr(struct sockaddr_in *s);
+
+struct nsdef {
+ struct nsdef *next;
+ char *type;
+ char *data;
+};
+
struct nssync {
char *tag;
char *zone_conf_file;
@@ -99,6 +110,9 @@ struct nssync {
char *rr_query;
char *rev_rr_query;
char *ns_query;
+
+ struct nsdef *nsdef_head, *nsdef_tail;
+ int myzone;
char *file_name;
char *temp_file_name;
diff --git a/src/output.c b/src/output.c
index a684201..fb8b66c 100644
--- a/src/output.c
+++ b/src/output.c
@@ -15,6 +15,9 @@
along with NSsync. If not, see <http://www.gnu.org/licenses/>. */
#include "nssync.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
#define S(s) ((s) ? (s) : NULL)
@@ -26,15 +29,49 @@ enum {
};
int
-format_ns_record(MYSQL_ROW row, unsigned nf, void *data)
+save_ns_record(MYSQL_ROW row, unsigned nf, void *data)
{
struct nssync *sp = data;
+ struct nsdef *ns;
if (nf != _ns_nfields) {
error("NS query returned wrong number of fields");
return 1;
}
+
+ ns = grecs_malloc(sizeof(*ns));
+ ns->type = grecs_strdup(row[f_ns_type]);
+ ns->data = grecs_strdup(row[f_ns_data]);
/* FIXME: TTL */
- fprintf(sp->fp, "\t%s\t%s\n", row[f_ns_type], row[f_ns_data]);
+ ns->next = NULL;
+
+ if (sp->nsdef_tail)
+ sp->nsdef_tail->next = ns;
+ else
+ sp->nsdef_head = ns;
+ sp->nsdef_tail = ns;
+
+ if (check_ns && !sp->myzone && strcasecmp(ns->type, "NS") == 0) {
+ struct addrinfo *res, *ap, hints;
+ int rc;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ rc = getaddrinfo(ns->data, NULL, &hints, &res);
+ if (rc) {
+ error("can't resolve %s: %s", ns->data,
+ gai_strerror(rc));
+ return 0;
+ }
+
+ for (ap = res; ap; ap = ap->ai_next) {
+ if (is_my_sockaddr((struct sockaddr_in*)res->ai_addr)) {
+ sp->myzone = 1;
+ break;
+ }
+ }
+ freeaddrinfo(res);
+ }
+
return 0;
}
@@ -95,12 +132,30 @@ is_reverse_zone(const char *str)
strcasecmp(str + len - sizeof(suffix) + 1, suffix) == 0;
}
+void
+free_nsdef(struct nssync *sp)
+{
+ struct nsdef *ns;
+
+ for (ns = sp->nsdef_head; ns; ) {
+ struct nsdef *next = ns->next;
+ free(ns->type);
+ free(ns->data);
+ free(ns);
+ ns = ns->next;
+ }
+ sp->nsdef_head = sp->nsdef_tail = NULL;
+}
+
int
format_soa_record(MYSQL_ROW row, unsigned nf, void *data)
{
struct nssync *sp = data;
struct wordsplit ws;
const char *env[3];
+ int wsflags = WRDSF_NOCMD | WRDSF_ENV | WRDSF_ENV_KV |
+ WRDSF_NOSPLIT | WRDSF_KEEPUNDEF;
+ struct nsdef *ns;
if (nf != _soa_nfields) {
error("SOA query returned wrong number of fields");
@@ -109,6 +164,32 @@ format_soa_record(MYSQL_ROW row, unsigned nf, void *data)
if (!row[f_soa_type])
return 0;
+ free_nsdef(sp);
+ sp->myzone = !check_ns;
+
+ /* Fill the list of NS servers */
+ env[0] = "zone";
+ env[1] = row[f_soa_zone];
+ env[2] = 0;
+
+ if (sp->ns_query) {
+ ws.ws_env = env;
+ if (wordsplit(sp->ns_query, &ws, wsflags)) {
+ error("cannot split ns_query: %s",
+ wordsplit_strerror(&ws));
+ exit(EX_SOFTWARE);
+ }
+ wsflags |= WRDSF_REUSE;
+ if (sql_do_query(ws.ws_wordv[0], save_ns_record, sp))
+ exit(EX_UNAVAILABLE);
+ }
+
+ if (!sp->myzone) {
+ debug(1,("%s: not served by me", row[f_soa_zone]));
+ wordsplit_free(&ws);
+ return 0;
+ }
+
grecs_free(sp->file_name);
sp->file_name = bindcf_lookup(sp, row[f_soa_zone]);
if (!sp->file_name)
@@ -140,29 +221,13 @@ format_soa_record(MYSQL_ROW row, unsigned nf, void *data)
row[f_soa_retry],
row[f_soa_expire],
row[f_soa_minimum]);
-
- env[0] = "zone";
- env[1] = row[f_soa_zone];
- env[2] = 0;
- if (sp->ns_query) {
- ws.ws_env = env;
- if (wordsplit(sp->ns_query, &ws,
- WRDSF_NOCMD | WRDSF_ENV | WRDSF_ENV_KV |
- WRDSF_NOSPLIT | WRDSF_KEEPUNDEF)) {
- error("cannot split ns_query: %s",
- wordsplit_strerror(&ws));
- exit(EX_SOFTWARE);
- }
-
- if (sql_do_query(ws.ws_wordv[0], format_ns_record, sp))
- exit(EX_UNAVAILABLE);
- }
+ for (ns = sp->nsdef_head; ns; ns = ns->next)
+ /* FIXME: TTL */
+ fprintf(sp->fp, "\t%s\t%s\n", ns->type, ns->data);
if (wordsplit((sp->rev_rr_query && is_reverse_zone(row[f_soa_zone])) ?
- sp->rev_rr_query : sp->rr_query, &ws,
- WRDSF_NOCMD | WRDSF_ENV | WRDSF_ENV_KV | WRDSF_NOSPLIT |
- WRDSF_KEEPUNDEF | WRDSF_REUSE)) {
+ sp->rev_rr_query : sp->rr_query, &ws, wsflags)) {
error("cannot split rr_query: %s", wordsplit_strerror(&ws));
exit(EX_SOFTWARE);
}

Return to:

Send suggestions and report system problems to the System administrator.