Compare commits

...
14 Commits
22 changed files with 932 additions and 220 deletions

No files matched your search

+6
View File
@@ -58,6 +58,12 @@ version 2.60
tested alpha code, it is NOT YET PRODUCTION READY. Test
reports would be greatly valued.
Support IPv6 router advertisements. This is a
simple-minded implementation, aimed at providing the
vestigial RA needed to go alongside IPv6. Is picks up
configuration from the DHCPv6 conf, and should just need
enabling with --enable-ra.
version 2.59
Fix regression in 2.58 which caused failure to start up
+4 -2
View File
@@ -47,9 +47,11 @@ VERSION= -DVERSION='\"`../bld/get-version`\"'
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o dhcp-common.o
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o
HDRS = dnsmasq.h config.h dhcp_protocol.h dhcp6_protocol.h dns_protocol.h
HDRS = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h
all : $(BUILDDIR)
+2 -1
View File
@@ -7,7 +7,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
forward.c helper.c lease.c log.c \
netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c
LOCAL_MODULE := dnsmasq
+2 -2
View File
@@ -18,10 +18,10 @@ elif grep '\$Format:%d\$' VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
echo UNKNOWN
else
vers=`cat VERSION | sed 's/[(), ]/\n/ g' | grep -m 1 $v[0-9]`
vers=`cat VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep $v[0-9]`
if [ $? -eq 0 ]; then
echo ${vers#v}
echo "${vers}" | head -n 1 | tail -c +2
else
cat VERSION
fi
+16
View File
@@ -157,6 +157,13 @@
# an explicit netmask instead.
#dhcp-range=192.168.0.0,static
# Enable DHCPv6. Note that the prefix-length does not need to be specified
# and defaults to 64 if missing/
#dhcp-range=1234::2, 1234::500, 64, 12h
# Not Router Advertisements, BUT NOT DHCP for this subnet.
#dhcp-range=1234::, ra-only
# Supply parameters for specified hosts using DHCP. There are lots
# of valid alternatives, so we will give examples of each. Note that
# IP addresses DO NOT have to be in the range given above, they just
@@ -219,6 +226,12 @@
# any machine with Ethernet address starting 11:22:33:
#dhcp-host=11:22:33:*:*:*,set:red
# Give a fixed IPv6 address and name to client with
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
# Note also the they [] around the IPv6 address are obilgatory.
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
# Ignore any clients which are not specified in dhcp-host lines
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
# This relies on the special "known" tag which is set when
@@ -270,6 +283,9 @@
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
# Send DHCPv6 option. Note [] around IPv6 addresses.
dhcp-option=option6:dns-server,[1234::77],[1234::88]
# Set the NTP time server address to be the same machine as
# is running dnsmasq
#dhcp-option=42,0.0.0.0
+28 -2
View File
@@ -529,14 +529,18 @@ The optional
sets an alphanumeric label which marks this network so that
dhcp options may be specified on a per-network basis.
When it is prefixed with 'tag:' instead, then its meaning changes from setting
a tag to matching it. Only one tag may be set, but more than one tag may be matched.
a tag to matching it. Only one tag may be set, but more than one tag
may be matched.
The end address may be replaced by the keyword
.B static
which tells dnsmasq to enable DHCP for the network specified, but not
to dynamically allocate IP addresses: only hosts which have static
addresses given via
.B dhcp-host
or from /etc/ethers will be served. The end address may be replaced by
or from /etc/ethers will be served.
The end address may be replaced by
the keyword
.B proxy
in which case dnsmasq will provide proxy-DHCP on the specified
@@ -546,6 +550,14 @@ and
.B pxe-service
for details, applies to IPv4 only.)
The end address may be replaced by
the keyword
.B ra-only
which tells dnsmasq to offer Router Advertisement only on this subnet,
and not DHCP. This applies to IPv6 only, see
.B enable-ra
for details.
The interface:<interface name> section is not normally used. See the
NOTES section for details of this.
.TP
@@ -1234,6 +1246,20 @@ added into dnsmasq's DNS view. This flag suppresses that behaviour,
this is useful, for instance, to allow Windows clients to update
Active Directory servers. See RFC 4702 for details.
.TP
.B --enable-ra
Enable dnsmasq's IPv6 Router Advertisement feature. DHCPv6 doesn't
handle complete network configuration in the same way as DHCPv4. Router
discovery and (possibly) prefix discovery for autonomous address
creation are handled by a different protocol. When DHCP is in use,
only a subset of this is needed, and dnsmasq can handle it, using
existing DHCP configuration to provide most data. When RA is enabled,
dnsmasq will advertise a prefix for each dhcp-range, with default
router and recursive DNS server as the relevant link-local address on
the machine running dnsmasq. The "managed address" bits are set,
except for a dhcp-range which is marked as "ra-only". In which case RA
is provided by no DHCPv6 service and the managed address bits are
cleared.
.TP
.B --enable-tftp[=<interface>]
Enable the TFTP server function. This is deliberately limited to that
needed to net-boot a client. Only reading is allowed; the tsize and
+2 -1
View File
@@ -199,7 +199,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
{
/* Assume ethernet again here */
struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
if (sdl->sdl_alen != 0 && !((*callback)(ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
if (sdl->sdl_alen != 0 && !((*callback)((int)if_nametoindex(ifr->ifr_name),
ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
goto err;
}
#endif
+89 -3
View File
@@ -53,14 +53,14 @@ ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
/* Very new Linux kernels return the actual size needed,
older ones always return truncated size */
if ((size_t)sz == daemon->dhcp_packet.iov_len)
if ((size_t)sz == msg->msg_iov->iov_len)
{
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
if (!expand_buf(msg->msg_iov, sz + 100))
return -1;
}
else
{
expand_buf(&daemon->dhcp_packet, sz);
expand_buf(msg->msg_iov, sz);
break;
}
}
@@ -358,4 +358,90 @@ void dhcp_update_configs(struct dhcp_config *configs)
}
#ifdef HAVE_DHCP6
static int join_multicast_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
int fd, i, max = *((int *)vparam);
struct dhcp_context *context;
struct iname *tmp;
(void)prefix;
(void)scope;
(void)dad;
/* record which interfaces we join on, so that we do it at most one per
interface, even when they have multiple addresses. Use outpacket
as an array of int, since it's always allocated here and easy
to expand for theoretical vast numbers of interfaces. */
for (i = 0; i < max; i++)
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
return 1;
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
return 0;
if (!indextoname(fd, if_index, ifrn_name))
{
close(fd);
return 0;
}
close(fd);
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
break;
if (!context)
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->ra_contexts &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
((int *)daemon->outpacket.iov_base)[max++] = if_index;
*((int *)vparam) = max;
return 1;
}
void join_multicast(void)
{
int count = 0;
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
}
#endif
#endif
File renamed without changes.
File renamed without changes.
+9 -88
View File
@@ -24,24 +24,15 @@ struct iface_param {
int ind;
};
struct listen_param {
int fd_or_iface;
struct listen_param *next;
};
static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
static int make_duid1(unsigned int type, char *mac, size_t maclen, void *parm);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
void dhcp6_init(void)
{
int fd;
struct sockaddr_in6 saddr;
struct listen_param *listenp, listen;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6;
#endif
@@ -65,81 +56,9 @@ void dhcp6_init(void)
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
/* join multicast groups on each interface we're interested in */
listen.fd_or_iface = fd;
listen.next = NULL;
if (!iface_enumerate(AF_INET6, &listen, join_multicast))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
for (listenp = listen.next; listenp; )
{
struct listen_param *tmp = listenp->next;
free(listenp);
listenp = tmp;
}
daemon->dhcp6fd = fd;
}
static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
struct listen_param *listenp, *param = vparam;
int fd = param->fd_or_iface;
struct dhcp_context *context;
struct iname *tmp;
(void)prefix;
(void)scope;
(void)dad;
/* record which interfaces we join on, so
that we do it at most one per interface, even when they
have multiple addresses */
for (listenp = param->next; listenp; listenp = listenp->next)
if (if_index == listenp->fd_or_iface)
return 1;
if (!indextoname(fd, if_index, ifrn_name))
return 0;
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
break;
if (!context)
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
listenp = whine_malloc(sizeof(struct listen_param));
listenp->fd_or_iface = if_index;
listenp->next = param->next;
param->next = listenp;
return 1;
}
void dhcp6_packet(time_t now)
{
struct dhcp_context *context;
@@ -151,7 +70,7 @@ void dhcp6_packet(time_t now)
struct cmsghdr align; /* this ensures alignment */
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
} control_u;
union mysockaddr from;
struct sockaddr_in6 from;
struct all_addr dest;
ssize_t sz;
struct ifreq ifr;
@@ -215,14 +134,14 @@ void dhcp6_packet(time_t now)
lease_prune(NULL, now); /* lose any expired leases */
msg.msg_iov = &daemon->dhcp_packet;
sz = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, sz, IN6_IS_ADDR_MULTICAST(&from.in6.sin6_addr), now);
sz = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
lease_update_file(now);
lease_update_dns();
if (sz != 0)
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, sz, 0, (struct sockaddr *)&from, sizeof(from)) &&
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, sz, 0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
retry_send());
}
@@ -244,7 +163,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
memcpy(&param->fallback, &local, IN6ADDRSZ);
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
{
@@ -455,13 +374,15 @@ void make_duid(time_t now)
die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
}
static int make_duid1(unsigned int type, char *mac, size_t maclen, void *parm)
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm)
{
/* create DUID as specified in RFC3315. We use the MAC of the
first interface we find that isn't loopback or P-to-P */
unsigned char *p;
(void)index;
daemon->duid = p = safe_malloc(maclen + 8);
daemon->duid_len = maclen + 8;
File renamed without changes.
+88 -9
View File
@@ -154,18 +154,41 @@ int main (int argc, char **argv)
before lease_init to allocate buffers it uses.*/
dhcp_common_init();
lease_init(now);
if (daemon->dhcp)
dhcp_init();
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
dhcp6_init();
#endif
}
# ifdef HAVE_DHCP6
/* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
if (daemon->ra_contexts || option_bool(OPT_RA))
{
/* link the DHCP6 contexts to the ra-only ones so we can traverse them all
from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
struct dhcp_context *context;
if (!daemon->ra_contexts)
daemon->ra_contexts = daemon->dhcp6;
else
{
for (context = daemon->ra_contexts; context->next; context = context->next);
context->next = daemon->dhcp6;
}
ra_init(now);
}
if (daemon->dhcp6)
dhcp6_init();
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
# endif
#endif
if (!enumerate_interfaces())
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
if (option_bool(OPT_NOWILD))
{
create_bound_listeners(1);
@@ -205,7 +228,8 @@ int main (int argc, char **argv)
#if defined(HAVE_SCRIPT)
/* Note getpwnam returns static storage */
if ((daemon->dhcp || daemon->dhcp6) && daemon->scriptuser &&
if ((daemon->dhcp || daemon->dhcp6) &&
daemon->scriptuser &&
(daemon->lease_change_command || daemon->luascript))
{
if ((ent_pw = getpwnam(daemon->scriptuser)))
@@ -495,6 +519,9 @@ int main (int argc, char **argv)
if (daemon->max_logs != 0)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
if (daemon->ra_contexts)
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
@@ -525,6 +552,8 @@ int main (int argc, char **argv)
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_RA_ONLY) ?
_("router advertisement only on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("DHCP, proxy on subnet %.0s%s%.0s") :
_("DHCP, IP range %s -- %s, lease time %s"),
@@ -535,7 +564,10 @@ int main (int argc, char **argv)
if (family == AF_INET)
{
family = AF_INET6;
dhcp_tmp = daemon->dhcp6;
if (daemon->ra_contexts)
dhcp_tmp = daemon->ra_contexts;
else
dhcp_tmp = daemon->dhcp6;
goto again;
}
#endif
@@ -652,7 +684,13 @@ int main (int argc, char **argv)
if (daemon->dhcp6)
{
FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd);
bump_maxfd(daemon->dhcp6fd, &maxfd);
if (daemon->ra_contexts)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
}
}
#endif
@@ -756,6 +794,9 @@ int main (int argc, char **argv)
{
if (FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
}
#endif
@@ -808,6 +849,11 @@ static void sig_handler(int sig)
}
}
void send_alarm(void)
{
send_event(pipewrite, EVENT_ALARM, 0, NULL);
}
void send_event(int fd, int event, int data, char *msg)
{
struct event_desc ev;
@@ -925,6 +971,16 @@ static void async_event(int pipe, time_t now)
lease_prune(NULL, now);
lease_update_file(now);
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
{
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
time_t next_event = periodic_ra(now);
if (next_event != 0)
alarm((unsigned)difftime(next_event, now));
}
#endif
#endif
break;
@@ -1089,6 +1145,16 @@ void clear_cache_and_reload(time_t now)
lease_update_file(now);
lease_update_dns();
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
{
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
time_t next_event = periodic_ra(now);
if (next_event != 0)
alarm((unsigned)difftime(next_event, now));
}
#endif
#endif
}
@@ -1372,7 +1438,15 @@ int icmp_ping(struct in_addr addr)
FD_SET(fd, &rset);
set_dns_listeners(now, &rset, &maxfd);
set_log_writer(&wset, &maxfd);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
}
#endif
if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
{
FD_ZERO(&rset);
@@ -1384,6 +1458,11 @@ int icmp_ping(struct in_addr addr)
check_log_writer(&wset);
check_dns_listeners(&rset, now);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
#endif
#ifdef HAVE_TFTP
check_tftp_listeners(&rset, now);
#endif
+36 -6
View File
@@ -56,10 +56,11 @@ typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#include "dns_protocol.h"
#include "dhcp_protocol.h"
#include "dns-protocol.h"
#include "dhcp-protocol.h"
#ifdef HAVE_DHCP6
#include "dhcp6_protocol.h"
#include "dhcp6-protocol.h"
#include "radv-protocol.h"
#endif
#define gettext_noop(S) (S)
@@ -215,7 +216,8 @@ struct event_desc {
#define OPT_CONSEC_ADDR 34
#define OPT_CONNTRACK 35
#define OPT_FQDN_UPDATE 36
#define OPT_LAST 37
#define OPT_RA 37
#define OPT_LAST 38
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -605,6 +607,7 @@ struct dhcp_context {
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix;
time_t ra_time;
#endif
int flags;
char *interface;
@@ -616,6 +619,8 @@ struct dhcp_context {
#define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8
#define CONTEXT_RA_ONLY 16
#define CONTEXT_RA_DONE 32
struct ping_result {
struct in_addr addr;
@@ -694,7 +699,7 @@ extern struct daemon {
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6;
struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_vendor *dhcp_vendors;
@@ -754,7 +759,7 @@ extern struct daemon {
int duid_len;
unsigned char *duid;
struct iovec outpacket;
int dhcp6fd;
int dhcp6fd, icmp6fd;
#endif
/* DBus stuff */
/* void * here to avoid depending on dbus headers outside dbus.c */
@@ -962,6 +967,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int make_icmp_sock(void);
int icmp_ping(struct in_addr addr);
#endif
void send_alarm(void);
void send_event(int fd, int event, int data, char *msg);
void clear_cache_and_reload(time_t now);
void poll_resolv(int force, int do_reload, time_t now);
@@ -1053,4 +1059,28 @@ void log_tags(struct dhcp_netid *netid, u32 xid);
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
void dhcp_update_configs(struct dhcp_config *configs);
void check_dhcp_hosts(int fatal);
# ifdef HAVE_DHCP6
void join_multicast(void);
# endif
#endif
/* outpacket.c */
#ifdef HAVE_DHCP6
void end_opt6(int container);
int save_counter(int newval);
void *expand(size_t headroom);
int new_opt6(int opt);
void *put_opt6(void *data, size_t len);
void put_opt6_long(unsigned int val);
void put_opt6_short(unsigned int val);
void put_opt6_char(unsigned int val);
void put_opt6_string(char *s);
#endif
/* radv.c */
#ifdef HAVE_DHCP6
void ra_init(time_t now);
void icmp6_packet(void);
time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now);
#endif
+3
View File
@@ -106,8 +106,11 @@ void send_from(int fd, int nowild, char *packet, size_t len,
msg.msg_controllen = 0;
goto retry;
}
if (retry_send())
goto retry;
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
}
}
+9 -1
View File
@@ -313,7 +313,15 @@ void lease_update_file(time_t now)
}
/* Set alarm for when the first lease expires + slop. */
for (next_event = 0, lease = leases; lease; lease = lease->next)
next_event = 0;
#ifdef HAVE_DHCP6
/* do timed RAs and determine when the next is */
if (daemon->ra_contexts)
next_event = periodic_ra(now);
#endif
for (lease = leases; lease; lease = lease->next)
if (lease->expires != 0 &&
(next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
next_event = lease->expires + 10;
+12 -1
View File
@@ -284,7 +284,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
if (mac && callback_ok && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) &&
!((*callback)((unsigned int)link->ifi_type, mac, maclen, parm)))
!((*callback)((int)link->ifi_index, (unsigned int)link->ifi_type, mac, maclen, parm)))
callback_ok = 0;
}
#endif
@@ -341,6 +341,17 @@ static void nl_routechange(struct nlmsghdr *h)
/* Force re-reading resolv file right now, for luck. */
daemon->last_resolv = 0;
#ifdef HAVE_DHCP6
/* force RAs to sync new network and pick up new interfaces. */
if (daemon->ra_contexts)
{
ra_start_unsolicted(dnsmasq_time());
/* cause lease_update_file to run after we return, in case we were called from
iface_enumerate and can't re-enter it now */
send_alarm();
}
#endif
if (daemon->srv_save)
{
if (daemon->srv_save->sfd)
+30 -2
View File
@@ -114,6 +114,7 @@ struct myoption {
#define LOPT_CONNTRACK 303
#define LOPT_FQDN 304
#define LOPT_LUASCRIPT 305
#define LOPT_RA 306
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -233,6 +234,7 @@ static const struct myoption opts[] =
{ "conntrack", 0, 0, LOPT_CONNTRACK },
{ "dhcp-client-update", 0, 0, LOPT_FQDN },
{ "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
{ "enable-ra", 0, 0, LOPT_RA },
{ NULL, 0, 0, 0 }
};
@@ -359,6 +361,7 @@ static struct {
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
{ 0, 0, NULL, NULL, NULL }
};
@@ -2330,17 +2333,32 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, a[0], &new->start6))
{
new->next = daemon->dhcp6;
new->prefix = 64; /* default */
daemon->dhcp6 = new;
if (strcmp(a[1], "static") == 0)
{
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
new->flags |= CONTEXT_STATIC;
}
else if (strcmp(a[1], "ra-only") == 0)
{
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
new->flags |= CONTEXT_RA_ONLY;
}
else if (!inet_pton(AF_INET6, a[1], &new->end6))
option = '?';
if (new->flags & CONTEXT_RA_ONLY)
{
new->next = daemon->ra_contexts;
daemon->ra_contexts = new;
}
else
{
new->next = daemon->dhcp6;
daemon->dhcp6 = new;
}
/* bare integer < 128 is prefix value */
if (option != '?' && k >= 3)
{
@@ -2403,6 +2421,16 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
}
}
}
#ifdef HAVE_DHCP6
/* lifetimes must be min 2 hrs, by RFC 2462.
This gets enforced in radv.c for DHCP ranges
which are legitimately less. */
if ((new->flags & CONTEXT_RA_ONLY) &&
new->lease_time < 7200)
new->lease_time = 7200;
#endif
break;
}
+108
View File
@@ -0,0 +1,108 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_DHCP6
static size_t outpacket_counter;
void end_opt6(int container)
{
void *p = daemon->outpacket.iov_base + container + 2;
u16 len = outpacket_counter - container - 4 ;
PUTSHORT(len, p);
}
int save_counter(int newval)
{
int ret = outpacket_counter;
if (newval != -1)
outpacket_counter = newval;
return ret;
}
void *expand(size_t headroom)
{
void *ret;
if (expand_buf(&daemon->outpacket, outpacket_counter + headroom))
{
ret = daemon->outpacket.iov_base + outpacket_counter;
outpacket_counter += headroom;
return ret;
}
return NULL;
}
int new_opt6(int opt)
{
int ret = outpacket_counter;
void *p;
if ((p = expand(4)))
{
PUTSHORT(opt, p);
PUTSHORT(0, p);
}
return ret;
}
void *put_opt6(void *data, size_t len)
{
void *p;
if ((p = expand(len)))
memcpy(p, data, len);
return p;
}
void put_opt6_long(unsigned int val)
{
void *p;
if ((p = expand(4)))
PUTLONG(val, p);
}
void put_opt6_short(unsigned int val)
{
void *p;
if ((p = expand(2)))
PUTSHORT(val, p);
}
void put_opt6_char(unsigned int val)
{
unsigned char *p;
if ((p = expand(1)))
*p = val;
}
void put_opt6_string(char *s)
{
put_opt6(s, strlen(s));
}
#endif
+44
View File
@@ -0,0 +1,44 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define ALL_HOSTS "FF02::1"
#define ALL_ROUTERS "FF02::2"
struct ra_packet {
u8 type, code;
u16 checksum;
u8 hop_limit, flags;
u16 lifetime;
u32 reachable_time;
u32 retrans_time;
};
struct prefix_opt {
u8 type, len, prefix_len, flags;
u32 valid_lifetime, preferred_lifetime, reserved;
struct in6_addr prefix;
};
#define ICMP6_ROUTER_SOLICIT 133
#define ICMP6_ROUTER_ADVERT 134
#define ICMP6_OPT_SOURCE_MAC 1
#define ICMP6_OPT_PREFIX 3
#define ICMP6_OPT_MTU 5
#define ICMP6_OPT_RDNSS 25
+424
View File
@@ -0,0 +1,424 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
It therefore cannot use any DHCP buffer resources except outpacket, which is
not used by DHCPv4 code. This code may also be called when DHCP 4 or 6 isn't
active, so we ensure that outpacket is allocated here too */
#include "dnsmasq.h"
#ifdef HAVE_DHCP6
#include <netinet/icmp6.h>
struct ra_param {
int ind, managed, found_context, first;
char *if_name;
struct in6_addr link_local;
};
struct search_param {
time_t now; int iface;
};
static void send_ra(int iface, char *iface_name, struct in6_addr *dest);
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static int hop_limit;
static time_t ra_short_period_start;
void ra_init(time_t now)
{
struct icmp6_filter filter;
int fd;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6;
#endif
int val = 255; /* radvd uses this value */
size_t len = sizeof(int);
/* ensure this is around even if we're not doing DHCPv6 */
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
#endif
!fix_fd(fd) ||
!set_ipv6pktinfo(fd) ||
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
daemon->icmp6fd = fd;
ra_start_unsolicted(now);
}
void ra_start_unsolicted(time_t now)
{
struct dhcp_context *context;
/* init timers so that we do ra's for all soon. some ra_times will end up zeroed
if it's not appropriate to advertise those contexts.
This gets re-called on a netlink route-change to re-do the advertisement
and pick up new interfaces */
/* range 0 - 5 */
for (context = daemon->ra_contexts; context; context = context->next)
context->ra_time = now + (rand16()/13000);
/* re-do frequently for a minute or so, in case the first gets lost. */
ra_short_period_start = now;
}
void icmp6_packet(void)
{
char interface[IF_NAMESIZE+1];
ssize_t sz;
int if_index = 0;
struct cmsghdr *cmptr;
struct msghdr msg;
union {
struct cmsghdr align; /* this ensures alignment */
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
} control_u;
struct sockaddr_in6 from;
unsigned char *p;
char *mac = "";
struct iname *tmp;
struct dhcp_context *context;
/* Note: use outpacket for input buffer */
msg.msg_control = control_u.control6;
msg.msg_controllen = sizeof(control_u);
msg.msg_flags = 0;
msg.msg_name = &from;
msg.msg_namelen = sizeof(from);
msg.msg_iov = &daemon->outpacket;
msg.msg_iovlen = 1;
if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
return;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
{
union {
unsigned char *c;
struct in6_pktinfo *p;
} p;
p.c = CMSG_DATA(cmptr);
if_index = p.p->ipi6_ifindex;
}
if (!indextoname(daemon->icmp6fd, if_index, interface))
return;
if (!iface_check(AF_LOCAL, NULL, interface))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, interface) == 0))
return;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, interface) == 0)
break;
if (!context)
return;
p = (unsigned char *)daemon->outpacket.iov_base;
if (p[0] != ICMP6_ROUTER_SOLICIT || p[1] != 0)
return;
/* look for link-layer address option for logging */
if (sz >= 16 && p[8] == ICMP6_OPT_SOURCE_MAC && (p[9] * 8) + 8 <= sz)
{
print_mac(daemon->namebuff, &p[10], (p[9] * 8) - 2);
mac = daemon->namebuff;
}
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
send_ra(if_index, interface, &from.sin6_addr);
}
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
{
struct ra_packet *ra;
struct ra_param parm;
struct ifreq ifr;
struct sockaddr_in6 addr;
struct dhcp_context *context;
save_counter(0);
ra = expand(sizeof(struct ra_packet));
ra->type = ICMP6_ROUTER_ADVERT;
ra->code = 0;
ra->hop_limit = hop_limit;
ra->flags = 0;
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
ra->reachable_time = 0;
ra->retrans_time = 0;
parm.ind = iface;
parm.managed = 0;
parm.found_context = 0;
parm.if_name = iface_name;
parm.first = 1;
for (context = daemon->ra_contexts; context; context = context->next)
context->flags &= ~CONTEXT_RA_DONE;
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
!parm.found_context)
return;
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
if (ioctl(daemon->icmp6fd, SIOCGIFMTU, &ifr) != -1)
{
put_opt6_char(ICMP6_OPT_MTU);
put_opt6_char(1);
put_opt6_short(0);
put_opt6_long(ifr.ifr_mtu);
}
iface_enumerate(AF_LOCAL, &iface, add_lla);
/* RDNSS, RFC 6106 */
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_local, IN6ADDRSZ);
/* set managed bits unless we're providing only RA on this link */
if (parm.managed)
ra->flags = 0xc0;
/* decide where we're sending */
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
addr.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(IPPROTO_ICMPV6);
if (dest)
{
memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr));
if (IN6_IS_ADDR_LINKLOCAL(dest) ||
IN6_IS_ADDR_MC_LINKLOCAL(dest))
addr.sin6_scope_id = iface;
}
else
inet_pton(AF_INET6, ALL_HOSTS, &addr.sin6_addr);
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
}
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context, *tmp;
struct ra_param *param = vparam;
struct prefix_opt *opt;
(void)scope; /* warning */
(void)dad;
if (if_index == param->ind)
{
if (IN6_IS_ADDR_LINKLOCAL(local))
param->link_local = *local;
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
if (!(context->flags & CONTEXT_RA_ONLY))
param->managed = 1;
if (context->flags & CONTEXT_RA_DONE)
continue;
/* subsequent prefixes on the same interface don't need timers */
if (!param->first)
context->ra_time = 0;
param->first = 0;
param->found_context = 1;
context->flags |= CONTEXT_RA_DONE;
/* mark this subnet and duplicates: as done. */
for (tmp = context->next; tmp; tmp = tmp->next)
if (tmp->prefix == prefix &&
is_same_net6(local, &tmp->start6, prefix) &&
is_same_net6(local, &tmp->end6, prefix))
{
tmp->flags |= CONTEXT_RA_DONE;
context->ra_time = 0;
}
if ((opt = expand(sizeof(struct prefix_opt))))
{
u64 addrpart = addr6part(&context->start6);
u64 mask = (prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU;
unsigned int time = context->lease_time;
/* lifetimes must be min 2 hrs, by RFC 2462 */
if (time < 7200)
time = 7200;
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = prefix;
/* autonomous only is we're not doing dhcp */
opt->flags = (context->flags & CONTEXT_RA_ONLY) ? 0xc0 : 0x00;
opt->valid_lifetime = opt->preferred_lifetime = htonl(time);
opt->reserved = 0;
opt->prefix = context->start6;
setaddr6part(&opt->prefix, addrpart & ~mask);
inet_ntop(AF_INET6, &opt->prefix, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
}
}
}
}
return 1;
}
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
{
(void)type;
if (index == *((int *)parm))
{
/* size is in units of 8 octets and includes type and length (2 bytes)
add 7 to round up */
int len = (maclen + 9) >> 3;
unsigned char *p = expand(len << 3);
memset(p, 0, len << 3);
*p++ = ICMP6_OPT_SOURCE_MAC;
*p++ = len;
memcpy(p, mac, maclen);
return 0;
}
return 1;
}
time_t periodic_ra(time_t now)
{
struct search_param param;
struct dhcp_context *context;
time_t next_event;
char interface[IF_NAMESIZE+1];
param.now = now;
while (1)
{
/* find overdue events, and time of first future event */
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
if (context->ra_time != 0)
{
if (difftime(context->ra_time, now) < 0.0)
break; /* overdue */
if (next_event == 0 || difftime(next_event, context->ra_time + 2) > 0.0)
next_event = context->ra_time + 2;
}
/* none overdue */
if (!context)
break;
/* There's a context overdue, but we can't find an interface
associated with it, because it's for a subnet we dont
have an interface on. Probably we're doing DHCP on
a remote subnet via a relay. Zero the timer, since we won't
ever be able to send ra's and satistfy it. */
if (iface_enumerate(AF_INET6, &param, iface_search))
context->ra_time = 0;
else if (indextoname(daemon->icmp6fd, param.iface, interface))
send_ra(param.iface, interface, NULL);
}
return next_event;
}
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct search_param *param = vparam;
struct dhcp_context *context;
(void)scope;
(void)dad;
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
if (context->ra_time != 0 && difftime(context->ra_time, param->now) < 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and zap other contexts on the same interface
so they don't timeout independently .*/
param->iface = if_index;
if (difftime(param->now, ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 450 - 600 */
context->ra_time = param->now + 450 + (rand16()/440);
return 0; /* found, abort */
}
return 1; /* keep searching */
}
#endif
+20 -102
View File
@@ -19,17 +19,6 @@
#ifdef HAVE_DHCP6
static size_t outpacket_counter;
static void end_opt6(int container);
static int save_counter(int newval);
static void *expand(size_t headroom);
static int new_opt6(int opt);
static void *put_opt6(void *data, size_t len);
static void put_opt6_short(unsigned int val);
static void put_opt6_long(unsigned int val);
static void put_opt6_string(char *s);
static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context,
int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dhcp_netid *tags, struct dhcp_context *context,
@@ -55,10 +44,10 @@ size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
vendor->netid.next = &vendor->netid;
outpacket_counter = 0;
save_counter(0);
if (dhcp6_maybe_relay(NULL, &relay_tags, context, interface, iface_name, fallback, daemon->dhcp_packet.iov_base, sz, is_unicast, now))
return outpacket_counter;
return save_counter(0);
return 0;
}
@@ -682,14 +671,17 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
lease_add_extradata(lease, NULL, 0, 0);
else
{
struct dhcp_netid *n, *l;
struct dhcp_netid *n, *l, *tmp = tags;
/* link temporarily */
for (n = context_tags; n && n->next; n = n->next);
if ((l = n))
l->next = tags;
{
l->next = tags;
tmp = context_tags;
}
for (n = run_tag_if(context_tags); n; n = n->next)
for (n = run_tag_if(tmp); n; n = n->next)
{
struct dhcp_netid *n1;
/* kill dupes */
@@ -1271,12 +1263,14 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
len += strlen(send_domain) + 1;
o = new_opt6(OPTION6_FQDN);
p = expand(len + 3);
*(p++) = fqdn_flags;
p = do_rfc1035_name(p, hostname);
if (send_domain)
p = do_rfc1035_name(p, send_domain);
*p = 0;
if ((p = expand(len + 3)))
{
*(p++) = fqdn_flags;
p = do_rfc1035_name(p, hostname);
if (send_domain)
p = do_rfc1035_name(p, send_domain);
*p = 0;
}
end_opt6(o);
}
@@ -1347,19 +1341,19 @@ static void log6_packet(char *type, unsigned char *clid, int clid_len, struct in
daemon->dhcp_buff2[0] = 0;
if(option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s %s%s",
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
xid,
type,
iface,
daemon->namebuff,
daemon->dhcp_buff2,
daemon->namebuff,
string ? string : "");
else
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s %s%s",
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
type,
iface,
daemon->namebuff,
daemon->dhcp_buff2,
daemon->namebuff,
string ? string : "");
}
@@ -1419,80 +1413,4 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
return ret;
}
static void end_opt6(int container)
{
void *p = daemon->outpacket.iov_base + container + 2;
u16 len = outpacket_counter - container - 4 ;
PUTSHORT(len, p);
}
static int save_counter(int newval)
{
int ret = outpacket_counter;
if (newval != -1)
outpacket_counter = newval;
return ret;
}
static void *expand(size_t headroom)
{
void *ret;
if (expand_buf(&daemon->outpacket, outpacket_counter + headroom))
{
ret = daemon->outpacket.iov_base + outpacket_counter;
outpacket_counter += headroom;
return ret;
}
return NULL;
}
static int new_opt6(int opt)
{
int ret = outpacket_counter;
void *p;
if ((p = expand(4)))
{
PUTSHORT(opt, p);
PUTSHORT(0, p);
}
return ret;
}
static void *put_opt6(void *data, size_t len)
{
void *p;
if ((p = expand(len)))
memcpy(p, data, len);
return p;
}
static void put_opt6_long(unsigned int val)
{
void *p;
if ((p = expand(4)))
PUTLONG(val, p);
}
static void put_opt6_short(unsigned int val)
{
void *p;
if ((p = expand(2)))
PUTSHORT(val, p);
}
static void put_opt6_string(char *s)
{
put_opt6(s, strlen(s));
}
#endif