Commit c8c30c30 authored by Daniel Salzman's avatar Daniel Salzman

yparser: use wire context for txt<->bin transformations

parent 423c1ec3
......@@ -328,7 +328,7 @@ Access control list rule definition.
.ft C
acl:
\- id: STR
address: ADDR[/INT] ...
address: ADDR[/INT] | ADDR\-ADDR ...
key: key_id ...
action: transfer | notify | update | control ...
deny: BOOL
......@@ -341,8 +341,8 @@ acl:
An ACL rule identifier.
.SS address
.sp
An ordered list of IP addresses or network subnets. The query must match
one of them. Empty value means that address match is not required.
An ordered list of IP addresses, network subnets, or network ranges. The query
must match one of them. Empty value means that address match is not required.
.sp
Default: empty
.SS key
......@@ -813,7 +813,7 @@ mod\-synth\-record:
prefix: STR
origin: DNAME
ttl: INT
network: ADDR[/INT]
network: ADDR[/INT] | ADDR\-ADDR
.ft P
.fi
.UNINDENT
......@@ -854,7 +854,7 @@ Time to live of the generated records.
Default: 3600
.SS network
.sp
A network subnet in the form of \fIaddress/prefix\fP\&.
An IP address, a network subnet, or a network range the query must match.
.sp
Default: empty
.SH MODULE DNSPROXY
......
......@@ -365,7 +365,7 @@ Access control list rule definition.
acl:
- id: STR
address: ADDR[/INT] ...
address: ADDR[/INT] | ADDR-ADDR ...
key: key_id ...
action: transfer | notify | update | control ...
deny: BOOL
......@@ -382,8 +382,8 @@ An ACL rule identifier.
address
-------
An ordered list of IP addresses or network subnets. The query must match
one of them. Empty value means that address match is not required.
An ordered list of IP addresses, network subnets, or network ranges. The query
must match one of them. Empty value means that address match is not required.
Default: empty
......@@ -944,7 +944,7 @@ given prefix and subnet.
prefix: STR
origin: DNAME
ttl: INT
network: ADDR[/INT]
network: ADDR[/INT] | ADDR-ADDR
.. _mod-synth-record_id:
......@@ -1002,7 +1002,7 @@ Default: 3600
network
-------
A network subnet in the form of *address/prefix*.
An IP address, a network subnet, or a network range the query must match.
Default: empty
......
......@@ -372,7 +372,7 @@ int64_t conf_int(
if (val->code == KNOT_EOK) {
conf_db_val(val);
return yp_int(val->data, val->len);
return yp_int(val->data);
} else {
return val->item->var.i.dflt;
}
......@@ -388,7 +388,7 @@ bool conf_bool(
if (val->code == KNOT_EOK) {
conf_db_val(val);
return yp_bool(val->len);
return yp_bool(val->data);
} else {
return val->item->var.b.dflt;
}
......@@ -442,20 +442,42 @@ const knot_dname_t* conf_dname(
}
}
void conf_data(
conf_val_t *val)
const uint8_t* conf_bin(
conf_val_t *val,
size_t *len)
{
assert(val != NULL && val->item != NULL && len != NULL);
assert(val->item->type == YP_THEX || val->item->type == YP_TB64 ||
(val->item->type == YP_TREF &&
(val->item->var.r.ref->var.g.id->type == YP_THEX ||
val->item->var.r.ref->var.g.id->type == YP_TB64)));
if (val->code == KNOT_EOK) {
conf_db_val(val);
*len = yp_bin_len(val->data);
return yp_bin(val->data);
} else {
*len = val->item->var.d.dflt_len;
return val->item->var.d.dflt;
}
}
const uint8_t* conf_data(
conf_val_t *val,
size_t *len)
{
assert(val != NULL && val->item != NULL);
assert(val->item->type == YP_TB64 || val->item->type == YP_TDATA ||
assert(val->item->type == YP_TDATA ||
(val->item->type == YP_TREF &&
(val->item->var.r.ref->var.g.id->type == YP_TB64 ||
val->item->var.r.ref->var.g.id->type == YP_TDATA)));
val->item->var.r.ref->var.g.id->type == YP_TDATA));
if (val->code == KNOT_EOK) {
conf_db_val(val);
*len = val->len;
return val->data;
} else {
val->data = (const uint8_t *)val->item->var.d.dflt;
val->len = val->item->var.d.dflt_len;
*len = val->item->var.d.dflt_len;
return val->item->var.d.dflt;
}
}
......@@ -471,24 +493,19 @@ struct sockaddr_storage conf_addr(
struct sockaddr_storage out = { AF_UNSPEC };
if (val->code == KNOT_EOK) {
int port;
bool no_port;
conf_db_val(val);
out = yp_addr(val->data, val->len, &port);
out = yp_addr(val->data, &no_port);
if (out.ss_family == AF_UNIX) {
// val->data[0] is socket type identifier!
if (val->data[1] == '/' || sock_base_dir == NULL) {
val->code = sockaddr_set(&out, AF_UNIX,
(char *)val->data + 1, 0);
} else {
if (val->data[1] != '/' && sock_base_dir != NULL) {
char *tmp = sprintf_alloc("%s/%s", sock_base_dir,
val->data + 1);
val->code = sockaddr_set(&out, AF_UNIX, tmp, 0);
free(tmp);
}
} else if (port != -1) {
sockaddr_port_set(&out, port);
} else {
} else if (no_port) {
sockaddr_port_set(&out, val->item->var.a.dflt_port);
}
} else {
......@@ -509,22 +526,44 @@ struct sockaddr_storage conf_addr(
return out;
}
struct sockaddr_storage conf_net(
struct sockaddr_storage conf_addr_range(
conf_val_t *val,
int *prefix_length)
struct sockaddr_storage *max_ss,
int *prefix_len)
{
assert(val != NULL && val->item != NULL && prefix_length != NULL);
assert(val->item->type == YP_TNET ||
assert(val != NULL && val->item != NULL && max_ss != NULL &&
prefix_len != NULL);
assert(val->item->type == YP_TDATA ||
(val->item->type == YP_TREF &&
val->item->var.r.ref->var.g.id->type == YP_TNET));
val->item->var.r.ref->var.g.id->type == YP_TDATA));
struct sockaddr_storage out = { AF_UNSPEC };
if (val->code == KNOT_EOK) {
conf_db_val(val);
out = yp_addr(val->data, val->len, prefix_length);
out = yp_addr_noport(val->data);
// addr_type, addr, format, formatted_data (port| addr| empty).
const uint8_t *format = val->data + sizeof(uint8_t) +
((out.ss_family == AF_INET) ?
IPV4_PREFIXLEN / 8 : IPV6_PREFIXLEN / 8);
// See addr_range_to_bin.
switch (*format) {
case 1:
max_ss->ss_family = AF_UNSPEC;
*prefix_len = yp_int(format + sizeof(uint8_t));
break;
case 2:
*max_ss = yp_addr_noport(format + sizeof(uint8_t));
*prefix_len = -1;
break;
default:
max_ss->ss_family = AF_UNSPEC;
*prefix_len = -1;
break;
}
} else {
*prefix_length = 0;
max_ss->ss_family = AF_UNSPEC;
*prefix_len = -1;
}
return out;
......@@ -865,9 +904,7 @@ conf_remote_t conf_remote_txn(
out.key.algorithm = conf_opt(&val);
val = conf_id_get_txn(conf, txn, C_KEY, C_SECRET, &key_id);
conf_data(&val);
out.key.secret.data = (uint8_t *)val.data;
out.key.secret.size = val.len;
out.key.secret.data = (uint8_t *)conf_bin(&val, &out.key.secret.size);
}
free(rundir);
......
This diff is collapsed.
......@@ -74,8 +74,7 @@ static const lookup_table_t log_severities[] = {
static const yp_item_t desc_server[] = {
{ C_IDENT, YP_TSTR, YP_VNONE },
{ C_VERSION, YP_TSTR, YP_VNONE },
{ C_NSID, YP_TDATA, YP_VDATA = { 0, NULL, hex_text_to_bin,
hex_text_to_txt } },
{ C_NSID, YP_THEX, YP_VNONE },
{ C_RUNDIR, YP_TSTR, YP_VSTR = { RUN_DIR } },
{ C_USER, YP_TSTR, YP_VNONE },
{ C_PIDFILE, YP_TSTR, YP_VSTR = { "knot.pid" } },
......@@ -108,7 +107,8 @@ static const yp_item_t desc_key[] = {
static const yp_item_t desc_acl[] = {
{ C_ID, YP_TSTR, YP_VNONE },
{ C_ADDR, YP_TNET, YP_VNONE, YP_FMULTI },
{ C_ADDR, YP_TDATA, YP_VDATA = { 0, NULL, addr_range_to_bin,
addr_range_to_txt }, YP_FMULTI },
{ C_KEY, YP_TREF, YP_VREF = { C_KEY }, YP_FMULTI, { check_ref } },
{ C_ACTION, YP_TOPT, YP_VOPT = { acl_actions, ACL_ACTION_NONE }, YP_FMULTI },
{ C_DENY, YP_TBOOL, YP_VNONE },
......
......@@ -14,7 +14,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <glob.h>
#include <inttypes.h>
#include <libgen.h>
......@@ -39,218 +38,233 @@
#include "libknot/internal/utils.h"
#include "libknot/yparser/yptrafo.h"
static int hex_to_num(char hex) {
if (hex >= '0' && hex <= '9') return hex - '0';
if (hex >= 'a' && hex <= 'f') return hex - 'a' + 10;
if (hex >= 'A' && hex <= 'F') return hex - 'A' + 10;
return -1;
}
int hex_text_to_bin(
char const *txt,
size_t txt_len,
uint8_t *bin,
size_t *bin_len)
int mod_id_to_bin(
YP_TXT_BIN_PARAMS)
{
// Check for hex notation (leading "0x").
if (txt_len >= 2 && txt[0] == '0' && txt[1] == 'x') {
txt += 2;
txt_len -= 2;
if (txt_len % 2 != 0) {
return KNOT_EINVAL;
} else if (*bin_len <= txt_len / 2) {
return KNOT_ESPACE;
}
YP_CHECK_PARAMS_BIN;
// Decode hex string.
for (size_t i = 0; i < txt_len; i++) {
if (isxdigit((int)txt[i]) == 0) {
return KNOT_EINVAL;
}
bin[i] = 16 * hex_to_num(txt[2 * i]) +
hex_to_num(txt[2 * i + 1]);
}
*bin_len = txt_len / 2;
} else {
if (*bin_len <= txt_len) {
return KNOT_ESPACE;
}
// Check for "mod_name/mod_id" format.
const uint8_t *pos = (uint8_t *)strchr((char *)in->position, '/');
if (pos == NULL || pos >= stop) {
return KNOT_EINVAL;
}
memcpy(bin, txt, txt_len);
*bin_len = txt_len;
// Check for missing module name.
if (pos == in->position) {
return KNOT_EINVAL;
}
return KNOT_EOK;
}
// Write mod_name in the yp_name_t format.
uint8_t name_len = pos - in->position;
wire_ctx_write_u8(out, name_len);
wire_ctx_write(out, in->position, name_len);
wire_ctx_skip(in, name_len);
int hex_text_to_txt(
uint8_t const *bin,
size_t bin_len,
char *txt,
size_t *txt_len)
{
bool printable = true;
// Skip the separator.
wire_ctx_skip(in, sizeof(uint8_t));
// Check for printable string.
for (size_t i = 0; i < bin_len; i++) {
if (isprint(bin[i]) == 0) {
printable = false;
break;
}
// Check for missing id.
if (wire_ctx_available(in) == 0) {
return KNOT_EINVAL;
}
if (printable) {
if (*txt_len <= bin_len) {
return KNOT_ESPACE;
}
// Write mod_id as a zero terminated string.
int ret = yp_str_to_bin(in, out, stop);
if (ret != KNOT_EOK) {
return ret;
}
memcpy(txt, bin, bin_len);
*txt_len = bin_len;
txt[*txt_len] = '\0';
} else {
static const char *hex = "0123456789ABCDEF";
YP_CHECK_RET;
}
if (*txt_len <= 2 + 2 * bin_len) {
return KNOT_ESPACE;
}
int mod_id_to_txt(
YP_BIN_TXT_PARAMS)
{
YP_CHECK_PARAMS_TXT;
// Write hex prefix.
txt[0] = '0';
txt[1] = 'x';
txt += 2;
// Write mod_name.
uint8_t name_len = wire_ctx_read_u8(in);
wire_ctx_write(out, in->position, name_len);
wire_ctx_skip(in, name_len);
// Encode data to hex.
for (size_t i = 0; i < bin_len; i++) {
txt[2 * i] = hex[bin[i] / 16];
txt[2 * i + 1] = hex[bin[i] % 16];
}
// Write the separator.
wire_ctx_write_u8(out, '/');
*txt_len = 2 + 2 * bin_len;
txt[*txt_len] = '\0';
// Write mod_id.
int ret = yp_str_to_txt(in, out);
if (ret != KNOT_EOK) {
return ret;
}
return KNOT_EOK;
YP_CHECK_RET;
}
int mod_id_to_bin(
char const *txt,
size_t txt_len,
uint8_t *bin,
size_t *bin_len)
int edns_opt_to_bin(
YP_TXT_BIN_PARAMS)
{
// Check for "mod_name/mod_id" format.
char *pos = index(txt, '/');
if (pos == NULL) {
YP_CHECK_PARAMS_BIN;
// Check for "code:[value]" format.
const uint8_t *pos = (uint8_t *)strchr((char *)in->position, ':');
if (pos == NULL || pos >= stop) {
return KNOT_EINVAL;
}
uint8_t name_len = pos - txt;
char *id = pos + 1;
size_t id_len = txt_len - name_len - 1;
// Output is mod_name in yp_name_t format and zero terminated id string.
size_t total_out_len = 1 + name_len + id_len + 1;
// Check for enough output room.
if (*bin_len < total_out_len) {
return KNOT_ESPACE;
// Write option code.
int ret = yp_int_to_bin(in, out, pos, 0, UINT16_MAX, YP_SNONE);
if (ret != KNOT_EOK) {
return ret;
}
// Write mod_name in yp_name_t format.
bin[0] = name_len;
memcpy(bin + 1, txt, name_len);
// Write mod_id as zero terminated string.
memcpy(bin + 1 + name_len, id, id_len + 1);
// Set output length.
*bin_len = total_out_len;
// Skip the separator.
wire_ctx_skip(in, sizeof(uint8_t));
return KNOT_EOK;
// Write option data.
ret = yp_hex_to_bin(in, out, stop);
if (ret != KNOT_EOK) {
return ret;
}
YP_CHECK_RET;
}
int mod_id_to_txt(
uint8_t const *bin,
size_t bin_len,
char *txt,
size_t *txt_len)
int edns_opt_to_txt(
YP_BIN_TXT_PARAMS)
{
int ret = snprintf(txt, *txt_len, "%.*s/%s", (int)bin[0], bin + 1,
bin + 1 + bin[0]);
if (ret <= 0 || ret >= *txt_len) {
return KNOT_ESPACE;
YP_CHECK_PARAMS_TXT;
// Write option code.
int ret = yp_int_to_txt(in, out, YP_SNONE);
if (ret != KNOT_EOK) {
return ret;
}
*txt_len = ret;
return KNOT_EOK;
// Write the separator.
wire_ctx_write_u8(out, ':');
// Write option data.
ret = yp_hex_to_txt(in, out);
if (ret != KNOT_EOK) {
return ret;
}
YP_CHECK_RET;
}
int edns_opt_to_bin(
char const *txt,
size_t txt_len,
uint8_t *bin,
size_t *bin_len)
int addr_range_to_bin(
YP_TXT_BIN_PARAMS)
{
char *suffix = NULL;
unsigned long number = strtoul(txt, &suffix, 10);
YP_CHECK_PARAMS_BIN;
// Check for "code:[value]" format.
if (suffix <= txt || *suffix != ':' || number > UINT16_MAX) {
return KNOT_EINVAL;
// Format: 0 - single address, 1 - address prefix, 2 - address range.
uint8_t format = 0;
// Check for the "addr/mask" format.
const uint8_t *pos = (uint8_t *)strchr((char *)in->position, '/');
if (pos >= stop) {
pos = NULL;
}
// Store the option code.
uint16_t code = number;
if (*bin_len < sizeof(code)) {
return KNOT_ESPACE;
if (pos != NULL) {
format = 1;
} else {
// Check for the "addr1-addr2" format.
pos = (uint8_t *)strchr((char *)in->position, '-');
if (pos >= stop) {
pos = NULL;
}
if (pos != NULL) {
format = 2;
}
}
wire_write_u16(bin, code);
bin += sizeof(code);
// Prepare suffix input (behind colon character).
size_t txt_suffix_len = txt_len - (suffix - txt) - 1;
size_t bin_suffix_len = *bin_len - sizeof(code);
suffix++;
// Store address1 type position.
uint8_t *type1 = out->position;
// Convert suffix data.
int ret = hex_text_to_bin(suffix, txt_suffix_len, bin, &bin_suffix_len);
// Write the first address.
int ret = yp_addr_noport_to_bin(in, out, pos, false);
if (ret != KNOT_EOK) {
return ret;
}
// Set output data length.
*bin_len = sizeof(code) + bin_suffix_len;
wire_ctx_write_u8(out, format);
return KNOT_EOK;
}
switch (format) {
case 1:
// Skip the separator.
wire_ctx_skip(in, sizeof(uint8_t));
int edns_opt_to_txt(
uint8_t const *bin,
size_t bin_len,
char *txt,
size_t *txt_len)
{
uint16_t code = wire_read_u16(bin);
// Write the prefix length.
ret = yp_int_to_bin(in, out, stop, 0, (*type1 == 4) ? 32 : 128,
YP_SNONE);
if (ret != KNOT_EOK) {
return ret;
}
break;
case 2:
// Skip the separator.
wire_ctx_skip(in, sizeof(uint8_t));
// Store address2 type position.
uint8_t *type2 = out->position;
// Write option code part.
int code_len = snprintf(txt, *txt_len, "%u:", code);
if (code_len <= 0 || code_len >= *txt_len) {
return KNOT_ESPACE;
// Write the second address.
ret = yp_addr_noport_to_bin(in, out, stop, false);
if (ret != KNOT_EOK) {
return ret;
}
// Check for address mismatch.
if (*type1 != *type2) {
return KNOT_EINVAL;
}
break;
default:
break;
}
size_t data_len = *txt_len - code_len;
YP_CHECK_RET;
}
int addr_range_to_txt(
YP_BIN_TXT_PARAMS)
{
YP_CHECK_PARAMS_TXT;
// Write possible option data part.
int ret = hex_text_to_txt(bin + sizeof(code), bin_len - sizeof(code),
txt + code_len, &data_len);
// Write the first address.
int ret = yp_addr_noport_to_txt(in, out);
if (ret != KNOT_EOK) {
return ret;
}
// Set output text length.
*txt_len = code_len + data_len;
uint8_t format = wire_ctx_read_u8(in);
return KNOT_EOK;
switch (format) {
case 1:
// Write the separator.
wire_ctx_write_u8(out, '/');
// Write the prefix length.
ret = yp_int_to_txt(in, out, YP_SNONE);
if (ret != KNOT_EOK) {
return ret;
}
break;
case 2:
// Write the separator.
wire_ctx_write_u8(out, '-');
// Write the second address.
ret = yp_addr_noport_to_txt(in, out);
if (ret != KNOT_EOK) {
return ret;
}
break;
default:
break;
}
YP_CHECK_RET;
}
int check_ref(
......
......@@ -51,46 +51,28 @@ typedef struct {
typedef int conf_check_f(conf_check_t *);
int hex_text_to_bin(
char const *txt,
size_t txt_len,
uint8_t *bin,
size_t *bin_len
);
int hex_text_to_txt(
uint8_t const *bin,
size_t bin_len,
char *txt,
size_t *txt_len
);
int mod_id_to_bin(
char const *txt,
size_t txt_len,
uint8_t *bin,
size_t *bin_len
YP_TXT_BIN_PARAMS
);
int mod_id_to_txt(
uint8_t const *bin,
size_t bin_len,
char *txt,
size_t *txt_len
YP_BIN_TXT_PARAMS
);
int edns_opt_to_bin(
char const *txt,
size_t txt_len,
uint8_t *bin,
size_t *bin_len
YP_TXT_BIN_PARAMS
);
int edns_opt_to_txt(
uint8_t const *bin,
size_t bin_len,
char *txt,
size_t *txt_len
YP_BIN_TXT_PARAMS
);
int addr_range_to_bin(
YP_TXT_BIN_PARAMS
);
int addr_range_to_txt(
YP_BIN_TXT_PARAMS
);
int check_ref(
......
......@@ -56,7 +56,8 @@ const yp_item_t scheme_mod_synth_record[] = {
{ MOD_PREFIX, YP_TSTR, YP_VNONE, YP_FNONE, { check_prefix } },
{ MOD_ORIGIN, YP_TDNAME, YP_VNONE },
{ MOD_TTL, YP_TINT, YP_VINT = { 0, UINT32_MAX, 3600, YP_STIME } },
{ MOD_NET, YP_TNET, YP_VNONE },
{ MOD_NET, YP_TDATA, YP_VDATA = { 0, NULL, addr_range_to_bin,
addr_range_to_txt }, YP_FMULTI },
{ C_COMMENT, YP_TSTR, YP_VNONE },
{ NULL }
};
......@@ -103,7 +104,7 @@ int check_mod_synth_record(conf_check_t *args)
return KNOT_EINVAL;
}
// Check network prefix.
// Check network subnet.
conf_val_t net = conf_rawid_get_txn(args->conf, args->txn, C_MOD_SYNTH_RECORD,
MOD_NET, args->previous->id,
args->previous->id_len);
......@@ -128,6 +129,7 @@ typedef struct synth_template {
char *zone;
uint32_t ttl;
struct sockaddr_storage addr;
struct sockaddr_storage addr_max;