Compare commits

..
11 Commits
Author SHA1 Message Date
Simon Kelley ff4964d01d Re-implement print_mac() to do its own buffer managment.
print_mac() used to output into caller-supplied buffer with no
length checking. The various callers supplied different
length buffers and did their own, ad-hoc, length checking before
calling print_mac(). This was an accident waiting to happen and
it had actually happened in couple of places, with buffer
overflows possible.

print_mac() now returns the address of its own buffer, which
is grown as required.

Thanks to Nicholas Carlini <npc@anthropic.com> for spotting this problem.
2026-05-31 21:37:48 +01:00
Michalis Vasileiadis 45771dc92c Fix OOB writes in contrib/leasequesry/leasequery.c
Thanks to Michalis Vasileiadis for spotting this.

print_mac() writes each MAC byte to its output buffer with unbounded
sprintf and is called from main() with pkt.header.hlen straight out
of a BOOTREPLY. hlen is an attacker-controlled uint8_t (up to 255),
each byte expands to up to 3 chars, and the destination is a 500-byte
stack buffer. A malicious leasequery server that echoes the client's
transaction ID and replies with DHCPLEASEACTIVE and an oversized
hlen overflows that stack buffer.

The patch caps len inside print_mac at DHCP_CHADDR_MAX (16), which is
the actual size of chaddr in the BOOTP header and an upper bound on
any legitimate hardware-address length. The other in-file caller of
print_mac already clamps its length argument to 14 before the call,
so this change is local to the vulnerable path.
2026-05-30 15:58:52 +01:00
Simon Kelley af73e48067 Include fc00::/8 in the set of local addresses.
The current local address range is fd00::/8, but RFC 4193
para 3.1/3.2 reserves fc00::/8 for future use as local addresses,
so add that to the list.

Thanks to Michalis Vasileiadis for spotting this omission.
2026-05-30 13:46:44 +01:00
Simon Kelley 77d4749a5e Fix DNSSEC frec use-after-free in TCP validation path.
Full credit to Jerry Tom <goonsomeway@gmail.com> for finding this.

When DNSSEC validation falls back to TCP (via a forked child process),
the parent uses a uid-based check to detect whether a frec has been
freed and reused before the child returns. It doesn't, however check for
the more likely scenario which is that the frec has simply been
freed via the timeout path in get_new_frec(). This leads to a
use-after-free on an already freed frec.
2026-05-29 17:24:54 +01:00
OpenAI Security Research Team 0375e40824 Fix bounds-checking in contrib/lease-tools/dhcp_release6.c
Credit to OpenAI Security Research Team, outbounddisclosures@openai.com
2026-05-29 16:28:49 +01:00
Simon Kelley 18a139f48f Change "limit" arg to add_pseudoheader() to a length.
Also ripple effects for most of its callers.

This fixes an OOB write caused by bad pointer arithmetic
calculating the pointer-to-end-of-packet used before.

Thanks to Donghyeon Jeong for spotting the bug.
2026-05-17 13:06:17 +01:00
Simon Kelley d5d2bfb74a Change "limit" arg to make_local_answer() to a length.
This fixes an OOB write caused by bad pointer arithmetic
calculating the pointer-to-end-of-packet used before.

Thanks to Donghyeon Jeong for spotting the bug.
2026-05-17 13:05:35 +01:00
Simon Kelley 7f5802c144 Tidy up get_line_alloc() 2026-05-17 00:33:55 +01:00
Simon Kelley 7280e46aa5 Check for too-small packets in relay_upstream6()
Before this fix, the code could read a couple of bytes beyond
valid data when an invalid too-short packet was recieved.

Thanks to Sokhna Walo DIAKHATE <sokhnawalodiakhate@esp.sn>
for the bug report.
2026-05-17 00:24:57 +01:00
Simon Kelley 754177b368 Fix hostname_issubdomain() confusion.
commit 1269f074f8 broke
hostname_issubdomain() and then accidentally fixed
some of the problems by inverting the argument order
in the new uses of the function it introduced.
All the pre-existing calls to hostname_issubdomain()
were left in a non-working state.

This fixes hostname_issubdomain() back to the state
before 1269f074f8, adds
some logic to give correct answers when comparing
to the root domain, and gets right the new calls to
hostname_issubdomain()  added in
1269f074f8

Thanks to Jean Thomas for spotting this problem.
2026-05-16 23:52:29 +01:00
Simon Kelley 228d7ff964 Remove arbitrary limit on config file line lengths.
Stop using the namebuff buffer to read config file
lines. This reduced in size in
014e909f78 and caused
regressions. We now resize the buffer as needed,
so there is no practical limit.

Use the same code to remove the same limit when reading
/etc/ethers and /etc/resolv.conf. Also when copying output
from the lease-change script into the log.

Thanks to Kevin Darbyshire-Bryant for finding the regresssion.
2026-05-16 21:37:11 +01:00
19 changed files with 295 additions and 181 deletions

No files matched your search

+44 -3
View File
@@ -233,31 +233,55 @@ struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, cons
return result;
}
static void copy_option_string(char *dst, size_t dst_len, const char *src, size_t src_len)
{
if (dst_len == 0)
return;
if (src_len >= dst_len)
src_len = dst_len - 1;
memcpy(dst, src, src_len);
dst[src_len] = '\0';
}
uint16_t parse_iana_suboption(char* buf, size_t len)
{
size_t current_pos = 0;
char option_value[1024];
while (current_pos < len)
{
if (len - current_pos < 2 * sizeof(uint16_t))
return UNSPEC_FAIL;
uint16_t option_type, option_len;
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
option_type = ntohs(option_type);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t);
if (option_len > len - current_pos)
return UNSPEC_FAIL;
if (option_type == STATUS_CODE)
{
uint16_t status;
if (option_len < sizeof(uint16_t))
return UNSPEC_FAIL;
memcpy(&status, buf + current_pos, sizeof(uint16_t));
status = ntohs(status);
if (status != SUCCESS)
{
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
option_value[option_len-sizeof(uint16_t)] ='\0';
copy_option_string(option_value, sizeof(option_value),
buf + current_pos + sizeof(uint16_t),
option_len - sizeof(uint16_t));
fprintf(stderr, "Error: %s\n", option_value);
}
return status;
}
current_pos += option_len;
}
return -2;
@@ -266,6 +290,9 @@ uint16_t parse_iana_suboption(char* buf, size_t len)
int16_t parse_packet(char* buf, size_t len)
{
int16_t ret = -1;
if (len < 4)
return UNSPEC_FAIL;
uint8_t type = buf[0];
/*skipping tx id. you need it, uncomment following line
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
@@ -277,20 +304,31 @@ int16_t parse_packet(char* buf, size_t len)
char option_value[1024];
while (current_pos < len)
{
if (len - current_pos < 2 * sizeof(uint16_t))
return UNSPEC_FAIL;
uint16_t option_type, option_len;
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
option_type = ntohs(option_type);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t);
if (option_len > len - current_pos)
return UNSPEC_FAIL;
if (option_type == STATUS_CODE)
{
uint16_t status;
if (option_len < sizeof(uint16_t))
return UNSPEC_FAIL;
memcpy(&status, buf + current_pos, sizeof(uint16_t));
status = ntohs(status);
if (status != SUCCESS)
{
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
copy_option_string(option_value, sizeof(option_value),
buf + current_pos + sizeof(uint16_t),
option_len - sizeof(uint16_t));
fprintf(stderr, "Error: %d %s\n", status, option_value);
return status;
}
@@ -301,6 +339,9 @@ int16_t parse_packet(char* buf, size_t len)
if (option_type == IA_NA )
{
if (option_len < 24)
return UNSPEC_FAIL;
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
if (result)
return result;
+9 -3
View File
@@ -331,9 +331,15 @@ static char *print_mac(char *buff, unsigned char *mac, int len)
if (len == 0)
sprintf(p, "<null>");
else
for (i = 0; i < len; i++)
p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
{
/* Server-controlled lengths (e.g. BOOTREPLY hlen) must not be trusted
to fit the destination buffer; cap at the actual chaddr field size. */
if (len > DHCP_CHADDR_MAX)
len = DHCP_CHADDR_MAX;
for (i = 0; i < len; i++)
p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
}
return buff;
}
+13 -10
View File
@@ -1091,10 +1091,12 @@ int cache_recv_insert(time_t now, int fd)
if (op == PIPE_OP_KILLED)
my_syslog(LOG_INFO, _("TCP process for DNSSEC validation timed out"));
/* There's a tiny chance that the frec may have been freed
and reused before the TCP process returns. Detect that with
the uid field which is unique modulo 2^32 for each use. */
if (uid == forward->uid)
/* There's a chance that the frec may have timed-out and been
freed before the TCP process returns, so check that the
frec is still marked in use. Even if it is in use, there's a tiny chance
that the frec may have been freed and _reused_ before the TCP process returns.
Detect that with the uid field which is unique modulo 2^32 for each use. */
if (forward->sentto && uid == forward->uid)
{
if (op == PIPE_OP_RESULT)
{
@@ -1407,9 +1409,10 @@ static int eatspace(FILE *f)
}
}
static int gettok(FILE *f, char *token)
static int gettok(FILE *f, char *token, size_t buffsz)
{
int c, count = 0;
int c;
unsigned int count = 0;
while (1)
{
@@ -1422,7 +1425,7 @@ static int gettok(FILE *f, char *token)
return eatspace(f);
}
if (count < (MAXDNAMESTR - 1))
if (count < (buffsz - 1))
{
token[count++] = c;
token[count] = 0;
@@ -1447,7 +1450,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
lineno += eatspace(f);
while ((atnl = gettok(f, token)) != -1)
while ((atnl = gettok(f, token, MAXDNAMESTR)) != -1)
{
if (inet_pton(AF_INET, token, &addr) > 0)
{
@@ -1465,7 +1468,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
{
my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
while (atnl == 0)
atnl = gettok(f, token);
atnl = gettok(f, token, MAXDNAMESTR);
lineno += atnl;
continue;
}
@@ -1483,7 +1486,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
int fqdn, nomem;
char *canon;
if ((atnl = gettok(f, token)) == -1)
if ((atnl = gettok(f, token, MAXDNAMESTR)) == -1)
break;
fqdn = !!strchr(token, '.');
+3 -3
View File
@@ -1055,7 +1055,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
DBusConnection *connection = (DBusConnection *)daemon->dbus;
DBusMessage* message = NULL;
DBusMessageIter args;
char *action_str, *mac = daemon->namebuff;
char *action_str, *mac;
unsigned char *p;
int i;
@@ -1068,7 +1068,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
#ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA))
{
print_mac(mac, lease->clid, lease->clid_len);
mac = print_mac(lease->clid, lease->clid_len);
inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
}
else
@@ -1076,7 +1076,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
{
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(mac, p, i);
mac = print_mac(p, i);
inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
}
+3 -3
View File
@@ -936,11 +936,11 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
trunc = 1;
opt_len = 14;
}
print_mac(buf, val, opt_len);
*buf = 0;
strncat(buf, print_mac(val, opt_len), buf_len);
if (trunc)
strncat(buf, "...", buf_len - strlen(buf));
}
return ot[o].name ? ot[o].name : "";
+8 -7
View File
@@ -925,7 +925,8 @@ void dhcp_read_ethers(void)
{
FILE *f = fopen(ETHERSFILE, "r");
unsigned int flags;
char *buff = daemon->namebuff;
size_t linesz = 0;
char *line = NULL;
char *ip, *cp;
struct in_addr addr;
unsigned char hwaddr[ETHER_ADDR_LEN];
@@ -958,22 +959,22 @@ void dhcp_read_ethers(void)
up = &config->next;
}
while (fgets(buff, MAXDNAMESTR, f))
while (get_line_alloc(f, &line, &linesz))
{
char *host = NULL;
lineno++;
while (strlen(buff) > 0 && isspace((unsigned char)buff[strlen(buff)-1]))
buff[strlen(buff)-1] = 0;
while (strlen(line) > 0 && isspace((unsigned char)line[strlen(line)-1]))
line[strlen(line)-1] = 0;
if ((*buff == '#') || (*buff == '+') || (*buff == 0))
if ((*line == '#') || (*line == '+') || (*line == 0))
continue;
for (ip = buff; *ip && !isspace((unsigned char)*ip); ip++);
for (ip = line; *ip && !isspace((unsigned char)*ip); ip++);
for(; *ip && isspace((unsigned char)*ip); ip++)
*ip = 0;
if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
if (!*ip || parse_hex(line, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
{
my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
continue;
+7 -6
View File
@@ -1468,7 +1468,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
/* dnssec.c */
#ifdef HAVE_DNSSEC
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int id, int type);
size_t dnssec_generate_query(struct dns_header *header, size_t outlen, char *name, int class, int id, int type);
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name,
char *keyname, int class, int *validate_count);
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name,
@@ -1516,6 +1516,7 @@ void *whine_malloc_real(const char *func, unsigned int line, size_t size);
void *whine_realloc_real(const char *wrapper, const char *func, unsigned int line, void *ptr, size_t size);
int expand_buf_real(const char *func, unsigned int line, struct iovec *iov, size_t size);
int expand_workspace_real(const char *func, unsigned int line, unsigned char ***wkspc, int *szp, int new);
int get_line_alloc(FILE *f, char **buffp, size_t *sizep);
int sa_len(union mysockaddr *addr);
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
int sockaddr_isnull(const union mysockaddr *s);
@@ -1537,7 +1538,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
unsigned int *wildcard_mask, int *mac_type);
int memcmp_masked(unsigned char *a, unsigned char *b, int len,
unsigned int mask);
char *print_mac(char *buff, unsigned char *mac, int len);
char *print_mac(unsigned char *mac, int len);
int read_write(int fd, unsigned char *packet, int size, int rw);
int read_writev(int fd, struct iovec *iov, int iovcnt, int rw);
void close_fds(long max_fd, int spare1, int spare2, int spare3);
@@ -1938,11 +1939,11 @@ void from_wire(char *name);
/* edns0.c */
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
size_t *len, unsigned char **p, int *is_sign, int *is_last);
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
size_t add_pseudoheader(struct dns_header *header, size_t plen, size_t out_size,
int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
size_t add_do_bit(struct dns_header *header, size_t plen, size_t outlen);
void edns0_needs_mac(union mysockaddr *addr, time_t now);
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
size_t add_edns0_config(struct dns_header *header, size_t plen, size_t outlen,
union mysockaddr *source, time_t now, int *cacheable);
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
@@ -1965,7 +1966,7 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout);
int filter_servers(int seed, int flags, int *lowout, int *highout);
int is_local_answer(time_t now, int first, char *name);
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header,
char *name, char *limit, int first, int last, int ede);
char *name, size_t limit, int first, int last, int ede);
int server_samegroup(struct server *a, struct server *b);
#ifdef HAVE_DNSSEC
int dnssec_server(struct server *server, char *keyname, int is_ds, int *firstp, int *lastp);
+5 -5
View File
@@ -383,7 +383,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
an attacker using signatures made with the key of an unrelated
zone he controls. Note that the root key is always allowed.
Ignore sigs which aren't valid */
if (*daemon->workspacename == 0 || hostname_issubdomain(name, daemon->workspacename) != 0)
if (*daemon->workspacename == 0 || hostname_issubdomain(daemon->workspacename, name) != 0)
{
if (gotkey)
{
@@ -2095,8 +2095,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
CNAME must be <subdomain>.<dname>
CNAME target must be <subdomain>.<dname_target>
<subdomain>s must match for name and target. */
if (hostname_issubdomain(daemon->cname, name) == 1 &&
hostname_issubdomain(daemon->workspacename, keyname) == 1 &&
if (hostname_issubdomain(name, daemon->cname) == 1 &&
hostname_issubdomain(keyname, daemon->workspacename) == 1 &&
name_prefix_len == strlen(daemon->workspacename) - strlen(keyname))
{
char save = daemon->cname[name_prefix_len];
@@ -2332,7 +2332,7 @@ int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
}
}
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name,
size_t dnssec_generate_query(struct dns_header *header, size_t outlen, char *name,
int class, int id, int type)
{
unsigned char *p;
@@ -2356,7 +2356,7 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
PUTSHORT(type, p);
PUTSHORT(class, p);
return add_do_bit(header, p - (unsigned char *)header, end);
return add_do_bit(header, p - (unsigned char *)header, outlen);
}
int errflags_to_ede(int status)
+4 -3
View File
@@ -408,12 +408,13 @@ int is_local_answer(time_t now, int first, char *name)
return rc;
}
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last, int ede)
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, size_t limit, int first, int last, int ede)
{
int trunc = 0, anscount = 0;
unsigned char *p;
int start;
union all_addr addr;
char *out_end = ((char *)header) + limit;
setup_reply(header, flags, ede);
@@ -443,7 +444,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
else
addr.addr4 = srv->addr;
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
if (add_resource_record(header, out_end, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
anscount++;
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
}
@@ -458,7 +459,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
else
addr.addr6 = srv->addr;
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
if (add_resource_record(header, out_end, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
anscount++;
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
}
+25 -22
View File
@@ -100,13 +100,14 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t
replace == 1 ->replace existing or add option
replace == 2 ->relpace existing option only.
*/
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
size_t add_pseudoheader(struct dns_header *header, size_t plen, size_t out_size,
int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
{
unsigned char *lenp = NULL, *datap = NULL, *p, *udp_len, *buff = NULL;
int rdlen = 0, is_sign, is_last;
unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
unsigned char *limit = ((unsigned char *)header) + out_size;
p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
if (is_sign)
@@ -247,9 +248,9 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
return p - (unsigned char *)header;
}
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
size_t add_do_bit(struct dns_header *header, size_t plen, size_t outlen)
{
return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1, 0);
return add_pseudoheader(header, plen, outlen, 0, NULL, 0, 1, 0);
}
static unsigned char char64(unsigned char c)
@@ -276,14 +277,16 @@ void edns0_needs_mac(union mysockaddr *addr, time_t now)
/* OPT_ADD_MAC = MAC is added (if available)
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
OPT_STRIP_MAC = MAC is removed */
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
OPT_STRIP_MAC = MAC is removed
Handle only six byte MACs. */
static size_t add_dns_client(struct dns_header *header, size_t plen, size_t outlen,
union mysockaddr *l3, time_t now, int *cacheablep)
{
int replace = 0, maclen = 0;
unsigned char mac[DHCP_CHADDR_MAX];
char encode[18]; /* handle 6 byte MACs ONLY */
char encode[9] = { 0 };
char *encoded = encode;
if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6)
{
if (option_bool(OPT_STRIP_MAC))
@@ -291,7 +294,7 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
*cacheablep = 0;
if (option_bool(OPT_MAC_HEX))
print_mac(encode, mac, maclen);
encoded = print_mac(mac, maclen);
else
{
encoder(mac, encode);
@@ -303,7 +306,7 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
replace = 2;
if (replace != 0 || maclen == 6)
plen = add_pseudoheader(header, plen, limit, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
plen = add_pseudoheader(header, plen, outlen, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encoded, strlen(encoded), 0, replace);
return plen;
}
@@ -312,7 +315,7 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
/* OPT_ADD_MAC = MAC is added (if available)
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
OPT_STRIP_MAC = MAC is removed */
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
static size_t add_mac(struct dns_header *header, size_t plen, size_t outlen,
union mysockaddr *l3, time_t now, int *cacheablep)
{
int maclen = 0, replace = 0;
@@ -328,7 +331,7 @@ static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *lim
replace = 2;
if (replace != 0 || maclen != 0)
plen = add_pseudoheader(header, plen, limit, EDNS0_OPTION_MAC, mac, maclen, 0, replace);
plen = add_pseudoheader(header, plen, outlen, EDNS0_OPTION_MAC, mac, maclen, 0, replace);
return plen;
}
@@ -409,7 +412,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source,
/* OPT_CLIENT_SUBNET = client subnet is added
OPT_CLIENT_SUBNET + OPT_STRIP_ECS = client subnet is replaced
OPT_STRIP_ECS = client subnet is removed */
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit,
static size_t add_source_addr(struct dns_header *header, size_t plen, size_t outlen,
union mysockaddr *source, int *cacheable)
{
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
@@ -439,7 +442,7 @@ static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned c
return plen;
}
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
return add_pseudoheader(header, plen, outlen, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
}
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
@@ -516,7 +519,7 @@ struct umbrella_opt {
u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
};
static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
static size_t add_umbrella_opt(struct dns_header *header, size_t plen, size_t outlen, union mysockaddr *source, int *cacheable)
{
*cacheable = 0;
@@ -548,28 +551,28 @@ static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned
PUTLONG(daemon->umbrella_asset, u);
}
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1);
return add_pseudoheader(header, plen, outlen, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1);
}
/* Set *check_subnet if we add a client subnet option, which needs to checked
in the reply. Set *cacheable to zero if we add an option which the answer
may depend on. */
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
size_t add_edns0_config(struct dns_header *header, size_t plen, size_t outlen,
union mysockaddr *source, time_t now, int *cacheable)
{
*cacheable = 1;
plen = add_mac(header, plen, limit, source, now, cacheable);
plen = add_dns_client(header, plen, limit, source, now, cacheable);
plen = add_mac(header, plen, outlen, source, now, cacheable);
plen = add_dns_client(header, plen, outlen, source, now, cacheable);
if (daemon->dns_client_id)
plen = add_pseudoheader(header, plen, limit, EDNS0_OPTION_NOMCPEID,
plen = add_pseudoheader(header, plen, outlen, EDNS0_OPTION_NOMCPEID,
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
if (option_bool(OPT_UMBRELLA))
plen = add_umbrella_opt(header, plen, limit, source, cacheable);
plen = add_umbrella_opt(header, plen, outlen, source, cacheable);
plen = add_source_addr(header, plen, limit, source, cacheable);
plen = add_source_addr(header, plen, outlen, source, cacheable);
return plen;
}
+21 -21
View File
@@ -375,7 +375,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
plen = add_do_bit(header, plen, ((unsigned char *) header) + daemon->edns_pktsz);
plen = add_do_bit(header, plen, daemon->edns_pktsz);
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
this allows it to select auth servers when one is returning bad data. */
@@ -514,7 +514,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
forwarded = 0;
/* Advertise the size of UDP reply we can accept. */
plen = add_pseudoheader(header, plen, (unsigned char *)(header + daemon->edns_pktsz), 0, NULL, 0, 0, 0);
plen = add_pseudoheader(header, plen, daemon->edns_pktsz, 0, NULL, 0, 0, 0);
/* check for send errors here (no route to host)
if we fail to send to all nameservers, send back an error
@@ -589,7 +589,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
reply:
if (udpfd != -1)
{
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, (char *)(header + replylimit), first, last, ede)))
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, replylimit, first, last, ede)))
return;
if (fwd_flags & FREC_HAS_PHEADER)
@@ -597,9 +597,9 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
u16 swap = htons((u16)ede);
if (ede != EDE_UNSET)
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, 0, 0);
plen = add_pseudoheader(header, plen, replylimit, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, 0, 0);
else
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), 0, NULL, 0, 0, 0);
plen = add_pseudoheader(header, plen, replylimit, 0, NULL, 0, 0, 0);
}
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
@@ -695,7 +695,7 @@ static struct ipsets *domain_find_sets(struct ipsets *setlist, const char *domai
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
union mysockaddr *query_source, unsigned char *limit, int ede)
union mysockaddr *query_source, size_t outlen, int ede)
{
unsigned char *pheader, *sizep;
struct ipsets *ipsets = NULL, *nftsets = NULL;
@@ -879,7 +879,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
if (pheader && ede != EDE_UNSET)
{
u16 swap = htons((u16)ede);
n = add_pseudoheader(header, n, limit, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
n = add_pseudoheader(header, n, outlen, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
}
if (RCODE(header) == NXDOMAIN)
@@ -1027,7 +1027,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
allocation of a new one: third arg of get_new_frec() does that. */
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, STAT_ISEQUAL(status, STAT_NEED_DS), NULL, NULL)) != -1 &&
(server = daemon->serverarray[serverind]) &&
(nn = dnssec_generate_query(header, ((unsigned char *) header) + daemon->edns_pktsz,
(nn = dnssec_generate_query(header, daemon->edns_pktsz,
daemon->keyname, forward->class, get_id(),
STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS)) &&
(fd = allocate_rfd(&rfds, server)) != -1 &&
@@ -1442,7 +1442,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
!(forward->flags & FREC_HAS_PHEADER), &forward->frec_src.source,
((unsigned char *)header) + daemon->edns_pktsz, ede)))
daemon->edns_pktsz, ede)))
{
struct frec_src *src, *prev;
int do_trunc;
@@ -1945,7 +1945,7 @@ void receive_query(struct listener *listen, time_t now)
{
int cacheable;
n = add_edns0_config(header, n, ((unsigned char *)header) + daemon->edns_pktsz, &source_addr, now, &cacheable);
n = add_edns0_config(header, n, daemon->edns_pktsz, &source_addr, now, &cacheable);
saved_question = blockdata_alloc((char *) header, (size_t)n);
if (!cacheable)
@@ -1979,12 +1979,12 @@ void receive_query(struct listener *listen, time_t now)
{
u16 swap = htons(ede);
m = add_pseudoheader(header, m, ((unsigned char *) header) + daemon->edns_pktsz,
EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
m = add_pseudoheader(header, m, daemon->edns_pktsz, EDNS0_OPTION_EDE,
(unsigned char *)&swap, 2, do_bit, 0);
}
else
m = add_pseudoheader(header, m, ((unsigned char *) header) + daemon->edns_pktsz,
0, NULL, 0, do_bit, 0);
m = add_pseudoheader(header, m, daemon->edns_pktsz, 0,
NULL, 0, do_bit, 0);
}
#ifdef HAVE_DUMPFILE
@@ -2326,7 +2326,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
query_header = (struct dns_header *)daemon->packet;
daemon->srv_save = NULL;
m = dnssec_generate_query(query_header, ((unsigned char *)query_header) + daemon->edns_pktsz, keyname, class, 0,
m = dnssec_generate_query(query_header, daemon->edns_pktsz, keyname, class, 0,
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1 ||
@@ -2479,7 +2479,7 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
out_header = bigbuff->iov_base;
/* Add edns0 pheader to query */
size = add_edns0_config(header, size, ((unsigned char *) header) + daemon->packet_buff_sz, &peer_addr, now, &cacheable);
size = add_edns0_config(header, size, daemon->packet_buff_sz, &peer_addr, now, &cacheable);
/* Clear buffer to avoid risk of information disclosure. */
memset(bigbuff->iov_base, 0, bigbuff->iov_len);
@@ -2620,7 +2620,7 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
size = add_do_bit(header, size, ((unsigned char *) header) + daemon->edns_pktsz);
size = add_do_bit(header, size, daemon->edns_pktsz);
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
this allows it to select auth servers when one is returning bad data. */
@@ -2715,7 +2715,7 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
m = process_reply(out_header, now, serv, (unsigned int)m,
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)out_header) + 65536, ede);
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, 65536, ede);
/* process_reply() adds pheader itself */
have_pseudoheader = 0;
@@ -2731,7 +2731,7 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
if (m == 0)
{
if (!(m = make_local_answer(flags, gotname, size, out_header, daemon->namebuff,
((char *) out_header) + 65536, first, last, ede)))
65536, first, last, ede)))
break;
}
else if (ede == EDE_UNSET)
@@ -2747,9 +2747,9 @@ void tcp_request(int confd, time_t now, struct iovec *bigbuff,
u16 swap = htons((u16)ede);
if (ede != EDE_UNSET)
m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
m = add_pseudoheader(out_header, m, 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
else
m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, 0, NULL, 0, do_bit, 0);
m = add_pseudoheader(out_header, m, 65536, 0, NULL, 0, do_bit, 0);
}
check_log_writer(1);
+6 -12
View File
@@ -533,18 +533,12 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
close(pipeout[0]);
else
{
while (fgets(daemon->packet, daemon->packet_buff_sz, fp))
{
/* do not include new lines, log will append them */
size_t len = strlen(daemon->packet);
if (len > 0)
{
--len;
if (daemon->packet[len] == '\n')
daemon->packet[len] = 0;
}
send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet);
}
char *line = NULL;
size_t linesz = 0;
while (get_line_alloc(fp, &line, &linesz))
send_event(event_fd, EVENT_SCRIPT_LOG, 0, line);
fclose(fp);
}
}
+5 -5
View File
@@ -1699,19 +1699,19 @@ void check_servers(int no_loop_check)
int reload_servers(char *fname)
{
FILE *f;
char *line;
char *line = NULL;
size_t linesz = 0;
int gotone = 0;
/* buff happens to be MAXDNAMESTR long... */
if (!(f = fopen(fname, "r")))
{
my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
return 0;
}
mark_servers(SERV_FROM_RESOLV);
while ((line = fgets(daemon->namebuff, MAXDNAMESTR, f)))
while (get_line_alloc(f, &line, &linesz))
{
union mysockaddr addr, source_addr;
char *token = strtok(line, " \t\n\r");
+32 -29
View File
@@ -5471,9 +5471,20 @@ err:
static void read_file(char *file, FILE *f, int hard_opt, int from_script)
{
volatile int lineno = 0;
char *buff = daemon->namebuff;
char *buff;
size_t buffsz;
/* Memory allocation failure longjmps here if mem_recover == 1 */
if (hard_opt != 0)
{
setjmp(mem_jmp);
mem_recover = 1;
}
while (fgets(buff, MAXDNAMESTR, f))
buff = NULL;
buffsz = 0;
while (get_line_alloc(f, &buff, &buffsz))
{
int white, i;
volatile int option;
@@ -5481,15 +5492,7 @@ static void read_file(char *file, FILE *f, int hard_opt, int from_script)
size_t len;
option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
/* Memory allocation failure longjmps here if mem_recover == 1 */
if (option != 0 || hard_opt == LOPT_REV_SERV)
{
if (setjmp(mem_jmp))
continue;
mem_recover = 1;
}
arg = NULL;
lineno++;
errmess = NULL;
@@ -5949,16 +5952,15 @@ void reread_dhcp(void)
void read_opts(int argc, char **argv, char *compile_opts)
{
size_t argbuf_size = 300;
char *argbuf = opt_malloc(argbuf_size);
char *buff = opt_malloc(MAXDNAMESTR+1);
char *argbuf = safe_malloc(argbuf_size);
int option, testmode = 0;
char *arg, *conffile = NULL;
opterr = 0;
daemon = opt_malloc(sizeof(struct daemon));
memset(daemon, 0, sizeof(struct daemon));
daemon->namebuff = buff;
daemon->namebuff = safe_malloc(MAXDNAMESTR+1);
daemon->workspacename = safe_malloc(MAXDNAMESTR+1);
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
@@ -6197,9 +6199,9 @@ void read_opts(int argc, char **argv, char *compile_opts)
/* create default, if not specified */
if (daemon->authserver && !daemon->hostmaster)
{
strcpy(buff, "hostmaster.");
strcat(buff, daemon->authserver);
daemon->hostmaster = opt_string_alloc(buff);
strcpy(daemon->namebuff, "hostmaster.");
strncat(daemon->namebuff, daemon->authserver, MAXDNAMESTR - strlen(daemon->namebuff));
daemon->hostmaster = opt_string_alloc(daemon->namebuff);
}
if (!daemon->dhcp_pxe_vendors)
@@ -6214,11 +6216,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
{
struct mx_srv_record *mx;
if (gethostname(buff, MAXDNAMESTR) == -1)
if (gethostname(daemon->namebuff, MAXDNAMESTR) == -1)
die(_("cannot get host-name: %s"), NULL, EC_MISC);
for (mx = daemon->mxnames; mx; mx = mx->next)
if (!mx->issrv && hostname_isequal(mx->name, buff))
if (!mx->issrv && hostname_isequal(mx->name, daemon->namebuff))
break;
if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
@@ -6227,12 +6229,12 @@ void read_opts(int argc, char **argv, char *compile_opts)
mx->next = daemon->mxnames;
mx->issrv = 0;
mx->target = NULL;
mx->name = opt_string_alloc(buff);
mx->name = opt_string_alloc(daemon->namebuff);
daemon->mxnames = mx;
}
if (!daemon->mxtarget)
daemon->mxtarget = opt_string_alloc(buff);
daemon->mxtarget = opt_string_alloc(daemon->namebuff);
for (mx = daemon->mxnames; mx; mx = mx->next)
if (!mx->issrv && !mx->target)
@@ -6247,7 +6249,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
if (option_bool(OPT_RESOLV_DOMAIN))
{
char *line;
char *line = NULL;
size_t linesz = 0;
FILE *f;
if (option_bool(OPT_NO_RESOLV) ||
@@ -6258,7 +6261,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
if (!(f = fopen((daemon->resolv_files)->name, "r")))
die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
while ((line = fgets(buff, MAXDNAMESTR, f)))
while (get_line_alloc(f, &line, &linesz))
{
char *token = strtok(line, " \t\n\r");
@@ -6278,7 +6281,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
if (daemon->domain_suffix)
{
/* add domain for any srv record without one. */
/* add domain for any srv record without one. */
struct mx_srv_record *srv;
for (srv = daemon->mxnames; srv; srv = srv->next)
@@ -6288,11 +6291,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
{
if (strlen(srv->name) + 1 + strlen(daemon->domain_suffix) > MAXDNAMESTR)
die(_("srv-host name %s too long after domain appended"), srv->name, EC_MISC);
strcpy(buff, srv->name);
strcat(buff, ".");
strcat(buff, daemon->domain_suffix);
strcpy(daemon->namebuff, srv->name);
strcat(daemon->namebuff, ".");
strcat(daemon->namebuff, daemon->domain_suffix);
free(srv->name);
if (!(srv->name = canonicalise_opt(buff)))
if (!(srv->name = canonicalise_opt(daemon->namebuff)))
die(_("bad srv-host name %s after domain appended"), srv->name, EC_MISC);
}
}
+2 -5
View File
@@ -215,11 +215,8 @@ void icmp6_packet(time_t now)
if (opt_sz == 0 || opt_sz > rem)
return; /* Bad packet */
if (p[0] == ICMP6_OPT_SOURCE_MAC && ((opt_sz - 2) * 3 - 1 < MAXDNAMESTR))
{
print_mac(daemon->namebuff, &p[2], opt_sz - 2);
mac = daemon->namebuff;
}
if (p[0] == ICMP6_OPT_SOURCE_MAC)
mac = print_mac(&p[2], opt_sz - 2);
}
if (!option_bool(OPT_QUIET_RA))
+1 -1
View File
@@ -448,7 +448,7 @@ int private_net6(struct in6_addr *a, int ban_localhost)
(IN6_IS_ADDR_LOOPBACK(a) && ban_localhost) || /* RFC 6303 4.3 */
IN6_IS_ADDR_LINKLOCAL(a) || /* RFC 6303 4.5 */
IN6_IS_ADDR_SITELOCAL(a) ||
((unsigned char *)a)[0] == 0xfd || /* RFC 6303 4.4 */
(((unsigned char *)a)[0] & 0xfe) == 0xfc || /* RFC 4196 3.1 */
((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
}
+10 -8
View File
@@ -1313,7 +1313,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
daemon->addrbuff, print_mac(daemon->namebuff, mac, len));
daemon->addrbuff, print_mac(mac, len));
}
else
{
@@ -1537,7 +1537,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
inet_ntop(AF_INET, &ltmp->addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
print_mac(ltmp->hwaddr, ltmp->hwaddr_len),
daemon->addrbuff);
lease = ltmp;
}
@@ -1918,16 +1918,18 @@ static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, char *err, u32 xid)
{
char *mac = "";
if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
return;
daemon->addrbuff[0] = daemon->namebuff[0] = 0;
daemon->addrbuff[0] = 0;
if (addr)
inet_ntop(AF_INET, addr, daemon->addrbuff, ADDRSTRLEN);
if (ext_mac)
print_mac(daemon->namebuff, ext_mac, mac_len);
mac = print_mac(ext_mac, mac_len);
if (option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s%s%s%s",
@@ -1936,7 +1938,7 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
interface,
daemon->addrbuff,
addr ? " " : "",
daemon->namebuff,
mac,
ext_mac ? " " : "",
string ? string : "",
err ? err : "");
@@ -1946,16 +1948,16 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
interface,
daemon->addrbuff,
addr ? " " : "",
daemon->namebuff,
mac,
ext_mac ? " " : "",
string ? string : "",
err ? err : "");
#ifdef HAVE_UBUS
if (!strcmp(type, "DHCPACK"))
ubus_event_bcast("dhcp.ack", daemon->namebuff, addr ? daemon->addrbuff : NULL, string, interface);
ubus_event_bcast("dhcp.ack", mac, addr ? daemon->addrbuff : NULL, string, interface);
else if (!strcmp(type, "DHCPRELEASE"))
ubus_event_bcast("dhcp.release", daemon->namebuff, addr ? daemon->addrbuff : NULL, string, interface);
ubus_event_bcast("dhcp.release", mac, addr ? daemon->addrbuff : NULL, string, interface);
#endif
}
+20 -18
View File
@@ -474,10 +474,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
if (state->mac_len != 0)
{
if (option_bool(OPT_LOG_OPTS))
{
print_mac(daemon->dhcp_buff, state->mac, state->mac_len);
my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid, daemon->dhcp_buff);
}
my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid,
print_mac(state->mac, state->mac_len));
for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next)
if ((unsigned)mac_opt->hwaddr_len == state->mac_len &&
@@ -2077,14 +2075,6 @@ static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, c
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
{
int clid_len = state->clid_len;
/* avoid buffer overflow */
if (clid_len > 100)
clid_len = 100;
print_mac(daemon->namebuff, state->clid, clid_len);
if (addr)
{
inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
@@ -2099,14 +2089,14 @@ static void log6_packet(struct state *state, char *type, struct in6_addr *addr,
type,
state->iface_name,
daemon->dhcp_buff2,
daemon->namebuff,
print_mac(state->clid, state->clid_len),
string ? string : "");
else
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
type,
state->iface_name,
daemon->dhcp_buff2,
daemon->namebuff,
print_mac(state->clid, state->clid_len),
string ? string : "");
}
@@ -2164,12 +2154,12 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
return ret;
}
/* return 0 if we're not configured to relay. */
int relay_upstream6(int iface_index, ssize_t sz,
struct in6_addr *peer_address, u32 scope_id, time_t now)
{
unsigned char *header;
unsigned char *inbuff = daemon->dhcp_packet.iov_base;
int msg_type = *inbuff;
int hopcount, o;
struct in6_addr multicast;
unsigned int maclen, mactype;
@@ -2186,10 +2176,22 @@ int relay_upstream6(int iface_index, ssize_t sz,
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
/* We need at least four bytes for valid client/server message
(type, and transaction ID) A relay-originated message needs more. */
if (sz < 4)
return 1;
/* Get hop count from nested relayed message */
if (msg_type == DHCP6RELAYFORW)
hopcount = *((unsigned char *)inbuff+1) + 1;
if (inbuff[0] == DHCP6RELAYFORW)
{
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
if (sz < 38)
return 1;
/* Get hop count from nested relayed message. */
hopcount = inbuff[1] + 1;
}
else
hopcount = 0;
+77 -17
View File
@@ -439,10 +439,14 @@ int hostname_issubdomain(char *a, char *b)
for (ap = a; *ap; ap++);
for (bp = b; *bp; bp++);
/* a shorter than b */
if ((ap - a) < (bp - b))
/* anything is a subdomain of the root domain. */
if (ap == a)
return (bp == b) ? 2 : 1;
/* b shorter than a */
if ((bp - b) < (ap - a))
return 0;
do
{
c1 = (unsigned char) *(--ap);
@@ -455,18 +459,17 @@ int hostname_issubdomain(char *a, char *b)
if (c1 != c2)
return 0;
} while (bp != b);
} while (ap != a);
if (ap == a)
if (bp == b)
return 2;
if (*(--ap) == '.')
if (*(--bp) == '.')
return 1;
return 0;
}
time_t dnsmasq_time(void)
{
#ifdef HAVE_BROKEN_RTC
@@ -689,18 +692,24 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask
return count;
}
char *print_mac(char *buff, unsigned char *mac, int len)
char *print_mac(unsigned char *mac, int len)
{
char *p = buff;
int i;
if (len == 0)
sprintf(p, "<null>");
else
for (i = 0; i < len; i++)
p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
static struct iovec buff = { NULL, 0 };
return buff;
/* each byte is two digits plus ':' except that last
which is two digits plus terminator. */
if (len == 0 || !expand_buf(&buff, len*3))
return "<null>";
else
{
char *p = buff.iov_base;
int i;
for (i = 0; i < len; i++)
p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
}
return buff.iov_base;
}
/* rc is return from sendto and friends.
@@ -1027,3 +1036,54 @@ void free_real(const char *func, unsigned int line, void *ptr)
free(ptr);
}
}
/* get lines from f, expand buffer as required. Buffer is freed when
EOF reached and we return zero. */
int get_line_alloc(FILE *f, char **buffp, size_t *sizep)
{
char c;
size_t cnt = 0;
char *buff = *buffp;
while (1) {
c = getc(f);
if (cnt == *sizep)
{
void *new;
if ((new = whine_realloc(buff, cnt + 1024)))
{
buff = *buffp = new;
*sizep = cnt + 1024;
}
else
{
/* allocation failed, ignore line.
Whine_realloc will have complained. */
while (c != '\n' && c != EOF)
c = getc(f);
cnt = 0;
continue;
}
}
buff[cnt] = 0;
if (c == '\n')
return 1;
if (c == EOF)
{
/* handle last line without '\n' */
if (cnt != 0)
return 1;
free(buff);
return 0;
}
buff[cnt++] = c;
}
}