Commit 8f9d93db authored by Marek Vavrusa's avatar Marek Vavrusa

Implemented parsing of priv-key-file v1.3 (-k, TSIG).

parent 3b9a1db4
......@@ -279,6 +279,8 @@ src/utils/common/params.c
src/utils/common/params.h
src/utils/common/resolv.c
src/utils/common/resolv.h
src/utils/common/token.c
src/utils/common/token.h
src/utils/common/netio.c
src/utils/common/netio.h
src/utils/common/rr-serialize.c
......
......@@ -41,6 +41,8 @@ kdig_SOURCES = \
utils/common/resolv.h \
utils/common/netio.c \
utils/common/netio.h \
utils/common/token.c \
utils/common/token.h \
utils/common/rr-serialize.h \
utils/common/rr-serialize.c \
utils/dig/dig_main.c \
......@@ -60,6 +62,8 @@ khost_SOURCES = \
utils/common/resolv.h \
utils/common/netio.c \
utils/common/netio.h \
utils/common/token.c \
utils/common/token.h \
utils/common/rr-serialize.h \
utils/common/rr-serialize.c \
utils/host/host_main.c \
......@@ -81,6 +85,8 @@ knsupdate_SOURCES = \
utils/common/resolv.h \
utils/common/netio.c \
utils/common/netio.h \
utils/common/token.c \
utils/common/token.h \
utils/common/rr-serialize.h \
utils/common/rr-serialize.c \
utils/common/exec.c \
......
......@@ -14,8 +14,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* FreeBSD POSIX2008 getline() */
#ifndef _WITH_GETLINE
#define _WITH_GETLINE
#endif
#include "utils/common/params.h"
#include <stdio.h>
#include <stdlib.h> // free
#include <netinet/in.h> // in_addr
#include <arpa/inet.h> // inet_pton
......@@ -26,6 +32,8 @@
#include "libknot/util/descriptor.h" // KNOT_RRTYPE
#include "utils/common/msg.h" // WARN
#include "libknot/dname.h" // knot_dname_t
#include "utils/common/token.h"
#include "libknot/dname.h"
#define IPV4_REVERSE_DOMAIN "in-addr.arpa."
#define IPV6_REVERSE_DOMAIN "ip6.arpa."
......@@ -43,6 +51,75 @@ static knot_dname_t* create_fqdn_from_str(const char *str, size_t len)
return d;
}
/* Table of known keys in private-key-format */
static const char *pkey_tbl[] = {
"\x09" "Activate:",
"\x0a" "Algorithm:",
"\x05" "Bits:",
"\x08" "Created:",
"\x04" "Key:",
"\x13" "Private-key-format:",
"\x08" "Publish:",
NULL
};
enum {
T_PKEY_FORMAT = 0,
T_PKEY_ALGO,
T_PKEY_KEY,
T_PKEY_BITS,
T_PKEY_CREATED,
T_PKEY_PUBLISH,
T_PKEY_ACTIVATE
};
static int params_parse_keyline(char *lp, int len, void *arg)
{
/* Discard nline */
if (lp[len - 1] == '\n') {
lp[len - 1] = '\0';
len -= 1;
}
knot_key_t *key = (knot_key_t *)arg;
int lpm = -1;
int bp = 0;
if ((bp = tok_scan(lp, pkey_tbl, &lpm)) < 0) {
DBG("%s: unknown token on line '%s', ignoring\n", __func__, lp);
return KNOT_EOK;
}
/* Found valid key. */
const char *k = pkey_tbl[bp];
char *v = (char *)tok_skipspace(lp + TOK_L(k));
size_t vlen = 0;
uint32_t n = 0;
switch(bp) {
case T_PKEY_FORMAT:
DBG("%s: file format '%s'\n", __func__, v);
break;
case T_PKEY_ALGO:
vlen = strcspn(v, SEP_CHARS);
v[vlen] = '\0'; /* Term after first tok */
if (params_parse_num(v, &n) != KNOT_EOK) {
return KNOT_EPARSEFAIL;
}
DBG("%s: algo = %u\n", __func__, n);
break;
case T_PKEY_KEY:
if (key->secret) free(key->secret);
key->secret = strndup(v, len);
DBG("%s: secret = '%s'\n", __func__, key->secret);
break;
case T_PKEY_BITS:
break;
default:
DBG("%s: %s = '%s'\n", __func__, TOK_S(k), v);
break;
}
return KNOT_EOK;
}
int parse_class(const char *rclass, uint16_t *class_num)
{
*class_num = knot_rrclass_from_string(rclass);
......@@ -269,3 +346,35 @@ int params_parse_tsig(const char *value, knot_key_t *key)
return KNOT_EOK;
}
int params_parse_keyfile(const char *filename, knot_key_t *key)
{
int ret = KNOT_EOK;
/* Fetch keyname from filename. */
const char *bn = strrchr(filename, '/');
if (!bn) bn = filename;
else ++bn; /* Skip final slash */
if (*bn == 'K') ++bn; /* Skip K */
const char* np = strchr(bn, '+');
if (np) { /* Attempt to extract dname */
key->name = knot_dname_new_from_str(bn, np-bn, NULL);
}
if (!key->name) {
ERR("keyfile not in format K{name}.+157+{rnd}.private\n");
return KNOT_ERROR;
}
FILE *fp = fopen(filename, "r"); /* Open file */
if (!fp) {
ERR("could not open key file '%s': %s\n",
filename, strerror(errno));
return KNOT_ERROR;
}
/* Parse lines. */
ret = tok_process_lines(fp, params_parse_keyline, key);
fclose(fp);
return ret;
}
......@@ -130,6 +130,8 @@ int params_parse_num(const char *value, uint32_t *dst);
int params_parse_tsig(const char *value, knot_key_t *key);
int params_parse_keyfile(const char *filename, knot_key_t *key);
#endif // _UTILS__PARAMS_H_
/*! @} */
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program 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 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* FreeBSD POSIX2008 getline() */
#ifndef _WITH_GETLINE
#define _WITH_GETLINE
#endif
#include "utils/common/token.h"
#include <stdio.h>
#include <stdlib.h> // free
#include <ctype.h> // isspace
#include <string.h> // memcmp
#include "common/errcode.h" // KNOT_EOK
#include "utils/common/msg.h" // ERR
int tok_scan(const char* lp, const char **tbl, int *lpm)
{
const char *prefix = lp; /* Ptr to line start. */
int i = 0, pl = 1; /* Match index, prefix length. */
unsigned char len = 0; /* Read length. */
for(;;) {
const char *tok = tbl[i];
if (*lp == '\0' || isspace(*lp)) {
if (tok && TOK_L(tok) == len) { /* Consumed whole w? */
return i; /* Identifier */
} else { /* Word is shorter than cmd? */
break;
}
}
/* Find next prefix match. */
++len;
while (tok) {
if (TOK_L(tok) >= len) { /* Is prefix of current token */
if (*lp < tok[pl]) { /* Terminate early. */
tok = NULL;
break; /* No match could be found. */
}
if (*lp == tok[pl]) { /* Match */
if(lpm) *lpm = i;
++pl;
break;
}
}
/* No early cut, no match - seek next. */
while ((tok = tbl[++i]) != NULL) {
if (TOK_L(tok) >= len &&
memcmp(TOK_S(tok), prefix, len) == 0) {
break;
}
}
}
if (tok == NULL) {
break; /* All tokens exhausted. */
} else {
++lp; /* Next char */
}
}
return -1;
}
int tok_find(const char *lp, const char **tbl)
{
int lpm = -1;
int bp = 0;
if ((bp = tok_scan(lp, tbl, &lpm)) < 0) {
if (lpm > -1) {
ERR("unexpected literal: '%s', did you mean '%s' ?\n",
lp, TOK_S(tbl[lpm]));
} else {
ERR("unexpected literal: '%s'\n", lp);
}
ERR("syntax error\n");
return KNOT_EPARSEFAIL;
}
return bp;
}
const char* tok_skipspace(const char *lp)
{
while (isspace(*lp)) ++lp; return lp;
}
int tok_process_lines(FILE *fp, lparse_f cb, void *arg)
{
int ret = KNOT_EOK;
/* Parse lines. */
char *buf = NULL;
size_t buflen = 0;
ssize_t rb = 0;
while ((rb = getline(&buf, &buflen, fp)) != -1) {
ret = cb(buf, rb, arg);
if (ret != KNOT_EOK) break;
}
free(buf);
return ret;
}
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program 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 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file token.h
*
* \author Marek Vavrusa <marek.vavrusa@nic.cz>
*
* \brief String tokenizer and simple scanner.
*
* \addtogroup utils
* @{
*/
#ifndef _UTILS__TOKEN_H_
#define _UTILS__TOKEN_H_
#include <stdio.h>
/*!
* \brief Example of token table:
*
* \warning Table _must_ be lexicographically ordered.
*
* const char *tok_tbl[] = {
* // LEN STRING
* "\x4" "abcd",
* "\x5" "class",
* NULL // END
* }
*/
/*! \brief String part of the token. */
#define TOK_S(x) ((x)+1)
/*! \brief Len of the token. */
#define TOK_L(x) ((unsigned char)(x)[0])
/*! \brief Function prototype for line parser. */
typedef int(*lparse_f)(char *lp, int len, void *arg);
/*!
* \brief Scan for matching token described by a match table.
*
* Table consists of strings, prefixed with 1B length.
*
* \param lp Pointer to current line.
* \param tbl Match description table.
* \param lpm Pointer to longest prefix match.
* \retval index to matching record.
* \retval -1 if no match is found, lpm may be set to longest prefix match.
*/
int tok_scan(const char* lp, const char **tbl, int *lpm);
/*!
* \brief Find token from table in a line buffer.
* \param lp Pointer to current line.
* \param tbl Match description table.
* \retval index to matching record.
* \retval error code if no match is found
*/
int tok_find(const char *lp, const char **tbl);
/*!
* \brief Return pointer to next non-blank character.
* \param lp Pointer to current line.
* \return ptr to next non-blank character.
*/
const char* tok_skipspace(const char *lp);
/*!
* \brief Process file by lines.
* \param fn File handle to be processed.
* \param cb Callback function to be called for each line.
* \param arg Pointer to be passed to callback function.
* \return KNOT_EOK if success.
* \return error returned by @cb function
*/
int tok_process_lines(FILE *fp, lparse_f cb, void *arg);
#endif // _UTILS__TOKEN_H_
/*! @} */
......@@ -14,22 +14,19 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* FreeBSD POSIX2008 getline() */
#ifndef _WITH_GETLINE
#define _WITH_GETLINE
#endif
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/socket.h>
#include "utils/nsupdate/nsupdate_exec.h"
#include "utils/common/params.h"
#include "utils/common/msg.h"
#include "utils/common/exec.h"
#include "utils/common/netio.h"
#include "utils/common/token.h"
#include "common/errcode.h"
#include "common/mempattern.h"
#include "libknot/dname.h"
......@@ -64,8 +61,6 @@ int cmd_zone(const char* lp, params_t *params);
* This way we could identify command byte-per-byte and
* cancel early if the next is lexicographically greater.
*/
#define CMD_S(x) ((x)+1)
#define CMD_L(x) ((unsigned char)(x)[0])
const char* cmd_array[] = {
"\x3" "add",
"\x6" "answer",
......@@ -129,13 +124,9 @@ enum {
/* RR parser flags */
enum {
PARSE_NODEFAULT = 1 << 0, /* Do not fill defaults. */
PARSE_NAMEONLY = 1 << 1, /* Parse only name. */
PARSE_NAMEONLY = 1 << 1 /* Parse only name. */
};
static inline const char* skipspace(const char *lp) {
while (isspace(*lp)) ++lp; return lp;
}
static int dname_isvalid(const char *lp, size_t len) {
knot_dname_t *dn = knot_dname_new_from_str(lp, len, NULL);
if (dn == NULL) {
......@@ -189,7 +180,7 @@ static int parse_partial_rr(scanner_t *s, const char *lp, unsigned flags) {
s->r_owner_length = knot_dname_size(owner);
memcpy(s->r_owner, knot_dname_name(owner), s->r_owner_length);
lp = skipspace(lp + len);
lp = tok_skipspace(lp + len);
/* Initialize */
s->r_type = KNOT_RRTYPE_ANY;
......@@ -214,7 +205,7 @@ static int parse_partial_rr(scanner_t *s, const char *lp, unsigned flags) {
if (ttl >= 0 && np && (*np == '\0' || isspace(*np))) {
s->r_ttl = ttl;
DBG("%s: parsed ttl=%lu\n", __func__, ttl);
lp = skipspace(np);
lp = tok_skipspace(np);
}
len = strcspn(lp, SEP_CHARS); /* Try to find class */
......@@ -224,7 +215,7 @@ static int parse_partial_rr(scanner_t *s, const char *lp, unsigned flags) {
if (v > 0) {
s->r_class = v;
DBG("%s: parsed class=%u\n", __func__, s->r_class);
lp = skipspace(lp + len);
lp = tok_skipspace(lp + len);
}
/* Class must not differ from specified. */
......@@ -243,7 +234,7 @@ static int parse_partial_rr(scanner_t *s, const char *lp, unsigned flags) {
if (v > 0) {
s->r_type = v;
DBG("%s: parsed type=%u '%s'\n", __func__, s->r_type, b2);
lp = skipspace(lp + len);
lp = tok_skipspace(lp + len);
}
/* Remainder */
......@@ -280,7 +271,7 @@ static server_t *parse_host(const char *lp, const char* default_port)
DBG("%s: parsed addr: %s\n", __func__, addr);
/* Store port/service if present. */
lp = skipspace(lp + len);
lp = tok_skipspace(lp + len);
if (*lp == '\0') {
srv = server_create(addr, default_port);
free(addr);
......@@ -418,107 +409,29 @@ static int pkt_sendrecv(params_t *params, server_t *srv,
return rb;
}
/*!
* \brief Scan for matching token described by a match table.
*
* Table consists of strings, prefixed with 1B length.
*
* \param fp File with contents to be read.
* \param tbl Match description table.
* \param lpm Pointer to longest prefix match.
* \retval index to matching record.
* \retval -1 if no match is found, lpm may be set to longest prefix match.
*/
static int tok_scan(const char* lp, const char **tbl, int *lpm)
static int nsupdate_process_line(char *lp, int len, void *arg)
{
const char *prefix = lp; /* Ptr to line start. */
int i = 0, pl = 1; /* Match index, prefix length. */
unsigned char len = 0; /* Read length. */
for(;;) {
const char *tok = tbl[i];
if (*lp == '\0' || isspace(*lp)) {
if (tok && CMD_L(tok) == len) { /* Consumed whole w? */
return i; /* Identifier */
} else { /* Word is shorter than cmd? */
break;
}
}
/* Find next prefix match. */
++len;
while (tok) {
if (CMD_L(tok) >= len) { /* Is prefix of current token */
if (*lp < tok[pl]) { /* Terminate early. */
tok = NULL;
break; /* No match could be found. */
}
if (*lp == tok[pl]) { /* Match */
if(lpm) *lpm = i;
++pl;
break;
}
}
/* No early cut, no match - seek next. */
while ((tok = tbl[++i]) != NULL) {
if (CMD_L(tok) >= len &&
memcmp(CMD_S(tok), prefix, len) == 0) {
break;
}
}
}
if (tok == NULL) {
break; /* All tokens exhausted. */
} else {
++lp; /* Next char */
}
}
return -1;
}
static int tok_find(const char *lp, const char **tbl)
{
int lpm = -1;
int bp = 0;
if ((bp = tok_scan(lp, tbl, &lpm)) < 0) {
if (lpm > -1) {
ERR("unexpected literal: '%s', did you mean '%s' ?\n",
lp, CMD_S(tbl[lpm]));
} else {
ERR("unexpected literal: '%s'\n", lp);
}
ERR("syntax error\n");
return KNOT_EPARSEFAIL;
params_t *params = (params_t *)arg;
if (lp[len - 1] == '\n') lp[len - 1] = '\0'; /* Discard nline */
int ret = tok_find(lp, cmd_array);
if (ret < 0) return ret; /* Syntax error */
const char *cmd = cmd_array[ret];
const char *val = tok_skipspace(lp + TOK_L(cmd));
ret = cmd_handle[ret](val, params);
if (ret != KNOT_EOK) {
ERR("operation '%s' failed\n", TOK_S(cmd));
DBG("reason - %s\n", knot_strerror(ret));
}
return bp;
return ret;
}
static int nsupdate_process(params_t *params, FILE *fp)
{
/* Process lines. */
int ret = KNOT_EOK;
char *buf = NULL;
size_t buflen = 0;
ssize_t rb = 0;
while ((rb = getline(&buf, &buflen, fp)) != -1) {
if (buf[rb - 1] == '\n') buf[rb - 1] = '\0'; /* Discard nline */
ret = tok_find(buf, cmd_array);
if (ret < 0) {
break; /* Syntax error */
} else {
const char *cmd = cmd_array[ret];
const char *lp = skipspace(buf + CMD_L(cmd));
ret = cmd_handle[ret](lp, params);
if (ret != KNOT_EOK) {
ERR("operation '%s' failed\n", CMD_S(cmd));
DBG("reason - %s\n", knot_strerror(ret));
break;
}
}
}
int ret = tok_process_lines(fp, nsupdate_process_line, params);
/* Check for longing query. */
nsupdate_params_t *npar = NSUP_PARAM(params);
......@@ -529,7 +442,6 @@ static int nsupdate_process(params_t *params, FILE *fp)
/* Free last answer. */
knot_packet_free(&npar->resp);
free(buf);
return ret;
}
......@@ -583,7 +495,7 @@ int cmd_update(const char* lp, params_t *params)
return KNOT_EPARSEFAIL;
}
return h[bp](skipspace(lp + CMD_L(cmd_array[bp])), params);
return h[bp](tok_skipspace(lp + TOK_L(cmd_array[bp])), params);
}
......@@ -713,8 +625,8 @@ int cmd_prereq(const char* lp, params_t *params)
if (bp < 0) return bp; /* Syntax error. */
const char *tok = pq_array[bp];
DBG("%s: type %s\n", __func__, CMD_S(tok));
lp = skipspace(lp + CMD_L(tok));
DBG("%s: type %s\n", __func__, TOK_S(tok));
lp = tok_skipspace(lp + TOK_L(tok));
switch(bp) {
case PQ_NXDOMAIN:
case PQ_YXDOMAIN:
......
......@@ -160,7 +160,7 @@ int nsupdate_params_parse(params_t *params, int argc, char *argv[])
server_t *srv = TAIL(params->servers);
/* Command line options processing. */
while ((opt = getopt(argc, argv, "dDvp:t:r:y:")) != -1) {
while ((opt = getopt(argc, argv, "dDvp:t:r:y:k:")) != -1) {
switch (opt) {
case 'd':
case 'D': /* Extra debugging. */
......@@ -190,6 +190,10 @@ int nsupdate_params_parse(params_t *params, int argc, char *argv[])
ret = params_parse_tsig(optarg, &params->key);
if (ret != KNOT_EOK) return ret;
break;
case 'k':
ret = params_parse_keyfile(optarg, &params->key);
if (ret != KNOT_EOK) return ret;
break;
default:
nsupdate_params_help(argc, argv);
return KNOT_ENOTSUP;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment