aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-08-27 14:05:40 +0300
committerSergey Poznyakoff <gray@gnu.org>2020-08-27 14:15:07 +0300
commit6a463b85146fc5a10a297617bd253a19b1bc6da7 (patch)
treef52df486e862bbdbe7ac341c3b5aa22c6ed32775
parent9b752a26211d60c7003a7590b027bd0000344523 (diff)
downloadnsu-6a463b85146fc5a10a297617bd253a19b1bc6da7.tar.gz
nsu-6a463b85146fc5a10a297617bd253a19b1bc6da7.tar.bz2
Improve debugging and keyfile support.
* Makefile (NSUSRC): Add log.c Add clean and allclean goals. * log.c: New file. * alg.c (nsu_keyfile_private_read,nsu_keyfile_key_read) (nsu_keyfile_read): New functions. * main.c: Move keyfile support to the library. Add debugging statements. * nsu.c: Add debugging statements. * nsu.h (nsu_log_level, nsu_logger): New externs. (nsu_log_msg): New proto. (nsu_log_enabled,nsu_log): New defines. (NSU_KEYFILE_): New constants. (nsu_keyfile_private_read,nsu_keyfile_key_read) (nsu_keyfile_read): New protos.
-rw-r--r--Makefile17
-rw-r--r--alg.c547
-rw-r--r--log.c36
-rw-r--r--main.c253
-rw-r--r--nsu.c8
-rw-r--r--nsu.h41
6 files changed, 666 insertions, 236 deletions
diff --git a/Makefile b/Makefile
index c74f4e7..f9bb6c8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,15 @@
CFLAGS=-ggdb
APPSRC=main.c y.tab.c lex.yy.c
-APPOBJ=${APPSRC: .c=.o}
+APPOBJ=${APPSRC:.c=.o}
-NSUSRC=nsu.c typestr.c alg.c
-NSUOBJ=${NSUSRC: .c=.o}
+NSUSRC=nsu.c typestr.c alg.c log.c
+NSUOBJ=${NSUSRC:.c=.o}
-nsu: main.o $(NSUOBJ) $(APPOBJ)
- cc $(CFLAGS) -o nsu $(NSUOBJ) $(APPOBJ) -lresolv -lnettle
+OBJS=$(NSUOBJ) $(APPOBJ)
+
+nsu: $(OBJS)
+ cc $(CFLAGS) -o nsu $(OBJS) -lresolv -lnettle
$(NSUOBJ) $(APPOBJ): nsu.h
@@ -19,4 +21,9 @@ lex.yy.o: y.tab.h
lex.yy.c: lexer.l
flex -d lexer.l
+clean:
+ rm -f nsu $(OBJS)
+
+allclean: clean
+ rm -f lex.yy.c y.tab.c y.tab.h
diff --git a/alg.c b/alg.c
index a0db787..1c1833c 100644
--- a/alg.c
+++ b/alg.c
@@ -1,5 +1,8 @@
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
#include <nettle/md5.h>
#include <nettle/sha1.h>
#include <nettle/sha2.h>
@@ -168,7 +171,551 @@ nsu_tsig_free(struct nsu_tsig *sgn)
free(sgn->digest);
free(sgn);
}
+
+/* Parse the keyfile name and attempt to extract the keyname from it.
+ *
+ * The FILENAME is expected to match the following pattern:
+ *
+ * K<KEYNAME>.+<ALGCODE>+<NUMBER>.<EXT>
+ *
+ * where <ALGCODE> and <NUMBER> are decimal numbers, <EXT> is any string,
+ * and <ALGCODE> equals ALG. If these conditions are met, the <KEYNAME>
+ * is copied to the allocated memory block and the address of that block
+ * is stored in KEYNAME.
+ *
+ * Return value: 0 - success; KEYNAME holds the key name.
+ * 1 - FILENAME doesn't match the pattern.
+ * -1 - system error; inspect errno for details.
+ */
+static int
+filename_to_keyname(char const *filename, int alg, char **keyname)
+{
+ char const *start, *p, *q;
+ char *key;
+ size_t len;
+
+ p = strrchr(filename, '/');
+ if (p)
+ filename = p + 1;
+
+ if (filename[0] != 'K')
+ return 1;
+ filename++;
+ start = filename;
+ len = strcspn(start, "+");
+ if (len < 2 || start[len] != '+' || start[len-1] != '.')
+ return 1;
+ filename += len + 1;
+
+ p = strchr(filename, '+');
+ if (!p)
+ return 1;
+ for (q = p + 1; *q && *q != '.'; q++) {
+ if (!isdigit(*q))
+ return 1;
+ }
+
+ q = p;
+ while (alg > 0) {
+ if (--q == p)
+ return 1;
+ else if (alg % 10 + '0' != *q)
+ return 1;
+ alg /= 10;
+ }
+
+ key = malloc(len);
+ if (!key)
+ return -1;
+ len--;
+ memcpy(key, start, len);
+ key[len] = 0;
+
+ *keyname = key;
+ return 0;
+}
+
+static int
+filename_to_alg(char const *filename, struct nsu_tsig_alg const **palg)
+{
+ long n;
+ char const *p, *q;
+ char *end;
+ size_t len;
+
+ p = strrchr(filename, '/');
+ if (p)
+ filename = p + 1;
+
+ if (filename[0] != 'K')
+ return 1;
+ filename++;
+ len = strcspn(filename, "+");
+ if (len < 2 || filename[len] != '+' || filename[len-1] != '.')
+ return 1;
+ filename += len + 1;
+
+ p = strchr(filename, '+');
+ if (!p)
+ return 1;
+ for (q = p + 1; *q && *q != '.'; q++) {
+ if (!isdigit(*q))
+ return 1;
+ }
+ errno = 0;
+ n = strtol(filename, &end, 10);
+ if (errno || *end != '+')
+ return 1;
+
+ *palg = nsu_tsig_alg_find_code(n);
+ return 0;
+}
+
+/* Parse the private key file generated by dnssec-keygen.
+ * On success, fill the return arguments:
+ *
+ * palg - pointer to the nsu_tsig_alg structure;
+ * pkeyname - (malloc) Key name or NULL if unable to deduce;
+ * pkey - (malloc) Key value.
+ * pkey_len - length of the key.
+ *
+ * Arguments marked with (malloc) are allocated.
+ *
+ * Return value:
+ * NSU_KEYFILE_OK - success;
+ * NSU_KEYFILE_BAD - bad file format;
+ * NSU_KEYFILE_ALG - file refers to an unknown or unsupported algorithm;
+ * NSU_KEYFILE_ERR - system error; inspect errno;
+ */
+int
+nsu_keyfile_private_read(char const *filename,
+ struct nsu_tsig_alg const **palg,
+ char **pkeyname,
+ uint8_t **pkey, size_t *pkey_len)
+{
+ FILE *fp;
+ char buf[512];
+ int lno = 0;
+ int rc = NSU_KEYFILE_OK;
+ struct nsu_tsig_alg const *alg = NULL;
+ uint8_t *key = NULL;
+ size_t key_len;
+ char *keyname = NULL;
+
+ static char algorithm_field[] = "Algorithm";
+ static int algorithm_length = sizeof(algorithm_field) - 1;
+ static char key_field[] = "Key";
+ static int key_length = sizeof(key_field) - 1;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ nsu_log(NSU_LOG_ERR, "can't open %s: %s",
+ filename, strerror(errno));
+ rc = NSU_KEYFILE_ERR;
+ } else {
+ nsu_log(NSU_LOG_DEBUG, "Parsing private keyfile %s", filename);
+ while (fgets(buf, sizeof(buf), fp)) {
+ size_t len, n;
+ lno++;
+ len = strlen(buf);
+ if (len == 0)
+ break;
+ if (buf[len-1] != '\n') {
+ nsu_log(NSU_LOG_ERR, "%s:%d: line too long",
+ filename, lno);
+ rc = NSU_KEYFILE_BAD;
+ break;
+ }
+ buf[--len] = '\n';
+ n = strcspn(buf, ":");
+ if (buf[n] == 0) {
+ nsu_log(NSU_LOG_ERR, "%s:%d: malformed line",
+ filename, lno);
+ rc = NSU_KEYFILE_BAD;
+ break;
+ }
+ if (n == algorithm_length &&
+ memcmp(algorithm_field, buf, n) == 0) {
+ char *p;
+ long code;
+ errno = 0;
+ code = strtol(buf + n + 1, &p, 10);
+ if (errno || *p != ' ') {
+ nsu_log(NSU_LOG_ERR,
+ "%s:%d: malformed line",
+ filename, lno);
+ rc = NSU_KEYFILE_BAD;
+ break;
+ }
+
+ alg = nsu_tsig_alg_find_code(code);
+ if (!alg) {
+ nsu_log(NSU_LOG_ERR,
+ "%s:%d: unsupported algorithm %s",
+ filename, lno, buf + n);
+ rc = NSU_KEYFILE_ALG;
+ break;
+ }
+ } else if (n == key_length &&
+ memcmp(key_field, buf, n) == 0) {
+ struct base64_decode_ctx ctx;
+ size_t src_len;
+ char *p;
+
+ p = buf + n + 1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ src_len = strlen(p);
+ key_len = BASE64_DECODE_LENGTH(src_len);
+ key = malloc(key_len);
+ if (!key) {
+ rc = NSU_KEYFILE_ERR;
+ break;
+ }
+
+ base64_decode_init(&ctx);
+ base64_decode_update(&ctx, &key_len, key,
+ src_len, p);
+ if (!base64_decode_final(&ctx)) {
+ nsu_log(NSU_LOG_ERR,
+ "%s:%d: bad base64",
+ filename, lno);
+ rc = NSU_KEYFILE_BAD;
+ break;
+ }
+ }
+ }
+ fclose(fp);
+ }
+
+ if (rc == NSU_KEYFILE_OK) {
+ if (!alg) {
+ nsu_log(NSU_LOG_ERR, "%s: no %s clause",
+ filename, algorithm_field);
+ rc = NSU_KEYFILE_BAD;
+ }
+ if (!key) {
+ nsu_log(NSU_LOG_ERR, "%s: no %s clause",
+ filename, key_field);
+ rc = NSU_KEYFILE_BAD;
+ }
+ }
+
+ if (rc == NSU_KEYFILE_OK) {
+ char const *basename = strrchr(filename, '/');
+ if (basename)
+ basename++;
+ else
+ basename = filename;
+ if (filename_to_keyname(filename, alg->code, &keyname) < 0)
+ rc = NSU_KEYFILE_ERR;
+ }
+
+ if (rc == NSU_KEYFILE_OK) {
+ nsu_log(NSU_LOG_DEBUG, "%s: algo=%s, keyname=%s, key length=%zu",
+ filename, alg->name, keyname ? keyname : "(unknown)",
+ key_len);
+ *pkeyname = keyname;
+ *palg = alg;
+ *pkey = key;
+ *pkey_len = key_len;
+ } else {
+ free(key);
+ free(keyname);
+ }
+
+ return rc;
+}
+
+/* Parse the private key file generated by dnssec-keygen.
+ * On success, fill the return arguments:
+ *
+ * pkeyname - (malloc) Key name or NULL if unable to deduce;
+ * pkey - (malloc) Key value.
+ * pkey_len - length of the key.
+ *
+ * Arguments marked with (malloc) are allocated.
+ *
+ * Return value: see nsu_keyfile_private_read
+ */
+int
+nsu_keyfile_key_read(char const *filename,
+ struct nsu_tsig_alg const **palg,
+ char **pkeyname,
+ uint8_t **pkey, size_t *pkey_len)
+{
+ char buf[512];
+ char *ret, *keyptr;
+ size_t n;
+ uint8_t *key = NULL;
+ FILE *fp;
+ int i;
+ size_t src_len, key_len;
+ struct base64_decode_ctx ctx;
+ int rc;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ nsu_log(NSU_LOG_ERR, "can't open %s: %s",
+ filename, strerror(errno));
+ rc = NSU_KEYFILE_ERR;
+ goto err;
+ }
+
+ nsu_log(NSU_LOG_DEBUG, "Parsing keyfile %s", filename);
+ if (!fgets(buf, sizeof(buf), fp)) {
+ nsu_log(NSU_LOG_ERR, "%s: read error", filename);
+ rc = NSU_KEYFILE_ERR;
+ goto err;
+ }
+
+ n = strcspn(buf, " ");
+ if (strncmp(buf + n, " IN KEY", 7)) {
+ nsu_log(NSU_LOG_ERR, "%s:%d: malformed line", filename, 1);
+ rc = NSU_KEYFILE_BAD;
+ goto err;
+ }
+ keyptr = buf + n + 7;
+ for (i = 0; i < 3; i++) {
+ while (*keyptr && isspace(*keyptr))
+ keyptr++;
+ while (*keyptr && isdigit(*keyptr))
+ keyptr++;
+ }
+ while (*keyptr && isspace(*keyptr))
+ keyptr++;
+
+ src_len = strlen(keyptr);
+ key_len = BASE64_DECODE_LENGTH(src_len);
+ key = malloc(key_len);
+ if (!key) {
+ rc = NSU_KEYFILE_ERR;
+ goto err;
+ }
+
+ base64_decode_init(&ctx);
+ base64_decode_update(&ctx, &key_len, key, src_len, keyptr);
+ if (!base64_decode_final(&ctx)) {
+ nsu_log(NSU_LOG_ERR, "%s:%d: bad base64", filename, 1);
+ rc = NSU_KEYFILE_BAD;
+ goto err;
+ }
+
+ if (buf[n-1] == '.')
+ --n;
+ ret = malloc(n+1);
+ if (!ret) {
+ rc = NSU_KEYFILE_ERR;
+ goto err;
+ }
+ memcpy(ret, buf, n);
+ ret[n] = 0;
+
+ filename_to_alg(filename, palg);
+ *pkeyname = ret;
+ *pkey = key;
+ *pkey_len = key_len;
+ nsu_log(NSU_LOG_DEBUG, "%s: algo=%s, keyname=%s, key length=%zu",
+ filename,
+ *palg ? (*palg)->name : "(unknown)",
+ ret, key_len);
+ rc = NSU_KEYFILE_OK;
+err:
+ if (rc != NSU_KEYFILE_OK)
+ free(key);
+
+ fclose(fp);
+
+ return rc;
+}
+
+static int
+is_suffix(char const *suf, char const *str)
+{
+ size_t suflen = strlen(suf);
+ size_t len = strlen(str);
+ return suflen < len && memcmp(str + len - suflen, suf, suflen) == 0;
+}
+
+static char const *priv_suffix = ".private";
+static char const *key_suffix = ".key";
+
+/*
+ * Create new file name by removing last SUFLEN characters from BASENAME
+ * and appending NEWSUF to the resulting string. Returned value is
+ * malloced.
+ */
+static char *
+makefilename(char const *basename, size_t suflen, char const *new_suf)
+{
+ size_t len = strlen(basename);
+ char *p;
+
+ if (len <= suflen) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ len -= suflen;
+ p = malloc(len + strlen(new_suf) + 1);
+ if (!p)
+ return p;
+
+ memcpy(p, basename, len);
+ strcpy(p + len, new_suf);
+
+ return p;
+}
+
+/*
+ * Read the keyfile NAME. On success, create struct nsu_tsig and
+ * populate it with the information obtained from the file.
+ *
+ * Return NSU_KEYFILE_OK on success, and another NSU_KEYFILE_* constant
+ * on error (see the description in nsu_keyfile_private_read).
+ *
+ * If NAME ends with ".private", that file is read. If the
+ * key name cannot be deduced from the file name, the ".key" file
+ * will be read in addition, in order to determine it.
+ *
+ * If NAME ends with dot, then first the dot is replaced with
+ * ".private" and an attempt is made to read that file as described
+ * above. If the private file does not exist, the suffix is replaced
+ * with ".key" and the file is read as described below.
+ *
+ * If NAME ends with ".key", the key file is read. The algorithm
+ * is then deduced from the file name.
+ */
+int
+nsu_keyfile_read(char const *name, struct nsu_tsig **ptsig)
+{
+ struct nsu_tsig_alg const *alg = NULL, *kalg;
+ uint8_t *key, *kkey;
+ size_t key_len, kkey_len;
+ char *keyname = NULL;
+ struct nsu_tsig *tsig;
+ int rc;
+ char *keyfilename = NULL;
+
+ if (is_suffix(priv_suffix, name)) {
+ rc = nsu_keyfile_private_read(name, &alg, &keyname,
+ &key, &key_len);
+ switch (rc) {
+ case NSU_KEYFILE_OK:
+ if (keyname)
+ name = NULL;
+ else {
+ keyfilename = makefilename(name,
+ strlen(priv_suffix),
+ key_suffix);
+ if (!keyfilename)
+ return NSU_KEYFILE_ERR;
+ name = keyfilename;
+ nsu_log(NSU_LOG_DEBUG,
+ "keyname not known, will try %s", name);
+ }
+ break;
+
+ case NSU_KEYFILE_BAD:
+ case NSU_KEYFILE_ALG:
+ case NSU_KEYFILE_ERR:
+ return rc;
+ }
+ } else if (is_suffix(".", name)) {
+ char *tmpname = makefilename(name, 1, priv_suffix);
+ if (!tmpname)
+ return NSU_KEYFILE_ERR;
+ rc = nsu_keyfile_private_read(tmpname,
+ &alg, &keyname, &key, &key_len);
+ free(tmpname);
+ switch (rc) {
+ case NSU_KEYFILE_OK:
+ if (keyname)
+ name = NULL;
+ else {
+ keyfilename = makefilename(name,
+ 1,
+ key_suffix);
+ if (!keyfilename)
+ return NSU_KEYFILE_ERR;
+ name = keyfilename;
+ nsu_log(NSU_LOG_DEBUG,
+ "keyname not known, will try %s", name);
+ }
+ break;
+
+ case NSU_KEYFILE_BAD:
+ case NSU_KEYFILE_ALG:
+ return rc;
+
+ case NSU_KEYFILE_ERR:
+ if (errno == ENOENT) {
+ keyfilename = makefilename(name,
+ 1,
+ key_suffix);
+ if (!keyfilename)
+ return NSU_KEYFILE_ERR;
+ nsu_log(NSU_LOG_DEBUG,
+ "file %s does not exist, "
+ "will try %s", name, keyfilename);
+ name = keyfilename;
+ } else
+ return rc;
+ }
+ } else if (!is_suffix(key_suffix, name)) {
+ nsu_log(NSU_LOG_DEBUG,
+ "%s: unknown keyfile suffix", name);
+ return NSU_KEYFILE_BAD;
+ }
+
+ if (name) {
+ rc = nsu_keyfile_key_read(name, &kalg, &keyname,
+ &kkey, &kkey_len);
+
+ if (rc == NSU_KEYFILE_OK) {
+ if (!alg)
+ alg = kalg;
+ else if (kalg != alg) {
+ nsu_log(NSU_LOG_ERR, "%s: algorithm mismatch",
+ name);
+ rc = NSU_KEYFILE_BAD;
+ }
+ }
+
+ if (rc == NSU_KEYFILE_OK) {
+ if (!key) {
+ key = kkey;
+ key_len = kkey_len;
+ kkey = NULL;
+ } else if (kkey_len != key_len ||
+ memcmp(kkey, key, key_len)) {
+ nsu_log(NSU_LOG_ERR, "%s: keys don't match",
+ name);
+ rc = NSU_KEYFILE_BAD;
+ }
+ }
+ free(kkey);
+ free(keyfilename);
+ }
+
+ if (rc == NSU_KEYFILE_OK) {
+ tsig = nsu_tsig_create(alg, keyname);
+ if (!tsig)
+ rc = NSU_KEYFILE_ERR;
+ else
+ nsu_tsig_set_key(tsig, key, key_len);
+ }
+
+ free(keyname);
+ free(key);
+
+ if (rc == NSU_KEYFILE_OK)
+ *ptsig = tsig;
+
+ return rc;
+}
+
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..37f4e48
--- /dev/null
+++ b/log.c
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "nsu.h"
+
+int nsu_log_level = NSU_LOG_ERR;
+
+static char const *nsu_severity_str[] = {
+ "debug",
+ "warning",
+ "error",
+};
+
+static void
+__nsu_log_prt(int severity, char const *fmt, va_list ap)
+{
+ if (severity >= 0 &&
+ severity < sizeof(nsu_severity_str)/sizeof(nsu_severity_str[0])) {
+ fprintf(stderr, "nsu %s: ", nsu_severity_str[severity]);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ }
+}
+
+void (*nsu_logger)(int, char const *, va_list) = __nsu_log_prt;
+
+void
+nsu_log_msg(int severity, char const *fmt, ...)
+{
+ if (nsu_logger) {
+ va_list ap;
+ va_start(ap, fmt);
+ nsu_logger(severity, fmt, ap);
+ va_end(ap);
+ }
+}
+
diff --git a/main.c b/main.c
index 0165709..9b9d1d9 100644
--- a/main.c
+++ b/main.c
@@ -319,224 +319,6 @@ get_arg_ul(char const *arg, unsigned long *np)
return 0;
}
-static int
-is_suffix(char const *suf, char const *str)
-{
- size_t suflen = strlen(suf);
- size_t len = strlen(str);
- return suflen < len && memcmp(str + len - suflen, suf, suflen) == 0;
-}
-
-static char const *priv_suffix = ".private";
-static char const *key_suffix = ".key";
-
-static struct nsu_tsig_alg const *
-keyfile_read_private(char const *name, uint8_t **pkey, size_t *pkey_len)
-{
- char *tmpname = NULL;
- FILE *fp;
- char buf[512];
- int lno = 0;
-
- struct nsu_tsig_alg const *alg = NULL;
- uint8_t *key;
- size_t key_len;
-
- static char algorithm_field[] = "Algorithm";
- static int algorithm_length = sizeof(algorithm_field) - 1;
- static char key_field[] = "Key";
- static int key_length = sizeof(key_field) - 1;
-
- if (is_suffix(key_suffix, name)) {
- size_t baselen = strlen(name) - strlen(key_suffix);
- tmpname = malloc(baselen + strlen(priv_suffix) + 1);
- if (!tmpname)
- abend_nomem();
- memcpy(tmpname, name, baselen);
- strcpy(tmpname + baselen, priv_suffix);
- name = tmpname;
- } else if (access(name, F_OK) && errno == ENOENT) {
- size_t namelen = strlen(name);
- if (name[namelen-1] == '.') {
- tmpname = malloc(namelen + strlen(priv_suffix));
- if (!tmpname)
- abend_nomem();
- memcpy(tmpname, name, namelen - 1);
- strcpy(tmpname + namelen - 1, priv_suffix);
- name = tmpname;
- }
- }
-
- fp = fopen(name, "r");
- if (!fp)
- abend("can't open %s: %s", name, strerror(errno));
- while (fgets(buf, sizeof(buf), fp)) {
- size_t len, n;
- lno++;
- len = strlen(buf);
- if (len == 0)
- break;
- if (buf[len-1] != '\n')
- abend("%s:%d: line too long", name, lno);
- buf[--len] = '\n';
- n = strcspn(buf, ":");
- if (buf[n] == 0)
- abend("%s:%d: malformed line", name, lno);
- if (n == algorithm_length &&
- memcmp(algorithm_field, buf, n) == 0) {
- char *p;
- long code;
- errno = 0;
- code = strtol(buf + n + 1, &p, 10);
- if (errno || *p != ' ')
- abend("%s:%d: malformed line", name, lno);
-
- alg = nsu_tsig_alg_find_code(code);
- if (!alg)
- abend("%s:%d: unsupported algorithm %s",
- name, lno, buf + n);
- } else if (n == key_length && memcmp(key_field, buf, n) == 0) {
- struct base64_decode_ctx ctx;
- size_t src_len;
- char *p;
-
- p = buf + n + 1;
- while (*p == ' ' || *p == '\t')
- p++;
- src_len = strlen(p);
- key_len = BASE64_DECODE_LENGTH(src_len);
- key = malloc(key_len);
- if (!key)
- abend_nomem();
-
- base64_decode_init(&ctx);
- base64_decode_update(&ctx, &key_len, key, src_len, p);
- if (!base64_decode_final(&ctx))
- abend("%s:%d: bad base64", name, lno);
- }
- }
- fclose(fp);
-
- if (!alg)
- abend("%s:%d: no %s clause", algorithm_field);
- if (!key)
- abend("%s:%d: no %s clause", key_field);
-
- free(tmpname);
-
- *pkey = key;
- *pkey_len = key_len;
- return alg;
-
-}
-
-static char *
-keyfile_read_key(char const *name, uint8_t **pkey, size_t *pkey_len)
-{
- char *tmpname = NULL;
- char buf[512];
- char *ret, *keyptr;
- size_t n;
- uint8_t *key;
- FILE *fp;
- int i;
- size_t src_len, key_len;
- struct base64_decode_ctx ctx;
-
- if (is_suffix(priv_suffix, name)) {
- size_t baselen = strlen(name) - strlen(priv_suffix);
- tmpname = malloc(baselen + strlen(key_suffix) + 1);
- if (!tmpname)
- abend_nomem();
- memcpy(tmpname, name, baselen);
- strcpy(tmpname + baselen, key_suffix);
- name = tmpname;
- } else if (access(name, F_OK) && errno == ENOENT) {
- size_t namelen = strlen(name);
- if (name[namelen-1] == '.') {
- tmpname = malloc(namelen + strlen(key_suffix));
- if (!tmpname)
- abend_nomem();
- memcpy(tmpname, name, namelen - 1);
- strcpy(tmpname + namelen - 1, key_suffix);
- name = tmpname;
- }
- }
-
- fp = fopen(name, "r");
- if (!fp)
- abend("can't open %s: %s", name, strerror(errno));
- if (!fgets(buf, sizeof(buf), fp))
- abend("%s: read error", name);
- fclose(fp);
-
- n = strcspn(buf, " ");
- if (strncmp(buf + n, " IN KEY", 7))
- abend("%s:%d: malformed line", name, 1);
-
- keyptr = buf + n + 7;
- for (i = 0; i < 3; i++) {
- while (*keyptr && isspace(*keyptr))
- keyptr++;
- while (*keyptr && isdigit(*keyptr))
- keyptr++;
- }
- while (*keyptr && isspace(*keyptr))
- keyptr++;
-
- src_len = strlen(keyptr);
- key_len = BASE64_DECODE_LENGTH(src_len);
- key = malloc(key_len);
- if (!key)
- abend_nomem();
-
- base64_decode_init(&ctx);
- base64_decode_update(&ctx, &key_len, key, src_len, keyptr);
- if (!base64_decode_final(&ctx))
- abend("%s:%d: bad base64", name, 1);
- *pkey = key;
- *pkey_len = key_len;
-
- if (buf[n-1] == '.')
- --n;
- ret = malloc(n+1);
- if (!ret)
- abend_nomem();
- memcpy(ret, buf, n);
- ret[n] = 0;
-
- free(tmpname);
-
- return ret;
-}
-
-static struct nsu_tsig *
-keyfile_read(char const *name)
-{
- struct nsu_tsig_alg const *alg;
- uint8_t *pkey, *key;
- size_t pkey_len, key_len;
- char *keyname;
- struct nsu_tsig *sgn;
-
- alg = keyfile_read_private(name, &pkey, &pkey_len);
- keyname = keyfile_read_key(name, &key, &key_len);
-
- if (pkey_len != key_len || memcmp(pkey, key, key_len))
- abend("%s: keys don't match", name);
- free(pkey);
-
- sgn = nsu_tsig_create(alg, keyname);
- free(keyname);
- if (!sgn)
- abend_nomem();
-
- nsu_tsig_set_key(sgn, key, key_len);
- free(key);
-
- return sgn;
-}
-
/*
* nsu
*/
@@ -576,7 +358,9 @@ main(int argc, char **argv)
break;
case 'x':
- if (yydebug == 1)
+ if (nsu_log_level != NSU_LOG_DEBUG)
+ nsu_log_level = NSU_LOG_DEBUG;
+ else if (yydebug == 1)
yy_flex_debug = 1;
else
yydebug = 1;
@@ -590,8 +374,24 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
- if (keyfile_name)
- tsig = keyfile_read(keyfile_name);
+ if (keyfile_name) {
+ switch (nsu_keyfile_read(keyfile_name, &tsig)) {
+ case NSU_KEYFILE_OK:
+ break;
+
+ case NSU_KEYFILE_BAD:
+ abend("bad keyfile format");
+
+ case NSU_KEYFILE_ALG:
+ abend("unknown or unsupported algorithm in keyfile");
+
+ case NSU_KEYFILE_ERR:
+ abend("%s: %s", keyfile_name, strerror(errno));
+
+ default:
+ abort();
+ }
+ }
if (input_file)
lexer_from_file(input_file);
@@ -620,7 +420,7 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen)
ns_msg handle;
int rcode;
- if (state->options & RES_DEBUG) {
+ if (nsu_log_enabled(NSU_LOG_DEBUG) || state->options & RES_DEBUG) {
char name[NS_MAXDNAME];
getnameinfo((struct sockaddr*)state->nsaddr_list,
@@ -628,7 +428,7 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen)
name, sizeof(name),
NULL, 0,
NI_NUMERICHOST);
- printf(";; trying nameserver %s\n", name);
+ nsu_log_msg(NSU_LOG_DEBUG, "trying nameserver %s", name);
}
rlen = res_nsend(state, qbuf, qlen,
@@ -666,7 +466,8 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen)
*/
case ns_r_notimpl:
case ns_r_servfail:
- if (state->options & RES_DEBUG) {
+ if (nsu_log_enabled(NSU_LOG_DEBUG)
+ || state->options & RES_DEBUG) {
char name[NS_MAXDNAME];
getnameinfo((struct sockaddr*)state->nsaddr_list,
@@ -674,8 +475,8 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen)
name, sizeof(name),
NULL, 0,
NI_NUMERICHOST);
- printf(";; nameserver %s: %s", name,
- ns_rcodestr(rcode));
+ nsu_log_msg(NSU_LOG_DEBUG, "nameserver %s: %s", name,
+ ns_rcodestr(rcode));
}
return update_retry;
diff --git a/nsu.c b/nsu.c
index ceaacf9..83db3bb 100644
--- a/nsu.c
+++ b/nsu.c
@@ -126,11 +126,9 @@ nsu_nmkquery(res_state statp,
u_char *dnptrs[20], **lastdnptr;
int class = ns_c_in;
int type = ns_t_soa;
-
-#ifdef DEBUG
- if (statp->options & RES_DEBUG)
- printf(";; make_update_query %s", zone);
-#endif
+
+ nsu_log(NSU_LOG_DEBUG, "%s: %s", __func__, zone);
+
/*
* Initialize header fields.
*/
diff --git a/nsu.h b/nsu.h
index 8f22ea3..b2b9cb3 100644
--- a/nsu.h
+++ b/nsu.h
@@ -1,4 +1,5 @@
#include <resolv.h>
+#include <stdarg.h>
enum {
NSU_PREREQ_YXRRSET, /* RRset exists (value independent) */
@@ -107,5 +108,45 @@ int nsu_mkquery(char const *zone,
nsu_rr *update, int num_update,
struct nsu_tsig *tsig,
u_char *buf, int buflen);
+
+enum {
+ NSU_LOG_DEBUG,
+ NSU_LOG_WARN,
+ NSU_LOG_ERR,
+ NSU_LOG_NONE
+};
+
+extern int nsu_log_level;
+extern void (*nsu_logger)(int, char const *, va_list);
+
+void nsu_log_msg(int severity, char const *fmt, ...);
+
+#define nsu_log_enabled(svr) ((svr) >= nsu_log_level)
+
+#define nsu_log(svr, fmt, ...) \
+ do { \
+ if (nsu_log_enabled(svr)) { \
+ nsu_log_msg(svr, fmt, __VA_ARGS__); \
+ } \
+ } while (0)
+
+enum {
+ NSU_KEYFILE_OK,
+ NSU_KEYFILE_BAD,
+ NSU_KEYFILE_ALG,
+ NSU_KEYFILE_ERR
+};
+
+int nsu_keyfile_key_read(char const *filename,
+ struct nsu_tsig_alg const **palg,
+ char **pkeyname,
+ uint8_t **pkey, size_t *pkey_len);
+int nsu_keyfile_private_read(char const *filename,
+ struct nsu_tsig_alg const **palg,
+ char **pkeyname,
+ uint8_t **pkey, size_t *pkey_len);
+
+int nsu_keyfile_read(char const *name, struct nsu_tsig **ptsig);
+

Return to:

Send suggestions and report system problems to the System administrator.