summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2022-02-01 00:18:44 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2022-02-02 18:28:27 +0000
commit7fbf1cce7b63e366138cb336d60020885d60f848 (patch)
treeedfda9e27b5dbdf1d6ea20542fbf0bedc0d73f9c
parentdbceeb4178af80619c0e319f71c4466daeedec82 (diff)
downloaddnsmasq-2.87test6.tar.gz
Improve the performance of DHCP relay.v2.87test6
On machines with many interfaces, enumerating them via netlink on each packet reciept is slow, and unneccesary. All we need is the local address->interface mapping, which can be cached in the relay structures.
-rw-r--r--src/dhcp.c179
-rw-r--r--src/dhcp6.c57
-rw-r--r--src/dnsmasq.h4
-rw-r--r--src/network.c11
-rw-r--r--src/rfc3315.c163
5 files changed, 212 insertions, 202 deletions
diff --git a/src/dhcp.c b/src/dhcp.c
index de766c1..a71ddf0 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -20,8 +20,6 @@
struct iface_param {
struct dhcp_context *current;
- struct dhcp_relay *relay;
- struct in_addr relay_local;
int ind;
};
@@ -34,7 +32,7 @@ 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 int 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)
@@ -307,12 +305,7 @@ void dhcp_packet(time_t now, int pxe_fd)
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, (union all_addr *)&iface_addr, ifr.ifr_name, NULL))
@@ -334,15 +327,19 @@ void dhcp_packet(time_t now, int pxe_fd)
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 (relay_upstream4(iface_index, mess, (size_t)sz))
+ return;
if (!iface_enumerate(AF_INET, &parm, complete_context))
return;
- /* We're relaying this request */
- if (parm.relay_local.s_addr != 0 &&
- relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
+ /* Check for a relay again after iface_enumerate/complete_context has had
+ chance to fill in relay->iface_index fields. This handles first time through
+ and any changes in interface config. */
+ if (relay_upstream4(iface_index, mess, (size_t)sz))
return;
-
+
/* May have configured relay, but not DHCP server */
if (!daemon->dhcp)
return;
@@ -631,14 +628,9 @@ 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.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;
- }
-
+ if (relay->local.addr4.s_addr == local.s_addr)
+ relay->iface_index = if_index;
+
return 1;
}
@@ -1079,85 +1071,96 @@ char *host_from_dns(struct in_addr addr)
return NULL;
}
-static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
+static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz)
{
- /* ->local is same value for all relays on ->current chain */
- union all_addr from;
-
+ struct in_addr giaddr = mess->giaddr;
+ u8 hops = mess->hops;
+ struct dhcp_relay *relay;
+
if (mess->op != BOOTREQUEST)
return 0;
- /* source address == relay address */
- from.addr4 = relay->local.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.addr4.s_addr)
- return 1;
- }
- else
- {
- /* plug in our address */
- mess->giaddr.s_addr = relay->local.addr4.s_addr;
- }
+ for (relay = daemon->relay4; relay; relay = relay->next)
+ if (relay->iface_index != 0 && relay->iface_index == iface_index)
+ break;
- if ((mess->hops++) > 20)
- return 1;
+ /* No relay config. */
+ if (!relay)
+ return 0;
+
+ for (; relay; relay = relay->next)
+ if (relay->iface_index != 0 && relay->iface_index == iface_index)
+ {
+ union mysockaddr to;
+ union all_addr from;
- for (; relay; relay = relay->current)
- {
- union mysockaddr to;
-
- to.sa.sa_family = AF_INET;
- to.in.sin_addr = relay->server.addr4;
- to.in.sin_port = htons(daemon->dhcp_server_port);
+ mess->hops = hops;
+ mess->giaddr = giaddr;
+
+ if ((mess->hops++) > 20)
+ continue;
+
+ /* source address == relay address */
+ from.addr4 = relay->local.addr4;
- /* Broadcasting to server. */
- if (relay->server.addr4.s_addr == 0)
+ /* 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(daemon->dhcp_server_port);
+
+ /* 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
{
- 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);
- return 1;
- }
-
- to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+ 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(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, 0);
}
-
-#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;
+#endif
- dump_packet(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, 0);
+ 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);
+ }
}
-#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);
- }
-
- /* Save this for replies */
- relay->iface_index = iface_index;
- }
return 1;
}
diff --git a/src/dhcp6.c b/src/dhcp6.c
index a343740..edb87a4 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -22,8 +22,7 @@
struct iface_param {
struct dhcp_context *current;
- struct dhcp_relay *relay;
- struct in6_addr fallback, relay_local, ll_addr, ula_addr;
+ struct in6_addr fallback, ll_addr, ula_addr;
int ind, addr_match;
};
@@ -90,7 +89,6 @@ 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;
@@ -105,7 +103,8 @@ void dhcp6_packet(time_t now)
struct iname *tmp;
unsigned short port;
struct in6_addr dst_addr;
-
+ struct in6_addr all_servers;
+
memset(&dst_addr, 0, sizeof(dst_addr));
msg.msg_control = control_u.control6;
@@ -164,8 +163,6 @@ void dhcp6_packet(time_t now)
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);
@@ -210,12 +207,24 @@ void dhcp6_packet(time_t now)
memset(&context->local6, 0, IN6ADDRSZ);
}
- for (relay = daemon->relay6; relay; relay = relay->next)
- relay->current = relay;
+ /* 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);
+
+ 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;
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
+ /* Check for a relay again after iface_enumerate/complete_context has had
+ chance to fill in relay->iface_index fields. This handles first time through
+ and any changes in interface config. */
+ 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;
+
if (daemon->if_names || daemon->if_addrs)
{
@@ -227,19 +236,6 @@ void dhcp6_packet(time_t now)
return;
}
- if (parm.relay)
- {
- /* Ignore requests sent to the ALL_SERVERS multicast address for relay when
- we're listening there for DHCPv6 server reasons. */
- struct in6_addr all_servers;
-
- inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
-
- if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
- relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id, now);
- return;
- }
-
/* May have configured relay, but not DHCP server */
if (!daemon->doing_dhcp6)
return;
@@ -326,6 +322,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct iname *tmp;
+ int match = !daemon->if_addrs;
(void)scope; /* warning */
@@ -347,7 +344,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
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;
+ match = param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
@@ -419,16 +416,12 @@ static int complete_context6(struct in6_addr *local, int prefix,
}
}
}
-
- for (relay = daemon->relay6; relay; relay = relay->next)
- if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6) && relay->current == relay &&
- (IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local)))
- {
- relay->current = param->relay;
- param->relay = relay;
- param->relay_local = *local;
- }
-
+
+ if (match)
+ for (relay = daemon->relay6; relay; relay = relay->next)
+ if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
+ relay->iface_index = if_index;
+
return 1;
}
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index ad2837e..2ffe808 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1089,7 +1089,7 @@ struct dhcp_relay {
struct snoop_record *next;
} *snoop_records;
#endif
- struct dhcp_relay *current, *next;
+ struct dhcp_relay *next;
};
extern struct daemon {
@@ -1682,7 +1682,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
unsigned short dhcp6_reply(struct dhcp_context *context, 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);
-void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address,
+int relay_upstream6(int iface_index, ssize_t sz, struct in6_addr *peer_address,
u32 scope_id, time_t now);
int relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
diff --git a/src/network.c b/src/network.c
index 7cd3371..68aaa6c 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1743,6 +1743,8 @@ int reload_servers(char *fname)
/* Called when addresses are added or deleted from an interface */
void newaddress(time_t now)
{
+ struct dhcp_relay *relay;
+
(void)now;
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
@@ -1751,6 +1753,12 @@ void newaddress(time_t now)
if (option_bool(OPT_CLEVERBIND))
create_bound_listeners(0);
+
+#ifdef HAVE_DHCP
+ /* clear cache of subnet->relay index */
+ for (relay = daemon->relay4; relay; relay = relay->next)
+ relay->iface_index = 0;
+#endif
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
@@ -1761,5 +1769,8 @@ void newaddress(time_t now)
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
+
+ for (relay = daemon->relay6; relay; relay = relay->next)
+ relay->iface_index = 0;
#endif
}
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 6c55672..cee8382 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -2100,110 +2100,113 @@ 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, time_t now)
+int relay_upstream6(int iface_index, ssize_t sz,
+ struct in6_addr *peer_address, u32 scope_id, time_t now)
{
- /* ->local is same value for all relays on ->current chain */
-
- union all_addr from;
unsigned char *header;
unsigned char *inbuff = daemon->dhcp_packet.iov_base;
int msg_type = *inbuff;
- int hopcount;
+ int hopcount, o;
struct in6_addr multicast;
unsigned int maclen, mactype;
unsigned char mac[DHCP_CHADDR_MAX];
+ struct dhcp_relay *relay;
+
+ for (relay = daemon->relay6; relay; relay = relay->next)
+ if (relay->iface_index != 0 && relay->iface_index == iface_index)
+ break;
+ /* No relay config. */
+ if (!relay)
+ return 0;
+
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
-
- /* source address == relay address */
- from.addr6 = relay->local.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;
-
reset_counter();
- if ((header = put_opt6(NULL, 34)))
+ /* RFC 3315 HOP_COUNT_LIMIT */
+ if (hopcount > 32 || !(header = put_opt6(NULL, 34)))
+ return 1;
+
+ header[0] = DHCP6RELAYFORW;
+ header[1] = hopcount;
+ memcpy(&header[18], peer_address, IN6ADDRSZ);
+
+ /* RFC-6939 */
+ if (maclen != 0)
{
- int o;
-
- header[0] = DHCP6RELAYFORW;
- header[1] = hopcount;
- memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
- memcpy(&header[18], peer_address, IN6ADDRSZ);
-
- /* RFC-6939 */
- if (maclen != 0)
- {
- o = new_opt6(OPTION6_CLIENT_MAC);
- put_opt6_short(mactype);
- put_opt6(mac, maclen);
- end_opt6(o);
- }
-
- o = new_opt6(OPTION6_RELAY_MSG);
- put_opt6(inbuff, sz);
+ o = new_opt6(OPTION6_CLIENT_MAC);
+ put_opt6_short(mactype);
+ put_opt6(mac, maclen);
end_opt6(o);
-
- for (; relay; relay = relay->current)
- {
- union mysockaddr to;
-
- to.sa.sa_family = AF_INET6;
- to.in6.sin6_addr = relay->server.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.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 DHCP relay via interface %s"), relay->interface);
- return;
- }
- }
-
-#ifdef HAVE_DUMPFILE
+ }
+
+ o = new_opt6(OPTION6_RELAY_MSG);
+ put_opt6(inbuff, sz);
+ end_opt6(o);
+
+ for (; relay; relay = relay->next)
+ if (relay->iface_index != 0 && relay->iface_index == iface_index)
+ {
+ union mysockaddr to;
+ union all_addr from;
+
+ /* source address == relay address */
+ from.addr6 = relay->local.addr6;
+ memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
+
+ to.sa.sa_family = AF_INET6;
+ to.in6.sin6_addr = relay->server.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.addr6, &multicast))
{
- union mysockaddr fromsock;
- fromsock.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
- fromsock.in6.sin6_addr = from.addr6;
- fromsock.sa.sa_family = AF_INET6;
- fromsock.in6.sin6_flowinfo = 0;
- fromsock.in6.sin6_scope_id = 0;
-
- dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), &fromsock, &to, 0);
+ 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 DHCP relay via interface %s"), relay->interface);
+ continue;
+ }
}
-#endif
- send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
+
+#ifdef HAVE_DUMPFILE
+ {
+ union mysockaddr fromsock;
+ fromsock.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
+ fromsock.in6.sin6_addr = from.addr6;
+ fromsock.sa.sa_family = AF_INET6;
+ fromsock.in6.sin6_flowinfo = 0;
+ fromsock.in6.sin6_scope_id = 0;
- if (option_bool(OPT_LOG_OPTS))
- {
- inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
- if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
- snprintf(daemon->namebuff, MAXDNAME, _("multicast via %s"), relay->interface);
- else
- inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
- my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->namebuff);
- }
-
- /* Save this for replies */
- relay->iface_index = scope_id;
+ dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), &fromsock, &to, 0);
}
- }
+#endif
+ send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
+
+ if (option_bool(OPT_LOG_OPTS))
+ {
+ inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
+ if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
+ snprintf(daemon->namebuff, MAXDNAME, _("multicast via %s"), relay->interface);
+ else
+ inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
+ my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->namebuff);
+ }
+
+ }
+
+ return 1;
}
int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)