mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Add --bind-dynamic
This commit is contained in:
@@ -7,6 +7,10 @@ version 2.63
|
|||||||
Allow more than one --tfp-root flag. The per-interface
|
Allow more than one --tfp-root flag. The per-interface
|
||||||
stuff is pointless without that.
|
stuff is pointless without that.
|
||||||
|
|
||||||
|
Add --bind-dynamic. A hybrid mode between the default and
|
||||||
|
--bind-interfaces which copes with dynamically created
|
||||||
|
interfaces.
|
||||||
|
|
||||||
|
|
||||||
version 2.62
|
version 2.62
|
||||||
Update German translation. Thanks to Conrad Kostecki.
|
Update German translation. Thanks to Conrad Kostecki.
|
||||||
|
|||||||
@@ -204,6 +204,17 @@ running another nameserver (or another instance of dnsmasq) on the
|
|||||||
same machine. Setting this option also enables multiple instances of
|
same machine. Setting this option also enables multiple instances of
|
||||||
dnsmasq which provide DHCP service to run in the same machine.
|
dnsmasq which provide DHCP service to run in the same machine.
|
||||||
.TP
|
.TP
|
||||||
|
.B --bind-dynamic
|
||||||
|
Enable a network mode which is a hybrid between
|
||||||
|
.B --bind-interfaces
|
||||||
|
and the default. Dnsmasq binds the address of indivdual interfaces,
|
||||||
|
allowing multiple dnsmasq instances, but if new interfaces or
|
||||||
|
addresses appear, it automatically listens on those (subject to any
|
||||||
|
access-control configuration). This makes dynamically created
|
||||||
|
interfaces work in the same way as the default. Implementing this
|
||||||
|
option requires non-standard networking APIs and it is only availble
|
||||||
|
under Linux.
|
||||||
|
.TP
|
||||||
.B \-y, --localise-queries
|
.B \-y, --localise-queries
|
||||||
Return answers to DNS queries from /etc/hosts which depend on the interface over which the query was
|
Return answers to DNS queries from /etc/hosts which depend on the interface over which the query was
|
||||||
received. If a name in /etc/hosts has more than one address associated with
|
received. If a name in /etc/hosts has more than one address associated with
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ static int make_fd(int port)
|
|||||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||||
instance binding port 67. That's OK if they serve different networks.
|
instance binding port 67. That's OK if they serve different networks.
|
||||||
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
||||||
if (option_bool(OPT_NOWILD))
|
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||||
{
|
{
|
||||||
#ifdef SO_REUSEPORT
|
#ifdef SO_REUSEPORT
|
||||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||||
|
|||||||
@@ -114,6 +114,9 @@ int main (int argc, char **argv)
|
|||||||
set_option_bool(OPT_NOWILD);
|
set_option_bool(OPT_NOWILD);
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
if (option_bool(OPT_CLEVERBIND))
|
||||||
|
die(_("--bind-dynamic not available on this platform"), NULL, EC_BADCONF);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_TFTP
|
#ifndef HAVE_TFTP
|
||||||
@@ -185,6 +188,9 @@ int main (int argc, char **argv)
|
|||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
/* After lease_init */
|
/* After lease_init */
|
||||||
netlink_init();
|
netlink_init();
|
||||||
|
|
||||||
|
if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
|
||||||
|
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
@@ -202,13 +208,14 @@ int main (int argc, char **argv)
|
|||||||
if (!enumerate_interfaces())
|
if (!enumerate_interfaces())
|
||||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||||
|
|
||||||
if (option_bool(OPT_NOWILD))
|
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||||
{
|
{
|
||||||
create_bound_listeners(1);
|
create_bound_listeners(1);
|
||||||
|
|
||||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
if (!option_bool(OPT_CLEVERBIND))
|
||||||
if (if_tmp->name && !if_tmp->used)
|
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||||
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
|
if (if_tmp->name && !if_tmp->used)
|
||||||
|
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
|
||||||
|
|
||||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
|
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
|
||||||
/* after enumerate_interfaces() */
|
/* after enumerate_interfaces() */
|
||||||
@@ -425,8 +432,9 @@ int main (int argc, char **argv)
|
|||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
||||||
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
|
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
|
||||||
ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
|
ports because of DAD, or we're doing it dynamically,
|
||||||
if (is_dad_listeners())
|
we need CAP_NET_BIND_SERVICE too. */
|
||||||
|
if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
|
||||||
data->effective = data->permitted = data->inheritable =
|
data->effective = data->permitted = data->inheritable =
|
||||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
|
||||||
(1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
|
(1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
|
||||||
@@ -474,7 +482,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
if (is_dad_listeners())
|
if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
|
||||||
data->effective = data->permitted =
|
data->effective = data->permitted =
|
||||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
|
||||||
else
|
else
|
||||||
@@ -1352,7 +1360,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (option_bool(OPT_NOWILD))
|
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||||
iface = listener->iface; /* May be NULL */
|
iface = listener->iface; /* May be NULL */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1369,7 +1377,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iface && !option_bool(OPT_NOWILD))
|
if (!iface && !(option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND)))
|
||||||
{
|
{
|
||||||
shutdown(confd, SHUT_RDWR);
|
shutdown(confd, SHUT_RDWR);
|
||||||
close(confd);
|
close(confd);
|
||||||
|
|||||||
@@ -219,7 +219,8 @@ struct event_desc {
|
|||||||
#define OPT_FQDN_UPDATE 36
|
#define OPT_FQDN_UPDATE 36
|
||||||
#define OPT_RA 37
|
#define OPT_RA 37
|
||||||
#define OPT_TFTP_LC 38
|
#define OPT_TFTP_LC 38
|
||||||
#define OPT_LAST 39
|
#define OPT_CLEVERBIND 39
|
||||||
|
#define OPT_LAST 40
|
||||||
|
|
||||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||||
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
if (udpfd != -1)
|
if (udpfd != -1)
|
||||||
{
|
{
|
||||||
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
||||||
send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -624,7 +624,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
{
|
{
|
||||||
header->id = htons(forward->orig_id);
|
header->id = htons(forward->orig_id);
|
||||||
header->hb4 |= HB4_RA; /* recursion if available */
|
header->hb4 |= HB4_RA; /* recursion if available */
|
||||||
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
|
send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||||
&forward->source, &forward->dest, forward->iface);
|
&forward->source, &forward->dest, forward->iface);
|
||||||
}
|
}
|
||||||
free_frec(forward); /* cancel */
|
free_frec(forward); /* cancel */
|
||||||
@@ -819,8 +819,8 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
dst_addr_4, netmask, now);
|
dst_addr_4, netmask, now);
|
||||||
if (m >= 1)
|
if (m >= 1)
|
||||||
{
|
{
|
||||||
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header,
|
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||||
m, &source_addr, &dst_addr, if_index);
|
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||||
daemon->local_answer++;
|
daemon->local_answer++;
|
||||||
}
|
}
|
||||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||||
|
|||||||
149
src/netlink.c
149
src/netlink.c
@@ -38,7 +38,7 @@
|
|||||||
static struct iovec iov;
|
static struct iovec iov;
|
||||||
static u32 netlink_pid;
|
static u32 netlink_pid;
|
||||||
|
|
||||||
static void nl_err(struct nlmsghdr *h);
|
static int nl_async(struct nlmsghdr *h);
|
||||||
static void nl_routechange(struct nlmsghdr *h);
|
static void nl_routechange(struct nlmsghdr *h);
|
||||||
|
|
||||||
void netlink_init(void)
|
void netlink_init(void)
|
||||||
@@ -49,10 +49,13 @@ void netlink_init(void)
|
|||||||
addr.nl_family = AF_NETLINK;
|
addr.nl_family = AF_NETLINK;
|
||||||
addr.nl_pad = 0;
|
addr.nl_pad = 0;
|
||||||
addr.nl_pid = 0; /* autobind */
|
addr.nl_pid = 0; /* autobind */
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
addr.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
|
|
||||||
#else
|
|
||||||
addr.nl_groups = RTMGRP_IPV4_ROUTE;
|
addr.nl_groups = RTMGRP_IPV4_ROUTE;
|
||||||
|
if (option_bool(OPT_CLEVERBIND))
|
||||||
|
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
addr.nl_groups |= RTMGRP_IPV6_ROUTE;
|
||||||
|
if (daemon->ra_contexts || option_bool(OPT_CLEVERBIND))
|
||||||
|
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* May not be able to have permission to set multicast groups don't die in that case */
|
/* May not be able to have permission to set multicast groups don't die in that case */
|
||||||
@@ -136,7 +139,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
struct nlmsghdr *h;
|
struct nlmsghdr *h;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
static unsigned int seq = 0;
|
static unsigned int seq = 0;
|
||||||
int callback_ok = 1;
|
int callback_ok = 1, newaddr = 0;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
@@ -182,12 +185,24 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||||
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid)
|
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
|
||||||
nl_routechange(h); /* May be multicast arriving async */
|
{
|
||||||
else if (h->nlmsg_type == NLMSG_ERROR)
|
/* May be multicast arriving async */
|
||||||
nl_err(h);
|
if (nl_async(h))
|
||||||
|
newaddr = 1;
|
||||||
|
}
|
||||||
else if (h->nlmsg_type == NLMSG_DONE)
|
else if (h->nlmsg_type == NLMSG_DONE)
|
||||||
return callback_ok;
|
{
|
||||||
|
/* handle async new interface address arrivals, these have to be done
|
||||||
|
after we complete as we're not re-entrant */
|
||||||
|
if (newaddr)
|
||||||
|
{
|
||||||
|
enumerate_interfaces();
|
||||||
|
create_bound_listeners(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback_ok;
|
||||||
|
}
|
||||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
||||||
{
|
{
|
||||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||||
@@ -295,7 +310,7 @@ void netlink_multicast(void)
|
|||||||
{
|
{
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
struct nlmsghdr *h;
|
struct nlmsghdr *h;
|
||||||
int flags;
|
int flags, newaddr = 0;
|
||||||
|
|
||||||
/* don't risk blocking reading netlink messages here. */
|
/* don't risk blocking reading netlink messages here. */
|
||||||
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
|
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
|
||||||
@@ -303,71 +318,83 @@ void netlink_multicast(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if ((len = netlink_recv()) != -1)
|
if ((len = netlink_recv()) != -1)
|
||||||
{
|
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
if (nl_async(h))
|
||||||
if (h->nlmsg_type == NLMSG_ERROR)
|
newaddr = 1;
|
||||||
nl_err(h);
|
|
||||||
else
|
|
||||||
nl_routechange(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* restore non-blocking status */
|
|
||||||
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nl_err(struct nlmsghdr *h)
|
|
||||||
{
|
|
||||||
struct nlmsgerr *err = NLMSG_DATA(h);
|
|
||||||
|
|
||||||
if (err->error != 0)
|
/* restore non-blocking status */
|
||||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
||||||
|
|
||||||
|
if (newaddr)
|
||||||
|
{
|
||||||
|
enumerate_interfaces();
|
||||||
|
create_bound_listeners(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nl_async(struct nlmsghdr *h)
|
||||||
|
{
|
||||||
|
if (h->nlmsg_type == NLMSG_ERROR)
|
||||||
|
{
|
||||||
|
struct nlmsgerr *err = NLMSG_DATA(h);
|
||||||
|
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
|
||||||
|
{
|
||||||
|
nl_routechange(h);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (h->nlmsg_type == RTM_NEWADDR)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
/* force RAs to sync new network and pick up new interfaces. */
|
||||||
|
if (daemon->ra_contexts)
|
||||||
|
{
|
||||||
|
schedule_subnet_map();
|
||||||
|
ra_start_unsolicted(dnsmasq_time(), NULL);
|
||||||
|
/* cause lease_update_file to run after we return, in case we were called from
|
||||||
|
iface_enumerate and can't re-enter it now */
|
||||||
|
send_alarm(0, 0);
|
||||||
|
}
|
||||||
|
return !!option_bool(OPT_CLEVERBIND); /* clever bind mode - rescan */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* We arrange to receive netlink multicast messages whenever the network route is added.
|
/* We arrange to receive netlink multicast messages whenever the network route is added.
|
||||||
If this happens and we still have a DNS packet in the buffer, we re-send it.
|
If this happens and we still have a DNS packet in the buffer, we re-send it.
|
||||||
This helps on DoD links, where frequently the packet which triggers dialling is
|
This helps on DoD links, where frequently the packet which triggers dialling is
|
||||||
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
|
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
|
||||||
failing. Note that we only accept these messages from the kernel (pid == 0) */
|
failing. */
|
||||||
static void nl_routechange(struct nlmsghdr *h)
|
static void nl_routechange(struct nlmsghdr *h)
|
||||||
{
|
{
|
||||||
if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
|
struct rtmsg *rtm = NLMSG_DATA(h);
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Force re-reading resolv file right now, for luck. */
|
||||||
|
daemon->last_resolv = 0;
|
||||||
|
|
||||||
|
if (daemon->srv_save)
|
||||||
{
|
{
|
||||||
struct rtmsg *rtm = NLMSG_DATA(h);
|
if (daemon->srv_save->sfd)
|
||||||
int fd;
|
fd = daemon->srv_save->sfd->fd;
|
||||||
|
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
|
||||||
if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK)
|
fd = daemon->rfd_save->fd;
|
||||||
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Force re-reading resolv file right now, for luck. */
|
|
||||||
daemon->last_resolv = 0;
|
|
||||||
|
|
||||||
#ifdef HAVE_DHCP6
|
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
|
||||||
/* force RAs to sync new network and pick up new interfaces. */
|
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
|
||||||
if (daemon->ra_contexts)
|
|
||||||
{
|
|
||||||
schedule_subnet_map();
|
|
||||||
ra_start_unsolicted(dnsmasq_time(), NULL);
|
|
||||||
/* cause lease_update_file to run after we return, in case we were called from
|
|
||||||
iface_enumerate and can't re-enter it now */
|
|
||||||
send_alarm(0, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (daemon->srv_save)
|
|
||||||
{
|
|
||||||
if (daemon->srv_save->sfd)
|
|
||||||
fd = daemon->srv_save->sfd->fd;
|
|
||||||
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
|
|
||||||
fd = daemon->rfd_save->fd;
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
|
|
||||||
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ struct myoption {
|
|||||||
#define LOPT_HOST_REC 308
|
#define LOPT_HOST_REC 308
|
||||||
#define LOPT_TFTP_LC 309
|
#define LOPT_TFTP_LC 309
|
||||||
#define LOPT_RR 310
|
#define LOPT_RR 310
|
||||||
|
#define LOPT_CLVERBIND 311
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -243,6 +244,7 @@ static const struct myoption opts[] =
|
|||||||
{ "enable-ra", 0, 0, LOPT_RA },
|
{ "enable-ra", 0, 0, LOPT_RA },
|
||||||
{ "dhcp-duid", 1, 0, LOPT_DUID },
|
{ "dhcp-duid", 1, 0, LOPT_DUID },
|
||||||
{ "host-record", 1, 0, LOPT_HOST_REC },
|
{ "host-record", 1, 0, LOPT_HOST_REC },
|
||||||
|
{ "bind-dynamic", 0, 0, LOPT_CLVERBIND },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -374,6 +376,7 @@ static struct {
|
|||||||
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
|
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
|
||||||
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
|
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
|
||||||
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
|
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
|
||||||
|
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL},
|
||||||
{ 0, 0, NULL, NULL, NULL }
|
{ 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user