Improve the performance of DHCP relay.

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.
This commit is contained in:
Simon Kelley
2022-02-01 00:18:44 +00:00
parent dbceeb4178
commit 7fbf1cce7b
5 changed files with 217 additions and 207 deletions

View File

@@ -20,8 +20,6 @@
struct iface_param { struct iface_param {
struct dhcp_context *current; struct dhcp_context *current;
struct dhcp_relay *relay;
struct in_addr relay_local;
int ind; 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); struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int check_listen_addrs(struct in_addr local, int if_index, char *label, static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam); struct in_addr netmask, struct in_addr broadcast, void *vparam);
static 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 struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
static int make_fd(int port) 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) for (context = daemon->dhcp; context; context = context->next)
context->current = context; context->current = context;
for (relay = daemon->relay4; relay; relay = relay->next)
relay->current = relay;
parm.current = NULL; parm.current = NULL;
parm.relay = NULL;
parm.relay_local.s_addr = 0;
parm.ind = iface_index; parm.ind = iface_index;
if (!iface_check(AF_INET, (union all_addr *)&iface_addr, ifr.ifr_name, NULL)) 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 */ 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); 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)) if (!iface_enumerate(AF_INET, &parm, complete_context))
return; return;
/* We're relaying this request */ /* Check for a relay again after iface_enumerate/complete_context has had
if (parm.relay_local.s_addr != 0 && chance to fill in relay->iface_index fields. This handles first time through
relay_upstream4(parm.relay, mess, (size_t)sz, iface_index)) and any changes in interface config. */
if (relay_upstream4(iface_index, mess, (size_t)sz))
return; return;
/* May have configured relay, but not DHCP server */ /* May have configured relay, but not DHCP server */
if (!daemon->dhcp) if (!daemon->dhcp)
return; 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) for (relay = daemon->relay4; relay; relay = relay->next)
if (if_index == param->ind && relay->local.addr4.s_addr == local.s_addr && relay->current == relay && if (relay->local.addr4.s_addr == local.s_addr)
(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr)) relay->iface_index = if_index;
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = local;
}
return 1; return 1;
} }
@@ -1079,85 +1071,96 @@ char *host_from_dns(struct in_addr addr)
return NULL; 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 */ struct in_addr giaddr = mess->giaddr;
union all_addr from; u8 hops = mess->hops;
struct dhcp_relay *relay;
if (mess->op != BOOTREQUEST) if (mess->op != BOOTREQUEST)
return 0; return 0;
/* source address == relay address */ for (relay = daemon->relay4; relay; relay = relay->next)
from.addr4 = relay->local.addr4; if (relay->iface_index != 0 && relay->iface_index == iface_index)
break;
/* No relay config. */
if (!relay)
return 0;
/* already gatewayed ? */ for (; relay; relay = relay->next)
if (mess->giaddr.s_addr) if (relay->iface_index != 0 && relay->iface_index == iface_index)
{
/* 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;
}
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.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);
return 1;
}
to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
}
#ifdef HAVE_DUMPFILE
{ {
union mysockaddr fromsock; union mysockaddr to;
fromsock.in.sin_port = htons(daemon->dhcp_server_port); union all_addr from;
fromsock.in.sin_addr = from.addr4;
fromsock.sa.sa_family = AF_INET; mess->hops = hops;
mess->giaddr = giaddr;
dump_packet(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, 0); if ((mess->hops++) > 20)
} continue;
#endif
/* source address == relay address */
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0); from.addr4 = relay->local.addr4;
if (option_bool(OPT_LOG_OPTS)) /* 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
{ {
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN); union mysockaddr fromsock;
if (relay->server.addr4.s_addr == 0) fromsock.in.sin_port = htons(daemon->dhcp_server_port);
snprintf(daemon->dhcp_buff2, DHCP_BUFF_SZ, _("broadcast via %s"), relay->interface); fromsock.in.sin_addr = from.addr4;
else fromsock.sa.sa_family = AF_INET;
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); dump_packet(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, 0);
} }
#endif
/* Save this for replies */
relay->iface_index = iface_index; 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);
}
}
return 1; return 1;
} }

View File

@@ -22,8 +22,7 @@
struct iface_param { struct iface_param {
struct dhcp_context *current; struct dhcp_context *current;
struct dhcp_relay *relay; struct in6_addr fallback, ll_addr, ula_addr;
struct in6_addr fallback, relay_local, ll_addr, ula_addr;
int ind, addr_match; int ind, addr_match;
}; };
@@ -90,7 +89,6 @@ void dhcp6_init(void)
void dhcp6_packet(time_t now) void dhcp6_packet(time_t now)
{ {
struct dhcp_context *context; struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param parm; struct iface_param parm;
struct cmsghdr *cmptr; struct cmsghdr *cmptr;
struct msghdr msg; struct msghdr msg;
@@ -105,7 +103,8 @@ void dhcp6_packet(time_t now)
struct iname *tmp; struct iname *tmp;
unsigned short port; unsigned short port;
struct in6_addr dst_addr; struct in6_addr dst_addr;
struct in6_addr all_servers;
memset(&dst_addr, 0, sizeof(dst_addr)); memset(&dst_addr, 0, sizeof(dst_addr));
msg.msg_control = control_u.control6; msg.msg_control = control_u.control6;
@@ -164,8 +163,6 @@ void dhcp6_packet(time_t now)
return; return;
parm.current = NULL; parm.current = NULL;
parm.relay = NULL;
memset(&parm.relay_local, 0, IN6ADDRSZ);
parm.ind = if_index; parm.ind = if_index;
parm.addr_match = 0; parm.addr_match = 0;
memset(&parm.fallback, 0, IN6ADDRSZ); memset(&parm.fallback, 0, IN6ADDRSZ);
@@ -210,12 +207,24 @@ void dhcp6_packet(time_t now)
memset(&context->local6, 0, IN6ADDRSZ); memset(&context->local6, 0, IN6ADDRSZ);
} }
for (relay = daemon->relay6; relay; relay = relay->next) /* Ignore requests sent to the ALL_SERVERS multicast address for relay when
relay->current = relay; 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)) if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return; 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) if (daemon->if_names || daemon->if_addrs)
{ {
@@ -227,19 +236,6 @@ void dhcp6_packet(time_t now)
return; 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 */ /* May have configured relay, but not DHCP server */
if (!daemon->doing_dhcp6) if (!daemon->doing_dhcp6)
return; return;
@@ -326,6 +322,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
struct dhcp_relay *relay; struct dhcp_relay *relay;
struct iface_param *param = vparam; struct iface_param *param = vparam;
struct iname *tmp; struct iname *tmp;
int match = !daemon->if_addrs;
(void)scope; /* warning */ (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) for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 && if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local)) 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 /* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only 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 (match)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6) && relay->current == relay && for (relay = daemon->relay6; relay; relay = relay->next)
(IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local))) if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
{ relay->iface_index = if_index;
relay->current = param->relay;
param->relay = relay;
param->relay_local = *local;
}
return 1; return 1;
} }

View File

@@ -1089,7 +1089,7 @@ struct dhcp_relay {
struct snoop_record *next; struct snoop_record *next;
} *snoop_records; } *snoop_records;
#endif #endif
struct dhcp_relay *current, *next; struct dhcp_relay *next;
}; };
extern struct daemon { 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, 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, struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
size_t sz, struct in6_addr *client_addr, time_t now); size_t sz, struct in6_addr *client_addr, time_t now);
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); u32 scope_id, time_t now);
int relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface); int relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);

View File

@@ -1743,6 +1743,8 @@ int reload_servers(char *fname)
/* Called when addresses are added or deleted from an interface */ /* Called when addresses are added or deleted from an interface */
void newaddress(time_t now) void newaddress(time_t now)
{ {
struct dhcp_relay *relay;
(void)now; (void)now;
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) || if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
@@ -1751,6 +1753,12 @@ void newaddress(time_t now)
if (option_bool(OPT_CLEVERBIND)) if (option_bool(OPT_CLEVERBIND))
create_bound_listeners(0); 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 #ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra) if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
@@ -1761,5 +1769,8 @@ void newaddress(time_t now)
if (daemon->doing_dhcp6) if (daemon->doing_dhcp6)
lease_find_interfaces(now); lease_find_interfaces(now);
for (relay = daemon->relay6; relay; relay = relay->next)
relay->iface_index = 0;
#endif #endif
} }

View File

@@ -2100,110 +2100,113 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
return ret; return ret;
} }
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, int relay_upstream6(int iface_index, ssize_t sz,
struct in6_addr *peer_address, u32 scope_id, time_t now) 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 *header;
unsigned char *inbuff = daemon->dhcp_packet.iov_base; unsigned char *inbuff = daemon->dhcp_packet.iov_base;
int msg_type = *inbuff; int msg_type = *inbuff;
int hopcount; int hopcount, o;
struct in6_addr multicast; struct in6_addr multicast;
unsigned int maclen, mactype; unsigned int maclen, mactype;
unsigned char mac[DHCP_CHADDR_MAX]; 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); inet_pton(AF_INET6, ALL_SERVERS, &multicast);
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now); 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 */ /* Get hop count from nested relayed message */
if (msg_type == DHCP6RELAYFORW) if (msg_type == DHCP6RELAYFORW)
hopcount = *((unsigned char *)inbuff+1) + 1; hopcount = *((unsigned char *)inbuff+1) + 1;
else else
hopcount = 0; hopcount = 0;
/* RFC 3315 HOP_COUNT_LIMIT */
if (hopcount > 32)
return;
reset_counter(); 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; o = new_opt6(OPTION6_CLIENT_MAC);
put_opt6_short(mactype);
header[0] = DHCP6RELAYFORW; put_opt6(mac, maclen);
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);
end_opt6(o); 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
{
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);
}
#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);
}
/* Save this for replies */
relay->iface_index = scope_id;
}
} }
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))
{
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;
}
}
#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;
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) int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)