mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-23 10:28:08 +00:00
processing if the configuration included overlapping pools or multiple fixed-address entries for a single address. This issue affected both IPv4 and IPv6. The fix allows a server to detect such conditions, provides the user with extra information and recommended steps to fix the problem. If the user enables the appropriate option in site.h then server will be terminated
1519 lines
32 KiB
C
1519 lines
32 KiB
C
/* print.c
|
|
|
|
Turn data structures into printable text. */
|
|
|
|
/*
|
|
* Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC")
|
|
* Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
|
|
* Copyright (c) 1995-2003 by Internet Software Consortium
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Internet Systems Consortium, Inc.
|
|
* 950 Charter Street
|
|
* Redwood City, CA 94063
|
|
* <info@isc.org>
|
|
* https://www.isc.org/
|
|
*
|
|
* This software has been written for Internet Systems Consortium
|
|
* by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
|
|
* To learn more about Internet Systems Consortium, see
|
|
* ``https://www.isc.org/''. To learn more about Vixie Enterprises,
|
|
* see ``http://www.vix.com''. To learn more about Nominum, Inc., see
|
|
* ``http://www.nominum.com''.
|
|
*/
|
|
|
|
#include "dhcpd.h"
|
|
|
|
int db_time_format = DEFAULT_TIME_FORMAT;
|
|
|
|
char *quotify_string (const char *s, const char *file, int line)
|
|
{
|
|
unsigned len = 0;
|
|
const char *sp;
|
|
char *buf, *nsp;
|
|
|
|
for (sp = s; sp && *sp; sp++) {
|
|
if (*sp == ' ')
|
|
len++;
|
|
else if (!isascii ((int)*sp) || !isprint ((int)*sp))
|
|
len += 4;
|
|
else if (*sp == '"' || *sp == '\\')
|
|
len += 2;
|
|
else
|
|
len++;
|
|
}
|
|
|
|
buf = dmalloc (len + 1, file, line);
|
|
if (buf) {
|
|
nsp = buf;
|
|
for (sp = s; sp && *sp; sp++) {
|
|
if (*sp == ' ')
|
|
*nsp++ = ' ';
|
|
else if (!isascii ((int)*sp) || !isprint ((int)*sp)) {
|
|
sprintf (nsp, "\\%03o",
|
|
*(const unsigned char *)sp);
|
|
nsp += 4;
|
|
} else if (*sp == '"' || *sp == '\\') {
|
|
*nsp++ = '\\';
|
|
*nsp++ = *sp;
|
|
} else
|
|
*nsp++ = *sp;
|
|
}
|
|
*nsp++ = 0;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
char *quotify_buf (const unsigned char *s, unsigned len,
|
|
const char *file, int line)
|
|
{
|
|
unsigned nulen = 0;
|
|
char *buf, *nsp;
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (s [i] == ' ')
|
|
nulen++;
|
|
else if (!isascii (s [i]) || !isprint (s [i]))
|
|
nulen += 4;
|
|
else if (s [i] == '"' || s [i] == '\\')
|
|
nulen += 2;
|
|
else
|
|
nulen++;
|
|
}
|
|
|
|
buf = dmalloc (nulen + 1, MDL);
|
|
if (buf) {
|
|
nsp = buf;
|
|
for (i = 0; i < len; i++) {
|
|
if (s [i] == ' ')
|
|
*nsp++ = ' ';
|
|
else if (!isascii (s [i]) || !isprint (s [i])) {
|
|
sprintf (nsp, "\\%03o", s [i]);
|
|
nsp += 4;
|
|
} else if (s [i] == '"' || s [i] == '\\') {
|
|
*nsp++ = '\\';
|
|
*nsp++ = s [i];
|
|
} else
|
|
*nsp++ = s [i];
|
|
}
|
|
*nsp++ = 0;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
char *print_base64 (const unsigned char *buf, unsigned len,
|
|
const char *file, int line)
|
|
{
|
|
char *s, *b;
|
|
unsigned bl;
|
|
int i;
|
|
unsigned val, extra;
|
|
static char to64 [] =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
bl = ((len * 4 + 2) / 3) + 1;
|
|
b = dmalloc (bl + 1, file, line);
|
|
if (!b)
|
|
return (char *)0;
|
|
|
|
i = 0;
|
|
s = b;
|
|
while (i != len) {
|
|
val = buf [i++];
|
|
extra = val & 3;
|
|
val = val >> 2;
|
|
*s++ = to64 [val];
|
|
if (i == len) {
|
|
*s++ = to64 [extra << 4];
|
|
*s++ = '=';
|
|
break;
|
|
}
|
|
val = (extra << 8) + buf [i++];
|
|
extra = val & 15;
|
|
val = val >> 4;
|
|
*s++ = to64 [val];
|
|
if (i == len) {
|
|
*s++ = to64 [extra << 2];
|
|
*s++ = '=';
|
|
break;
|
|
}
|
|
val = (extra << 8) + buf [i++];
|
|
extra = val & 0x3f;
|
|
val = val >> 6;
|
|
*s++ = to64 [val];
|
|
*s++ = to64 [extra];
|
|
}
|
|
if (!len)
|
|
*s++ = '=';
|
|
*s++ = 0;
|
|
if (s > b + bl + 1)
|
|
abort ();
|
|
return b;
|
|
}
|
|
|
|
char *print_hw_addr (htype, hlen, data)
|
|
const int htype;
|
|
const int hlen;
|
|
const unsigned char *data;
|
|
{
|
|
static char habuf [49];
|
|
char *s;
|
|
int i;
|
|
|
|
if (hlen <= 0)
|
|
habuf [0] = 0;
|
|
else {
|
|
s = habuf;
|
|
for (i = 0; i < hlen; i++) {
|
|
sprintf (s, "%02x", data [i]);
|
|
s += strlen (s);
|
|
*s++ = ':';
|
|
}
|
|
*--s = 0;
|
|
}
|
|
return habuf;
|
|
}
|
|
|
|
void print_lease (lease)
|
|
struct lease *lease;
|
|
{
|
|
struct tm *t;
|
|
char tbuf [32];
|
|
|
|
log_debug (" Lease %s",
|
|
piaddr (lease -> ip_addr));
|
|
|
|
t = gmtime (&lease -> starts);
|
|
strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
|
|
log_debug (" start %s", tbuf);
|
|
|
|
t = gmtime (&lease -> ends);
|
|
strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
|
|
log_debug (" end %s", tbuf);
|
|
|
|
if (lease -> hardware_addr.hlen)
|
|
log_debug (" hardware addr = %s",
|
|
print_hw_addr (lease -> hardware_addr.hbuf [0],
|
|
lease -> hardware_addr.hlen - 1,
|
|
&lease -> hardware_addr.hbuf [1]));
|
|
log_debug (" host %s ",
|
|
lease -> host ? lease -> host -> name : "<none>");
|
|
}
|
|
|
|
#if defined (DEBUG_PACKET)
|
|
void dump_packet_option (struct option_cache *oc,
|
|
struct packet *packet,
|
|
struct lease *lease,
|
|
struct client_state *client,
|
|
struct option_state *in_options,
|
|
struct option_state *cfg_options,
|
|
struct binding_scope **scope,
|
|
struct universe *u, void *foo)
|
|
{
|
|
const char *name, *dot;
|
|
struct data_string ds;
|
|
memset (&ds, 0, sizeof ds);
|
|
|
|
if (u != &dhcp_universe) {
|
|
name = u -> name;
|
|
dot = ".";
|
|
} else {
|
|
name = "";
|
|
dot = "";
|
|
}
|
|
if (evaluate_option_cache (&ds, packet, lease, client,
|
|
in_options, cfg_options, scope, oc, MDL)) {
|
|
log_debug (" option %s%s%s %s;\n",
|
|
name, dot, oc -> option -> name,
|
|
pretty_print_option (oc -> option,
|
|
ds.data, ds.len, 1, 1));
|
|
data_string_forget (&ds, MDL);
|
|
}
|
|
}
|
|
|
|
void dump_packet (tp)
|
|
struct packet *tp;
|
|
{
|
|
struct dhcp_packet *tdp = tp -> raw;
|
|
|
|
log_debug ("packet length %d", tp -> packet_length);
|
|
log_debug ("op = %d htype = %d hlen = %d hops = %d",
|
|
tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops);
|
|
log_debug ("xid = %x secs = %ld flags = %x",
|
|
tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags);
|
|
log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr));
|
|
log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr));
|
|
log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr));
|
|
log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr));
|
|
log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
|
|
((unsigned char *)(tdp -> chaddr)) [0],
|
|
((unsigned char *)(tdp -> chaddr)) [1],
|
|
((unsigned char *)(tdp -> chaddr)) [2],
|
|
((unsigned char *)(tdp -> chaddr)) [3],
|
|
((unsigned char *)(tdp -> chaddr)) [4],
|
|
((unsigned char *)(tdp -> chaddr)) [5]);
|
|
log_debug ("filename = %s", tdp -> file);
|
|
log_debug ("server_name = %s", tdp -> sname);
|
|
if (tp -> options_valid) {
|
|
int i;
|
|
|
|
for (i = 0; i < tp -> options -> universe_count; i++) {
|
|
if (tp -> options -> universes [i]) {
|
|
option_space_foreach (tp, (struct lease *)0,
|
|
(struct client_state *)0,
|
|
(struct option_state *)0,
|
|
tp -> options,
|
|
&global_scope,
|
|
universes [i], 0,
|
|
dump_packet_option);
|
|
}
|
|
}
|
|
}
|
|
log_debug ("%s", "");
|
|
}
|
|
#endif
|
|
|
|
void dump_raw (buf, len)
|
|
const unsigned char *buf;
|
|
unsigned len;
|
|
{
|
|
int i;
|
|
char lbuf [80];
|
|
int lbix = 0;
|
|
|
|
/*
|
|
1 2 3 4 5 6 7
|
|
01234567890123456789012345678901234567890123456789012345678901234567890123
|
|
280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................
|
|
*/
|
|
|
|
memset(lbuf, ' ', 79);
|
|
lbuf [79] = 0;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if ((i & 15) == 0) {
|
|
if (lbix) {
|
|
lbuf[53]=' ';
|
|
lbuf[54]=' ';
|
|
lbuf[55]=' ';
|
|
lbuf[73]='\0';
|
|
log_info ("%s", lbuf);
|
|
}
|
|
memset(lbuf, ' ', 79);
|
|
lbuf [79] = 0;
|
|
sprintf (lbuf, "%03x:", i);
|
|
lbix = 4;
|
|
} else if ((i & 7) == 0)
|
|
lbuf [lbix++] = ' ';
|
|
|
|
if(isprint(buf[i])) {
|
|
lbuf[56+(i%16)]=buf[i];
|
|
} else {
|
|
lbuf[56+(i%16)]='.';
|
|
}
|
|
|
|
sprintf (&lbuf [lbix], " %02x", buf [i]);
|
|
lbix += 3;
|
|
lbuf[lbix]=' ';
|
|
|
|
}
|
|
lbuf[53]=' ';
|
|
lbuf[54]=' ';
|
|
lbuf[55]=' ';
|
|
lbuf[73]='\0';
|
|
log_info ("%s", lbuf);
|
|
}
|
|
|
|
void hash_dump (table)
|
|
struct hash_table *table;
|
|
{
|
|
int i;
|
|
struct hash_bucket *bp;
|
|
|
|
if (!table)
|
|
return;
|
|
|
|
for (i = 0; i < table -> hash_count; i++) {
|
|
if (!table -> buckets [i])
|
|
continue;
|
|
log_info ("hash bucket %d:", i);
|
|
for (bp = table -> buckets [i]; bp; bp = bp -> next) {
|
|
if (bp -> len)
|
|
dump_raw (bp -> name, bp -> len);
|
|
else
|
|
log_info ("%s", (const char *)bp -> name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* print a string as hex. This only outputs
|
|
* colon separated hex list no matter what
|
|
* the input looks like. See print_hex
|
|
* for a function that prints either cshl
|
|
* or a string if all bytes are printible
|
|
* It only uses limit characters from buf
|
|
* and doesn't do anything if buf == NULL
|
|
*
|
|
* len - length of data
|
|
* data - input data
|
|
* limit - length of buf to use
|
|
* buf - output buffer
|
|
*/
|
|
void print_hex_only (len, data, limit, buf)
|
|
unsigned len;
|
|
const u_int8_t *data;
|
|
unsigned limit;
|
|
char *buf;
|
|
{
|
|
unsigned i;
|
|
|
|
if ((buf == NULL) || (limit < 3))
|
|
return;
|
|
|
|
for (i = 0; (i < limit / 3) && (i < len); i++) {
|
|
sprintf(&buf[i*3], "%02x:", data[i]);
|
|
}
|
|
buf[(i * 3) - 1] = 0;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* print a string as either text if all the characters
|
|
* are printable or colon separated hex if they aren't
|
|
*
|
|
* len - length of data
|
|
* data - input data
|
|
* limit - length of buf to use
|
|
* buf - output buffer
|
|
*/
|
|
void print_hex_or_string (len, data, limit, buf)
|
|
unsigned len;
|
|
const u_int8_t *data;
|
|
unsigned limit;
|
|
char *buf;
|
|
{
|
|
unsigned i;
|
|
if ((buf == NULL) || (limit < 3))
|
|
return;
|
|
|
|
for (i = 0; (i < (limit - 3)) && (i < len); i++) {
|
|
if (!isascii(data[i]) || !isprint(data[i])) {
|
|
print_hex_only(len, data, limit, buf);
|
|
return;
|
|
}
|
|
}
|
|
|
|
buf[0] = '"';
|
|
i = len;
|
|
if (i > (limit - 3))
|
|
i = limit - 3;
|
|
memcpy(&buf[1], data, i);
|
|
buf[i + 1] = '"';
|
|
buf[i + 2] = 0;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* print a string as either hex or text
|
|
* using static buffers to hold the output
|
|
*
|
|
* len - length of data
|
|
* data - input data
|
|
* limit - length of buf
|
|
* buf_num - the output buffer to use
|
|
*/
|
|
#define HBLEN 1024
|
|
char *print_hex(len, data, limit, buf_num)
|
|
unsigned len;
|
|
const u_int8_t *data;
|
|
unsigned limit;
|
|
unsigned buf_num;
|
|
{
|
|
static char hex_buf_1[HBLEN + 1];
|
|
static char hex_buf_2[HBLEN + 1];
|
|
static char hex_buf_3[HBLEN + 1];
|
|
char *hex_buf;
|
|
|
|
switch(buf_num) {
|
|
case 0:
|
|
hex_buf = hex_buf_1;
|
|
if (limit >= sizeof(hex_buf_1))
|
|
limit = sizeof(hex_buf_1);
|
|
break;
|
|
case 1:
|
|
hex_buf = hex_buf_2;
|
|
if (limit >= sizeof(hex_buf_2))
|
|
limit = sizeof(hex_buf_2);
|
|
break;
|
|
case 2:
|
|
hex_buf = hex_buf_3;
|
|
if (limit >= sizeof(hex_buf_3))
|
|
limit = sizeof(hex_buf_3);
|
|
break;
|
|
default:
|
|
return(NULL);
|
|
}
|
|
|
|
print_hex_or_string(len, data, limit, hex_buf);
|
|
return(hex_buf);
|
|
}
|
|
|
|
#define DQLEN 80
|
|
|
|
char *print_dotted_quads (len, data)
|
|
unsigned len;
|
|
const u_int8_t *data;
|
|
{
|
|
static char dq_buf [DQLEN + 1];
|
|
int i;
|
|
char *s, *last;
|
|
|
|
s = &dq_buf [0];
|
|
last = s;
|
|
|
|
i = 0;
|
|
|
|
/* %Audit% Loop bounds checks to 21 bytes. %2004.06.17,Safe%
|
|
* The sprintf can't exceed 18 bytes, and since the loop enforces
|
|
* 21 bytes of space per iteration at no time can we exit the
|
|
* loop without at least 3 bytes spare.
|
|
*/
|
|
do {
|
|
sprintf (s, "%u.%u.%u.%u, ",
|
|
data [i], data [i + 1], data [i + 2], data [i + 3]);
|
|
s += strlen (s);
|
|
i += 4;
|
|
} while ((s - &dq_buf [0] > DQLEN - 21) &&
|
|
i + 3 < len);
|
|
if (i == len)
|
|
s [-2] = 0;
|
|
else
|
|
strcpy (s, "...");
|
|
return dq_buf;
|
|
}
|
|
|
|
char *print_dec_1 (val)
|
|
unsigned long val;
|
|
{
|
|
static char vbuf [32];
|
|
sprintf (vbuf, "%lu", val);
|
|
return vbuf;
|
|
}
|
|
|
|
char *print_dec_2 (val)
|
|
unsigned long val;
|
|
{
|
|
static char vbuf [32];
|
|
sprintf (vbuf, "%lu", val);
|
|
return vbuf;
|
|
}
|
|
|
|
static unsigned print_subexpression (struct expression *, char *, unsigned);
|
|
|
|
static unsigned print_subexpression (expr, buf, len)
|
|
struct expression *expr;
|
|
char *buf;
|
|
unsigned len;
|
|
{
|
|
unsigned rv, left;
|
|
const char *s;
|
|
|
|
switch (expr -> op) {
|
|
case expr_none:
|
|
if (len > 3) {
|
|
strcpy (buf, "nil");
|
|
return 3;
|
|
}
|
|
break;
|
|
|
|
case expr_match:
|
|
if (len > 7) {
|
|
strcpy (buf, "(match)");
|
|
return 7;
|
|
}
|
|
break;
|
|
|
|
case expr_check:
|
|
rv = 10 + strlen (expr -> data.check -> name);
|
|
if (len > rv) {
|
|
sprintf (buf, "(check %s)",
|
|
expr -> data.check -> name);
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_equal:
|
|
if (len > 6) {
|
|
rv = 4;
|
|
strcpy (buf, "(eq ");
|
|
rv += print_subexpression (expr -> data.equal [0],
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.equal [1],
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_not_equal:
|
|
if (len > 7) {
|
|
rv = 5;
|
|
strcpy (buf, "(neq ");
|
|
rv += print_subexpression (expr -> data.equal [0],
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.equal [1],
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_regex_match:
|
|
if (len > 10) {
|
|
rv = 4;
|
|
strcpy(buf, "(regex ");
|
|
rv += print_subexpression(expr->data.equal[0],
|
|
buf + rv, len - rv - 2);
|
|
buf[rv++] = ' ';
|
|
rv += print_subexpression(expr->data.equal[1],
|
|
buf + rv, len - rv - 1);
|
|
buf[rv++] = ')';
|
|
buf[rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_substring:
|
|
if (len > 11) {
|
|
rv = 8;
|
|
strcpy (buf, "(substr ");
|
|
rv += print_subexpression (expr -> data.substring.expr,
|
|
buf + rv, len - rv - 3);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression
|
|
(expr -> data.substring.offset,
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.substring.len,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_suffix:
|
|
if (len > 10) {
|
|
rv = 8;
|
|
strcpy (buf, "(suffix ");
|
|
rv += print_subexpression (expr -> data.suffix.expr,
|
|
buf + rv, len - rv - 2);
|
|
if (len > rv)
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.suffix.len,
|
|
buf + rv, len - rv - 1);
|
|
if (len > rv)
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_lcase:
|
|
if (len > 9) {
|
|
rv = 7;
|
|
strcpy(buf, "(lcase ");
|
|
rv += print_subexpression(expr->data.lcase,
|
|
buf + rv, len - rv - 1);
|
|
buf[rv++] = ')';
|
|
buf[rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_ucase:
|
|
if (len > 9) {
|
|
rv = 7;
|
|
strcpy(buf, "(ucase ");
|
|
rv += print_subexpression(expr->data.ucase,
|
|
buf + rv, len - rv - 1);
|
|
buf[rv++] = ')';
|
|
buf[rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_concat:
|
|
if (len > 10) {
|
|
rv = 8;
|
|
strcpy (buf, "(concat ");
|
|
rv += print_subexpression (expr -> data.concat [0],
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.concat [1],
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_pick_first_value:
|
|
if (len > 8) {
|
|
rv = 6;
|
|
strcpy (buf, "(pick1st ");
|
|
rv += print_subexpression
|
|
(expr -> data.pick_first_value.car,
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression
|
|
(expr -> data.pick_first_value.cdr,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_host_lookup:
|
|
rv = 15 + strlen (expr -> data.host_lookup -> hostname);
|
|
if (len > rv) {
|
|
sprintf (buf, "(dns-lookup %s)",
|
|
expr -> data.host_lookup -> hostname);
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_and:
|
|
s = "and";
|
|
binop:
|
|
rv = strlen (s);
|
|
if (len > rv + 4) {
|
|
buf [0] = '(';
|
|
strcpy (&buf [1], s);
|
|
rv += 1;
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.and [0],
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.and [1],
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_or:
|
|
s = "or";
|
|
goto binop;
|
|
|
|
case expr_add:
|
|
s = "+";
|
|
goto binop;
|
|
|
|
case expr_subtract:
|
|
s = "-";
|
|
goto binop;
|
|
|
|
case expr_multiply:
|
|
s = "*";
|
|
goto binop;
|
|
|
|
case expr_divide:
|
|
s = "/";
|
|
goto binop;
|
|
|
|
case expr_remainder:
|
|
s = "%";
|
|
goto binop;
|
|
|
|
case expr_binary_and:
|
|
s = "&";
|
|
goto binop;
|
|
|
|
case expr_binary_or:
|
|
s = "|";
|
|
goto binop;
|
|
|
|
case expr_binary_xor:
|
|
s = "^";
|
|
goto binop;
|
|
|
|
case expr_not:
|
|
if (len > 6) {
|
|
rv = 5;
|
|
strcpy (buf, "(not ");
|
|
rv += print_subexpression (expr -> data.not,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_config_option:
|
|
s = "cfg-option";
|
|
goto dooption;
|
|
|
|
case expr_option:
|
|
s = "option";
|
|
dooption:
|
|
rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) +
|
|
strlen (expr -> data.option -> universe -> name));
|
|
if (len > rv) {
|
|
sprintf (buf, "(option %s.%s)",
|
|
expr -> data.option -> universe -> name,
|
|
expr -> data.option -> name);
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_hardware:
|
|
if (len > 10) {
|
|
strcpy (buf, "(hardware)");
|
|
return 10;
|
|
}
|
|
break;
|
|
|
|
case expr_packet:
|
|
if (len > 10) {
|
|
rv = 8;
|
|
strcpy (buf, "(substr ");
|
|
rv += print_subexpression (expr -> data.packet.offset,
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.packet.len,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_const_data:
|
|
s = print_hex_1 (expr -> data.const_data.len,
|
|
expr -> data.const_data.data, len);
|
|
rv = strlen (s);
|
|
if (rv >= len)
|
|
rv = len - 1;
|
|
strncpy (buf, s, rv);
|
|
buf [rv] = 0;
|
|
return rv;
|
|
|
|
case expr_encapsulate:
|
|
rv = 13;
|
|
strcpy (buf, "(encapsulate ");
|
|
rv += expr -> data.encapsulate.len;
|
|
if (rv + 2 > len)
|
|
rv = len - 2;
|
|
strncpy (buf,
|
|
(const char *)expr -> data.encapsulate.data, rv - 13);
|
|
buf [rv++] = ')';
|
|
buf [rv++] = 0;
|
|
break;
|
|
|
|
case expr_extract_int8:
|
|
if (len > 7) {
|
|
rv = 6;
|
|
strcpy (buf, "(int8 ");
|
|
rv += print_subexpression (expr -> data.extract_int,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_extract_int16:
|
|
if (len > 8) {
|
|
rv = 7;
|
|
strcpy (buf, "(int16 ");
|
|
rv += print_subexpression (expr -> data.extract_int,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_extract_int32:
|
|
if (len > 8) {
|
|
rv = 7;
|
|
strcpy (buf, "(int32 ");
|
|
rv += print_subexpression (expr -> data.extract_int,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_encode_int8:
|
|
if (len > 7) {
|
|
rv = 6;
|
|
strcpy (buf, "(to-int8 ");
|
|
rv += print_subexpression (expr -> data.encode_int,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_encode_int16:
|
|
if (len > 8) {
|
|
rv = 7;
|
|
strcpy (buf, "(to-int16 ");
|
|
rv += print_subexpression (expr -> data.encode_int,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_encode_int32:
|
|
if (len > 8) {
|
|
rv = 7;
|
|
strcpy (buf, "(to-int32 ");
|
|
rv += print_subexpression (expr -> data.encode_int,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_const_int:
|
|
s = print_dec_1 (expr -> data.const_int);
|
|
rv = strlen (s);
|
|
if (len > rv) {
|
|
strcpy (buf, s);
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_exists:
|
|
rv = 10 + (strlen (expr -> data.option -> name) +
|
|
strlen (expr -> data.option -> universe -> name));
|
|
if (len > rv) {
|
|
sprintf (buf, "(exists %s.%s)",
|
|
expr -> data.option -> universe -> name,
|
|
expr -> data.option -> name);
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_variable_exists:
|
|
rv = 10 + strlen (expr -> data.variable);
|
|
if (len > rv) {
|
|
sprintf (buf, "(defined %s)", expr -> data.variable);
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_variable_reference:
|
|
rv = strlen (expr -> data.variable);
|
|
if (len > rv) {
|
|
sprintf (buf, "%s", expr -> data.variable);
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_known:
|
|
s = "known";
|
|
astring:
|
|
rv = strlen (s);
|
|
if (len > rv) {
|
|
strcpy (buf, s);
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_leased_address:
|
|
s = "leased-address";
|
|
goto astring;
|
|
|
|
case expr_client_state:
|
|
s = "client-state";
|
|
goto astring;
|
|
|
|
case expr_host_decl_name:
|
|
s = "host-decl-name";
|
|
goto astring;
|
|
|
|
case expr_lease_time:
|
|
s = "lease-time";
|
|
goto astring;
|
|
|
|
case expr_static:
|
|
s = "static";
|
|
goto astring;
|
|
|
|
case expr_filename:
|
|
s = "filename";
|
|
goto astring;
|
|
|
|
case expr_sname:
|
|
s = "server-name";
|
|
goto astring;
|
|
|
|
case expr_reverse:
|
|
if (len > 11) {
|
|
rv = 13;
|
|
strcpy (buf, "(reverse ");
|
|
rv += print_subexpression (expr -> data.reverse.width,
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.reverse.buffer,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_binary_to_ascii:
|
|
if (len > 5) {
|
|
rv = 9;
|
|
strcpy (buf, "(b2a ");
|
|
rv += print_subexpression (expr -> data.b2a.base,
|
|
buf + rv, len - rv - 4);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.b2a.width,
|
|
buf + rv, len - rv - 3);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.b2a.separator,
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.b2a.buffer,
|
|
buf + rv, len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_dns_transaction:
|
|
rv = 10;
|
|
if (len < rv + 2) {
|
|
buf [0] = '(';
|
|
strcpy (&buf [1], "ns-update ");
|
|
while (len < rv + 2) {
|
|
rv += print_subexpression
|
|
(expr -> data.dns_transaction.car,
|
|
buf + rv, len - rv - 2);
|
|
buf [rv++] = ' ';
|
|
expr = expr -> data.dns_transaction.cdr;
|
|
}
|
|
buf [rv - 1] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
return 0;
|
|
|
|
case expr_ns_delete:
|
|
s = "delete";
|
|
left = 4;
|
|
goto dodnsupd;
|
|
case expr_ns_exists:
|
|
s = "exists";
|
|
left = 4;
|
|
goto dodnsupd;
|
|
case expr_ns_not_exists:
|
|
s = "not_exists";
|
|
left = 4;
|
|
goto dodnsupd;
|
|
case expr_ns_add:
|
|
s = "update";
|
|
left = 5;
|
|
dodnsupd:
|
|
rv = strlen (s);
|
|
if (len > strlen (s) + 1) {
|
|
buf [0] = '(';
|
|
strcpy (buf + 1, s);
|
|
rv++;
|
|
buf [rv++] = ' ';
|
|
s = print_dec_1 (expr -> data.ns_add.rrclass);
|
|
if (len > rv + strlen (s) + left) {
|
|
strcpy (&buf [rv], s);
|
|
rv += strlen (&buf [rv]);
|
|
}
|
|
buf [rv++] = ' ';
|
|
left--;
|
|
s = print_dec_1 (expr -> data.ns_add.rrtype);
|
|
if (len > rv + strlen (s) + left) {
|
|
strcpy (&buf [rv], s);
|
|
rv += strlen (&buf [rv]);
|
|
}
|
|
buf [rv++] = ' ';
|
|
left--;
|
|
rv += print_subexpression
|
|
(expr -> data.ns_add.rrname,
|
|
buf + rv, len - rv - left);
|
|
buf [rv++] = ' ';
|
|
left--;
|
|
rv += print_subexpression
|
|
(expr -> data.ns_add.rrdata,
|
|
buf + rv, len - rv - left);
|
|
buf [rv++] = ' ';
|
|
left--;
|
|
rv += print_subexpression
|
|
(expr -> data.ns_add.ttl,
|
|
buf + rv, len - rv - left);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_null:
|
|
if (len > 6) {
|
|
strcpy (buf, "(null)");
|
|
return 6;
|
|
}
|
|
break;
|
|
case expr_funcall:
|
|
rv = 12 + strlen (expr -> data.funcall.name);
|
|
if (len > rv + 1) {
|
|
strcpy (buf, "(funcall ");
|
|
strcpy (buf + 9, expr -> data.funcall.name);
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression
|
|
(expr -> data.funcall.arglist, buf + rv,
|
|
len - rv - 1);
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_arg:
|
|
rv = print_subexpression (expr -> data.arg.val, buf, len);
|
|
if (expr -> data.arg.next && rv + 2 < len) {
|
|
buf [rv++] = ' ';
|
|
rv += print_subexpression (expr -> data.arg.next,
|
|
buf, len);
|
|
if (rv + 1 < len)
|
|
buf [rv++] = 0;
|
|
return rv;
|
|
}
|
|
break;
|
|
|
|
case expr_function:
|
|
rv = 9;
|
|
if (len > rv + 1) {
|
|
struct string_list *foo;
|
|
strcpy (buf, "(function");
|
|
for (foo = expr -> data.func -> args;
|
|
foo; foo = foo -> next) {
|
|
if (len > rv + 2 + strlen (foo -> string)) {
|
|
buf [rv - 1] = ' ';
|
|
strcpy (&buf [rv], foo -> string);
|
|
rv += strlen (foo -> string);
|
|
}
|
|
}
|
|
buf [rv++] = ')';
|
|
buf [rv] = 0;
|
|
return rv;
|
|
}
|
|
|
|
case expr_gethostname:
|
|
if (len > 13) {
|
|
strcpy(buf, "(gethostname)");
|
|
return 13;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
log_fatal("Impossible case at %s:%d (undefined expression "
|
|
"%d).", MDL, expr->op);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void print_expression (name, expr)
|
|
const char *name;
|
|
struct expression *expr;
|
|
{
|
|
char buf [1024];
|
|
|
|
print_subexpression (expr, buf, sizeof buf);
|
|
log_info ("%s: %s", name, buf);
|
|
}
|
|
|
|
int token_print_indent_concat (FILE *file, int col, int indent,
|
|
const char *prefix,
|
|
const char *suffix, ...)
|
|
{
|
|
va_list list;
|
|
unsigned len;
|
|
char *s, *t, *u;
|
|
|
|
va_start (list, suffix);
|
|
s = va_arg (list, char *);
|
|
len = 0;
|
|
while (s) {
|
|
len += strlen (s);
|
|
s = va_arg (list, char *);
|
|
}
|
|
va_end (list);
|
|
|
|
t = dmalloc (len + 1, MDL);
|
|
if (!t)
|
|
log_fatal ("token_print_indent: no memory for copy buffer");
|
|
|
|
va_start (list, suffix);
|
|
s = va_arg (list, char *);
|
|
u = t;
|
|
while (s) {
|
|
len = strlen (s);
|
|
strcpy (u, s);
|
|
u += len;
|
|
s = va_arg (list, char *);
|
|
}
|
|
va_end (list);
|
|
|
|
len = token_print_indent (file, col, indent,
|
|
prefix, suffix, t);
|
|
dfree (t, MDL);
|
|
return col;
|
|
}
|
|
|
|
int token_indent_data_string (FILE *file, int col, int indent,
|
|
const char *prefix, const char *suffix,
|
|
struct data_string *data)
|
|
{
|
|
int i;
|
|
char *buf;
|
|
char obuf [3];
|
|
|
|
/* See if this is just ASCII. */
|
|
for (i = 0; i < data -> len; i++)
|
|
if (!isascii (data -> data [i]) ||
|
|
!isprint (data -> data [i]))
|
|
break;
|
|
|
|
/* If we have a purely ASCII string, output it as text. */
|
|
if (i == data -> len) {
|
|
buf = dmalloc (data -> len + 3, MDL);
|
|
if (buf) {
|
|
buf [0] = '"';
|
|
memcpy (buf + 1, data -> data, data -> len);
|
|
buf [data -> len + 1] = '"';
|
|
buf [data -> len + 2] = 0;
|
|
i = token_print_indent (file, col, indent,
|
|
prefix, suffix, buf);
|
|
dfree (buf, MDL);
|
|
return i;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < data -> len; i++) {
|
|
sprintf (obuf, "%2.2x", data -> data [i]);
|
|
col = token_print_indent (file, col, indent,
|
|
i == 0 ? prefix : "",
|
|
(i + 1 == data -> len
|
|
? suffix
|
|
: ""), obuf);
|
|
if (i + 1 != data -> len)
|
|
col = token_print_indent (file, col, indent,
|
|
prefix, suffix, ":");
|
|
}
|
|
return col;
|
|
}
|
|
|
|
int token_print_indent (FILE *file, int col, int indent,
|
|
const char *prefix,
|
|
const char *suffix, const char *buf)
|
|
{
|
|
int len = strlen (buf) + strlen (prefix);
|
|
if (col + len > 79) {
|
|
if (indent + len < 79) {
|
|
indent_spaces (file, indent);
|
|
col = indent;
|
|
} else {
|
|
indent_spaces (file, col);
|
|
col = len > 79 ? 0 : 79 - len - 1;
|
|
}
|
|
} else if (prefix && *prefix) {
|
|
fputs (prefix, file);
|
|
col += strlen (prefix);
|
|
}
|
|
fputs (buf, file);
|
|
col += len;
|
|
if (suffix && *suffix) {
|
|
if (col + strlen (suffix) > 79) {
|
|
indent_spaces (file, indent);
|
|
col = indent;
|
|
} else {
|
|
fputs (suffix, file);
|
|
col += strlen (suffix);
|
|
}
|
|
}
|
|
return col;
|
|
}
|
|
|
|
void indent_spaces (FILE *file, int indent)
|
|
{
|
|
int i;
|
|
fputc ('\n', file);
|
|
for (i = 0; i < indent; i++)
|
|
fputc (' ', file);
|
|
}
|
|
|
|
#if defined (NSUPDATE)
|
|
#if defined (DEBUG_DNS_UPDATES)
|
|
/*
|
|
* direction outbound (messages to the dns server)
|
|
* inbound (messages from the dns server)
|
|
* ddns_cb is the control block associated with the message
|
|
* result is the result from the dns code. For outbound calls
|
|
* it is from the call to pass the message to the dns library.
|
|
* For inbound calls it is from the event returned by the library.
|
|
*
|
|
* For outbound messages we print whatever we think is interesting
|
|
* from the control block.
|
|
* For inbound messages we only print the transaction id pointer
|
|
* and the result and expect that the user will match them up as
|
|
* necessary. Note well: the transaction information is opaque to
|
|
* us so we simply print the pointer to it. This should be sufficient
|
|
* to match requests and replys in a short sequence but is awkward
|
|
* when trying to use it for longer sequences.
|
|
*/
|
|
void
|
|
print_dns_status (int direction,
|
|
struct dhcp_ddns_cb *ddns_cb,
|
|
isc_result_t result)
|
|
{
|
|
char obuf[1024];
|
|
char *s = obuf, *end = &obuf[sizeof(obuf)-2];
|
|
char *en;
|
|
const char *result_str;
|
|
char ddns_address[
|
|
sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
|
|
|
|
if (direction == DDNS_PRINT_INBOUND) {
|
|
log_info("DDNS reply: id ptr %p, result: %s",
|
|
ddns_cb->transaction, isc_result_totext(result));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* To avoid having to figure out if any of the strings
|
|
* aren't NULL terminated, just 0 the whole string
|
|
*/
|
|
memset(obuf, 0, 1024);
|
|
|
|
en = "DDNS request: id ptr ";
|
|
if (s + strlen(en) + 16 < end) {
|
|
sprintf(s, "%s%p", en, ddns_cb->transaction);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
|
|
switch (ddns_cb->state) {
|
|
case DDNS_STATE_ADD_FW_NXDOMAIN:
|
|
en = " add forward ";
|
|
break;
|
|
case DDNS_STATE_ADD_FW_YXDHCID:
|
|
en = " modify forward ";
|
|
break;
|
|
|
|
case DDNS_STATE_ADD_PTR:
|
|
en = " add reverse ";
|
|
break;
|
|
|
|
case DDNS_STATE_REM_FW_YXDHCID:
|
|
en = " remove forward ";
|
|
break;
|
|
|
|
case DDNS_STATE_REM_FW_NXRR:
|
|
en = " remove rrset ";
|
|
break;
|
|
|
|
case DDNS_STATE_REM_PTR:
|
|
en = " remove reverse ";
|
|
break;
|
|
|
|
case DDNS_STATE_CLEANUP:
|
|
en = " cleanup ";
|
|
break;
|
|
|
|
default:
|
|
en = " unknown state ";
|
|
break;
|
|
}
|
|
|
|
switch (ddns_cb->state) {
|
|
case DDNS_STATE_ADD_FW_NXDOMAIN:
|
|
case DDNS_STATE_ADD_FW_YXDHCID:
|
|
case DDNS_STATE_REM_FW_YXDHCID:
|
|
case DDNS_STATE_REM_FW_NXRR:
|
|
strcpy(ddns_address, piaddr(ddns_cb->address));
|
|
if (s + strlen(en) + strlen(ddns_address) +
|
|
ddns_cb->fwd_name.len + 5 < end) {
|
|
sprintf(s, "%s%s for %.*s", en, ddns_address,
|
|
ddns_cb->fwd_name.len,
|
|
ddns_cb->fwd_name.data);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
break;
|
|
|
|
case DDNS_STATE_ADD_PTR:
|
|
case DDNS_STATE_REM_PTR:
|
|
if (s + strlen(en) + ddns_cb->fwd_name.len +
|
|
ddns_cb->rev_name.len + 5 < end) {
|
|
sprintf(s, "%s%.*s for %.*s", en,
|
|
ddns_cb->fwd_name.len,
|
|
ddns_cb->fwd_name.data,
|
|
ddns_cb->rev_name.len,
|
|
ddns_cb->rev_name.data);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
break;
|
|
|
|
case DDNS_STATE_CLEANUP:
|
|
default:
|
|
if (s + strlen(en) < end) {
|
|
sprintf(s, "%s", en);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
break;
|
|
}
|
|
|
|
en = " zone: ";
|
|
if (s + strlen(en) + strlen((char *)ddns_cb->zone_name) < end) {
|
|
sprintf(s, "%s%s", en, ddns_cb->zone_name);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
|
|
en = " dhcid: ";
|
|
if (ddns_cb->dhcid.len > 0) {
|
|
if (s + strlen(en) + ddns_cb->dhcid.len-1 < end) {
|
|
strcpy(s, en);
|
|
s += strlen(s);
|
|
strncpy(s, (char *)ddns_cb->dhcid.data+1,
|
|
ddns_cb->dhcid.len-1);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
} else {
|
|
en = " dhcid: <empty>";
|
|
if (s + strlen(en) < end) {
|
|
strcpy(s, en);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
}
|
|
|
|
en = " ttl: ";
|
|
if (s + strlen(en) + 10 < end) {
|
|
sprintf(s, "%s%ld", en, ddns_cb->ttl);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
|
|
en = " result: ";
|
|
result_str = isc_result_totext(result);
|
|
if (s + strlen(en) + strlen(result_str) < end) {
|
|
sprintf(s, "%s%s", en, result_str);
|
|
s += strlen(s);
|
|
} else {
|
|
goto bailout;
|
|
}
|
|
|
|
bailout:
|
|
/*
|
|
* We either finished building the string or ran out
|
|
* of space, print whatever we have in case it is useful
|
|
*/
|
|
log_info("%s", obuf);
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
#endif /* NSUPDATE */
|
|
|
|
/* Format the given time as "A; # B", where A is the format
|
|
* used by the parser, and B is the local time, for humans.
|
|
*/
|
|
const char *
|
|
print_time(TIME t)
|
|
{
|
|
static char buf[sizeof("epoch 9223372036854775807; "
|
|
"# Wed Jun 30 21:49:08 2147483647")];
|
|
static char buf1[sizeof("# Wed Jun 30 21:49:08 2147483647")];
|
|
time_t since_epoch;
|
|
/* The string: "6 2147483647/12/31 23:59:60;"
|
|
* is smaller than the other, used to declare the buffer size, so
|
|
* we can use one buffer for both.
|
|
*/
|
|
|
|
if (t == MAX_TIME)
|
|
return "never;";
|
|
|
|
if (t < 0)
|
|
return NULL;
|
|
|
|
/* For those lucky enough to have a 128-bit time_t, ensure that
|
|
* whatever (corrupt) value we're given doesn't exceed the static
|
|
* buffer.
|
|
*/
|
|
#if (MAX_TIME > 0x7fffffffffffffff)
|
|
if (t > 0x7fffffffffffffff)
|
|
return NULL;
|
|
#endif
|
|
|
|
if (db_time_format == LOCAL_TIME_FORMAT) {
|
|
since_epoch = mktime(localtime(&t));
|
|
if ((strftime(buf1, sizeof(buf1),
|
|
"# %a %b %d %H:%M:%S %Y",
|
|
localtime(&t)) == 0) ||
|
|
(snprintf(buf, sizeof(buf), "epoch %lu; %s",
|
|
(unsigned long)since_epoch, buf1) >= sizeof(buf)))
|
|
return NULL;
|
|
|
|
} else {
|
|
/* No bounds check for the year is necessary - in this case,
|
|
* strftime() will run out of space and assert an error.
|
|
*/
|
|
if (strftime(buf, sizeof(buf), "%w %Y/%m/%d %H:%M:%S;",
|
|
gmtime(&t)) == 0)
|
|
return NULL;
|
|
}
|
|
|
|
return buf;
|
|
}
|