mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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).
|
||||
|
||||
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
|
||||
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.">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
|
||||
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
||||
+26
-3
@@ -673,7 +673,7 @@ machine on which dnsmasq is running) for each
|
||||
local machine. Local machines are those in /etc/hosts or with DHCP
|
||||
leases.
|
||||
.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
|
||||
domain defaults to that given by
|
||||
.B --domain.
|
||||
@@ -1487,7 +1487,28 @@ DHCPv4 to a DHCPv6 server or vice-versa.
|
||||
The DHCP relay function for IPv6 includes the ability to snoop
|
||||
prefix-delegation from relayed DHCP transactions. See
|
||||
.B --dhcp-script
|
||||
for details.
|
||||
for details.
|
||||
.TP
|
||||
.B --dhcp-split-relay=<local address>,[<server address>[#<server port>]],<server-facing-interface>
|
||||
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 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 interface parameter is mandatory and a cannot be a wildcard.
|
||||
|
||||
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>
|
||||
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
||||
@@ -1739,7 +1760,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
|
||||
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
|
||||
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).
|
||||
.TP
|
||||
.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
|
||||
dnsmasq(8).
|
||||
</BODY>
|
||||
</HTML>
|
||||
+4
-2
@@ -2360,6 +2360,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
source = "reply";
|
||||
else if (flags & F_AUTH)
|
||||
source = "auth";
|
||||
else if (flags & F_QUERY)
|
||||
source = "query";
|
||||
else if (flags & F_SECSTAT)
|
||||
{
|
||||
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
|
||||
@@ -2400,8 +2402,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
source = "non-query opcode";
|
||||
name = opcodestring;
|
||||
}
|
||||
else if (!(flags & F_AUTH))
|
||||
source = "query";
|
||||
else if (type > 0)
|
||||
source = querystr(source, type);
|
||||
|
||||
verb = "from";
|
||||
}
|
||||
|
||||
+11
-1
@@ -290,6 +290,7 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_BSD_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
#define NO_IPSET
|
||||
/* Define before sys/socket.h is included so we get socklen_t */
|
||||
#define _BSD_SOCKLEN_T_
|
||||
/* Select the RFC_3542 version of the IPv6 socket API.
|
||||
@@ -349,7 +350,6 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_LINUX_NETWORK)
|
||||
#undef HAVE_IPSET
|
||||
#undef HAVE_NFTSET
|
||||
#endif
|
||||
|
||||
@@ -357,6 +357,16 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_IPSET
|
||||
#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
|
||||
#undef HAVE_LOOP
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -1067,10 +1067,12 @@ void log_relay(int family, struct dhcp_relay *relay)
|
||||
{
|
||||
if (broadcast)
|
||||
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
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP 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"), daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
#define SUBOPT_REMOTE_ID 2
|
||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||
#define SUBOPT_FLAGS 10 /* RFC 5010 */
|
||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||
|
||||
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
||||
|
||||
+25
-127
@@ -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);
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
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)
|
||||
{
|
||||
@@ -151,6 +149,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
struct arpreq arp_req;
|
||||
struct timeval tv;
|
||||
struct in_addr dst_addr;
|
||||
#endif
|
||||
|
||||
union {
|
||||
@@ -176,13 +175,11 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
(sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
|
||||
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 (ioctl(fd, SIOCGSTAMP, &tv) == 0)
|
||||
recvtime = tv.tv_sec;
|
||||
|
||||
dst_addr.s_addr = 0;
|
||||
|
||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
@@ -194,7 +191,8 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -224,7 +222,25 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
iface_index = *(p.i);
|
||||
}
|
||||
#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) ||
|
||||
ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
|
||||
return;
|
||||
@@ -344,7 +360,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
if (!iface_enumerate(AF_INET, &parm, (callback_t){.af_inet=complete_context}))
|
||||
return;
|
||||
|
||||
relay_upstream4(iface_index, mess, (size_t)sz);
|
||||
relay_upstream4(iface_index, mess, (size_t)sz, unicast_dest);
|
||||
|
||||
/* May have configured relay, but not DHCP server */
|
||||
if (!daemon->dhcp)
|
||||
@@ -1091,122 +1107,4 @@ char *host_from_dns(struct in_addr addr)
|
||||
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
|
||||
+15
-7
@@ -176,6 +176,7 @@ void dhcp6_packet(time_t now)
|
||||
else
|
||||
{
|
||||
struct dhcp_bridge *bridge, *alias;
|
||||
int multicast_dest = 0;
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
@@ -231,13 +232,20 @@ void dhcp6_packet(time_t now)
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
/* Ignore requests sent to the ALL_SERVERS multicast address for relay when
|
||||
we're listening there for DHCPv6 server reasons. */
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
|
||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &all_servers);
|
||||
if (IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
||||
multicast_dest = 1;
|
||||
|
||||
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers) &&
|
||||
relay_upstream6(if_index, (size_t)sz, &from.sin6_addr, from.sin6_scope_id, now))
|
||||
return;
|
||||
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}))
|
||||
return;
|
||||
@@ -266,7 +274,7 @@ void dhcp6_packet(time_t now)
|
||||
|
||||
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);
|
||||
|
||||
/* The port in the source address of the original request should
|
||||
|
||||
+1
-1
@@ -1777,9 +1777,9 @@ void clear_cache_and_reload(time_t now)
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
reread_dhcp();
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
reread_dhcp();
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
|
||||
+5
-2
@@ -1148,6 +1148,7 @@ struct dhcp_relay {
|
||||
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 port; /* Port of relay we forward to. */
|
||||
int split_mode; /* Split address allocation and relay address. */
|
||||
#ifdef HAVE_SCRIPT
|
||||
struct snoop_record {
|
||||
struct in6_addr client, prefix;
|
||||
@@ -1666,6 +1667,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
time_t recvtime, struct in_addr leasequery_source);
|
||||
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||
int clid_len, unsigned char *clid, int *len_out);
|
||||
void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz, int unicast);
|
||||
struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
|
||||
#endif
|
||||
|
||||
/* dnsmasq.c */
|
||||
@@ -1801,7 +1804,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
|
||||
|
||||
/* rfc3315.c */
|
||||
#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,
|
||||
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,
|
||||
@@ -1938,7 +1941,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);
|
||||
int server_samegroup(struct server *a, struct server *b);
|
||||
#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
|
||||
void mark_servers(int flag);
|
||||
void cleanup_servers(void);
|
||||
|
||||
+24
-8
@@ -95,6 +95,7 @@ void build_server_array(void)
|
||||
|
||||
A flag of F_SERVER returns an upstream server only.
|
||||
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_CONFIG returns anything that generates a local
|
||||
reply of IPv4 or IPV6.
|
||||
@@ -106,12 +107,23 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
||||
ssize_t qlen;
|
||||
int try, high, low = 0;
|
||||
int nlow = 0, nhigh = 0;
|
||||
char *cp, *qdomain = domain;
|
||||
|
||||
char *cp, *qdomain;
|
||||
|
||||
/* may be no configured servers. */
|
||||
if (daemon->serverarraysz == 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 '.' */
|
||||
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
|
||||
if (*cp == '.')
|
||||
@@ -244,7 +256,10 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
||||
if (nodots &&
|
||||
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
|
||||
(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)
|
||||
*lowout = nlow;
|
||||
@@ -343,7 +358,8 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
else
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
@@ -399,7 +415,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
||||
|
||||
setup_reply(header, flags, ede);
|
||||
|
||||
gotname &= ~F_QUERY;
|
||||
gotname &= ~(F_QUERY | F_DS);
|
||||
|
||||
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||
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
|
||||
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;
|
||||
|
||||
|
||||
/* Find server to send DNSSEC query to. This will normally be the
|
||||
same as for the original query, but may be another if
|
||||
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;
|
||||
|
||||
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))
|
||||
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 */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
|
||||
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
|
||||
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]) &&
|
||||
(nn = dnssec_generate_query(header, ((unsigned char *) header) + daemon->edns_pktsz,
|
||||
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;
|
||||
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;
|
||||
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,
|
||||
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;
|
||||
break;
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_IPSET)
|
||||
#if defined(HAVE_LINUX_IPSET)
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
+27
-6
@@ -196,6 +196,7 @@ struct myoption {
|
||||
#define LOPT_NO_ENCODE 387
|
||||
#define LOPT_DO_ENCODE 388
|
||||
#define LOPT_LEASEQUERY 389
|
||||
#define LOPT_SPLIT_RELAY 390
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -374,6 +375,7 @@ static const struct myoption opts[] =
|
||||
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
|
||||
{ "dnssec-limits", 1, 0, LOPT_DNSSEC_LIMITS },
|
||||
{ "dhcp-relay", 1, 0, LOPT_RELAY },
|
||||
{ "dhcp-split-relay", 1, 0, LOPT_SPLIT_RELAY },
|
||||
{ "ra-param", 1, 0, LOPT_RA_PARAM },
|
||||
{ "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
|
||||
{ "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_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_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_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 },
|
||||
@@ -2917,13 +2920,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
break;
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
# endif
|
||||
case LOPT_LEASEQUERY:
|
||||
set_option_bool(OPT_LEASEQUERY);
|
||||
if (!arg)
|
||||
break;
|
||||
#pragma GCC diagnostic pop
|
||||
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
case 'B': /* --bogus-nxdomain */
|
||||
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;
|
||||
|
||||
case LOPT_RELAY: /* --dhcp-relay */
|
||||
case LOPT_SPLIT_RELAY: /* --dhcp-splt-relay */
|
||||
{
|
||||
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
|
||||
char *two = split(arg);
|
||||
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;
|
||||
|
||||
if (two)
|
||||
@@ -4744,7 +4761,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->relay4 = new;
|
||||
}
|
||||
#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, '#');
|
||||
|
||||
@@ -4765,7 +4782,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->relay6 = new;
|
||||
}
|
||||
#endif
|
||||
|
||||
else
|
||||
two = NULL;
|
||||
|
||||
new->interface = opt_string_alloc(three);
|
||||
}
|
||||
|
||||
@@ -6258,6 +6277,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
strchr(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);
|
||||
strcat(buff, ".");
|
||||
strcat(buff, daemon->domain_suffix);
|
||||
|
||||
+3
-4
@@ -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) == 0x00000000) && ban_localhost) /* RFC 5735 section 3. "here" network */ ||
|
||||
((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 & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
|
||||
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
|
||||
@@ -1244,12 +1245,10 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
||||
return F_IPV4 | F_IPV6;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Make the behaviour for DS and DNSKEY queries we forward the same
|
||||
as for DS and DNSKEY queries we originate. */
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DS || qtype == T_DNSKEY))
|
||||
return F_DNSSECOK;
|
||||
#endif
|
||||
if (qtype == T_DS || qtype == T_DNSKEY)
|
||||
return F_DNSSECOK | (qtype == T_DS ? F_DS : 0);
|
||||
|
||||
return F_QUERY;
|
||||
}
|
||||
|
||||
+195
-1
@@ -204,6 +204,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
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 */
|
||||
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
|
||||
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;
|
||||
force = 1;
|
||||
if (mess->giaddr.s_addr)
|
||||
via_relay = 1;
|
||||
}
|
||||
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)
|
||||
context_tmp->local = fallback;
|
||||
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 */
|
||||
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
|
||||
@@ -3044,4 +3055,187 @@ static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
|
||||
}
|
||||
}
|
||||
|
||||
void relay_upstream4(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)
|
||||
return;
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
if (relay->iface_index != 0 && relay->iface_index == iface_index)
|
||||
{
|
||||
union mysockaddr to;
|
||||
union all_addr from;
|
||||
struct ifreq ifr;
|
||||
|
||||
/* restore orig packet */
|
||||
mess->hops = hops;
|
||||
mess->giaddr = giaddr;
|
||||
if (endopt)
|
||||
*endopt = OPTION_END;
|
||||
sz = orig_sz;
|
||||
|
||||
if ((mess->hops++) > 20)
|
||||
continue;
|
||||
|
||||
if (relay->interface)
|
||||
{
|
||||
safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
}
|
||||
|
||||
if (!relay->split_mode)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* plug in our address */
|
||||
from.addr4 = mess->giaddr = relay->local.addr4;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Split mode. We put our address on the server-facing interface
|
||||
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. */
|
||||
|
||||
/* get our address on the server-facing interface. */
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
||||
continue;
|
||||
|
||||
/* already gatewayed ? */
|
||||
if (giaddr.s_addr)
|
||||
{
|
||||
/* if so check if by us, to stomp on loops. */
|
||||
if (giaddr.s_addr == ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* giaddr is our address on the outgoing interface in split mode. */
|
||||
from.addr4 = mess->giaddr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
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 (3 bytes).
|
||||
New END option is a 18th byte, so we need 18 bytes free.
|
||||
We only need to do this once, and poke the address into the same place each time. */
|
||||
|
||||
if (!(endopt = option_find1((&mess->options[0] + sizeof(u32)), ((unsigned char *)mess) + sz, OPTION_END, 0)) ||
|
||||
(endopt + 18 > (unsigned char *)(mess + 1)))
|
||||
continue;
|
||||
|
||||
endopt[1] = 15; /* 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] = OPTION_END;
|
||||
sz = (endopt - (unsigned char *)mess) + 18;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
endopt[0] = OPTION_AGENT_ID;
|
||||
}
|
||||
|
||||
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 (!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->hops = hops;
|
||||
mess->giaddr = giaddr;
|
||||
if (endopt)
|
||||
*endopt = OPTION_END;
|
||||
}
|
||||
|
||||
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 (relay->split_mode)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
safe_strncpy(ifr.ifr_name, arrival_interface, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
/* giaddr is our address on the returning interface in split mode. */
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1 ||
|
||||
mess->giaddr.s_addr != ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr)
|
||||
continue;
|
||||
}
|
||||
else if (mess->giaddr.s_addr != relay->local.addr4.s_addr)
|
||||
continue;
|
||||
|
||||
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
|
||||
return relay->iface_index != 0 ? relay : NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_DHCP */
|
||||
+81
-81
@@ -21,7 +21,7 @@
|
||||
|
||||
struct state {
|
||||
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;
|
||||
struct dhcp_context *context;
|
||||
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))
|
||||
|
||||
|
||||
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,
|
||||
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();
|
||||
state.context = context;
|
||||
state.multicast_dest = multicast_dest;
|
||||
state.interface = interface;
|
||||
state.iface_name = iface_name;
|
||||
state.fallback = fallback;
|
||||
@@ -244,7 +245,11 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
|
||||
struct in6_addr align;
|
||||
/* the packet data is unaligned, copy to aligned storage */
|
||||
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
|
||||
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))
|
||||
@@ -333,20 +338,24 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
else if (msg_type != DHCP6IREQ)
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
else if (msg_type == DHCP6IREQ)
|
||||
{
|
||||
/* If server-id provided, it must match. */
|
||||
if (opt && (opt6_len(opt) != daemon->duid_len ||
|
||||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
|
||||
|
||||
/* server-id must match except for SOLICIT, CONFIRM and REBIND messages, which MUST NOT
|
||||
have a server-id. 3315 para 15.x */
|
||||
if (msg_type == DHCP6IREQ)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
else
|
||||
@@ -634,7 +643,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
|
||||
case DHCP6SOLICIT:
|
||||
{
|
||||
int address_assigned = 0;
|
||||
int address_assigned;
|
||||
/* tags without all prefix-class tags */
|
||||
struct dhcp_netid *solicit_tags;
|
||||
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:
|
||||
solicit_tags = tagif;
|
||||
address_assigned = 0;
|
||||
|
||||
if (ignore)
|
||||
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 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
|
||||
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
|
||||
@@ -799,7 +800,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
o = new_opt6(OPTION6_PREFERENCE);
|
||||
put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
|
||||
end_opt6(o);
|
||||
tagif = add_options(state, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -819,7 +819,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tagif = add_options(state, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -977,8 +978,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||||
{
|
||||
if (msg_type == DHCP6REBIND)
|
||||
{
|
||||
/* When rebinding, we can create a lease if it doesn't exist. */
|
||||
lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
|
||||
/* When rebinding, we can create a lease if it doesn't exist, as long
|
||||
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)
|
||||
lease_set_iaid(lease, state->iaid);
|
||||
else
|
||||
@@ -2276,64 +2279,61 @@ int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
|
||||
{
|
||||
void *opt, *opts = inbuff + 34;
|
||||
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)
|
||||
{
|
||||
peer->sin6_port = ntohs(DHCPV6_SERVER_PORT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
peer->sin6_port = ntohs(DHCPV6_CLIENT_PORT);
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (daemon->lease_change_command && encap_type == DHCP6REPLY)
|
||||
{
|
||||
/* decapsulate relayed message */
|
||||
opts = opt6_ptr(opt, 4);
|
||||
end = opt6_ptr(opt, opt6_len(opt));
|
||||
|
||||
for (opt = opts; opt; opt = opt6_next(opt, end))
|
||||
if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12)
|
||||
{
|
||||
void *ia_opts = opt6_ptr(opt, 12);
|
||||
void *ia_end = opt6_ptr(opt, opt6_len(opt));
|
||||
void *ia_opt;
|
||||
|
||||
for (ia_opt = ia_opts; ia_opt; ia_opt = opt6_next(ia_opt, ia_end))
|
||||
/* valid lifetime must not be zero. */
|
||||
if (opt6_type(ia_opt) == OPTION6_IAPREFIX && opt6_len(ia_opt) >= 25 && opt6_uint(ia_opt, 4, 4) != 0)
|
||||
{
|
||||
if (daemon->free_snoops ||
|
||||
(daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
|
||||
{
|
||||
struct snoop_record *snoop = daemon->free_snoops;
|
||||
|
||||
daemon->free_snoops = snoop->next;
|
||||
snoop->client = peer->sin6_addr;
|
||||
snoop->prefix_len = opt6_uint(ia_opt, 8, 1);
|
||||
memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ);
|
||||
snoop->next = relay->snoop_records;
|
||||
relay->snoop_records = snoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((opt = opt6_find(opts, end, OPTION6_RELAY_MSG, 4)))
|
||||
{
|
||||
int encap_type = opt6_uint(opt, 0, 1);
|
||||
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)
|
||||
{
|
||||
peer->sin6_port = ntohs(DHCPV6_SERVER_PORT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
peer->sin6_port = ntohs(DHCPV6_CLIENT_PORT);
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (daemon->lease_change_command && encap_type == DHCP6REPLY)
|
||||
{
|
||||
/* skip over message type and transaction-id. to get to options. */
|
||||
opts = opt6_ptr(opt, 4);
|
||||
end = opt6_ptr(opt, opt6_len(opt));
|
||||
|
||||
if ((opt = opt6_find(opts, end, OPTION6_IA_PD, 12)))
|
||||
{
|
||||
opts = opt6_ptr(opt, 12);
|
||||
end = opt6_ptr(opt, opt6_len(opt));
|
||||
|
||||
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. */
|
||||
if (opt6_uint(opt, 4, 4) != 0)
|
||||
{
|
||||
if (daemon->free_snoops ||
|
||||
(daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
|
||||
{
|
||||
struct snoop_record *snoop = daemon->free_snoops;
|
||||
|
||||
daemon->free_snoops = snoop->next;
|
||||
snoop->client = peer->sin6_addr;
|
||||
snoop->prefix_len = opt6_uint(opt, 8, 1);
|
||||
memcpy(&snoop->prefix, opt6_ptr(opt, 9), IN6ADDRSZ);
|
||||
snoop->next = relay->snoop_records;
|
||||
relay->snoop_records = snoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
int do_snoop_script_run(void)
|
||||
{
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
|
||||
#if defined(HAVE_BSD_IPSET)
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
+33
-4
@@ -34,6 +34,10 @@
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
/* SURF random number generator */
|
||||
|
||||
static u32 seed[32];
|
||||
@@ -831,9 +835,34 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
||||
#endif
|
||||
|
||||
#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;
|
||||
|
||||
@@ -855,9 +884,9 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
||||
|
||||
closedir(d);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* fallback, dumb code. */
|
||||
for (max_fd--; max_fd >= 0; max_fd--)
|
||||
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&
|
||||
|
||||
Reference in new issue
Block a user