mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1677c6e10b | ||
|
|
ff30fa4b91 | ||
|
|
c91c66ee63 | ||
|
|
fc9f6985ab | ||
|
|
ea5b0e64e2 | ||
|
|
e775264539 | ||
|
|
d976d94e3d | ||
|
|
3034746748 | ||
|
|
3ceea9e755 | ||
|
|
dfcef19fb4 | ||
|
|
f74b74e521 | ||
|
|
c9342cb556 | ||
|
|
2b844b8c83 | ||
|
|
65e9a8957c | ||
|
|
da868a2fbe | ||
|
|
bceb5287b9 | ||
|
|
84445dec26 | ||
|
|
c70b92b2a4 | ||
|
|
57e582492b | ||
|
|
ec8f3e65c1 | ||
|
|
15841f187d | ||
|
|
ade97495e6 | ||
|
|
2b19285724 | ||
|
|
a444715bf0 | ||
|
|
14e81b6976 | ||
|
|
6ce7f2d55a |
No files matched your search
@@ -61,6 +61,15 @@ version 2.92
|
|||||||
|
|
||||||
Add TFTP options windowsize (RFC 7440) and timeout (RFC 2349).
|
Add TFTP options windowsize (RFC 7440) and timeout (RFC 2349).
|
||||||
|
|
||||||
|
Change the behaviour of the DHVPv6 server when a REBIND message
|
||||||
|
is received but no lease exists. Under these circumstances a new
|
||||||
|
lease is created _only_ when the --dhcp-authoritative option is
|
||||||
|
set. This matches the behavior of the DHCPv4 server.
|
||||||
|
|
||||||
|
Add --dhcp-split-relay option. This makes a DHCPv4 relay which
|
||||||
|
is functional when client and server networks aren't mutually
|
||||||
|
route-able.
|
||||||
|
|
||||||
|
|
||||||
version 2.91
|
version 2.91
|
||||||
Fix spurious "resource limit exceeded messages". Thanks to
|
Fix spurious "resource limit exceeded messages". Thanks to
|
||||||
|
|||||||
@@ -95,7 +95,5 @@ a contribution towards my expenses, please use the donation button below.
|
|||||||
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online.">
|
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online.">
|
||||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
|
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
</BODY>
|
</BODY>
|
||||||
|
</HTML>
|
||||||
+28
-2
@@ -673,7 +673,7 @@ machine on which dnsmasq is running) for each
|
|||||||
local machine. Local machines are those in /etc/hosts or with DHCP
|
local machine. Local machines are those in /etc/hosts or with DHCP
|
||||||
leases.
|
leases.
|
||||||
.TP
|
.TP
|
||||||
.B \-W, --srv-host=<_service>.<_prot>.[<domain>],[<target>[,<port>[,<priority>[,<weight>]]]]
|
.B \-W, --srv-host=<_service>.<_prot>[.<domain>],[<target>[,<port>[,<priority>[,<weight>]]]]
|
||||||
Return a SRV DNS record. See RFC2782 for details. If not supplied, the
|
Return a SRV DNS record. See RFC2782 for details. If not supplied, the
|
||||||
domain defaults to that given by
|
domain defaults to that given by
|
||||||
.B --domain.
|
.B --domain.
|
||||||
@@ -1489,6 +1489,30 @@ prefix-delegation from relayed DHCP transactions. See
|
|||||||
.B --dhcp-script
|
.B --dhcp-script
|
||||||
for details.
|
for details.
|
||||||
.TP
|
.TP
|
||||||
|
.B --dhcp-split-relay=<local address>,[<server address>[#<server port>]],<server-facing-interface>|<server-facing-address>
|
||||||
|
A usefully enchanced version of DHCPv4 relay. IPv4 DHCP normally uses a single address
|
||||||
|
for two functions; it is used by the DHCP server to determine which network to allocate
|
||||||
|
an address on, and it is used as the address of the relay to which the server sends packets.
|
||||||
|
|
||||||
|
This version of DHCP relay splits these functions. It uses the address of the server-facing relay
|
||||||
|
interface or a directly-specified address as the address that the server talks to. The address of the client-facing interface
|
||||||
|
(the first item in the config) is used as to determine the client's subnet. The
|
||||||
|
local address is also used as server-ID override so that the client always sends requests
|
||||||
|
via the relay. The effect of this is that server doesn't require
|
||||||
|
a route to the client network and the clients don't require a route to the server.
|
||||||
|
|
||||||
|
The third parameter is mandatory. If it is an interface name it cannot be a wildcard and the same filtering as descibed in
|
||||||
|
--dhcp-relay applies; answers from the server must arrve via the specified interface. If the third parameter
|
||||||
|
is an IP address it must be an address of a local interface which is routable from the server; In this case no filtering
|
||||||
|
is done, the reply packets can arrive via any route.
|
||||||
|
|
||||||
|
If setting up a network where the client networks have limited routing, be careful
|
||||||
|
about configuring the DHCP server. Dnsmasq, as DHCP server, will set the default route to the
|
||||||
|
client-facing relay interface unless explicitly configured: that is a sensible default.
|
||||||
|
The normal default DNS server (the same address as the DHCP server)
|
||||||
|
will not be appropriate when there is no route bewteen the
|
||||||
|
two, so this will have to be explicitly configured.
|
||||||
|
.TP
|
||||||
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
|
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
|
||||||
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
||||||
"vendor class" which represents, in some sense, the type of host. This option
|
"vendor class" which represents, in some sense, the type of host. This option
|
||||||
@@ -1739,7 +1763,9 @@ For DHCPv4, it changes the behaviour from strict RFC compliance so that DHCP req
|
|||||||
unknown leases from unknown hosts are not ignored. This allows new hosts
|
unknown leases from unknown hosts are not ignored. This allows new hosts
|
||||||
to get a lease without a tedious timeout under all circumstances. It also
|
to get a lease without a tedious timeout under all circumstances. It also
|
||||||
allows dnsmasq to rebuild its lease database without each client needing to
|
allows dnsmasq to rebuild its lease database without each client needing to
|
||||||
reacquire a lease, if the database is lost. For DHCPv6 it sets the
|
reacquire a lease, if the database is lost. For DHCPv6 it controls the same
|
||||||
|
behaviour as DHCPv4 with missing leases (except for the RFC uncompliance - the
|
||||||
|
DHCPv6 RFCs allow this behaviour if configured). It also sets the
|
||||||
priority in replies to 255 (the maximum) instead of 0 (the minimum).
|
priority in replies to 255 (the maximum) instead of 0 (the minimum).
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-rapid-commit
|
.B --dhcp-rapid-commit
|
||||||
|
|||||||
@@ -229,3 +229,5 @@ contents of the cache to the syslog.
|
|||||||
|
|
||||||
<P>For a complete listing of options please take a look at the manpage
|
<P>For a complete listing of options please take a look at the manpage
|
||||||
dnsmasq(8).
|
dnsmasq(8).
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
+7
-6
@@ -938,15 +938,14 @@ int cache_recv_insert(time_t now, int fd)
|
|||||||
if (newc)
|
if (newc)
|
||||||
{
|
{
|
||||||
newc->addr.cname.is_name_ptr = 0;
|
newc->addr.cname.is_name_ptr = 0;
|
||||||
|
newc->addr.cname.target.cache = crecp;
|
||||||
|
|
||||||
if (!crecp)
|
if (crecp)
|
||||||
newc->addr.cname.target.cache = NULL;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
next_uid(crecp);
|
next_uid(crecp);
|
||||||
newc->addr.cname.target.cache = crecp;
|
|
||||||
newc->addr.cname.uid = crecp->uid;
|
newc->addr.cname.uid = crecp->uid;
|
||||||
}
|
}
|
||||||
|
crecp = newc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2360,6 +2359,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
|||||||
source = "reply";
|
source = "reply";
|
||||||
else if (flags & F_AUTH)
|
else if (flags & F_AUTH)
|
||||||
source = "auth";
|
source = "auth";
|
||||||
|
else if (flags & F_QUERY)
|
||||||
|
source = "query";
|
||||||
else if (flags & F_SECSTAT)
|
else if (flags & F_SECSTAT)
|
||||||
{
|
{
|
||||||
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
|
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
|
||||||
@@ -2400,8 +2401,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
|||||||
source = "non-query opcode";
|
source = "non-query opcode";
|
||||||
name = opcodestring;
|
name = opcodestring;
|
||||||
}
|
}
|
||||||
else if (!(flags & F_AUTH))
|
else if (type > 0)
|
||||||
source = "query";
|
source = querystr(source, type);
|
||||||
|
|
||||||
verb = "from";
|
verb = "from";
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-1
@@ -290,6 +290,7 @@ HAVE_SOCKADDR_SA_LEN
|
|||||||
#define HAVE_BSD_NETWORK
|
#define HAVE_BSD_NETWORK
|
||||||
#define HAVE_GETOPT_LONG
|
#define HAVE_GETOPT_LONG
|
||||||
#define HAVE_SOCKADDR_SA_LEN
|
#define HAVE_SOCKADDR_SA_LEN
|
||||||
|
#define NO_IPSET
|
||||||
/* Define before sys/socket.h is included so we get socklen_t */
|
/* Define before sys/socket.h is included so we get socklen_t */
|
||||||
#define _BSD_SOCKLEN_T_
|
#define _BSD_SOCKLEN_T_
|
||||||
/* Select the RFC_3542 version of the IPv6 socket API.
|
/* Select the RFC_3542 version of the IPv6 socket API.
|
||||||
@@ -349,7 +350,6 @@ HAVE_SOCKADDR_SA_LEN
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(HAVE_LINUX_NETWORK)
|
#if !defined(HAVE_LINUX_NETWORK)
|
||||||
#undef HAVE_IPSET
|
|
||||||
#undef HAVE_NFTSET
|
#undef HAVE_NFTSET
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -357,6 +357,16 @@ HAVE_SOCKADDR_SA_LEN
|
|||||||
#undef HAVE_IPSET
|
#undef HAVE_IPSET
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_IPSET)
|
||||||
|
# if defined(HAVE_LINUX_NETWORK)
|
||||||
|
# define HAVE_LINUX_IPSET
|
||||||
|
# elif defined(HAVE_BSD_NETWORK)
|
||||||
|
# define HAVE_BSD_IPSET
|
||||||
|
# else
|
||||||
|
# undef HAVE_IPSET
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef NO_LOOP
|
#ifdef NO_LOOP
|
||||||
#undef HAVE_LOOP
|
#undef HAVE_LOOP
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1067,6 +1067,8 @@ void log_relay(int family, struct dhcp_relay *relay)
|
|||||||
{
|
{
|
||||||
if (broadcast)
|
if (broadcast)
|
||||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s via %s"), daemon->addrbuff, relay->interface);
|
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s via %s"), daemon->addrbuff, relay->interface);
|
||||||
|
else if (relay->split_mode)
|
||||||
|
my_syslog(MS_DHCP | LOG_INFO, _("DHCP split-relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
|
||||||
else
|
else
|
||||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
|
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
#define SUBOPT_REMOTE_ID 2
|
#define SUBOPT_REMOTE_ID 2
|
||||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||||
|
#define SUBOPT_FLAGS 10 /* RFC 5010 */
|
||||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||||
|
|
||||||
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
||||||
|
|||||||
+44
-132
@@ -32,8 +32,6 @@ static int complete_context(struct in_addr local, int if_index, char *label,
|
|||||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||||
static void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz);
|
|
||||||
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
|
|
||||||
|
|
||||||
static int make_fd(int port)
|
static int make_fd(int port)
|
||||||
{
|
{
|
||||||
@@ -144,13 +142,14 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
|
int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
|
||||||
int rcvd_iface_index;
|
int rcvd_iface_index, relay_index;
|
||||||
struct in_addr iface_addr;
|
struct in_addr iface_addr;
|
||||||
struct iface_param parm;
|
struct iface_param parm;
|
||||||
time_t recvtime = now;
|
time_t recvtime = now;
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
struct arpreq arp_req;
|
struct arpreq arp_req;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
struct in_addr dst_addr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
union {
|
union {
|
||||||
@@ -176,14 +175,12 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
(sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
|
(sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef HAVE_DUMPFILE
|
|
||||||
dump_packet_udp(DUMP_DHCP, (void *)daemon->dhcp_packet.iov_base, sz, (union mysockaddr *)&dest, NULL, fd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined (HAVE_LINUX_NETWORK)
|
#if defined (HAVE_LINUX_NETWORK)
|
||||||
if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
|
if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
|
||||||
recvtime = tv.tv_sec;
|
recvtime = tv.tv_sec;
|
||||||
|
|
||||||
|
dst_addr.s_addr = 0;
|
||||||
|
|
||||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
@@ -194,7 +191,8 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
} p;
|
} p;
|
||||||
p.c = CMSG_DATA(cmptr);
|
p.c = CMSG_DATA(cmptr);
|
||||||
iface_index = p.p->ipi_ifindex;
|
iface_index = p.p->ipi_ifindex;
|
||||||
if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
|
dst_addr = p.p->ipi_addr;
|
||||||
|
if (dst_addr.s_addr != INADDR_BROADCAST)
|
||||||
unicast_dest = 1;
|
unicast_dest = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +223,24 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DUMPFILE
|
||||||
|
union mysockaddr *sockp = NULL;
|
||||||
|
|
||||||
|
# ifdef HAVE_LINUX_NETWORK
|
||||||
|
union mysockaddr tosock;
|
||||||
|
|
||||||
|
sockp = &tosock;
|
||||||
|
tosock.in.sin_port = htons(daemon->dhcp_server_port);
|
||||||
|
tosock.in.sin_addr = dst_addr;
|
||||||
|
tosock.sa.sa_family = AF_INET;
|
||||||
|
# ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
tosock.in.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
dump_packet_udp(DUMP_DHCP, (void *)daemon->dhcp_packet.iov_base, sz, (union mysockaddr *)&dest, sockp, -1);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
|
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
|
||||||
ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
|
ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
|
||||||
return;
|
return;
|
||||||
@@ -286,10 +302,10 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
unicast_dest = 1;
|
unicast_dest = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
|
if ((relay_index = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, ifr.ifr_name)))
|
||||||
{
|
{
|
||||||
/* Reply from server, using us as relay. */
|
/* Reply from server, using us as relay. */
|
||||||
rcvd_iface_index = relay->iface_index;
|
rcvd_iface_index = relay_index;
|
||||||
if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
|
if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
|
||||||
return;
|
return;
|
||||||
is_relay_reply = 1;
|
is_relay_reply = 1;
|
||||||
@@ -314,10 +330,13 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
if (tmp->name && (tmp->flags & INAME_4) && wildcard_match(tmp->name, ifr.ifr_name))
|
if (tmp->name && (tmp->flags & INAME_4) && wildcard_match(tmp->name, ifr.ifr_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* unlinked contexts/relays are marked by context->current == context */
|
/* unlinked contexts are marked by context->current == context */
|
||||||
for (context = daemon->dhcp; context; context = context->next)
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
context->current = context;
|
context->current = context;
|
||||||
|
|
||||||
|
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||||
|
relay->matchcount = 0;
|
||||||
|
|
||||||
parm.current = NULL;
|
parm.current = NULL;
|
||||||
parm.ind = iface_index;
|
parm.ind = iface_index;
|
||||||
|
|
||||||
@@ -344,7 +363,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
if (!iface_enumerate(AF_INET, &parm, (callback_t){.af_inet=complete_context}))
|
if (!iface_enumerate(AF_INET, &parm, (callback_t){.af_inet=complete_context}))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
relay_upstream4(iface_index, mess, (size_t)sz);
|
relay_upstream4(iface_addr, iface_index, mess, (size_t)sz, unicast_dest);
|
||||||
|
|
||||||
/* May have configured relay, but not DHCP server */
|
/* May have configured relay, but not DHCP server */
|
||||||
if (!daemon->dhcp)
|
if (!daemon->dhcp)
|
||||||
@@ -648,8 +667,19 @@ static int complete_context(struct in_addr local, int if_index, char *label,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||||
if (relay->local.addr4.s_addr == local.s_addr)
|
if (!relay->split_mode && relay->local.addr4.s_addr == local.s_addr)
|
||||||
relay->iface_index = if_index;
|
{
|
||||||
|
if (if_index == param->ind)
|
||||||
|
relay->iface_index = if_index;
|
||||||
|
|
||||||
|
/* More than one interface with the relay address breaks things. */
|
||||||
|
if (relay->matchcount++ == 1 && !relay->warned)
|
||||||
|
{
|
||||||
|
relay->warned = 1;
|
||||||
|
inet_ntop(AF_INET, &local, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP relay address %s appears on more than one interface"), daemon->addrbuff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1091,122 +1121,4 @@ char *host_from_dns(struct in_addr addr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz)
|
|
||||||
{
|
|
||||||
struct in_addr giaddr = mess->giaddr;
|
|
||||||
u8 hops = mess->hops;
|
|
||||||
struct dhcp_relay *relay;
|
|
||||||
|
|
||||||
if (mess->op != BOOTREQUEST)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
|
||||||
if (relay->iface_index != 0 && relay->iface_index == iface_index)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* No relay config. */
|
|
||||||
if (!relay)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (; relay; relay = relay->next)
|
|
||||||
if (relay->iface_index != 0 && relay->iface_index == iface_index)
|
|
||||||
{
|
|
||||||
union mysockaddr to;
|
|
||||||
union all_addr from;
|
|
||||||
|
|
||||||
mess->hops = hops;
|
|
||||||
mess->giaddr = giaddr;
|
|
||||||
|
|
||||||
if ((mess->hops++) > 20)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* source address == relay address */
|
|
||||||
from.addr4 = relay->local.addr4;
|
|
||||||
|
|
||||||
/* already gatewayed ? */
|
|
||||||
if (giaddr.s_addr)
|
|
||||||
{
|
|
||||||
/* if so check if by us, to stomp on loops. */
|
|
||||||
if (giaddr.s_addr == relay->local.addr4.s_addr)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* plug in our address */
|
|
||||||
mess->giaddr.s_addr = relay->local.addr4.s_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
to.sa.sa_family = AF_INET;
|
|
||||||
to.in.sin_addr = relay->server.addr4;
|
|
||||||
to.in.sin_port = htons(relay->port);
|
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
|
||||||
to.in.sin_len = sizeof(struct sockaddr_in);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_DUMPFILE
|
|
||||||
{
|
|
||||||
union mysockaddr fromsock;
|
|
||||||
fromsock.in.sin_port = htons(daemon->dhcp_server_port);
|
|
||||||
fromsock.in.sin_addr = from.addr4;
|
|
||||||
fromsock.sa.sa_family = AF_INET;
|
|
||||||
|
|
||||||
dump_packet_udp(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, -1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* restore in case of a local reply. */
|
|
||||||
mess->giaddr = giaddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
|
|
||||||
{
|
|
||||||
struct dhcp_relay *relay;
|
|
||||||
|
|
||||||
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
|
||||||
{
|
|
||||||
if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
|
|
||||||
{
|
|
||||||
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
|
|
||||||
return relay->iface_index != 0 ? relay : NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+30
-8
@@ -89,6 +89,7 @@ void dhcp6_init(void)
|
|||||||
void dhcp6_packet(time_t now)
|
void dhcp6_packet(time_t now)
|
||||||
{
|
{
|
||||||
struct dhcp_context *context;
|
struct dhcp_context *context;
|
||||||
|
struct dhcp_relay *relay;
|
||||||
struct iface_param parm;
|
struct iface_param parm;
|
||||||
struct cmsghdr *cmptr;
|
struct cmsghdr *cmptr;
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
@@ -176,6 +177,7 @@ void dhcp6_packet(time_t now)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct dhcp_bridge *bridge, *alias;
|
struct dhcp_bridge *bridge, *alias;
|
||||||
|
int multicast_dest = 0;
|
||||||
|
|
||||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||||
@@ -231,13 +233,23 @@ void dhcp6_packet(time_t now)
|
|||||||
memset(&context->local6, 0, IN6ADDRSZ);
|
memset(&context->local6, 0, IN6ADDRSZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore requests sent to the ALL_SERVERS multicast address for relay when
|
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||||
we're listening there for DHCPv6 server reasons. */
|
relay->matchcount = 0;
|
||||||
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
|
|
||||||
|
|
||||||
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers) &&
|
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &all_servers);
|
||||||
relay_upstream6(if_index, (size_t)sz, &from.sin6_addr, from.sin6_scope_id, now))
|
if (IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
||||||
return;
|
multicast_dest = 1;
|
||||||
|
|
||||||
|
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
|
||||||
|
if (IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
||||||
|
multicast_dest = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Ignore requests sent to the ALL_SERVERS multicast address for relay when
|
||||||
|
we're listening there for DHCPv6 server reasons. */
|
||||||
|
if (relay_upstream6(if_index, (size_t)sz, &from.sin6_addr, from.sin6_scope_id, now))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!iface_enumerate(AF_INET6, &parm, (callback_t){.af_inet6=complete_context6}))
|
if (!iface_enumerate(AF_INET6, &parm, (callback_t){.af_inet6=complete_context6}))
|
||||||
return;
|
return;
|
||||||
@@ -266,7 +278,7 @@ void dhcp6_packet(time_t now)
|
|||||||
|
|
||||||
lease_prune(NULL, now); /* lose any expired leases */
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
|
|
||||||
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
port = dhcp6_reply(parm.current, multicast_dest, if_index, ifr.ifr_name, &parm.fallback,
|
||||||
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
|
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
|
||||||
|
|
||||||
/* The port in the source address of the original request should
|
/* The port in the source address of the original request should
|
||||||
@@ -444,7 +456,17 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
|||||||
if (match)
|
if (match)
|
||||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||||
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
|
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
|
||||||
relay->iface_index = if_index;
|
{
|
||||||
|
relay->iface_index = if_index;
|
||||||
|
|
||||||
|
/* More than one interface with the relay address breaks things. */
|
||||||
|
if (relay->matchcount++ == 1 && !relay->warned)
|
||||||
|
{
|
||||||
|
relay->warned = 1;
|
||||||
|
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP relay address %s appears on more than one interface"), daemon->addrbuff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1777,9 +1777,9 @@ void clear_cache_and_reload(time_t now)
|
|||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||||
{
|
{
|
||||||
|
reread_dhcp();
|
||||||
if (option_bool(OPT_ETHERS))
|
if (option_bool(OPT_ETHERS))
|
||||||
dhcp_read_ethers();
|
dhcp_read_ethers();
|
||||||
reread_dhcp();
|
|
||||||
dhcp_update_configs(daemon->dhcp_conf);
|
dhcp_update_configs(daemon->dhcp_conf);
|
||||||
lease_update_from_configs();
|
lease_update_from_configs();
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
|
|||||||
+8
-3
@@ -1144,10 +1144,12 @@ struct dhcp_relay {
|
|||||||
union {
|
union {
|
||||||
struct in_addr addr4;
|
struct in_addr addr4;
|
||||||
struct in6_addr addr6;
|
struct in6_addr addr6;
|
||||||
} local, server;
|
} local, server, uplink;
|
||||||
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
|
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
|
||||||
int iface_index; /* working - interface in which requests arrived, for return */
|
int iface_index; /* working - interface in which requests arrived, for return */
|
||||||
int port; /* Port of relay we forward to. */
|
int port; /* Port of relay we forward to. */
|
||||||
|
int split_mode; /* Split address allocation and relay address. */
|
||||||
|
int warned, matchcount;
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
struct snoop_record {
|
struct snoop_record {
|
||||||
struct in6_addr client, prefix;
|
struct in6_addr client, prefix;
|
||||||
@@ -1666,6 +1668,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
time_t recvtime, struct in_addr leasequery_source);
|
time_t recvtime, struct in_addr leasequery_source);
|
||||||
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||||
int clid_len, unsigned char *clid, int *len_out);
|
int clid_len, unsigned char *clid, int *len_out);
|
||||||
|
void relay_upstream4(struct in_addr iface_addr, int iface_index,
|
||||||
|
struct dhcp_packet *mess, size_t sz, int unicast);
|
||||||
|
unsigned int relay_reply4(struct dhcp_packet *mess, size_t sz, char *arrival_interface);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* dnsmasq.c */
|
/* dnsmasq.c */
|
||||||
@@ -1801,7 +1806,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
|
|||||||
|
|
||||||
/* rfc3315.c */
|
/* rfc3315.c */
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
unsigned short dhcp6_reply(struct dhcp_context *context, int multicast_dest, int interface, char *iface_name,
|
||||||
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
|
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
|
||||||
size_t sz, struct in6_addr *client_addr, time_t now);
|
size_t sz, struct in6_addr *client_addr, time_t now);
|
||||||
int relay_upstream6(int iface_index, ssize_t sz, struct in6_addr *peer_address,
|
int relay_upstream6(int iface_index, ssize_t sz, struct in6_addr *peer_address,
|
||||||
@@ -1938,7 +1943,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
|||||||
char *name, char *limit, int first, int last, int ede);
|
char *name, char *limit, int first, int last, int ede);
|
||||||
int server_samegroup(struct server *a, struct server *b);
|
int server_samegroup(struct server *a, struct server *b);
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp);
|
int dnssec_server(struct server *server, char *keyname, int is_ds, int *firstp, int *lastp);
|
||||||
#endif
|
#endif
|
||||||
void mark_servers(int flag);
|
void mark_servers(int flag);
|
||||||
void cleanup_servers(void);
|
void cleanup_servers(void);
|
||||||
|
|||||||
+22
-6
@@ -95,6 +95,7 @@ void build_server_array(void)
|
|||||||
|
|
||||||
A flag of F_SERVER returns an upstream server only.
|
A flag of F_SERVER returns an upstream server only.
|
||||||
A flag of F_DNSSECOK disables NODOTS servers from consideration.
|
A flag of F_DNSSECOK disables NODOTS servers from consideration.
|
||||||
|
A flag of F_DS returns parent domain server.
|
||||||
A flag of F_DOMAINSRV returns a domain-specific server only.
|
A flag of F_DOMAINSRV returns a domain-specific server only.
|
||||||
A flag of F_CONFIG returns anything that generates a local
|
A flag of F_CONFIG returns anything that generates a local
|
||||||
reply of IPv4 or IPV6.
|
reply of IPv4 or IPV6.
|
||||||
@@ -106,12 +107,23 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
|||||||
ssize_t qlen;
|
ssize_t qlen;
|
||||||
int try, high, low = 0;
|
int try, high, low = 0;
|
||||||
int nlow = 0, nhigh = 0;
|
int nlow = 0, nhigh = 0;
|
||||||
char *cp, *qdomain = domain;
|
char *cp, *qdomain;
|
||||||
|
|
||||||
/* may be no configured servers. */
|
/* may be no configured servers. */
|
||||||
if (daemon->serverarraysz == 0)
|
if (daemon->serverarraysz == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* DS records should come from the parent domain. */
|
||||||
|
if (flags & F_DS)
|
||||||
|
{
|
||||||
|
if ((cp = strchr(domain, '.')))
|
||||||
|
domain = cp+1;
|
||||||
|
else
|
||||||
|
domain = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
qdomain = domain;
|
||||||
|
|
||||||
/* find query length and presence of '.' */
|
/* find query length and presence of '.' */
|
||||||
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
|
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
|
||||||
if (*cp == '.')
|
if (*cp == '.')
|
||||||
@@ -244,7 +256,10 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
|||||||
if (nodots &&
|
if (nodots &&
|
||||||
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
|
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
|
||||||
(nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
|
(nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
|
||||||
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
|
{
|
||||||
|
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
|
||||||
|
qlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (lowout)
|
if (lowout)
|
||||||
*lowout = nlow;
|
*lowout = nlow;
|
||||||
@@ -343,7 +358,8 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* If we want a server for a particular domain, and this one isn't, return nothing. */
|
/* If we want a server for a particular domain, and this one isn't, return nothing. */
|
||||||
if (nlow != nhigh && (flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
if (nlow < daemon->serverarraysz && nlow != nhigh && (flags & F_DOMAINSRV) &&
|
||||||
|
daemon->serverarray[nlow]->domain_len == 0 && !(daemon->serverarray[nlow]->flags & SERV_FOR_NODOTS))
|
||||||
nlow = nhigh;
|
nlow = nhigh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -399,7 +415,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
|||||||
|
|
||||||
setup_reply(header, flags, ede);
|
setup_reply(header, flags, ede);
|
||||||
|
|
||||||
gotname &= ~F_QUERY;
|
gotname &= ~(F_QUERY | F_DS);
|
||||||
|
|
||||||
if (flags & (F_NXDOMAIN | F_NOERR))
|
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
|
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
|
||||||
@@ -459,14 +475,14 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
|
int dnssec_server(struct server *server, char *keyname, int is_ds, int *firstp, int *lastp)
|
||||||
{
|
{
|
||||||
int first, last, index;
|
int first, last, index;
|
||||||
|
|
||||||
/* Find server to send DNSSEC query to. This will normally be the
|
/* Find server to send DNSSEC query to. This will normally be the
|
||||||
same as for the original query, but may be another if
|
same as for the original query, but may be another if
|
||||||
servers for domains are involved. */
|
servers for domains are involved. */
|
||||||
if (!lookup_domain(keyname, F_SERVER | F_DNSSECOK, &first, &last))
|
if (!lookup_domain(keyname, F_SERVER | F_DNSSECOK | (is_ds ? F_DS : 0), &first, &last))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (index = first; index != last; index++)
|
for (index = first; index != last; index++)
|
||||||
|
|||||||
+13
-13
@@ -763,6 +763,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
|
if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
|
||||||
header->hb4 &= ~HB4_AD;
|
header->hb4 &= ~HB4_AD;
|
||||||
|
|
||||||
|
/* Complain loudly if the upstream server is non-recursive. */
|
||||||
|
if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
|
||||||
|
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
||||||
|
{
|
||||||
|
(void)prettyprint_addr(&server->addr, daemon->namebuff);
|
||||||
|
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
||||||
|
if (!option_bool(OPT_LOG))
|
||||||
|
server->flags |= SERV_WARNED_RECURSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
header->hb4 |= HB4_RA; /* recursion if available */
|
header->hb4 |= HB4_RA; /* recursion if available */
|
||||||
|
|
||||||
if (OPCODE(header) != QUERY)
|
if (OPCODE(header) != QUERY)
|
||||||
@@ -778,16 +788,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
return resize_packet(header, n, pheader, plen);
|
return resize_packet(header, n, pheader, plen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complain loudly if the upstream server is non-recursive. */
|
|
||||||
if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
|
|
||||||
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
|
||||||
{
|
|
||||||
(void)prettyprint_addr(&server->addr, daemon->namebuff);
|
|
||||||
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
|
||||||
if (!option_bool(OPT_LOG))
|
|
||||||
server->flags |= SERV_WARNED_RECURSIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header->hb3 & HB3_TC)
|
if (header->hb3 & HB3_TC)
|
||||||
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
|
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
|
||||||
else if (!bogusanswer || (header->hb4 & HB4_CD))
|
else if (!bogusanswer || (header->hb4 & HB4_CD))
|
||||||
@@ -1024,7 +1024,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
|||||||
|
|
||||||
/* Make sure we don't expire and free the orig frec during the
|
/* Make sure we don't expire and free the orig frec during the
|
||||||
allocation of a new one: third arg of get_new_frec() does that. */
|
allocation of a new one: third arg of get_new_frec() does that. */
|
||||||
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, NULL, NULL)) != -1 &&
|
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, STAT_ISEQUAL(status, STAT_NEED_DS), NULL, NULL)) != -1 &&
|
||||||
(server = daemon->serverarray[serverind]) &&
|
(server = daemon->serverarray[serverind]) &&
|
||||||
(nn = dnssec_generate_query(header, ((unsigned char *) header) + daemon->edns_pktsz,
|
(nn = dnssec_generate_query(header, ((unsigned char *) header) + daemon->edns_pktsz,
|
||||||
daemon->keyname, forward->class, get_id(),
|
daemon->keyname, forward->class, get_id(),
|
||||||
@@ -2199,7 +2199,7 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
|||||||
first = start = server->arrayposn;
|
first = start = server->arrayposn;
|
||||||
last = first + 1;
|
last = first + 1;
|
||||||
|
|
||||||
if (!STAT_ISEQUAL(status, STAT_OK) && (start = dnssec_server(server, name, &first, &last)) == -1)
|
if (!STAT_ISEQUAL(status, STAT_OK) && (start = dnssec_server(server, name, STAT_ISEQUAL(status, STAT_NEED_DS), &first, &last)) == -1)
|
||||||
new_status = STAT_ABANDONED;
|
new_status = STAT_ABANDONED;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2307,7 +2307,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0,
|
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0,
|
||||||
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
||||||
|
|
||||||
if ((start = dnssec_server(server, keyname, &first, &last)) == -1)
|
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1)
|
||||||
{
|
{
|
||||||
new_status = STAT_ABANDONED;
|
new_status = STAT_ABANDONED;
|
||||||
break;
|
break;
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
#if defined(HAVE_IPSET)
|
#if defined(HAVE_LINUX_IPSET)
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|||||||
+28
-4
@@ -196,6 +196,7 @@ struct myoption {
|
|||||||
#define LOPT_NO_ENCODE 387
|
#define LOPT_NO_ENCODE 387
|
||||||
#define LOPT_DO_ENCODE 388
|
#define LOPT_DO_ENCODE 388
|
||||||
#define LOPT_LEASEQUERY 389
|
#define LOPT_LEASEQUERY 389
|
||||||
|
#define LOPT_SPLIT_RELAY 390
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -374,6 +375,7 @@ static const struct myoption opts[] =
|
|||||||
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
|
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
|
||||||
{ "dnssec-limits", 1, 0, LOPT_DNSSEC_LIMITS },
|
{ "dnssec-limits", 1, 0, LOPT_DNSSEC_LIMITS },
|
||||||
{ "dhcp-relay", 1, 0, LOPT_RELAY },
|
{ "dhcp-relay", 1, 0, LOPT_RELAY },
|
||||||
|
{ "dhcp-split-relay", 1, 0, LOPT_SPLIT_RELAY },
|
||||||
{ "ra-param", 1, 0, LOPT_RA_PARAM },
|
{ "ra-param", 1, 0, LOPT_RA_PARAM },
|
||||||
{ "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
|
{ "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
|
||||||
{ "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
|
{ "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
|
||||||
@@ -542,6 +544,7 @@ static struct {
|
|||||||
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
|
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
|
||||||
{ LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
|
{ LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
|
||||||
{ LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<iface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
|
{ LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<iface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
|
||||||
|
{ LOPT_SPLIT_RELAY, ARG_DUP, "<local-addr>,<server>,<iface>", gettext_noop("Relay DHCP requests to a remote server"), NULL},
|
||||||
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
||||||
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
||||||
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
||||||
@@ -2917,13 +2920,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
#pragma GCC diagnostic push
|
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
|
# endif
|
||||||
case LOPT_LEASEQUERY:
|
case LOPT_LEASEQUERY:
|
||||||
set_option_bool(OPT_LEASEQUERY);
|
set_option_bool(OPT_LEASEQUERY);
|
||||||
if (!arg)
|
if (!arg)
|
||||||
break;
|
break;
|
||||||
#pragma GCC diagnostic pop
|
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
case 'B': /* --bogus-nxdomain */
|
case 'B': /* --bogus-nxdomain */
|
||||||
case LOPT_IGNORE_ADDR: /* --ignore-address */
|
case LOPT_IGNORE_ADDR: /* --ignore-address */
|
||||||
@@ -4712,11 +4719,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case LOPT_RELAY: /* --dhcp-relay */
|
case LOPT_RELAY: /* --dhcp-relay */
|
||||||
|
case LOPT_SPLIT_RELAY: /* --dhcp-splt-relay */
|
||||||
{
|
{
|
||||||
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
|
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
|
||||||
char *two = split(arg);
|
char *two = split(arg);
|
||||||
char *three = split(two);
|
char *three = split(two);
|
||||||
|
|
||||||
|
if (option == LOPT_SPLIT_RELAY)
|
||||||
|
{
|
||||||
|
new->split_mode = 1;
|
||||||
|
|
||||||
|
/* split mode must have two addresses and a non-wildcard interface name. */
|
||||||
|
if (!three || strchr(three, '*'))
|
||||||
|
two = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
new->iface_index = 0;
|
new->iface_index = 0;
|
||||||
|
|
||||||
if (two)
|
if (two)
|
||||||
@@ -4739,12 +4756,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
else
|
else
|
||||||
three = two;
|
three = two;
|
||||||
}
|
}
|
||||||
|
else if (new->split_mode && inet_pton(AF_INET, three, &new->uplink))
|
||||||
|
/* Third arg in split mode can be an address. */
|
||||||
|
three = NULL;
|
||||||
|
|
||||||
new->next = daemon->relay4;
|
new->next = daemon->relay4;
|
||||||
daemon->relay4 = new;
|
daemon->relay4 = new;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
else if (inet_pton(AF_INET6, arg, &new->local))
|
else if (inet_pton(AF_INET6, arg, &new->local) && !new->split_mode)
|
||||||
{
|
{
|
||||||
char *hash = split_chr(two, '#');
|
char *hash = split_chr(two, '#');
|
||||||
|
|
||||||
@@ -4765,6 +4785,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
daemon->relay6 = new;
|
daemon->relay6 = new;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
else
|
||||||
|
two = NULL;
|
||||||
|
|
||||||
new->interface = opt_string_alloc(three);
|
new->interface = opt_string_alloc(three);
|
||||||
}
|
}
|
||||||
@@ -6258,6 +6280,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||||||
strchr(srv->name, '.') &&
|
strchr(srv->name, '.') &&
|
||||||
strchr(srv->name, '.') == strrchr(srv->name, '.'))
|
strchr(srv->name, '.') == strrchr(srv->name, '.'))
|
||||||
{
|
{
|
||||||
|
if (strlen(srv->name) + 1 + strlen(daemon->domain_suffix) > MAXDNAME)
|
||||||
|
die(_("srv-host name %s too long after domain appended"), srv->name, EC_MISC);
|
||||||
strcpy(buff, srv->name);
|
strcpy(buff, srv->name);
|
||||||
strcat(buff, ".");
|
strcat(buff, ".");
|
||||||
strcat(buff, daemon->domain_suffix);
|
strcat(buff, daemon->domain_suffix);
|
||||||
|
|||||||
+24
-11
@@ -415,6 +415,7 @@ int private_net(struct in_addr addr, int ban_localhost)
|
|||||||
(((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
|
(((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
|
||||||
(((ip_addr & 0xFF000000) == 0x00000000) && ban_localhost) /* RFC 5735 section 3. "here" network */ ||
|
(((ip_addr & 0xFF000000) == 0x00000000) && ban_localhost) /* RFC 5735 section 3. "here" network */ ||
|
||||||
((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
|
((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
|
||||||
|
((ip_addr & 0xFFC00000) == 0x64400000) /* 100.64.0.0/10 (CG-NAT) RFC6598/RFC7793*/ ||
|
||||||
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
|
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
|
||||||
((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
|
((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
|
||||||
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
|
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
|
||||||
@@ -515,7 +516,7 @@ int do_doctor(struct dns_header *header, size_t qlen, char *namebuff)
|
|||||||
Cache said SOA and return the difference in length between name and the name of the
|
Cache said SOA and return the difference in length between name and the name of the
|
||||||
SOA RR so we can look it up again.
|
SOA RR so we can look it up again.
|
||||||
*/
|
*/
|
||||||
static int find_soa(struct dns_header *header, size_t qlen, char *name, int *substring, unsigned long *ttlp, int no_cache, time_t now)
|
static int find_soa(struct dns_header *header, size_t qlen, char *name, int *substring, unsigned long *ttlp, int cache, time_t now)
|
||||||
{
|
{
|
||||||
unsigned char *p, *psave;
|
unsigned char *p, *psave;
|
||||||
int qtype, qclass, rdlen;
|
int qtype, qclass, rdlen;
|
||||||
@@ -555,7 +556,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
|
|||||||
{
|
{
|
||||||
int prefix = name_len - soa_len;
|
int prefix = name_len - soa_len;
|
||||||
|
|
||||||
if (!no_cache)
|
if (cache)
|
||||||
{
|
{
|
||||||
if (!(addr.rrblock.rrdata = blockdata_alloc(NULL, 0)))
|
if (!(addr.rrblock.rrdata = blockdata_alloc(NULL, 0)))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -567,12 +568,12 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
|
|||||||
{
|
{
|
||||||
if (!extract_name(header, qlen, &p, daemon->workspacename, EXTR_NAME_EXTRACT, 0))
|
if (!extract_name(header, qlen, &p, daemon->workspacename, EXTR_NAME_EXTRACT, 0))
|
||||||
{
|
{
|
||||||
if (!no_cache)
|
if (cache)
|
||||||
blockdata_free(addr.rrblock.rrdata);
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!no_cache)
|
if (cache)
|
||||||
{
|
{
|
||||||
len = to_wire(daemon->workspacename);
|
len = to_wire(daemon->workspacename);
|
||||||
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, daemon->workspacename, len))
|
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, daemon->workspacename, len))
|
||||||
@@ -587,13 +588,13 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
|
|||||||
|
|
||||||
if (!CHECK_LEN(header, p, qlen, 20))
|
if (!CHECK_LEN(header, p, qlen, 20))
|
||||||
{
|
{
|
||||||
if (!no_cache)
|
if (cache)
|
||||||
blockdata_free(addr.rrblock.rrdata);
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rest of RR */
|
/* rest of RR */
|
||||||
if (!no_cache)
|
if (cache)
|
||||||
{
|
{
|
||||||
int secflag = 0;
|
int secflag = 0;
|
||||||
|
|
||||||
@@ -1078,7 +1079,17 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
|
|
||||||
if (insert && !option_bool(OPT_NO_NEG))
|
if (insert && !option_bool(OPT_NO_NEG))
|
||||||
{
|
{
|
||||||
int substring, have_soa = find_soa(header, qlen, name, &substring, &ttl, no_cache_dnssec, now);
|
/* The order of records going into the cache matters (see cache_recv_insert()).
|
||||||
|
The target of a CNAME must immediately follow the CNAME.
|
||||||
|
(CNAME has already gone into the cache at this point)
|
||||||
|
Here we call find_soa to get the ttl and substring, but
|
||||||
|
we DON'T LET IT INSERT the SOA into the cache if our negative record is a CNAME target
|
||||||
|
so that the SOA doesn't come before the CNAME target.
|
||||||
|
|
||||||
|
We call find_soa() again after inserting the CNAME target to insert the SOA
|
||||||
|
if necessary. */
|
||||||
|
|
||||||
|
int substring, have_soa = find_soa(header, qlen, name, &substring, &ttl, cpp == NULL, now);
|
||||||
|
|
||||||
if (have_soa || daemon->neg_ttl)
|
if (have_soa || daemon->neg_ttl)
|
||||||
{
|
{
|
||||||
@@ -1100,6 +1111,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
next_uid(newc);
|
next_uid(newc);
|
||||||
cpp->addr.cname.target.cache = newc;
|
cpp->addr.cname.target.cache = newc;
|
||||||
cpp->addr.cname.uid = newc->uid;
|
cpp->addr.cname.uid = newc->uid;
|
||||||
|
|
||||||
|
/* we didn't insert the SOA before a CNAME target above, do it now. */
|
||||||
|
if (have_soa)
|
||||||
|
find_soa(header, qlen, name, NULL, NULL, 1, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1244,12 +1259,10 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
|||||||
return F_IPV4 | F_IPV6;
|
return F_IPV4 | F_IPV6;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
|
||||||
/* Make the behaviour for DS and DNSKEY queries we forward the same
|
/* Make the behaviour for DS and DNSKEY queries we forward the same
|
||||||
as for DS and DNSKEY queries we originate. */
|
as for DS and DNSKEY queries we originate. */
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DS || qtype == T_DNSKEY))
|
if (qtype == T_DS || qtype == T_DNSKEY)
|
||||||
return F_DNSSECOK;
|
return F_DNSSECOK | (qtype == T_DS ? F_DS : 0);
|
||||||
#endif
|
|
||||||
|
|
||||||
return F_QUERY;
|
return F_QUERY;
|
||||||
}
|
}
|
||||||
|
|||||||
+215
-1
@@ -204,6 +204,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
memcpy(agent_id, opt, total);
|
memcpy(agent_id, opt, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* look for RFC5010 flags sub-option */
|
||||||
|
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_FLAGS, INADDRSZ)))
|
||||||
|
unicast_dest = !!(option_uint(opt, 0, 1) & 0x80);
|
||||||
|
|
||||||
/* look for RFC3527 Link selection sub-option */
|
/* look for RFC3527 Link selection sub-option */
|
||||||
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
|
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
|
||||||
subnet_addr = option_addr(sopt);
|
subnet_addr = option_addr(sopt);
|
||||||
@@ -289,6 +293,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
{
|
{
|
||||||
addr = subnet_addr;
|
addr = subnet_addr;
|
||||||
force = 1;
|
force = 1;
|
||||||
|
if (mess->giaddr.s_addr)
|
||||||
|
via_relay = 1;
|
||||||
}
|
}
|
||||||
else if (mess->giaddr.s_addr)
|
else if (mess->giaddr.s_addr)
|
||||||
{
|
{
|
||||||
@@ -357,7 +363,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
if (context_tmp->local.s_addr == 0)
|
if (context_tmp->local.s_addr == 0)
|
||||||
context_tmp->local = fallback;
|
context_tmp->local = fallback;
|
||||||
if (context_tmp->router.s_addr == 0 && !share)
|
if (context_tmp->router.s_addr == 0 && !share)
|
||||||
context_tmp->router = mess->giaddr;
|
{
|
||||||
|
if (override.s_addr)
|
||||||
|
context_tmp->router = override;
|
||||||
|
else
|
||||||
|
context_tmp->router = mess->giaddr;
|
||||||
|
}
|
||||||
|
|
||||||
/* fill in missing broadcast addresses for relayed ranges */
|
/* fill in missing broadcast addresses for relayed ranges */
|
||||||
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
|
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
|
||||||
@@ -3044,4 +3055,207 @@ static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void relay_upstream4(struct in_addr iface_addr, int iface_index, struct dhcp_packet *mess, size_t sz, int unicast)
|
||||||
|
{
|
||||||
|
struct in_addr giaddr = mess->giaddr;
|
||||||
|
u8 hops = mess->hops;
|
||||||
|
struct dhcp_relay *relay;
|
||||||
|
size_t orig_sz = sz;
|
||||||
|
unsigned char *endopt = NULL;
|
||||||
|
|
||||||
|
if (mess->op != BOOTREQUEST || (mess->hops++) > 20)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||||
|
{
|
||||||
|
union mysockaddr to;
|
||||||
|
union all_addr from;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
/* restore orig packet */
|
||||||
|
mess->giaddr = giaddr;
|
||||||
|
if (endopt)
|
||||||
|
*endopt = OPTION_END;
|
||||||
|
sz = orig_sz;
|
||||||
|
|
||||||
|
if (relay->interface)
|
||||||
|
{
|
||||||
|
safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
|
||||||
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!relay->split_mode && relay->iface_index && relay->iface_index == iface_index)
|
||||||
|
{
|
||||||
|
/* already gatewayed ? */
|
||||||
|
if (giaddr.s_addr)
|
||||||
|
{
|
||||||
|
/* if so check if by us, to stomp on loops. */
|
||||||
|
if (giaddr.s_addr == relay->local.addr4.s_addr)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* plug in our address */
|
||||||
|
mess->giaddr = relay->local.addr4;
|
||||||
|
|
||||||
|
from.addr4 = relay->local.addr4;
|
||||||
|
}
|
||||||
|
else if (relay->split_mode && relay->local.addr4.s_addr == iface_addr.s_addr)
|
||||||
|
{
|
||||||
|
/* Split mode. We put our address on the server-facing interface
|
||||||
|
or a directly specified third address into giaddr for the server to talk back to us on.
|
||||||
|
|
||||||
|
Our address on client-facing interface goes into agent-id subnet-selector subopt,
|
||||||
|
so that the server allocates the correct address. We also send a
|
||||||
|
remote-id with the interface on which the request arrived,
|
||||||
|
so that we can send the reply back the same way. */
|
||||||
|
unsigned int net_index = htonl(iface_index);
|
||||||
|
|
||||||
|
if (relay->interface)
|
||||||
|
{
|
||||||
|
/* get our address on the server-facing interface. */
|
||||||
|
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
||||||
|
continue;
|
||||||
|
relay->uplink.addr4 = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* already gatewayed ? */
|
||||||
|
if (giaddr.s_addr)
|
||||||
|
{
|
||||||
|
/* if so check if by us, to stomp on loops. */
|
||||||
|
if (giaddr.s_addr == relay->uplink.addr4.s_addr)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* giaddr is our address on the outgoing interface in split mode. */
|
||||||
|
mess->giaddr = relay->uplink.addr4;
|
||||||
|
|
||||||
|
if (!endopt)
|
||||||
|
{
|
||||||
|
/* Add an RFC3026 relay agent information option (2 bytes) at the very end of the options.
|
||||||
|
Said option to contain a RFC 3527 link selection sub option (6 bytes) and
|
||||||
|
RFC 5017 serverid-override option (6 bytes) and RFC5010 flags (3 bytes) and
|
||||||
|
an RFC3046 remote-id which holds an interface index (6 bytes)
|
||||||
|
|
||||||
|
New END option is a 24th byte, so we need 24 bytes free.
|
||||||
|
We only need to do this once, and poke the address/interface/flags into the same place each time. */
|
||||||
|
|
||||||
|
if (!(endopt = option_find1((&mess->options[0] + sizeof(u32)), ((unsigned char *)mess) + sz, OPTION_END, 0)) ||
|
||||||
|
(endopt + 24 > (unsigned char *)(mess + 1)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
endopt[1] = 21; /* length */
|
||||||
|
endopt[2] = SUBOPT_SUBNET_SELECT;
|
||||||
|
endopt[3] = 4; /* length */
|
||||||
|
endopt[8] = SUBOPT_SERVER_OR;
|
||||||
|
endopt[9] = 4;
|
||||||
|
endopt[14] = SUBOPT_FLAGS;
|
||||||
|
endopt[15] = 1; /* length */
|
||||||
|
endopt[17] = SUBOPT_REMOTE_ID;
|
||||||
|
endopt[18] = 4; /* length */
|
||||||
|
endopt[23] = OPTION_END;
|
||||||
|
sz = (endopt - (unsigned char *)mess) + 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IP address is already in network byte order */
|
||||||
|
memcpy(&endopt[4], &relay->local.addr4.s_addr, INADDRSZ);
|
||||||
|
memcpy(&endopt[10], &relay->local.addr4.s_addr, INADDRSZ);
|
||||||
|
endopt[16] = unicast ? 0x80 : 0x00;
|
||||||
|
memcpy(&endopt[19], &net_index, 4);
|
||||||
|
endopt[0] = OPTION_AGENT_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
from.addr4 = relay->uplink.addr4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
to.sa.sa_family = AF_INET;
|
||||||
|
to.in.sin_addr = relay->server.addr4;
|
||||||
|
to.in.sin_port = htons(relay->port);
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
to.in.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Broadcasting to server. */
|
||||||
|
if (relay->server.addr4.s_addr == 0)
|
||||||
|
{
|
||||||
|
if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
|
||||||
|
{
|
||||||
|
my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s: %s"), relay->interface, strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DUMPFILE
|
||||||
|
{
|
||||||
|
union mysockaddr fromsock;
|
||||||
|
fromsock.in.sin_port = htons(daemon->dhcp_server_port);
|
||||||
|
fromsock.in.sin_addr = from.addr4;
|
||||||
|
fromsock.sa.sa_family = AF_INET;
|
||||||
|
|
||||||
|
dump_packet_udp(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, -1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* restore in case of a local reply. */
|
||||||
|
mess->hops = hops;
|
||||||
|
mess->giaddr = giaddr;
|
||||||
|
if (endopt)
|
||||||
|
*endopt = OPTION_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int relay_reply4(struct dhcp_packet *mess, size_t sz, char *arrival_interface)
|
||||||
|
{
|
||||||
|
struct dhcp_relay *relay;
|
||||||
|
|
||||||
|
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||||
|
{
|
||||||
|
unsigned int return_iface = 0;
|
||||||
|
|
||||||
|
if (relay->split_mode)
|
||||||
|
{
|
||||||
|
unsigned char *opt, *sopt;
|
||||||
|
|
||||||
|
/* giaddr is our address on the returning interface in split mode. */
|
||||||
|
if (mess->giaddr.s_addr == relay->uplink.addr4.s_addr &&
|
||||||
|
(opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
|
||||||
|
{
|
||||||
|
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, sizeof(unsigned int))))
|
||||||
|
return_iface = option_uint(sopt, 0, sizeof(unsigned int));
|
||||||
|
|
||||||
|
/* delete agent info before return RFC 3046 para 2.1 */
|
||||||
|
*opt = OPTION_END;
|
||||||
|
memset(opt + 1, 0, option_len(opt) + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
|
||||||
|
return_iface = relay->iface_index;
|
||||||
|
|
||||||
|
if (return_iface && (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
|
||||||
|
return return_iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* HAVE_DHCP */
|
#endif /* HAVE_DHCP */
|
||||||
+69
-69
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
struct state {
|
struct state {
|
||||||
unsigned char *clid;
|
unsigned char *clid;
|
||||||
int clid_len, ia_type, interface, hostname_auth, lease_allocate;
|
int multicast_dest, clid_len, ia_type, interface, hostname_auth, lease_allocate;
|
||||||
char *client_hostname, *hostname, *domain, *send_domain;
|
char *client_hostname, *hostname, *domain, *send_domain;
|
||||||
struct dhcp_context *context;
|
struct dhcp_context *context;
|
||||||
struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
|
struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
|
||||||
@@ -68,7 +68,7 @@ static void calculate_times(struct dhcp_context *context, unsigned int *min_time
|
|||||||
#define opt6_user_vendor_next(opt, end) (opt6_next(((uint8_t *) opt) - 2, end))
|
#define opt6_user_vendor_next(opt, end) (opt6_next(((uint8_t *) opt) - 2, end))
|
||||||
|
|
||||||
|
|
||||||
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
unsigned short dhcp6_reply(struct dhcp_context *context, int multicast_dest, int interface, char *iface_name,
|
||||||
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
|
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
|
||||||
size_t sz, struct in6_addr *client_addr, time_t now)
|
size_t sz, struct in6_addr *client_addr, time_t now)
|
||||||
{
|
{
|
||||||
@@ -87,6 +87,7 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
|
|||||||
|
|
||||||
reset_counter();
|
reset_counter();
|
||||||
state.context = context;
|
state.context = context;
|
||||||
|
state.multicast_dest = multicast_dest;
|
||||||
state.interface = interface;
|
state.interface = interface;
|
||||||
state.iface_name = iface_name;
|
state.iface_name = iface_name;
|
||||||
state.fallback = fallback;
|
state.fallback = fallback;
|
||||||
@@ -244,7 +245,11 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
|||||||
struct in6_addr align;
|
struct in6_addr align;
|
||||||
/* the packet data is unaligned, copy to aligned storage */
|
/* the packet data is unaligned, copy to aligned storage */
|
||||||
memcpy(&align, inbuff + 2, IN6ADDRSZ);
|
memcpy(&align, inbuff + 2, IN6ADDRSZ);
|
||||||
state->link_address = &align;
|
|
||||||
|
|
||||||
|
/* RFC6221 para 4 */
|
||||||
|
if (!IN6_IS_ADDR_UNSPECIFIED(&align))
|
||||||
|
state->link_address = &align;
|
||||||
/* zero is_unicast since that is now known to refer to the
|
/* zero is_unicast since that is now known to refer to the
|
||||||
relayed packet, not the original sent by the client */
|
relayed packet, not the original sent by the client */
|
||||||
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
|
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
|
||||||
@@ -333,20 +338,24 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
else if (msg_type != DHCP6IREQ)
|
else if (msg_type != DHCP6IREQ)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* server-id must match except for SOLICIT, CONFIRM and REBIND messages, which MUST NOT
|
|
||||||
have a server-id. 3315 para 15.x */
|
|
||||||
opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1);
|
opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1);
|
||||||
|
|
||||||
if (msg_type == DHCP6SOLICIT || msg_type == DHCP6CONFIRM || msg_type == DHCP6REBIND)
|
if (msg_type == DHCP6SOLICIT || msg_type == DHCP6CONFIRM || msg_type == DHCP6REBIND || msg_type == DHCP6IREQ)
|
||||||
{
|
{
|
||||||
if (opt)
|
/* Above message types must be multicast 3315 Section 15. */
|
||||||
|
if (!state->multicast_dest)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
else if (msg_type == DHCP6IREQ)
|
/* server-id must match except for SOLICIT, CONFIRM and REBIND messages, which MUST NOT
|
||||||
{
|
have a server-id. 3315 para 15.x */
|
||||||
/* If server-id provided, it must match. */
|
if (msg_type == DHCP6IREQ)
|
||||||
if (opt && (opt6_len(opt) != daemon->duid_len ||
|
{
|
||||||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
|
/* If server-id provided in IREQ, it must match. */
|
||||||
|
if (opt && (opt6_len(opt) != daemon->duid_len ||
|
||||||
|
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (opt)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -634,7 +643,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
|
|
||||||
case DHCP6SOLICIT:
|
case DHCP6SOLICIT:
|
||||||
{
|
{
|
||||||
int address_assigned = 0;
|
int address_assigned;
|
||||||
/* tags without all prefix-class tags */
|
/* tags without all prefix-class tags */
|
||||||
struct dhcp_netid *solicit_tags;
|
struct dhcp_netid *solicit_tags;
|
||||||
struct dhcp_context *c;
|
struct dhcp_context *c;
|
||||||
@@ -653,6 +662,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
|
|
||||||
request_no_address:
|
request_no_address:
|
||||||
solicit_tags = tagif;
|
solicit_tags = tagif;
|
||||||
|
address_assigned = 0;
|
||||||
|
|
||||||
if (ignore)
|
if (ignore)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -764,15 +774,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
|
|
||||||
if (address_assigned != 1)
|
if (address_assigned != 1)
|
||||||
{
|
{
|
||||||
/* If the server will not assign any addresses to any IAs in a
|
|
||||||
subsequent Request from the client, the server MUST send an Advertise
|
|
||||||
message to the client that doesn't include any IA options. */
|
|
||||||
if (!state->lease_allocate)
|
|
||||||
{
|
|
||||||
save_counter(o);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the server cannot assign any addresses to an IA in the message
|
/* If the server cannot assign any addresses to an IA in the message
|
||||||
from the client, the server MUST include the IA in the Reply message
|
from the client, the server MUST include the IA in the Reply message
|
||||||
with no addresses in the IA and a Status Code option in the IA
|
with no addresses in the IA and a Status Code option in the IA
|
||||||
@@ -799,7 +800,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
o = new_opt6(OPTION6_PREFERENCE);
|
o = new_opt6(OPTION6_PREFERENCE);
|
||||||
put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
|
put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
|
||||||
end_opt6(o);
|
end_opt6(o);
|
||||||
tagif = add_options(state, 0);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -820,6 +820,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tagif = add_options(state, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -977,8 +978,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
|||||||
{
|
{
|
||||||
if (msg_type == DHCP6REBIND)
|
if (msg_type == DHCP6REBIND)
|
||||||
{
|
{
|
||||||
/* When rebinding, we can create a lease if it doesn't exist. */
|
/* When rebinding, we can create a lease if it doesn't exist, as long
|
||||||
lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
|
as --dhcp-authoritative is set. */
|
||||||
|
if (option_bool(OPT_AUTHORITATIVE))
|
||||||
|
lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
|
||||||
if (lease)
|
if (lease)
|
||||||
lease_set_iaid(lease, state->iaid);
|
lease_set_iaid(lease, state->iaid);
|
||||||
else
|
else
|
||||||
@@ -2276,59 +2279,56 @@ int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
|
|||||||
{
|
{
|
||||||
void *opt, *opts = inbuff + 34;
|
void *opt, *opts = inbuff + 34;
|
||||||
void *end = inbuff + sz;
|
void *end = inbuff + sz;
|
||||||
for (opt = opts; opt; opt = opt6_next(opt, end))
|
|
||||||
if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
|
|
||||||
{
|
|
||||||
int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
|
|
||||||
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
|
|
||||||
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
|
|
||||||
peer->sin6_scope_id = relay->iface_index;
|
|
||||||
|
|
||||||
if (encap_type == DHCP6RELAYREPL)
|
if ((opt = opt6_find(opts, end, OPTION6_RELAY_MSG, 4)))
|
||||||
{
|
{
|
||||||
peer->sin6_port = ntohs(DHCPV6_SERVER_PORT);
|
int encap_type = opt6_uint(opt, 0, 1);
|
||||||
return 1;
|
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
|
||||||
}
|
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
|
||||||
|
peer->sin6_scope_id = relay->iface_index;
|
||||||
|
|
||||||
peer->sin6_port = ntohs(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
|
#ifdef HAVE_SCRIPT
|
||||||
if (daemon->lease_change_command && encap_type == DHCP6REPLY)
|
if (daemon->lease_change_command && encap_type == DHCP6REPLY)
|
||||||
{
|
{
|
||||||
/* decapsulate relayed message */
|
/* skip over message type and transaction-id. to get to options. */
|
||||||
opts = opt6_ptr(opt, 4);
|
opts = opt6_ptr(opt, 4);
|
||||||
end = opt6_ptr(opt, opt6_len(opt));
|
end = opt6_ptr(opt, opt6_len(opt));
|
||||||
|
|
||||||
for (opt = opts; opt; opt = opt6_next(opt, end))
|
if ((opt = opt6_find(opts, end, OPTION6_IA_PD, 12)))
|
||||||
if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12)
|
{
|
||||||
{
|
opts = opt6_ptr(opt, 12);
|
||||||
void *ia_opts = opt6_ptr(opt, 12);
|
end = opt6_ptr(opt, opt6_len(opt));
|
||||||
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))
|
for (opt = opt6_find(opts, end, OPTION6_IAPREFIX, 25); opt; opt = opt6_find(opt6_next(opt, end), end, OPTION6_IAPREFIX, 25))
|
||||||
/* valid lifetime must not be zero. */
|
/* 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 (opt6_uint(opt, 4, 4) != 0)
|
||||||
|
{
|
||||||
|
if (daemon->free_snoops ||
|
||||||
|
(daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
|
||||||
{
|
{
|
||||||
if (daemon->free_snoops ||
|
struct snoop_record *snoop = daemon->free_snoops;
|
||||||
(daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
|
|
||||||
{
|
|
||||||
struct snoop_record *snoop = daemon->free_snoops;
|
|
||||||
|
|
||||||
daemon->free_snoops = snoop->next;
|
daemon->free_snoops = snoop->next;
|
||||||
snoop->client = peer->sin6_addr;
|
snoop->client = peer->sin6_addr;
|
||||||
snoop->prefix_len = opt6_uint(ia_opt, 8, 1);
|
snoop->prefix_len = opt6_uint(opt, 8, 1);
|
||||||
memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ);
|
memcpy(&snoop->prefix, opt6_ptr(opt, 9), IN6ADDRSZ);
|
||||||
snoop->next = relay->snoop_records;
|
snoop->next = relay->snoop_records;
|
||||||
relay->snoop_records = snoop;
|
relay->snoop_records = snoop;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
|
#if defined(HAVE_BSD_IPSET)
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|||||||
+32
-3
@@ -34,6 +34,10 @@
|
|||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_BSD_NETWORK
|
||||||
|
#include <libgen.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* SURF random number generator */
|
/* SURF random number generator */
|
||||||
|
|
||||||
static u32 seed[32];
|
static u32 seed[32];
|
||||||
@@ -831,9 +835,34 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef FDESCFS
|
#ifdef FDESCFS
|
||||||
DIR *d;
|
DIR *d = NULL;
|
||||||
|
|
||||||
if ((d = opendir(FDESCFS)))
|
# ifdef HAVE_BSD_NETWORK
|
||||||
|
dev_t dirdev = 0;
|
||||||
|
char fdescfs[] = FDESCFS; /* string must be writable */
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
/* On BSD, fdescfs is normally mounted at /dev/fd. However
|
||||||
|
if it is NOT mounted, devfs creates a directory at /dev/fd
|
||||||
|
which contains (only) the file descriptors 0,1 and 2.
|
||||||
|
|
||||||
|
Under these conditions, opendir() will succeed, and
|
||||||
|
if we proceed we will fail to close extant
|
||||||
|
file descriptors which should be closed.
|
||||||
|
|
||||||
|
Check that there is a filesystem mounted at /dev/fd
|
||||||
|
by checking that the device changes between /dev/fd
|
||||||
|
and /dev. If if doesn't, fall back to the dumb path. */
|
||||||
|
|
||||||
|
if (stat(fdescfs, &statbuf) != -1)
|
||||||
|
dirdev = statbuf.st_dev;
|
||||||
|
|
||||||
|
if (stat(dirname(fdescfs), &statbuf) != -1 &&
|
||||||
|
dirdev != statbuf.st_dev)
|
||||||
|
# endif
|
||||||
|
d = opendir(FDESCFS);
|
||||||
|
|
||||||
|
if (d)
|
||||||
{
|
{
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
|
|
||||||
@@ -855,7 +884,7 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
|||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* fallback, dumb code. */
|
/* fallback, dumb code. */
|
||||||
|
|||||||
Reference in new issue
Block a user