mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2026-04-19 16:20:04 +01:00
More development on dhcp-split-relay.
This commit is contained in:
@@ -1489,19 +1489,22 @@ prefix-delegation from relayed DHCP transactions. See
|
|||||||
.B --dhcp-script
|
.B --dhcp-script
|
||||||
for details.
|
for details.
|
||||||
.TP
|
.TP
|
||||||
.B --dhcp-split-relay=<local address>,[<server address>[#<server port>]],<server-facing-interface>
|
.B --dhcp-split-relay=<local address>,[<server address>[#<server port>]],<server-facing-interface>|<server-facing-address>
|
||||||
A usefully enchanced version of DHCPv4 relay. IPv4 DHCP normally uses a single address
|
A usefully enchanced version of DHCPv4 relay. IPv4 DHCP normally uses a single address
|
||||||
for two functions; it is used by the DHCP server to determine which network to allocate
|
for two functions; it is used by the DHCP server to determine which network to allocate
|
||||||
an address on, and it is used as the address of the relay to which the server sends packets.
|
an address on, and it is used as the address of the relay to which the server sends packets.
|
||||||
|
|
||||||
This version of DHCP relay splits these functions. It uses the address of the server-facing relay
|
This version of DHCP relay splits these functions. It uses the address of the server-facing relay
|
||||||
interface as the address that the server talks to. The address of the client-facing interface
|
interface or a directly-specified address as the address that the server talks to. The address of the client-facing interface
|
||||||
(the first item in the config) is used as to determine the client's subnet. The
|
(the first item in the config) is used as to determine the client's subnet. The
|
||||||
local address is also used as server-ID override so that the client always sends requests
|
local address is also used as server-ID override so that the client always sends requests
|
||||||
via the relay. The effect of this is that server doesn't require
|
via the relay. The effect of this is that server doesn't require
|
||||||
a route to the client network and the clients don't require a route to the server.
|
a route to the client network and the clients don't require a route to the server.
|
||||||
|
|
||||||
The interface parameter is mandatory and a cannot be a wildcard.
|
The third parameter is mandatory. If it is an interface name it cannot be a wildcard and the same filtering as descibed in
|
||||||
|
--dhcp-relay applies; answers from the server must arrve via the specified interface. If the third parameter
|
||||||
|
is an IP address it must be an address of a local interface which is routable from the server; In this case no filtering
|
||||||
|
is done, the reply packets can arrive via any route.
|
||||||
|
|
||||||
If setting up a network where the client networks have limited routing, be careful
|
If setting up a network where the client networks have limited routing, be careful
|
||||||
about configuring the DHCP server. Dnsmasq, as DHCP server, will set the default route to the
|
about configuring the DHCP server. Dnsmasq, as DHCP server, will set the default route to the
|
||||||
|
|||||||
26
src/dhcp.c
26
src/dhcp.c
@@ -142,7 +142,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
|
int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
|
||||||
int rcvd_iface_index;
|
int rcvd_iface_index, relay_index;
|
||||||
struct in_addr iface_addr;
|
struct in_addr iface_addr;
|
||||||
struct iface_param parm;
|
struct iface_param parm;
|
||||||
time_t recvtime = now;
|
time_t recvtime = now;
|
||||||
@@ -302,10 +302,10 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
unicast_dest = 1;
|
unicast_dest = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
|
if ((relay_index = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, ifr.ifr_name)))
|
||||||
{
|
{
|
||||||
/* Reply from server, using us as relay. */
|
/* Reply from server, using us as relay. */
|
||||||
rcvd_iface_index = relay->iface_index;
|
rcvd_iface_index = relay_index;
|
||||||
if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
|
if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
|
||||||
return;
|
return;
|
||||||
is_relay_reply = 1;
|
is_relay_reply = 1;
|
||||||
@@ -330,10 +330,13 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
if (tmp->name && (tmp->flags & INAME_4) && wildcard_match(tmp->name, ifr.ifr_name))
|
if (tmp->name && (tmp->flags & INAME_4) && wildcard_match(tmp->name, ifr.ifr_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* unlinked contexts/relays are marked by context->current == context */
|
/* unlinked contexts are marked by context->current == context */
|
||||||
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->matchcount = 0;
|
||||||
|
|
||||||
parm.current = NULL;
|
parm.current = NULL;
|
||||||
parm.ind = iface_index;
|
parm.ind = iface_index;
|
||||||
|
|
||||||
@@ -360,7 +363,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
if (!iface_enumerate(AF_INET, &parm, (callback_t){.af_inet=complete_context}))
|
if (!iface_enumerate(AF_INET, &parm, (callback_t){.af_inet=complete_context}))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
relay_upstream4(iface_index, mess, (size_t)sz, unicast_dest);
|
relay_upstream4(iface_addr, iface_index, mess, (size_t)sz, unicast_dest);
|
||||||
|
|
||||||
/* May have configured relay, but not DHCP server */
|
/* May have configured relay, but not DHCP server */
|
||||||
if (!daemon->dhcp)
|
if (!daemon->dhcp)
|
||||||
@@ -664,9 +667,20 @@ 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 (relay->local.addr4.s_addr == local.s_addr)
|
if (!relay->split_mode && relay->local.addr4.s_addr == local.s_addr)
|
||||||
|
{
|
||||||
|
if (if_index == param->ind)
|
||||||
relay->iface_index = if_index;
|
relay->iface_index = if_index;
|
||||||
|
|
||||||
|
/* More than one interface with the relay address breaks things. */
|
||||||
|
if (relay->matchcount++ == 1 && !relay->warned)
|
||||||
|
{
|
||||||
|
relay->warned = 1;
|
||||||
|
inet_ntop(AF_INET, &local, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP relay address %s appears on more than one interface"), daemon->addrbuff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
src/dhcp6.c
14
src/dhcp6.c
@@ -89,6 +89,7 @@ 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;
|
||||||
@@ -232,6 +233,9 @@ void dhcp6_packet(time_t now)
|
|||||||
memset(&context->local6, 0, IN6ADDRSZ);
|
memset(&context->local6, 0, IN6ADDRSZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||||
|
relay->matchcount = 0;
|
||||||
|
|
||||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &all_servers);
|
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &all_servers);
|
||||||
if (IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
if (IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
||||||
multicast_dest = 1;
|
multicast_dest = 1;
|
||||||
@@ -452,8 +456,18 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
|||||||
if (match)
|
if (match)
|
||||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||||
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
|
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
|
||||||
|
{
|
||||||
relay->iface_index = if_index;
|
relay->iface_index = if_index;
|
||||||
|
|
||||||
|
/* More than one interface with the relay address breaks things. */
|
||||||
|
if (relay->matchcount++ == 1 && !relay->warned)
|
||||||
|
{
|
||||||
|
relay->warned = 1;
|
||||||
|
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP relay address %s appears on more than one interface"), daemon->addrbuff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1144,11 +1144,12 @@ struct dhcp_relay {
|
|||||||
union {
|
union {
|
||||||
struct in_addr addr4;
|
struct in_addr addr4;
|
||||||
struct in6_addr addr6;
|
struct in6_addr addr6;
|
||||||
} local, server;
|
} local, server, uplink;
|
||||||
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
|
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
|
||||||
int iface_index; /* working - interface in which requests arrived, for return */
|
int iface_index; /* working - interface in which requests arrived, for return */
|
||||||
int port; /* Port of relay we forward to. */
|
int port; /* Port of relay we forward to. */
|
||||||
int split_mode; /* Split address allocation and relay address. */
|
int split_mode; /* Split address allocation and relay address. */
|
||||||
|
int warned, matchcount;
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
struct snoop_record {
|
struct snoop_record {
|
||||||
struct in6_addr client, prefix;
|
struct in6_addr client, prefix;
|
||||||
@@ -1667,8 +1668,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
time_t recvtime, struct in_addr leasequery_source);
|
time_t recvtime, struct in_addr leasequery_source);
|
||||||
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||||
int clid_len, unsigned char *clid, int *len_out);
|
int clid_len, unsigned char *clid, int *len_out);
|
||||||
void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz, int unicast);
|
void relay_upstream4(struct in_addr iface_addr, int iface_index,
|
||||||
struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
|
struct dhcp_packet *mess, size_t sz, int unicast);
|
||||||
|
unsigned int relay_reply4(struct dhcp_packet *mess, size_t sz, char *arrival_interface);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* dnsmasq.c */
|
/* dnsmasq.c */
|
||||||
|
|||||||
@@ -4756,6 +4756,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
else
|
else
|
||||||
three = two;
|
three = two;
|
||||||
}
|
}
|
||||||
|
else if (new->split_mode && inet_pton(AF_INET, three, &new->uplink))
|
||||||
|
/* Third arg in split mode can be an address. */
|
||||||
|
three = NULL;
|
||||||
|
|
||||||
new->next = daemon->relay4;
|
new->next = daemon->relay4;
|
||||||
daemon->relay4 = new;
|
daemon->relay4 = new;
|
||||||
|
|||||||
106
src/rfc2131.c
106
src/rfc2131.c
@@ -3055,7 +3055,7 @@ static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz, int unicast)
|
void relay_upstream4(struct in_addr iface_addr, int iface_index, struct dhcp_packet *mess, size_t sz, int unicast)
|
||||||
{
|
{
|
||||||
struct in_addr giaddr = mess->giaddr;
|
struct in_addr giaddr = mess->giaddr;
|
||||||
u8 hops = mess->hops;
|
u8 hops = mess->hops;
|
||||||
@@ -3063,33 +3063,28 @@ void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz, int u
|
|||||||
size_t orig_sz = sz;
|
size_t orig_sz = sz;
|
||||||
unsigned char *endopt = NULL;
|
unsigned char *endopt = NULL;
|
||||||
|
|
||||||
if (mess->op != BOOTREQUEST)
|
if (mess->op != BOOTREQUEST || (mess->hops++) > 20)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||||
if (relay->iface_index != 0 && relay->iface_index == iface_index)
|
|
||||||
{
|
{
|
||||||
union mysockaddr to;
|
union mysockaddr to;
|
||||||
union all_addr from;
|
union all_addr from;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
|
||||||
/* restore orig packet */
|
/* restore orig packet */
|
||||||
mess->hops = hops;
|
|
||||||
mess->giaddr = giaddr;
|
mess->giaddr = giaddr;
|
||||||
if (endopt)
|
if (endopt)
|
||||||
*endopt = OPTION_END;
|
*endopt = OPTION_END;
|
||||||
sz = orig_sz;
|
sz = orig_sz;
|
||||||
|
|
||||||
if ((mess->hops++) > 20)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (relay->interface)
|
if (relay->interface)
|
||||||
{
|
{
|
||||||
safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
|
safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!relay->split_mode)
|
if (!relay->split_mode && relay->iface_index && relay->iface_index == iface_index)
|
||||||
{
|
{
|
||||||
/* already gatewayed ? */
|
/* already gatewayed ? */
|
||||||
if (giaddr.s_addr)
|
if (giaddr.s_addr)
|
||||||
@@ -3098,63 +3093,83 @@ void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz, int u
|
|||||||
if (giaddr.s_addr == relay->local.addr4.s_addr)
|
if (giaddr.s_addr == relay->local.addr4.s_addr)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* plug in our address */
|
|
||||||
from.addr4 = mess->giaddr = relay->local.addr4;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
/* plug in our address */
|
||||||
|
mess->giaddr = relay->local.addr4;
|
||||||
|
|
||||||
|
from.addr4 = relay->local.addr4;
|
||||||
|
}
|
||||||
|
else if (relay->split_mode && relay->local.addr4.s_addr == iface_addr.s_addr)
|
||||||
{
|
{
|
||||||
/* Split mode. We put our address on the server-facing interface
|
/* Split mode. We put our address on the server-facing interface
|
||||||
into giaddr for the server to talk back to us on.
|
or a directly specified third address into giaddr for the server to talk back to us on.
|
||||||
|
|
||||||
Our address on client-facing interface goes into agent-id
|
Our address on client-facing interface goes into agent-id subnet-selector subopt,
|
||||||
subnet-selector subopt, so that the server allocates the correct address. */
|
so that the server allocates the correct address. We also send a
|
||||||
|
remote-id with the interface on which the request arrived,
|
||||||
|
so that we can send the reply back the same way. */
|
||||||
|
unsigned int net_index = htonl(iface_index);
|
||||||
|
|
||||||
|
if (relay->interface)
|
||||||
|
{
|
||||||
/* get our address on the server-facing interface. */
|
/* get our address on the server-facing interface. */
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
||||||
continue;
|
continue;
|
||||||
|
relay->uplink.addr4 = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
}
|
||||||
|
|
||||||
/* already gatewayed ? */
|
/* already gatewayed ? */
|
||||||
if (giaddr.s_addr)
|
if (giaddr.s_addr)
|
||||||
{
|
{
|
||||||
/* if so check if by us, to stomp on loops. */
|
/* if so check if by us, to stomp on loops. */
|
||||||
if (giaddr.s_addr == ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr)
|
if (giaddr.s_addr == relay->uplink.addr4.s_addr)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* giaddr is our address on the outgoing interface in split mode. */
|
/* giaddr is our address on the outgoing interface in split mode. */
|
||||||
from.addr4 = mess->giaddr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
mess->giaddr = relay->uplink.addr4;
|
||||||
|
|
||||||
if (!endopt)
|
if (!endopt)
|
||||||
{
|
{
|
||||||
/* Add an RFC3026 relay agent information option (2 bytes) at the very end of the options.
|
/* Add an RFC3026 relay agent information option (2 bytes) at the very end of the options.
|
||||||
Said option to contain a RFC 3527 link selection sub option (6 bytes) and
|
Said option to contain a RFC 3527 link selection sub option (6 bytes) and
|
||||||
RFC 5017 serverid-override option (6 bytes) and RFC5010 (3 bytes).
|
RFC 5017 serverid-override option (6 bytes) and RFC5010 flags (3 bytes) and
|
||||||
New END option is a 18th byte, so we need 18 bytes free.
|
an RFC3046 remote-id which holds an interface index (6 bytes)
|
||||||
We only need to do this once, and poke the address into the same place each time. */
|
|
||||||
|
New END option is a 24th byte, so we need 24 bytes free.
|
||||||
|
We only need to do this once, and poke the address/interface/flags into the same place each time. */
|
||||||
|
|
||||||
if (!(endopt = option_find1((&mess->options[0] + sizeof(u32)), ((unsigned char *)mess) + sz, OPTION_END, 0)) ||
|
if (!(endopt = option_find1((&mess->options[0] + sizeof(u32)), ((unsigned char *)mess) + sz, OPTION_END, 0)) ||
|
||||||
(endopt + 18 > (unsigned char *)(mess + 1)))
|
(endopt + 24 > (unsigned char *)(mess + 1)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
endopt[1] = 15; /* length */
|
endopt[1] = 21; /* length */
|
||||||
endopt[2] = SUBOPT_SUBNET_SELECT;
|
endopt[2] = SUBOPT_SUBNET_SELECT;
|
||||||
endopt[3] = 4; /* length */
|
endopt[3] = 4; /* length */
|
||||||
endopt[8] = SUBOPT_SERVER_OR;
|
endopt[8] = SUBOPT_SERVER_OR;
|
||||||
endopt[9] = 4;
|
endopt[9] = 4;
|
||||||
endopt[14] = SUBOPT_FLAGS;
|
endopt[14] = SUBOPT_FLAGS;
|
||||||
endopt[15] = 1; /* length */
|
endopt[15] = 1; /* length */
|
||||||
endopt[17] = OPTION_END;
|
endopt[17] = SUBOPT_REMOTE_ID;
|
||||||
sz = (endopt - (unsigned char *)mess) + 18;
|
endopt[18] = 4; /* length */
|
||||||
|
endopt[23] = OPTION_END;
|
||||||
|
sz = (endopt - (unsigned char *)mess) + 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IP address is already in network byte order */
|
/* IP address is already in network byte order */
|
||||||
memcpy(&endopt[4], &relay->local.addr4.s_addr, INADDRSZ);
|
memcpy(&endopt[4], &relay->local.addr4.s_addr, INADDRSZ);
|
||||||
memcpy(&endopt[10], &relay->local.addr4.s_addr, INADDRSZ);
|
memcpy(&endopt[10], &relay->local.addr4.s_addr, INADDRSZ);
|
||||||
endopt[16] = unicast ? 0x80 : 0x00;
|
endopt[16] = unicast ? 0x80 : 0x00;
|
||||||
|
memcpy(&endopt[19], &net_index, 4);
|
||||||
endopt[0] = OPTION_AGENT_ID;
|
endopt[0] = OPTION_AGENT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
from.addr4 = relay->uplink.addr4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
to.sa.sa_family = AF_INET;
|
to.sa.sa_family = AF_INET;
|
||||||
to.in.sin_addr = relay->server.addr4;
|
to.in.sin_addr = relay->server.addr4;
|
||||||
to.in.sin_port = htons(relay->port);
|
to.in.sin_port = htons(relay->port);
|
||||||
@@ -3165,10 +3180,9 @@ void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz, int u
|
|||||||
/* Broadcasting to server. */
|
/* Broadcasting to server. */
|
||||||
if (relay->server.addr4.s_addr == 0)
|
if (relay->server.addr4.s_addr == 0)
|
||||||
{
|
{
|
||||||
if (!relay->interface || strchr(relay->interface, '*') ||
|
if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
|
||||||
ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
|
|
||||||
{
|
{
|
||||||
my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s"), relay->interface);
|
my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s: %s"), relay->interface, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3206,35 +3220,41 @@ void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz, int u
|
|||||||
*endopt = OPTION_END;
|
*endopt = OPTION_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
|
unsigned int relay_reply4(struct dhcp_packet *mess, size_t sz, char *arrival_interface)
|
||||||
{
|
{
|
||||||
struct dhcp_relay *relay;
|
struct dhcp_relay *relay;
|
||||||
|
|
||||||
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
|
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||||
{
|
{
|
||||||
|
unsigned int return_iface = 0;
|
||||||
|
|
||||||
if (relay->split_mode)
|
if (relay->split_mode)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
unsigned char *opt, *sopt;
|
||||||
|
|
||||||
safe_strncpy(ifr.ifr_name, arrival_interface, IF_NAMESIZE);
|
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
|
||||||
|
|
||||||
/* giaddr is our address on the returning interface in split mode. */
|
/* giaddr is our address on the returning interface in split mode. */
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1 ||
|
if (mess->giaddr.s_addr == relay->uplink.addr4.s_addr &&
|
||||||
mess->giaddr.s_addr != ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr)
|
(opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
|
||||||
continue;
|
{
|
||||||
}
|
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, sizeof(unsigned int))))
|
||||||
else if (mess->giaddr.s_addr != relay->local.addr4.s_addr)
|
return_iface = option_uint(sopt, 0, sizeof(unsigned int));
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
|
/* delete agent info before return RFC 3046 para 2.1 */
|
||||||
return relay->iface_index != 0 ? relay : NULL;
|
*opt = OPTION_END;
|
||||||
|
memset(opt + 1, 0, option_len(opt) + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
|
||||||
|
return_iface = relay->iface_index;
|
||||||
|
|
||||||
|
if (return_iface && (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
|
||||||
|
return return_iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user