Merge pull request #1273 from pi-hole/update/dnsmasq

Update embedded dnsmasq
This commit is contained in:
DL6ER
2022-01-05 17:23:29 +01:00
committed by GitHub
17 changed files with 445 additions and 187 deletions
+1 -1
View File
@@ -11,6 +11,6 @@
cmake_minimum_required(VERSION 2.8.12)
project(PIHOLE_FTL C)
set(DNSMASQ_VERSION pi-hole-2.87test4-6)
set(DNSMASQ_VERSION pi-hole-2.87test4-18)
add_subdirectory(src)
+1 -1
View File
@@ -414,7 +414,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
{
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) ||
if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV | F_NXDOMAIN)) ||
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
{
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
+17 -1
View File
@@ -985,11 +985,27 @@ void log_context(int family, struct dhcp_context *context)
void log_relay(int family, struct dhcp_relay *relay)
{
int broadcast = relay->server.addr4.s_addr == 0;
inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
#ifdef HAVE_DHCP6
struct in6_addr multicast;
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
if (family == AF_INET6)
broadcast = IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast);
#endif
if (relay->interface)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
{
if (broadcast)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s via %s"), daemon->addrbuff, relay->interface);
else
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
}
else
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
}
+24 -3
View File
@@ -1095,14 +1095,35 @@ static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess,
to.sa.sa_family = AF_INET;
to.in.sin_addr = relay->server.addr4;
to.in.sin_port = htons(daemon->dhcp_server_port);
/* Broadcasting to server. */
if (relay->server.addr4.s_addr == 0)
{
struct ifreq ifr;
if (relay->interface)
safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
if (!relay->interface || strchr(relay->interface, '*') ||
ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
{
my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s"), relay->interface);
return 1;
}
to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
}
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
if (relay->server.addr4.s_addr == 0)
snprintf(daemon->dhcp_buff2, DHCP_BUFF_SZ, _("broadcast via %s"), relay->interface);
else
inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
}
/* Save this for replies */
+2
View File
@@ -55,6 +55,8 @@
#define OPTION6_RECONF_ACCEPT 20
#define OPTION6_DNS_SERVER 23
#define OPTION6_DOMAIN_SEARCH 24
#define OPTION6_IA_PD 25
#define OPTION6_IAPREFIX 26
#define OPTION6_REFRESH_TIME 32
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
+1 -2
View File
@@ -135,9 +135,8 @@ void dhcp6_packet(time_t now)
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) != 0)
if (relay_reply6(&from, sz, ifr.ifr_name))
{
from.sin6_port = htons(port);
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&from,
sizeof(from))));
+14 -1
View File
@@ -743,7 +743,11 @@ int main_dnsmasq (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#ifdef HAVE_SCRIPT
if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP)) &&
if ((daemon->dhcp ||
daemon->dhcp6 ||
daemon->relay6 ||
option_bool(OPT_TFTP) ||
option_bool(OPT_SCRIPT_ARP)) &&
(daemon->lease_change_command || daemon->luascript))
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
@@ -1152,6 +1156,10 @@ int main_dnsmasq (int argc, char **argv)
while (helper_buf_empty() && do_tftp_script_run());
# endif
# ifdef HAVE_DHCP6
while (helper_buf_empty() && do_snoop_script_run());
# endif
if (!helper_buf_empty())
poll_listen(daemon->helperfd, POLLOUT);
#else
@@ -1713,6 +1721,11 @@ static void poll_resolv(int force, int do_reload, time_t now)
}
else
{
/* If we're delaying things, we don't call check_servers(), but
reload_servers() may have deleted some servers, rendering the server_array
invalid, so just rebuild that here. Once reload_servers() succeeds,
we call check_servers() above, which calls build_server_array itself. */
build_server_array();
latest->mtime = 0;
if (!warned)
{
+20 -1
View File
@@ -790,6 +790,7 @@ struct frec {
#define ACTION_TFTP 5
#define ACTION_ARP 6
#define ACTION_ARP_DEL 7
#define ACTION_RELAY_SNOOP 8
#define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */
@@ -1088,6 +1089,13 @@ struct dhcp_relay {
union all_addr local, server;
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
int iface_index; /* working - interface in which requests arrived, for return */
#ifdef HAVE_SCRIPT
struct snoop_record {
struct in6_addr client, prefix;
int prefix_len;
struct snoop_record *next;
} *snoop_records;
#endif
struct dhcp_relay *current, *next;
};
@@ -1239,13 +1247,18 @@ extern struct daemon {
unsigned char *duid;
struct iovec outpacket;
int dhcp6fd, icmp6fd;
# ifdef HAVE_SCRIPT
struct snoop_record *free_snoops;
# endif
#endif
/* DBus stuff */
/* void * here to avoid depending on dbus headers outside dbus.c */
void *dbus;
#ifdef HAVE_DBUS
struct watch *watches;
#endif
/* UBus stuff */
#ifdef HAVE_UBUS
/* void * here to avoid depending on ubus headers outside ubus.c */
@@ -1659,6 +1672,9 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
void queue_arp(int action, unsigned char *mac, int maclen,
int family, union all_addr *addr);
int helper_buf_empty(void);
#ifdef HAVE_DHCP6
void queue_relay_snoop(struct in6_addr *client, int if_index, struct in6_addr *prefix, int prefix_len);
#endif
#endif
/* tftp.c */
@@ -1704,7 +1720,10 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address,
u32 scope_id, time_t now);
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
int relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
# ifdef HAVE_SCRIPT
int do_snoop_script_run(void);
# endif
#endif
/* dhcp-common.c */
+92 -72
View File
@@ -395,7 +395,7 @@ 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)
{
int trunc = 0;
int trunc = 0, anscount = 0;
unsigned char *p;
int start;
union all_addr addr;
@@ -419,7 +419,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
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))
header->ancount = htons(ntohs(header->ancount) + 1);
anscount++;
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
}
@@ -434,13 +434,14 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
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))
header->ancount = htons(ntohs(header->ancount) + 1);
anscount++;
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
}
if (trunc)
header->hb3 |= HB3_TC;
header->ancount = htons(anscount);
return p - (unsigned char *)header;
}
@@ -541,22 +542,39 @@ static int order_qsort(const void *a, const void *b)
return rc;
}
/* Must be called before add_update_server() to set daemon->servers_tail */
void mark_servers(int flag)
{
struct server *serv;
struct server *serv, **up;
daemon->servers_tail = NULL;
/* mark everything with argument flag */
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->flags & flag)
serv->flags |= SERV_MARK;
else
serv->flags &= ~SERV_MARK;
{
if (serv->flags & flag)
serv->flags |= SERV_MARK;
else
serv->flags &= ~SERV_MARK;
for (serv = daemon->local_domains; serv; serv = serv->next)
if (serv->flags & flag)
serv->flags |= SERV_MARK;
else
serv->flags &= ~SERV_MARK;
daemon->servers_tail = serv;
}
/* --address etc is different: since they are expected to be
1) numerous and 2) not reloaded often. We just delete
and recreate. */
if (flag)
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = serv->next)
{
if (serv->flags & flag)
{
*up = serv->next;
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
}
void cleanup_servers(void)
@@ -564,7 +582,7 @@ void cleanup_servers(void)
struct server *serv, *tmp, **up;
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
for (serv = daemon->servers, up = &daemon->servers, daemon->servers_tail = NULL; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
@@ -580,19 +598,6 @@ void cleanup_servers(void)
daemon->servers_tail = serv;
}
}
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
*up = serv->next;
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
}
int add_update_server(int flags,
@@ -625,36 +630,17 @@ int add_update_server(int flags,
if (!alloc_domain)
return 0;
/* See if there is a suitable candidate, and unmark
only do this for forwarding servers, not
address or local, to avoid delays on large numbers. */
if (flags & SERV_IS_LOCAL)
for (serv = daemon->servers; serv; serv = serv->next)
if ((serv->flags & SERV_MARK) &&
hostname_isequal(alloc_domain, serv->domain))
break;
if (serv)
{
free(alloc_domain);
alloc_domain = serv->domain;
}
else
{
size_t size;
if (flags & SERV_IS_LOCAL)
{
if (flags & SERV_6ADDR)
size = sizeof(struct serv_addr6);
else if (flags & SERV_4ADDR)
size = sizeof(struct serv_addr4);
else
size = sizeof(struct serv_local);
}
if (flags & SERV_6ADDR)
size = sizeof(struct serv_addr6);
else if (flags & SERV_4ADDR)
size = sizeof(struct serv_addr4);
else
size = sizeof(struct server);
size = sizeof(struct serv_local);
if (!(serv = whine_malloc(size)))
{
@@ -662,19 +648,53 @@ int add_update_server(int flags,
return 0;
}
if (flags & SERV_IS_LOCAL)
serv->next = daemon->local_domains;
daemon->local_domains = serv;
if (flags & SERV_4ADDR)
((struct serv_addr4*)serv)->addr = local_addr->addr4;
if (flags & SERV_6ADDR)
((struct serv_addr6*)serv)->addr = local_addr->addr6;
}
else
{
/* Upstream servers. See if there is a suitable candidate, if so unmark
and move to the end of the list, for order. The entry found may already
be at the end. */
struct server **up, *tmp;
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
serv->next = daemon->local_domains;
daemon->local_domains = serv;
tmp = serv->next;
if ((serv->flags & SERV_MARK) &&
hostname_isequal(alloc_domain, serv->domain))
{
/* Need to move down? */
if (serv->next)
{
*up = serv->next;
daemon->servers_tail->next = serv;
daemon->servers_tail = serv;
serv->next = NULL;
}
break;
}
}
if (flags & SERV_4ADDR)
((struct serv_addr4*)serv)->addr = local_addr->addr4;
if (flags & SERV_6ADDR)
((struct serv_addr6*)serv)->addr = local_addr->addr6;
if (serv)
{
free(alloc_domain);
alloc_domain = serv->domain;
}
else
{
if (!(serv = whine_malloc(sizeof(struct server))))
{
free(alloc_domain);
return 0;
}
memset(serv, 0, sizeof(struct server));
/* Add to the end of the chain, for order */
@@ -683,20 +703,20 @@ int add_update_server(int flags,
else
daemon->servers = serv;
daemon->servers_tail = serv;
}
#ifdef HAVE_LOOP
serv->uid = rand32();
serv->uid = rand32();
#endif
if (interface)
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
if (addr)
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
}
if (interface)
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
if (addr)
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
}
serv->flags = flags;
serv->domain = alloc_domain;
serv->domain_len = strlen(alloc_domain);
+22 -20
View File
@@ -460,31 +460,33 @@ static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
u8 *u = &opt.fields[0];
if (daemon->umbrella_org) {
PUTSHORT(UMBRELLA_ORG, u);
PUTLONG(daemon->umbrella_org, u);
}
int family = source->sa.sa_family;
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
if (daemon->umbrella_org)
{
PUTSHORT(UMBRELLA_ORG, u);
PUTLONG(daemon->umbrella_org, u);
}
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
memcpy(u, get_addrp(source, family), size);
u += size;
if (option_bool(OPT_UMBRELLA_DEVID))
{
PUTSHORT(UMBRELLA_DEVICE, u);
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
u += UMBRELLA_DEVICESZ;
}
if (option_bool(OPT_UMBRELLA_DEVID)) {
PUTSHORT(UMBRELLA_DEVICE, u);
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
u += UMBRELLA_DEVICESZ;
}
if (daemon->umbrella_asset) {
PUTSHORT(UMBRELLA_ASSET, u);
PUTLONG(daemon->umbrella_asset, u);
}
int len = u - &opt.magic[0];
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, len, 0, 1);
if (daemon->umbrella_asset)
{
PUTSHORT(UMBRELLA_ASSET, u);
PUTLONG(daemon->umbrella_asset, u);
}
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 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
+7 -1
View File
@@ -1666,6 +1666,9 @@ void receive_query(struct listener *listen, time_t now)
if (m >= 1)
{
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr);
#endif
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
(char *)header, m, &source_addr, &dst_addr, if_index);
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
@@ -1679,6 +1682,9 @@ void receive_query(struct listener *listen, time_t now)
local_auth, do_bit, have_pseudoheader);
if (m >= 1)
{
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr);
#endif
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
if (local_auth)
if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
@@ -1978,7 +1984,7 @@ unsigned char *tcp_request(int confd, time_t now,
bool piholeblocked = false;
/**********************************************/
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet;
#ifdef HAVE_CONNTRACK
+56 -7
View File
@@ -238,8 +238,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
is6 = (data.flags != AF_INET);
data.action = ACTION_ARP;
}
else
continue;
else if (data.action == ACTION_RELAY_SNOOP)
{
is6 = 1;
action_str = "relay-snoop";
}
else
continue;
/************************** Pi-hole modification **************************/
FTL_log_helper(1, action_str);
@@ -295,7 +300,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
char *dot;
hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0;
if (data.action != ACTION_TFTP)
if (data.action != ACTION_TFTP && data.action != ACTION_RELAY_SNOOP)
{
if (!legal_hostname(hostname))
hostname = NULL;
@@ -341,6 +346,24 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
}
}
else if (data.action == ACTION_RELAY_SNOOP)
{
lua_getglobal(lua, "snoop");
if (lua_type(lua, -1) != LUA_TFUNCTION)
lua_pop(lua, 1); /* tftp function optional */
else
{
lua_pushstring(lua, action_str); /* arg1 - action */
lua_newtable(lua); /* arg2 - data table */
lua_pushstring(lua, daemon->addrbuff);
lua_setfield(lua, -2, "client_address");
lua_pushstring(lua, hostname);
lua_setfield(lua, -2, "prefix");
lua_pushstring(lua, data.interface);
lua_setfield(lua, -2, "client_interface");
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
}
}
else if (data.action == ACTION_ARP)
{
lua_getglobal(lua, "arp");
@@ -441,8 +464,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata_lua(buf, end, "relay_address");
else if (data.giaddr.s_addr != 0)
{
inet_ntop(AF_INET, &data.giaddr, daemon->addrbuff, ADDRSTRLEN);
lua_pushstring(lua, daemon->addrbuff);
inet_ntop(AF_INET, &data.giaddr, daemon->dhcp_buff2, ADDRSTRLEN);
lua_pushstring(lua, daemon->dhcp_buff2);
lua_setfield(lua, -2, "relay_address");
}
@@ -562,7 +585,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
close(pipeout[1]);
}
if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
if (data.action != ACTION_TFTP && data.action != ACTION_ARP && data.action != ACTION_RELAY_SNOOP)
{
#ifdef HAVE_DHCP6
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
@@ -624,7 +647,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
const char *giaddr = NULL;
if (data.giaddr.s_addr != 0)
giaddr = inet_ntop(AF_INET, &data.giaddr, daemon->addrbuff, ADDRSTRLEN);
giaddr = inet_ntop(AF_INET, &data.giaddr, daemon->dhcp_buff2, ADDRSTRLEN);
my_setenv("DNSMASQ_RELAY_ADDRESS", giaddr, &err);
}
@@ -649,6 +672,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
close(pipefd[0]);
if (data.action == ACTION_RELAY_SNOOP)
strcpy(daemon->packet, data.interface);
/**************************** Pi-hole modification ****************************/
FTL_log_helper(5, daemon->lease_change_command, action_str,
(is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff,
@@ -828,6 +854,29 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
bytes_in_buf = p - (unsigned char *)buf;
}
#ifdef HAVE_DHCP6
void queue_relay_snoop(struct in6_addr *client, int if_index, struct in6_addr *prefix, int prefix_len)
{
/* no script */
if (daemon->helperfd == -1)
return;
inet_ntop(AF_INET6, prefix, daemon->addrbuff, ADDRSTRLEN);
/* 5 for /nnn and zero on the end of the prefix. */
buff_alloc(sizeof(struct script_data) + ADDRSTRLEN + 5);
memset(buf, 0, sizeof(struct script_data));
buf->action = ACTION_RELAY_SNOOP;
buf->addr6 = *client;
buf->hostname_len = sprintf((char *)(buf+1), "%s/%u", daemon->addrbuff, prefix_len) + 1;
indextoname(daemon->dhcp6fd, if_index, buf->interface);
bytes_in_buf = sizeof(struct script_data) + buf->hostname_len;
}
#endif
#ifdef HAVE_TFTP
/* This nastily re-uses DHCP-fields for TFTP stuff */
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
+2 -2
View File
@@ -492,11 +492,11 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
}
if (addr->sa.sa_family == AF_INET &&
!iface_check(AF_INET, (union all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
!iface_check(AF_INET, (union all_addr *)&addr->in.sin_addr, label, &auth_dns))
return 1;
if (addr->sa.sa_family == AF_INET6 &&
!iface_check(AF_INET6, (union all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
!iface_check(AF_INET6, (union all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
return 1;
#ifdef HAVE_DHCP
+92 -50
View File
@@ -361,7 +361,7 @@ static const struct myoption opts[] =
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
{ "umbrella", 2, 0, LOPT_UMBRELLA },
{ "umbrella", 2, 0, LOPT_UMBRELLA },
{ "quiet-tftp", 0, 0, LOPT_QUIET_TFTP },
{ NULL, 0, 0, 0 }
};
@@ -2523,39 +2523,48 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_UMBRELLA: /* --umbrella */
set_option_bool(OPT_UMBRELLA);
while (arg) {
comma = split(arg);
if (strstr(arg, "deviceid:")) {
arg += 9;
if (strlen(arg) != 16)
ret_err(gen_err);
for (char *p = arg; *p; p++) {
if (!isxdigit((int)*p))
ret_err(gen_err);
}
set_option_bool(OPT_UMBRELLA_DEVID);
u8 *u = daemon->umbrella_device;
char word[3];
for (u8 i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
memcpy(word, &(arg[0]), 2);
*u++ = strtoul(word, NULL, 16);
}
}
else if (strstr(arg, "orgid:")) {
if (!strtoul_check(arg+6, &daemon->umbrella_org)) {
ret_err(gen_err);
}
}
else if (strstr(arg, "assetid:")) {
if (!strtoul_check(arg+8, &daemon->umbrella_asset)) {
ret_err(gen_err);
}
}
arg = comma;
}
while (arg)
{
comma = split(arg);
if (strstr(arg, "deviceid:"))
{
char *p;
u8 *u = daemon->umbrella_device;
char word[3];
arg += 9;
if (strlen(arg) != 16)
ret_err(gen_err);
for (p = arg; *p; p++)
if (!isxdigit((int)*p))
ret_err(gen_err);
set_option_bool(OPT_UMBRELLA_DEVID);
for (i = 0; i < (int)sizeof(daemon->umbrella_device); i++, arg+=2)
{
memcpy(word, &(arg[0]), 2);
*u++ = strtoul(word, NULL, 16);
}
}
else if (strstr(arg, "orgid:"))
{
if (!strtoul_check(arg+6, &daemon->umbrella_org))
ret_err(gen_err);
}
else if (strstr(arg, "assetid:"))
{
if (!strtoul_check(arg+8, &daemon->umbrella_asset))
ret_err(gen_err);
}
else
ret_err(gen_err);
arg = comma;
}
break;
case LOPT_ADD_MAC: /* --add-mac */
if (!arg)
set_option_bool(OPT_ADD_MAC);
@@ -4132,7 +4141,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_SUBSCR: /* --dhcp-subscrid */
{
unsigned char *p;
int dig = 0;
int dig, colon;
struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
if (!(comma = split(arg)))
@@ -4156,13 +4165,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else
comma = arg;
for (p = (unsigned char *)comma; *p; p++)
for (dig = 0, colon = 0, p = (unsigned char *)comma; *p; p++)
if (isxdigit(*p))
dig = 1;
else if (*p != ':')
else if (*p == ':')
colon = 1;
else
break;
unhide_metas(comma);
if (option == 'U' || option == 'j' || *p || !dig)
if (option == 'U' || option == 'j' || *p || !dig || !colon)
{
new->len = strlen(comma);
new->data = opt_malloc(new->len);
@@ -4285,26 +4297,56 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
break;
case LOPT_RELAY: /* --dhcp-relay */
{
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
comma = split(arg);
new->interface = opt_string_alloc(split(comma));
char *two = split(arg);
char *three = split(two);
new->iface_index = 0;
if (comma && inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
if (two)
{
new->next = daemon->relay4;
daemon->relay4 = new;
}
if (inet_pton(AF_INET, arg, &new->local))
{
if (!inet_pton(AF_INET, two, &new->server))
{
new->server.addr4.s_addr = 0;
/* Fail for three arg version where there are not two addresses.
Also fail when broadcasting to wildcard address. */
if (three || strchr(two, '*'))
two = NULL;
else
three = two;
}
new->next = daemon->relay4;
daemon->relay4 = new;
}
#ifdef HAVE_DHCP6
else if (comma && inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
{
new->next = daemon->relay6;
daemon->relay6 = new;
}
else if (inet_pton(AF_INET6, arg, &new->local))
{
if (!inet_pton(AF_INET6, two, &new->server))
{
inet_pton(AF_INET6, ALL_SERVERS, &new->server.addr6);
/* Fail for three arg version where there are not two addresses.
Also fail when multicasting to wildcard address. */
if (three || strchr(two, '*'))
two = NULL;
else
three = two;
}
new->next = daemon->relay6;
daemon->relay6 = new;
}
#endif
else
new->interface = opt_string_alloc(three);
}
if (!two)
{
free(new->interface);
ret_err_free(_("Bad dhcp-relay"), new);
+4 -4
View File
@@ -129,9 +129,9 @@ int is_valid_dns_name(const char *value)
size_t num_bytes = 0;
size_t num_labels = 0;
const char *label = NULL;
const char *c, *label = NULL;
int is_label_numeric = 1;
for (const char *c = value;; c++)
for (c = value;; c++)
{
if (*c &&
*c != '-' && *c != '.' &&
@@ -242,11 +242,11 @@ int is_valid_dns_name_pattern(const char *value)
size_t num_bytes = 0;
size_t num_labels = 0;
const char *label = NULL;
const char *c, *label = NULL;
int is_label_numeric = 1;
size_t num_wildcards = 0;
int previous_label_has_wildcard = 1;
for (const char *c = value;; c++)
for (c = value;; c++)
{
if (*c &&
*c != '*' && /* Wildcard. */
+78 -7
View File
@@ -2170,7 +2170,10 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
if (!relay->interface || strchr(relay->interface, '*') ||
(multicast_iface = if_nametoindex(relay->interface)) == 0 ||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
{
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast DHCP relay via interface %s"), relay->interface);
return;
}
}
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
@@ -2178,8 +2181,11 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
snprintf(daemon->namebuff, MAXDNAME, _("multicast via %s"), relay->interface);
else
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->namebuff);
}
/* Save this for replies */
@@ -2188,7 +2194,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
}
}
unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
{
struct dhcp_relay *relay;
struct in6_addr link;
@@ -2220,11 +2226,76 @@ unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
peer->sin6_scope_id = relay->iface_index;
return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
}
}
if (encap_type == DHCP6RELAYREPL)
{
peer->sin6_port = ntohs(DHCPV6_SERVER_PORT);
return 1;
}
peer->sin6_port = ntohs(DHCPV6_CLIENT_PORT);
#ifdef HAVE_SCRIPT
if (daemon->lease_change_command && encap_type == DHCP6REPLY)
{
/* decapsulate relayed message */
opts = opt6_ptr(opt, 4);
end = opt6_ptr(opt, opt6_len(opt));
for (opt = opts; opt; opt = opt6_next(opt, end))
if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12)
{
void *ia_opts = opt6_ptr(opt, 12);
void *ia_end = opt6_ptr(opt, opt6_len(opt));
void *ia_opt;
for (ia_opt = ia_opts; ia_opt; ia_opt = opt6_next(ia_opt, ia_end))
/* valid lifetime must not be zero. */
if (opt6_type(ia_opt) == OPTION6_IAPREFIX && opt6_len(ia_opt) >= 25 && opt6_uint(ia_opt, 4, 4) != 0)
{
if (daemon->free_snoops ||
(daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
{
struct snoop_record *snoop = daemon->free_snoops;
daemon->free_snoops = snoop->next;
snoop->client = peer->sin6_addr;
snoop->prefix_len = opt6_uint(ia_opt, 8, 1);
memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ);
snoop->next = relay->snoop_records;
relay->snoop_records = snoop;
}
}
}
}
#endif
return 1;
}
}
return 0;
}
#ifdef HAVE_SCRIPT
int do_snoop_script_run(void)
{
struct dhcp_relay *relay;
struct snoop_record *snoop;
for (relay = daemon->relay6; relay; relay = relay->next)
if ((snoop = relay->snoop_records))
{
relay->snoop_records = snoop->next;
snoop->next = daemon->free_snoops;
daemon->free_snoops = snoop;
queue_relay_snoop(&snoop->client, relay->iface_index, &snoop->prefix, snoop->prefix_len);
return 1;
}
return 0;
}
#endif
#endif
+12 -14
View File
@@ -19,9 +19,9 @@
#ifdef HAVE_TFTP
static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len);
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client);
static void free_transfer(struct tftp_transfer *transfer);
static ssize_t tftp_err(int err, char *packet, char *message, char *file);
static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2);
static ssize_t tftp_err_oops(char *packet, const char *file);
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
static char *next(char **p, char *end);
@@ -362,7 +362,7 @@ void tftp_request(struct listener *listen, time_t now)
!(mode = next(&p, end)) ||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
{
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff, NULL);
is_err = 1;
}
else
@@ -472,7 +472,7 @@ void tftp_request(struct listener *listen, time_t now)
strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
/* check permissions and open file */
if ((transfer->file = check_tftp_fileperm(&len, prefix)))
if ((transfer->file = check_tftp_fileperm(&len, prefix, daemon->addrbuff)))
{
if ((len = get_block(packet, transfer)) == -1)
len = tftp_err_oops(packet, daemon->namebuff);
@@ -492,7 +492,7 @@ void tftp_request(struct listener *listen, time_t now)
}
}
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client)
{
char *packet = daemon->packet, *namebuff = daemon->namebuff;
struct tftp_file *file;
@@ -509,7 +509,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
{
if (errno == ENOENT)
{
*len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);
*len = tftp_err(ERR_FNF, packet, _("file %s not found for %s"), namebuff, client);
return NULL;
}
else if (errno == EACCES)
@@ -562,8 +562,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
return file;
perm:
errno = EACCES;
*len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff);
*len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff, strerror(EACCES));
if (fd != -1)
close(fd);
return NULL;
@@ -599,7 +598,7 @@ void check_tftp_listeners(time_t now)
{
/* Wrong source address. See rfc1350 para 4. */
prettyprint_addr(&peer, daemon->addrbuff);
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff, NULL);
while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer))));
}
}
@@ -743,22 +742,21 @@ static void sanitise(char *buf)
}
#define MAXMESSAGE 500 /* limit to make packet < 512 bytes and definitely smaller than buffer */
static ssize_t tftp_err(int err, char *packet, char *message, char *file)
static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2)
{
struct errmess {
unsigned short op, err;
char message[];
} *mess = (struct errmess *)packet;
ssize_t len, ret = 4;
char *errstr = strerror(errno);
memset(packet, 0, daemon->packet_buff_sz);
if (file)
sanitise(file);
mess->op = htons(OP_ERR);
mess->err = htons(err);
len = snprintf(mess->message, MAXMESSAGE, message, file, errstr);
len = snprintf(mess->message, MAXMESSAGE, message, file, arg2);
ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
if (err != ERR_FNF || !option_bool(OPT_QUIET_TFTP))
@@ -772,7 +770,7 @@ static ssize_t tftp_err_oops(char *packet, const char *file)
/* May have >1 refs to file, so potentially mangle a copy of the name */
if (file != daemon->namebuff)
strcpy(daemon->namebuff, file);
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff, strerror(errno));
}
/* return -1 for error, zero for done. */