mirror of
https://git.freebsd.org/src.git
synced 2026-01-11 19:57:22 +00:00
arp: fix adding proxy entries for P2P interfaces
The old rtsock implementation used in-kernel workaround to do so. When route to specified destination address used P2P interface, the kernel did the search with ifa_ifwithnet() for most suitable network and then add proxy entry to this interface. Use similar approach with netlink implementation. We already have get_ether_addr() function that does almost the same thing as ifa_ifwithnet(). Use it when we find that destination route uses P2P interface and then try to guess suitable interface. This should fix the use of netlink-based arp(8) in mpd5. Rename get_ether_addr() to get_ifinfo(), since now it is used to find only ifindex in case when hwaddr is specified by user. Also make set_nl() and delete_nl() prototype similar to rtsock. And allow '-i' to be used with '-S', since we already allow the same for '-s'. PR: 290221 Reported by: eugen Reviewed by: eugen MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D53113
This commit is contained in:
parent
86db3c735d
commit
c26d6bf9da
3 changed files with 40 additions and 21 deletions
|
|
@ -81,7 +81,6 @@ static int get(char *host);
|
|||
static int file(char *name);
|
||||
static struct rt_msghdr *rtmsg(int cmd,
|
||||
struct sockaddr_in *dst, struct sockaddr_dl *sdl);
|
||||
static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr);
|
||||
static int set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m,
|
||||
char *host);
|
||||
|
||||
|
|
@ -143,7 +142,8 @@ main(int argc, char *argv[])
|
|||
if (!func)
|
||||
func = F_GET;
|
||||
if (opts.rifname) {
|
||||
if (func != F_GET && func != F_SET && !(func == F_DELETE && opts.aflag))
|
||||
if (func != F_GET && func != F_SET && func != F_REPLACE &&
|
||||
!(func == F_DELETE && opts.aflag))
|
||||
xo_errx(1, "-i not applicable to this operation");
|
||||
if ((opts.rifindex = if_nametoindex(opts.rifname)) == 0) {
|
||||
if (errno == ENXIO)
|
||||
|
|
@ -273,7 +273,6 @@ getaddr(char *host)
|
|||
return (&reply);
|
||||
}
|
||||
|
||||
int valid_type(int type);
|
||||
/*
|
||||
* Returns true if the type is a valid one for ARP.
|
||||
*/
|
||||
|
|
@ -357,11 +356,14 @@ set(int argc, char **argv)
|
|||
}
|
||||
ea = (struct ether_addr *)LLADDR(&sdl_m);
|
||||
if ((opts.flags & RTF_ANNOUNCE) && !strcmp(eaddr, "auto")) {
|
||||
if (!get_ether_addr(dst->sin_addr.s_addr, ea)) {
|
||||
uint32_t ifindex;
|
||||
if (!get_ifinfo(dst->sin_addr.s_addr, ea, &ifindex)) {
|
||||
xo_warnx("no interface found for %s",
|
||||
inet_ntoa(dst->sin_addr));
|
||||
inet_ntoa(dst->sin_addr));
|
||||
return (1);
|
||||
}
|
||||
if (opts.rifindex == 0)
|
||||
opts.rifindex = ifindex;
|
||||
sdl_m.sdl_alen = ETHER_ADDR_LEN;
|
||||
} else {
|
||||
struct ether_addr *ea1 = ether_aton(eaddr);
|
||||
|
|
@ -375,7 +377,7 @@ set(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
#ifndef WITHOUT_NETLINK
|
||||
return (set_nl(opts.rifindex, dst, &sdl_m, host));
|
||||
return (set_nl(dst, &sdl_m, host));
|
||||
#else
|
||||
return (set_rtsock(dst, &sdl_m, host));
|
||||
#endif
|
||||
|
|
@ -522,7 +524,7 @@ delete(char *host)
|
|||
#ifdef WITHOUT_NETLINK
|
||||
return (delete_rtsock(host));
|
||||
#else
|
||||
return (delete_nl(0, host));
|
||||
return (delete_nl(host));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -819,11 +821,11 @@ doit:
|
|||
}
|
||||
|
||||
/*
|
||||
* get_ether_addr - get the hardware address of an interface on the
|
||||
* same subnet as ipaddr.
|
||||
* get_ifinfo - get the hardware address and if_index of an interface
|
||||
* on the same subnet as ipaddr.
|
||||
*/
|
||||
static int
|
||||
get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr)
|
||||
int
|
||||
get_ifinfo(in_addr_t ipaddr, struct ether_addr *hwaddr, uint32_t *pifindex)
|
||||
{
|
||||
struct ifaddrs *ifa, *ifd, *ifas = NULL;
|
||||
in_addr_t ina, mask;
|
||||
|
|
@ -862,7 +864,13 @@ get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr)
|
|||
}
|
||||
if (ifa == NULL)
|
||||
goto done;
|
||||
|
||||
if (pifindex != NULL)
|
||||
*pifindex = if_nametoindex(ifa->ifa_name);
|
||||
if (hwaddr == NULL) {
|
||||
/* ether addr is not required */
|
||||
retval = ETHER_ADDR_LEN;
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* Now scan through again looking for a link-level address
|
||||
* for this interface.
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
#define _USR_SBIN_ARP_ARP_H_
|
||||
|
||||
int valid_type(int type);
|
||||
int get_ifinfo(in_addr_t ipaddr, struct ether_addr *hwaddr, uint32_t *pifindex);
|
||||
struct sockaddr_in *getaddr(char *host);
|
||||
int print_entries_nl(uint32_t ifindex, struct in_addr addr);
|
||||
|
||||
struct arp_opts {
|
||||
bool aflag;
|
||||
|
|
@ -11,13 +11,12 @@ struct arp_opts {
|
|||
time_t expire_time;
|
||||
int flags;
|
||||
char *rifname;
|
||||
unsigned int rifindex;
|
||||
uint32_t rifindex;
|
||||
};
|
||||
extern struct arp_opts opts;
|
||||
|
||||
int print_entries_nl(uint32_t ifindex, struct in_addr addr);
|
||||
int delete_nl(uint32_t ifindex, char *host);
|
||||
int set_nl(uint32_t ifindex, struct sockaddr_in *dst, struct sockaddr_dl *sdl,
|
||||
char *host);
|
||||
int delete_nl(char *host);
|
||||
int set_nl(struct sockaddr_in *dst, struct sockaddr_dl *sdl, char *host);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -79,13 +79,15 @@ get_link_info(struct snl_state *ss, uint32_t ifindex,
|
|||
|
||||
|
||||
static bool
|
||||
has_l2(struct snl_state *ss, uint32_t ifindex)
|
||||
has_l2(struct snl_state *ss, uint32_t ifindex, uint32_t *pflags)
|
||||
{
|
||||
struct snl_parsed_link_simple link = {};
|
||||
|
||||
*pflags = 0;
|
||||
if (!get_link_info(ss, ifindex, &link))
|
||||
return (false);
|
||||
|
||||
*pflags = link.ifi_flags;
|
||||
return (valid_type(link.ifi_type) != 0);
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +106,7 @@ static int
|
|||
guess_ifindex(struct snl_state *ss, uint32_t fibnum, struct in_addr addr)
|
||||
{
|
||||
struct snl_writer nw;
|
||||
uint32_t ifindex, ifflags;
|
||||
|
||||
snl_init_writer(ss, &nw);
|
||||
|
||||
|
|
@ -133,9 +136,16 @@ guess_ifindex(struct snl_state *ss, uint32_t fibnum, struct in_addr addr)
|
|||
return (0);
|
||||
|
||||
/* Check if the interface is of supported type */
|
||||
if (has_l2(ss, r.rta_oif))
|
||||
if (has_l2(ss, r.rta_oif, &ifflags))
|
||||
return (r.rta_oif);
|
||||
|
||||
/* Check if we are doing proxy arp for P2P interface */
|
||||
if (ifflags & IFF_POINTOPOINT) {
|
||||
/* Guess interface by dst prefix */
|
||||
if (get_ifinfo(addr.s_addr, NULL, &ifindex))
|
||||
return (ifindex);
|
||||
}
|
||||
|
||||
/* Check the case when we matched the loopback route for P2P */
|
||||
snl_init_writer(ss, &nw);
|
||||
hdr = snl_create_msg_request(&nw, RTM_GETNEXTHOP);
|
||||
|
|
@ -326,11 +336,12 @@ print_entries_nl(uint32_t ifindex, struct in_addr addr)
|
|||
}
|
||||
|
||||
int
|
||||
delete_nl(uint32_t ifindex, char *host)
|
||||
delete_nl(char *host)
|
||||
{
|
||||
struct snl_state ss = {};
|
||||
struct snl_writer nw;
|
||||
struct sockaddr_in *dst;
|
||||
uint32_t ifindex = opts.rifindex;
|
||||
|
||||
dst = getaddr(host);
|
||||
if (dst == NULL)
|
||||
|
|
@ -375,10 +386,11 @@ delete_nl(uint32_t ifindex, char *host)
|
|||
}
|
||||
|
||||
int
|
||||
set_nl(uint32_t ifindex, struct sockaddr_in *dst, struct sockaddr_dl *sdl, char *host)
|
||||
set_nl(struct sockaddr_in *dst, struct sockaddr_dl *sdl, char *host)
|
||||
{
|
||||
struct snl_state ss = {};
|
||||
struct snl_writer nw;
|
||||
uint32_t ifindex = opts.rifindex;
|
||||
|
||||
nl_init_socket(&ss);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue