Skip to content

Commit

Permalink
Use ifindex to identify interfaces
Browse files Browse the repository at this point in the history
This adds support for identifying interfaces by their indexes instead of
by IP. This allows the use of unnumbered links with igmpproxy.

For this to work, it requires the OS to have the ip_mreqn struct as well
as the VIFF_USE_IFINDEX option for MRT_ADD_VIF. If unavailable it falls
back to the original behavior of just identifying interfaces by IP.
  • Loading branch information
lorenz committed Dec 27, 2022
1 parent 9762cf8 commit 865a73c
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 21 deletions.
6 changes: 6 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], [], [], [[
#include <netinet/in.h>
]])

# Check for Linux-style extension struct ip_mreqn (Linux, FreeBSD)
# Adopted from https://github.com/troglobit/smcroute/blob/2.5.6/configure.ac#L144
AC_CHECK_MEMBER([struct ip_mreqn.imr_ifindex],
AC_DEFINE([HAVE_STRUCT_IP_MREQN], [1], [Define to 1 if you have a Linux-style struct ip_mreqn]),
[], [[#include <netinet/in.h>]])

AC_SEARCH_LIBS(socket, socket)

AC_SEARCH_LIBS([clock_gettime],[rt])
Expand Down
14 changes: 12 additions & 2 deletions src/ifvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ void rebuildIfVc () {

memcpy( IfReq.ifr_name, Dp->Name, sizeof( IfReq.ifr_name ) );

if (ioctl(Sock, SIOCGIFINDEX, &IfReq ) < 0)
my_log(LOG_ERR, errno, "ioctl SIOCGIFINDEX for %s", IfReq.ifr_name);
Dp->ifIndex = IfReq.ifr_ifindex;

// Get the subnet mask...
if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0)
my_log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name);
Expand Down Expand Up @@ -175,8 +179,9 @@ void rebuildIfVc () {
}

// Debug log the result...
my_log( LOG_DEBUG, 0, "rebuildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s",
my_log( LOG_DEBUG, 0, "rebuildIfVc: Interface %s Index: %d Addr: %s, Flags: 0x%04x, Network: %s",
Dp->Name,
Dp->ifIndex,
fmtInAdr( FmtBu, Dp->InAdr ),
Dp->Flags,
inetFmts(subnet, mask, s1));
Expand Down Expand Up @@ -268,6 +273,10 @@ void buildIfVc(void) {

memcpy( IfReq.ifr_name, IfDescEp->Name, sizeof( IfReq.ifr_name ) );

if (ioctl(Sock, SIOCGIFINDEX, &IfReq ) < 0)
my_log(LOG_ERR, errno, "ioctl SIOCGIFINDEX for %s", IfReq.ifr_name);
IfDescEp->ifIndex = IfReq.ifr_ifindex;

// Get the subnet mask...
if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0)
my_log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name);
Expand Down Expand Up @@ -313,8 +322,9 @@ void buildIfVc(void) {
IfDescEp->ratelimit = DEFAULT_RATELIMIT;

// Debug log the result...
my_log( LOG_DEBUG, 0, "buildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s",
my_log( LOG_DEBUG, 0, "buildIfVc: Interface %s Index: %d Addr: %s, Flags: 0x%04x, Network: %s",
IfDescEp->Name,
IfDescEp->ifIndex,
fmtInAdr( FmtBu, IfDescEp->InAdr ),
IfDescEp->Flags,
inetFmts(subnet,mask, s1));
Expand Down
10 changes: 6 additions & 4 deletions src/igmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,16 +295,18 @@ static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t g
/*
* Call build_igmp() to build an IGMP message in the output packet buffer.
* Then send the message from the interface with IP address 'src' to
* destination 'dst'.
* destination 'dst'. If struct ip_mreqn is present on the target OS, it is
* used instead of 'src' to select the sending interface. 'src' is still used
* as the source IP.
*/
void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen, int ifidx) {
struct sockaddr_in sdst;
int setloop = 0, setigmpsource = 0;

buildIgmp(src, dst, type, code, group, datalen);

if (IN_MULTICAST(ntohl(dst))) {
k_set_if(src);
k_set_if(src, ifidx);
setigmpsource = 1;
if (type != IGMP_DVMRP || dst == allhosts_group) {
setloop = 1;
Expand Down Expand Up @@ -334,7 +336,7 @@ void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, in
k_set_loop(false);
}
// Restore original...
k_set_if(INADDR_ANY);
k_set_if(INADDR_ANY, 0);
}

my_log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
Expand Down
5 changes: 3 additions & 2 deletions src/igmpproxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ struct SubnetList {
struct IfDesc {
char Name[IF_NAMESIZE];
struct in_addr InAdr; /* == 0 for non IP interfaces */
int ifIndex;
short Flags;
short state;
struct SubnetList* allowednets;
Expand Down Expand Up @@ -232,7 +233,7 @@ extern uint32_t allrouters_group;
extern uint32_t alligmp3_group;
void initIgmp(void);
void acceptIgmp(int);
void sendIgmp (uint32_t, uint32_t, int, int, uint32_t,int);
void sendIgmp (uint32_t, uint32_t, int, int, uint32_t, int, int);

/* lib.c
*/
Expand All @@ -247,7 +248,7 @@ void k_set_rcvbuf(int bufsize, int minsize);
void k_hdr_include(int hdrincl);
void k_set_ttl(int t);
void k_set_loop(int l);
void k_set_if(uint32_t ifa);
void k_set_if(uint32_t ifa, int ifidx);
void k_join(struct IfDesc *ifd, uint32_t grp);
void k_leave(struct IfDesc *ifd, uint32_t grp);

Expand Down
33 changes: 24 additions & 9 deletions src/kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,22 +100,32 @@ void k_set_loop(int l) {
(char *)&loop, sizeof(loop)) < 0)
my_log(LOG_WARNING, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
}
void k_set_if(uint32_t ifa, int ifidx) {
#ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn ifsel;
ifsel.imr_address.s_addr = ifa;
ifsel.imr_ifindex = ifidx;
#else
struct in_addr ifsel;
ifsel.s_addr = ifa;
#endif

void k_set_if(uint32_t ifa) {
struct in_addr adr;

adr.s_addr = ifa;
if (setsockopt(MRouterFD, IPPROTO_IP, IP_MULTICAST_IF,
(char *)&adr, sizeof(adr)) < 0)
(char *)&ifsel, sizeof(ifsel)) < 0)
my_log(LOG_WARNING, errno, "setsockopt IP_MULTICAST_IF %s",
inetFmt(ifa, s1));
}

void k_join(struct IfDesc *ifd, uint32_t grp) {
#ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn mreq;
mreq.imr_address.s_addr = ifd->InAdr.s_addr;
mreq.imr_ifindex = ifd->ifIndex;
#else
struct ip_mreq mreq;

mreq.imr_multiaddr.s_addr = grp;
mreq.imr_interface.s_addr = ifd->InAdr.s_addr;
#endif
mreq.imr_multiaddr.s_addr = grp;

my_log(LOG_NOTICE, 0, "Joining group %s on interface %s", inetFmt(grp, s1), ifd->Name);

Expand All @@ -134,10 +144,15 @@ void k_join(struct IfDesc *ifd, uint32_t grp) {
}

void k_leave(struct IfDesc *ifd, uint32_t grp) {
#ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn mreq;
mreq.imr_address.s_addr = ifd->InAdr.s_addr;
mreq.imr_ifindex = ifd->ifIndex;
#else
struct ip_mreq mreq;

mreq.imr_multiaddr.s_addr = grp;
mreq.imr_interface.s_addr = ifd->InAdr.s_addr;
#endif
mreq.imr_multiaddr.s_addr = grp;

my_log(LOG_NOTICE, 0, "Leaving group %s on interface %s", inetFmt(grp, s1), ifd->Name);

Expand Down
8 changes: 7 additions & 1 deletion src/mroute-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,17 @@ void addVIF( struct IfDesc *IfDp )
VifDp->IfDp = IfDp;

VifCtl.vifc_vifi = VifDp - VifDescVc;
VifCtl.vifc_flags = 0; /* no tunnel, no source routing, register ? */
VifCtl.vifc_threshold = VifDp->IfDp->threshold; // Packet TTL must be at least 1 to pass them
VifCtl.vifc_rate_limit = VifDp->IfDp->ratelimit; // Ratelimit

#ifdef VIFF_USE_IFINDEX
VifCtl.vifc_flags = VIFF_USE_IFINDEX;
VifCtl.vifc_lcl_ifindex = VifDp->IfDp->ifIndex;
#else
VifCtl.vifc_flags = 0;
VifCtl.vifc_lcl_addr.s_addr = VifDp->IfDp->InAdr.s_addr;
#endif

VifCtl.vifc_rmt_addr.s_addr = INADDR_ANY;

// Set the index...
Expand Down
7 changes: 4 additions & 3 deletions src/request.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ void sendGroupSpecificMemberQuery(void *argument) {
sendIgmp(Dp->InAdr.s_addr, gvDesc->group,
IGMP_MEMBERSHIP_QUERY,
conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
gvDesc->group, 0);
gvDesc->group, 0, Dp->ifIndex);

my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
inetFmt(Dp->InAdr.s_addr,s1), inetFmt(gvDesc->group,s2),
Expand Down Expand Up @@ -232,11 +232,12 @@ void sendGeneralMembershipQuery(void) {
// Send the membership query...
sendIgmp(Dp->InAdr.s_addr, allhosts_group,
IGMP_MEMBERSHIP_QUERY,
conf->queryResponseInterval * IGMP_TIMER_SCALE, 0, 0);
conf->queryResponseInterval * IGMP_TIMER_SCALE, 0, 0, Dp->ifIndex);

my_log(LOG_DEBUG, 0,
"Sent membership query from %s to %s. Delay: %d",
"Sent membership query from %s ifIndex %d to %s. Delay: %d",
inetFmt(Dp->InAdr.s_addr,s1),
Dp->ifIndex,
inetFmt(allhosts_group,s2),
conf->queryResponseInterval);
}
Expand Down

0 comments on commit 865a73c

Please sign in to comment.