mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Add --dhcp-relay config option.
This commit is contained in:
@@ -101,6 +101,8 @@ version 2.67
|
||||
(provide TFTP to the same interfaces we provide DHCP to)
|
||||
is retained. Thanks to Lonnie Abelbeck for the suggestion.
|
||||
|
||||
Add --dhcp-relay config option.
|
||||
|
||||
|
||||
version 2.66
|
||||
Add the ability to act as an authoritative DNS
|
||||
|
||||
@@ -973,6 +973,38 @@ DHCP options. This make extra space available in the DHCP packet for
|
||||
options but can, rarely, confuse old or broken clients. This flag
|
||||
forces "simple and safe" behaviour to avoid problems in such a case.
|
||||
.TP
|
||||
.B --dhcp-relay=<local address>,<server address>[,<interface]
|
||||
Configure dnsmasq to do DHCP relay. The local address is an address
|
||||
allocated to an interface on the host running dnsmasq. All DHCP
|
||||
requests arriving on that interface will we relayed to a remote DHCP
|
||||
server at the server address. It is possible to relay from a single local
|
||||
address to multiple remote servers by using multiple dhcp-relay
|
||||
configs with the same local address and different server
|
||||
addresses. A server address must be an IP literal address, not a
|
||||
domain name. In the case of DHCPv6, the server address may be the
|
||||
ALL_SERVERS multicast address, ff05::1:3. In this case the interface
|
||||
must be given, not be wildcard, and is used to direct the multicast to the
|
||||
correct interface to reach the DHCP server.
|
||||
|
||||
Access control for DHCP clients has the same rules as for the DHCP
|
||||
server, see --interface, --except-interface, etc. The optional
|
||||
interface name in the dhcp-relay config has a different function: it
|
||||
controls on which interface DHCP replies from the server will be
|
||||
accepted. This is intended for configurations which have three
|
||||
interfaces: one being relayed from, a second connecting the DHCP
|
||||
server, and a third untrusted network, typically the wider
|
||||
internet. It avoids the possibility of spoof replies arriving via this
|
||||
third interface.
|
||||
|
||||
It is allowed to have dnsmasq act as a DHCP server on one set of
|
||||
interfaces and relay from a disjoint set of interfaces. Note that
|
||||
whilst it is quite possible to write configurations which appear to
|
||||
act as a server and a relay on the same interface, this is not
|
||||
supported: the relay function will take precedence.
|
||||
|
||||
Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
|
||||
DHCPv4 to a DHCPv6 server or vice-versa.
|
||||
.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
|
||||
"vendor class" which represents, in some sense, the type of host. This option
|
||||
|
||||
@@ -757,6 +757,16 @@ void log_context(int family, struct dhcp_context *context)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void log_relay(int family, struct dhcp_relay *relay)
|
||||
{
|
||||
inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
|
||||
|
||||
if (relay->interface)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
208
src/dhcp.c
208
src/dhcp.c
@@ -20,6 +20,8 @@
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct dhcp_relay *relay;
|
||||
struct in_addr relay_local;
|
||||
int ind;
|
||||
};
|
||||
|
||||
@@ -32,6 +34,8 @@ 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 int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
|
||||
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
|
||||
|
||||
static int make_fd(int port)
|
||||
{
|
||||
@@ -132,6 +136,8 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
||||
struct dhcp_packet *mess;
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
int is_relay_reply = 0;
|
||||
struct iname *tmp;
|
||||
struct ifreq ifr;
|
||||
struct msghdr msg;
|
||||
@@ -250,57 +256,86 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
unicast_dest = 1;
|
||||
#endif
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
|
||||
{
|
||||
/* Reply from server, using us as relay. */
|
||||
iface_index = relay->iface_index;
|
||||
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
|
||||
return;
|
||||
is_relay_reply = 1;
|
||||
iov.iov_len = sz;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = iface_index;
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
|
||||
{
|
||||
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||
for a secondary */
|
||||
struct match_param match;
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
else
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
match.matched = 0;
|
||||
match.ind = iface_index;
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!daemon->if_addrs ||
|
||||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||
!match.matched)
|
||||
/* unlinked contexts/relays are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
relay->current = relay;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.relay = NULL;
|
||||
parm.relay_local.s_addr = 0;
|
||||
parm.ind = iface_index;
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
|
||||
{
|
||||
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||
for a secondary */
|
||||
struct match_param match;
|
||||
|
||||
match.matched = 0;
|
||||
match.ind = iface_index;
|
||||
|
||||
if (!daemon->if_addrs ||
|
||||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||
!match.matched)
|
||||
return;
|
||||
|
||||
iface_addr = match.addr;
|
||||
/* make sure secondary address gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
|
||||
iface_addr = match.addr;
|
||||
/* make sure secondary address gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
/* We're relaying this request */
|
||||
if (parm.relay_local.s_addr != 0 &&
|
||||
relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
|
||||
return;
|
||||
|
||||
/* May have configured relay, but not DHCP server */
|
||||
if (!daemon->dhcp)
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
if (iov.iov_len == 0)
|
||||
return;
|
||||
if (iov.iov_len == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
msg.msg_name = &dest;
|
||||
msg.msg_namelen = sizeof(dest);
|
||||
@@ -321,7 +356,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
if (mess->ciaddr.s_addr != 0)
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
}
|
||||
else if (mess->giaddr.s_addr)
|
||||
else if (mess->giaddr.s_addr && !is_relay_reply)
|
||||
{
|
||||
/* Send to BOOTP relay */
|
||||
dest.sin_port = htons(daemon->dhcp_server_port);
|
||||
@@ -334,7 +369,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
source port too, and send back to that. If we're replying
|
||||
to a DHCPINFORM, trust the source address always. */
|
||||
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
|
||||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
|
||||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
|
||||
{
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
@@ -450,6 +485,7 @@ static int complete_context(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param *param = vparam;
|
||||
|
||||
(void)label;
|
||||
@@ -495,6 +531,15 @@ static int complete_context(struct in_addr local, int if_index, char *label,
|
||||
}
|
||||
}
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay &&
|
||||
(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
|
||||
{
|
||||
relay->current = param->relay;
|
||||
param->relay = relay;
|
||||
param->relay_local = local;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -988,5 +1033,74 @@ char *host_from_dns(struct in_addr addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
|
||||
{
|
||||
/* ->local is same value for all relays on ->current chain */
|
||||
struct all_addr from;
|
||||
|
||||
if (mess->op != BOOTREQUEST)
|
||||
return 0;
|
||||
|
||||
/* source address == relay address */
|
||||
from.addr.addr4 = relay->local.addr.addr4;
|
||||
|
||||
/* already gatewayed ? */
|
||||
if (mess->giaddr.s_addr)
|
||||
{
|
||||
/* if so check if by us, to stomp on loops. */
|
||||
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* plug in our address */
|
||||
mess->giaddr.s_addr = relay->local.addr.addr4.s_addr;
|
||||
}
|
||||
|
||||
if ((mess->hops++) > 20)
|
||||
return 1;
|
||||
|
||||
for (; relay; relay = relay->current)
|
||||
{
|
||||
union mysockaddr to;
|
||||
|
||||
to.sa.sa_family = AF_INET;
|
||||
to.in.sin_addr = relay->server.addr.addr4;
|
||||
to.in.sin_port = htons(daemon->dhcp_server_port);
|
||||
|
||||
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);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr.addr4));
|
||||
}
|
||||
|
||||
/* Save this for replies */
|
||||
relay->iface_index = iface_index;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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.addr.addr4.s_addr)
|
||||
{
|
||||
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
|
||||
return relay->iface_index != 0 ? relay : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
221
src/dhcp6.c
221
src/dhcp6.c
@@ -20,7 +20,8 @@
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct in6_addr fallback;
|
||||
struct dhcp_relay *relay;
|
||||
struct in6_addr fallback, relay_local;
|
||||
int ind, addr_match;
|
||||
};
|
||||
|
||||
@@ -87,6 +88,7 @@ void dhcp6_init(void)
|
||||
void dhcp6_packet(time_t now)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param parm;
|
||||
struct cmsghdr *cmptr;
|
||||
struct msghdr msg;
|
||||
@@ -126,56 +128,75 @@ void dhcp6_packet(time_t now)
|
||||
|
||||
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = if_index;
|
||||
parm.addr_match = 0;
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||
{
|
||||
/* wildcard context for DHCP-stateless only */
|
||||
parm.current = context;
|
||||
context->current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
|
||||
{
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
break;
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.relay = NULL;
|
||||
memset(&parm.relay_local, 0, IN6ADDRSZ);
|
||||
parm.ind = if_index;
|
||||
parm.addr_match = 0;
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||
{
|
||||
/* wildcard context for DHCP-stateless only */
|
||||
parm.current = context;
|
||||
context->current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
if (!tmp && !parm.addr_match)
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
relay->current = relay;
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
break;
|
||||
|
||||
if (!tmp && !parm.addr_match)
|
||||
return;
|
||||
}
|
||||
|
||||
if (parm.relay)
|
||||
{
|
||||
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* May have configured relay, but not DHCP server */
|
||||
if (!daemon->doing_dhcp6)
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
port = 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(0);
|
||||
}
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
port = 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(0);
|
||||
|
||||
|
||||
/* The port in the source address of the original request should
|
||||
be correct, but at least once client sends from the server port,
|
||||
so we explicitly send to the client port to a client, and the
|
||||
@@ -194,70 +215,84 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
||||
unsigned int valid, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param *param = vparam;
|
||||
struct iname *tmp;
|
||||
|
||||
(void)scope; /* warning */
|
||||
|
||||
if (if_index == param->ind &&
|
||||
!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
/* if we have --listen-address config, see if the
|
||||
arrival interface has a matching address. */
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
|
||||
param->addr_match = 1;
|
||||
|
||||
/* Determine a globally address on the arrival interface, even
|
||||
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. */
|
||||
param->fallback = *local;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
{
|
||||
if ((context->flags & CONTEXT_DHCP) &&
|
||||
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
/* if we have --listen-address config, see if the
|
||||
arrival interface has a matching address. */
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
|
||||
param->addr_match = 1;
|
||||
|
||||
/* Determine a globally address on the arrival interface, even
|
||||
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. */
|
||||
param->fallback = *local;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
|
||||
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (context->current == context)
|
||||
if ((context->flags & CONTEXT_DHCP) &&
|
||||
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
struct dhcp_context *tmp, **up;
|
||||
|
||||
/* use interface values only for contructed contexts */
|
||||
if (!(context->flags & CONTEXT_CONSTRUCTED))
|
||||
preferred = valid = 0xffffffff;
|
||||
else if (flags & IFACE_DEPRECATED)
|
||||
preferred = 0;
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
preferred = 0;
|
||||
|
||||
/* order chain, longest preferred time first */
|
||||
for (up = ¶m->current, tmp = param->current; tmp; tmp = tmp->current)
|
||||
if (tmp->preferred <= preferred)
|
||||
break;
|
||||
else
|
||||
up = &tmp->current;
|
||||
|
||||
context->current = *up;
|
||||
*up = context;
|
||||
context->local6 = *local;
|
||||
context->preferred = preferred;
|
||||
context->valid = valid;
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (context->current == context)
|
||||
{
|
||||
struct dhcp_context *tmp, **up;
|
||||
|
||||
/* use interface values only for contructed contexts */
|
||||
if (!(context->flags & CONTEXT_CONSTRUCTED))
|
||||
preferred = valid = 0xffffffff;
|
||||
else if (flags & IFACE_DEPRECATED)
|
||||
preferred = 0;
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
preferred = 0;
|
||||
|
||||
/* order chain, longest preferred time first */
|
||||
for (up = ¶m->current, tmp = param->current; tmp; tmp = tmp->current)
|
||||
if (tmp->preferred <= preferred)
|
||||
break;
|
||||
else
|
||||
up = &tmp->current;
|
||||
|
||||
context->current = *up;
|
||||
*up = context;
|
||||
context->local6 = *local;
|
||||
context->preferred = preferred;
|
||||
context->valid = valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr.addr6) && relay->current == relay &&
|
||||
(IN6_IS_ADDR_UNSPECIFIED(¶m->relay_local) || IN6_ARE_ADDR_EQUAL(local, ¶m->relay_local)))
|
||||
{
|
||||
relay->current = param->relay;
|
||||
param->relay = relay;
|
||||
param->relay_local = *local;
|
||||
}
|
||||
|
||||
}
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
|
||||
|
||||
@@ -52,6 +52,7 @@ int main (int argc, char **argv)
|
||||
cap_user_data_t data = NULL;
|
||||
#endif
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
setlocale(LC_ALL, "");
|
||||
@@ -166,50 +167,47 @@ int main (int argc, char **argv)
|
||||
daemon->soa_sn = now;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
{
|
||||
daemon->doing_ra = option_bool(OPT_RA);
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
daemon->doing_ra = option_bool(OPT_RA);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
daemon->doing_dhcp6 = 1;
|
||||
if (context->flags & CONTEXT_RA)
|
||||
daemon->doing_ra = 1;
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
daemon->doing_dhcp6 = 1;
|
||||
if (context->flags & CONTEXT_RA)
|
||||
daemon->doing_ra = 1;
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
if (context->flags & CONTEXT_TEMPLATE)
|
||||
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
|
||||
if (context->flags & CONTEXT_TEMPLATE)
|
||||
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Note that order matters here, we must call lease_init before
|
||||
creating any file descriptors which shouldn't be leaked
|
||||
to the lease-script init process. We need to call common_init
|
||||
before lease_init to allocate buffers it uses.*/
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
dhcp_common_init();
|
||||
lease_init(now);
|
||||
}
|
||||
|
||||
if (daemon->dhcp)
|
||||
dhcp_init();
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
if (daemon->doing_ra)
|
||||
ra_init(now);
|
||||
|
||||
if (daemon->doing_dhcp6)
|
||||
dhcp6_init();
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* Note that order matters here, we must call lease_init before
|
||||
creating any file descriptors which shouldn't be leaked
|
||||
to the lease-script init process. We need to call common_init
|
||||
before lease_init to allocate buffers it uses.*/
|
||||
if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
|
||||
{
|
||||
dhcp_common_init();
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
lease_init(now);
|
||||
}
|
||||
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
dhcp_init();
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
if (daemon->doing_ra)
|
||||
ra_init(now);
|
||||
|
||||
if (daemon->doing_dhcp6 || daemon->relay6)
|
||||
dhcp6_init();
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -239,7 +237,7 @@ int main (int argc, char **argv)
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
|
||||
/* after enumerate_interfaces() */
|
||||
if (daemon->dhcp)
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
bindtodevice(daemon->dhcpfd);
|
||||
if (daemon->enable_pxe)
|
||||
@@ -248,7 +246,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
|
||||
if (daemon->doing_dhcp6)
|
||||
if (daemon->doing_dhcp6 || daemon->relay6)
|
||||
bindtodevice(daemon->dhcp6fd);
|
||||
#endif
|
||||
}
|
||||
@@ -257,7 +255,7 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* after enumerate_interfaces() */
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
join_multicast(1);
|
||||
#endif
|
||||
|
||||
@@ -641,10 +639,16 @@ int main (int argc, char **argv)
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
log_context(AF_INET, context);
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
log_relay(AF_INET, relay);
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
log_context(AF_INET6, context);
|
||||
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
log_relay(AF_INET6, relay);
|
||||
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
dhcp_construct_contexts(now);
|
||||
|
||||
@@ -749,7 +753,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
FD_SET(daemon->dhcpfd, &rset);
|
||||
bump_maxfd(daemon->dhcpfd, &maxfd);
|
||||
@@ -762,7 +766,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_dhcp6)
|
||||
if (daemon->doing_dhcp6 || daemon->relay6)
|
||||
{
|
||||
FD_SET(daemon->dhcp6fd, &rset);
|
||||
bump_maxfd(daemon->dhcp6fd, &maxfd);
|
||||
@@ -874,7 +878,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
if (FD_ISSET(daemon->dhcpfd, &rset))
|
||||
dhcp_packet(now, 0);
|
||||
@@ -883,7 +887,7 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
dhcp6_packet(now);
|
||||
|
||||
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
|
||||
@@ -775,6 +775,12 @@ struct tftp_prefix {
|
||||
struct tftp_prefix *next;
|
||||
};
|
||||
|
||||
struct dhcp_relay {
|
||||
struct all_addr local, server;
|
||||
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
|
||||
int iface_index; /* working - interface in which requests arrived, for return */
|
||||
struct dhcp_relay *current, *next;
|
||||
};
|
||||
|
||||
extern struct daemon {
|
||||
/* datastuctures representing the command-line and
|
||||
@@ -824,6 +830,7 @@ extern struct daemon {
|
||||
struct pxe_service *pxe_services;
|
||||
struct tag_if *tag_if;
|
||||
struct addr_list *override_relays;
|
||||
struct dhcp_relay *relay4, *relay6;
|
||||
int override;
|
||||
int enable_pxe;
|
||||
int doing_ra, doing_dhcp6;
|
||||
@@ -1217,6 +1224,9 @@ void dhcp_construct_contexts(time_t now);
|
||||
#ifdef HAVE_DHCP6
|
||||
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
||||
struct in6_addr *fallback, size_t sz, int is_multicast, time_t now);
|
||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
|
||||
|
||||
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
|
||||
#endif
|
||||
|
||||
/* dhcp-common.c */
|
||||
@@ -1243,6 +1253,7 @@ void bindtodevice(int fd);
|
||||
void display_opts6(void);
|
||||
# endif
|
||||
void log_context(int family, struct dhcp_context *context);
|
||||
void log_relay(int family, struct dhcp_relay *relay);
|
||||
#endif
|
||||
|
||||
/* outpacket.c */
|
||||
|
||||
@@ -402,18 +402,18 @@ static int nl_async(struct nlmsghdr *h)
|
||||
|
||||
static void nl_newaddress(time_t now)
|
||||
{
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
create_bound_listeners(0);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
join_multicast(0);
|
||||
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
{
|
||||
join_multicast(0);
|
||||
dhcp_construct_contexts(now);
|
||||
}
|
||||
dhcp_construct_contexts(now);
|
||||
|
||||
if (daemon->doing_dhcp6)
|
||||
lease_find_interfaces(now);
|
||||
|
||||
@@ -851,7 +851,7 @@ void join_multicast(int dienow)
|
||||
|
||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_dhcp6 &&
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
err = 1;
|
||||
|
||||
|
||||
28
src/option.c
28
src/option.c
@@ -133,6 +133,7 @@ struct myoption {
|
||||
#define LOPT_PREF_CLSS 321
|
||||
#endif
|
||||
#define LOPT_FAST_RA 322
|
||||
#define LOPT_RELAY 323
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -271,6 +272,7 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
||||
#endif
|
||||
{ "force-fast-ra", 0, 0, LOPT_FAST_RA },
|
||||
{ "dhcp-relay", 1, 0, LOPT_RELAY },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -389,6 +391,7 @@ static struct {
|
||||
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
|
||||
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
|
||||
{ LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
|
||||
{ LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
|
||||
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", 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 },
|
||||
@@ -3178,6 +3181,31 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
arg = comma;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOPT_RELAY: /* --dhcp-relay */
|
||||
{
|
||||
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
|
||||
comma = split(arg);
|
||||
new->interface = opt_string_alloc(split(comma));
|
||||
new->iface_index = 0;
|
||||
if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
|
||||
{
|
||||
new->next = daemon->relay4;
|
||||
daemon->relay4 = new;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
|
||||
{
|
||||
new->next = daemon->relay6;
|
||||
daemon->relay6 = new;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
ret_err(_("Bad dhcp-relay"));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
|
||||
@@ -70,9 +70,9 @@ void *put_opt6(void *data, size_t len)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = expand(len)))
|
||||
if ((p = expand(len)) && data)
|
||||
memcpy(p, data, len);
|
||||
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
120
src/rfc3315.c
120
src/rfc3315.c
@@ -155,7 +155,8 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
|
||||
return 0;
|
||||
|
||||
/* copy header stuff into reply message and set type to reply */
|
||||
outmsgtypep = put_opt6(inbuff, 34);
|
||||
if (!(outmsgtypep = put_opt6(inbuff, 34)))
|
||||
return 0;
|
||||
*outmsgtypep = DHCP6RELAYREPL;
|
||||
|
||||
/* look for relay options and set tags if found. */
|
||||
@@ -252,7 +253,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
state.tags = &v6_id;
|
||||
|
||||
/* copy over transaction-id, and save pointer to message type */
|
||||
outmsgtypep = put_opt6(inbuff, 4);
|
||||
if (!(outmsgtypep = put_opt6(inbuff, 4)))
|
||||
return 0;
|
||||
start_opts = save_counter(-1);
|
||||
state.xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
|
||||
|
||||
@@ -1912,4 +1914,118 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
|
||||
{
|
||||
/* ->local is same value for all relays on ->current chain */
|
||||
|
||||
struct all_addr from;
|
||||
unsigned char *header;
|
||||
unsigned char *inbuff = daemon->dhcp_packet.iov_base;
|
||||
int msg_type = *inbuff;
|
||||
int hopcount;
|
||||
struct in6_addr multicast;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
|
||||
|
||||
/* source address == relay address */
|
||||
from.addr.addr6 = relay->local.addr.addr6;
|
||||
|
||||
/* Get hop count from nested relayed message */
|
||||
if (msg_type == DHCP6RELAYFORW)
|
||||
hopcount = *((unsigned char *)inbuff+1) + 1;
|
||||
else
|
||||
hopcount = 0;
|
||||
|
||||
/* RFC 3315 HOP_COUNT_LIMIT */
|
||||
if (hopcount > 32)
|
||||
return;
|
||||
|
||||
save_counter(0);
|
||||
|
||||
if ((header = put_opt6(NULL, 34)))
|
||||
{
|
||||
int o;
|
||||
|
||||
header[0] = DHCP6RELAYFORW;
|
||||
header[1] = hopcount;
|
||||
memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
|
||||
memcpy(&header[18], peer_address, IN6ADDRSZ);
|
||||
|
||||
o = new_opt6(OPTION6_RELAY_MSG);
|
||||
put_opt6(inbuff, sz);
|
||||
end_opt6(o);
|
||||
|
||||
for (; relay; relay = relay->current)
|
||||
{
|
||||
union mysockaddr to;
|
||||
|
||||
to.sa.sa_family = AF_INET6;
|
||||
to.in6.sin6_addr = relay->server.addr.addr6;
|
||||
to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
|
||||
to.in6.sin6_flowinfo = 0;
|
||||
to.in6.sin6_scope_id = 0;
|
||||
|
||||
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))
|
||||
{
|
||||
int multicast_iface;
|
||||
if (!relay->interface || strchr(relay->interface, '*') ||
|
||||
(multicast_iface = if_nametoindex(relay->interface)) == 0 ||
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
|
||||
}
|
||||
|
||||
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(0), &to, &from, 0);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
|
||||
/* Save this for replies */
|
||||
relay->iface_index = scope_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
|
||||
{
|
||||
struct dhcp_relay *relay;
|
||||
struct in6_addr link;
|
||||
unsigned char *inbuff = daemon->dhcp_packet.iov_base;
|
||||
|
||||
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
|
||||
which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
|
||||
|
||||
if (sz < 38 || *inbuff != DHCP6RELAYREPL)
|
||||
return 0;
|
||||
|
||||
memcpy(&link, &inbuff[2], IN6ADDRSZ);
|
||||
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
|
||||
(!relay->interface || wildcard_match(relay->interface, arrival_interface)))
|
||||
break;
|
||||
|
||||
save_counter(0);
|
||||
|
||||
if (relay)
|
||||
{
|
||||
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;
|
||||
return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user