igmpproxy: update to 0.4

arm-master
pedro 3 years ago
parent fecf29971a
commit 6bff09aa45

@ -4,6 +4,7 @@ Aim Wang <aimwang@users.sourceforge.net>
Alexey Charkov <alchark@gmail.com>
Ambroz Bizjak <ambrop7@users.sourceforge.net>
Antti Seppälä <a.seppala@gmail.com>
Björn Ketelaars <bjorn.ketelaars@hydroxide.nl>
Christian Ruppert <idl0r@gentoo.org>
Conrad Kostecki <ConiKost@gmx.de>
Constantin Baranov <const@mimas.ru>

@ -1,3 +1,32 @@
2022-10-29 12:01:46 +0200 Pali Rohár <pali.rohar@gmail.com>
* Release version 0.4
2021-07-09 22:19:12 +0200 Björn Ketelaars <bjorn.ketelaars@hydroxide.nl>
* Complement phyint whitelist with blacklist
Fixes: #54
Implement new phyint configuration option (blacklist), which enables
blocking of specific traffic.
2021-06-29 20:17:47 +0200 Björn Ketelaars <bjorn.ketelaars@hydroxide.nl>
* Chroot and drop privileges after startup
With this PR:
- The apparent root directory can be changed after startup, thus denying
igmpproxy access to files and commands outside that environmental
directory tree.
- igmpproxy can drop root privileges after startup by changing id to
another user.
2021-07-04 14:14:50 +0200 Pali Rohár <pali.rohar@gmail.com>
* Add travis apt repositories for Ubuntu Precise
2021-01-04 18:40:01 +0100 Pali Rohár <pali.rohar@gmail.com>
* Release version 0.3

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for igmpproxy 0.3.
# Generated by GNU Autoconf 2.69 for igmpproxy 0.4.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@ -576,8 +576,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='igmpproxy'
PACKAGE_TARNAME='igmpproxy'
PACKAGE_VERSION='0.3'
PACKAGE_STRING='igmpproxy 0.3'
PACKAGE_VERSION='0.4'
PACKAGE_STRING='igmpproxy 0.4'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@ -1241,7 +1241,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures igmpproxy 0.3 to adapt to many kinds of systems.
\`configure' configures igmpproxy 0.4 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1312,7 +1312,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of igmpproxy 0.3:";;
short | recursive ) echo "Configuration of igmpproxy 0.4:";;
esac
cat <<\_ACEOF
@ -1402,7 +1402,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
igmpproxy configure 0.3
igmpproxy configure 0.4
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1560,7 +1560,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by igmpproxy $as_me 0.3, which was
It was created by igmpproxy $as_me 0.4, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2423,7 +2423,7 @@ fi
# Define the identity of the package.
PACKAGE='igmpproxy'
VERSION='0.3'
VERSION='0.4'
cat >>confdefs.h <<_ACEOF
@ -4499,7 +4499,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by igmpproxy $as_me 0.3, which was
This file was extended by igmpproxy $as_me 0.4, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -4569,7 +4569,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
igmpproxy config.status 0.3
igmpproxy config.status 0.4
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

@ -1,5 +1,5 @@
AC_PREREQ([2.63])
AC_INIT([igmpproxy], [0.3])
AC_INIT([igmpproxy], [0.4])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/igmpproxy.c])
AC_CONFIG_HEADERS([config.h])

@ -41,7 +41,29 @@ aliases not in use should be configured as disabled.
Any line in the configuration file starting with
.B #
is treated as a comment. Keywords and parameters can be distributed over many lines.
The configuration file has two main keywords:
The configuration file has four main keywords:
.B chroot
.I directory
.RS
Changes the apparent root directory to the given path after startup, thus
denying
.B igmpproxy
access to files and commands outside that environmental directory tree.
.RE
.B user
.I username
.RS
Specifies the userid to which
.B igmpproxy
will change after startup.
.B igmpproxy
must be started as root, but it will drop root privileges to the specified
user.
.RE
.B quickleave
.RS
@ -139,6 +161,26 @@ You may also specify whitelist entries for the upstream interface. Only igmp mem
for explicitly whitelisted multicast groups will be sent out on the upstream interface. This
is useful if you want to use multicast groups only between your downstream interfaces, like SSDP
from a UPnP server.
This option can be combined with
.B blacklist
for fine-grained control.
.RE
.B blacklist
.I networkaddr
.RS
Defines a blacklist for multicast groups. Similar to
.B whitelist
except that if a blacklist entry is defined, all igmp membership reports for
that multicast group will be ignored and therefore not be served by igmpproxy.
Each time a multicast group is forwarded or requested, whitelist and blacklist
entries are evaluated in sequential order, from first to last. The last matching
entry decides what action is taken; if no entry matches the multicast group, the
default action is to serve. Note that, if at least one whitelist entry is
defined before any blacklist entry, all igmp membership reports for not
explicitly whitelisted multicast groups will be ignored.
.RE
.SH EXAMPLE

@ -196,6 +196,31 @@ int loadConfig(char *configFile) {
// Read next token...
token = nextConfigToken();
continue;
}
else if(strcmp("chroot", token)==0) {
// path is in next token
token = nextConfigToken();
if (snprintf(commonConfig.chroot, sizeof(commonConfig.chroot), "%s",
token) >= (int)sizeof(commonConfig.chroot))
my_log(LOG_ERR, 0, "Config: chroot is truncated");
my_log(LOG_DEBUG, 0, "Config: chroot set to %s",
commonConfig.chroot);
token = nextConfigToken();
continue;
}
else if(strcmp("user", token)==0) {
// username is in next token
token = nextConfigToken();
if (snprintf(commonConfig.user, sizeof(commonConfig.user), "%s",
token) >= (int)sizeof(commonConfig.user))
my_log(LOG_ERR, 0, "Config: user is truncated");
my_log(LOG_DEBUG, 0, "Config: user set to %s", commonConfig.user);
token = nextConfigToken();
continue;
} else {
// Unparsable token... Exit...
closeConfigFile();
@ -326,10 +351,26 @@ struct vifconfig *parsePhyintToken(void) {
*agrpPtr = parseSubnetAddress(token);
if(*agrpPtr == NULL) {
parseError = 1;
my_log(LOG_WARNING, 0, "Unable to parse subnet address.");
break;
free(tmpPtr->name);
free(tmpPtr);
my_log(LOG_ERR, 0, "Unable to parse subnet address.");
} else {
(*agrpPtr)->allow = true;
agrpPtr = &(*agrpPtr)->next;
}
}
else if(strcmp("blacklist", token)==0) {
// Blacklist
token = nextConfigToken();
my_log(LOG_DEBUG, 0, "Config: IF: Got blacklist token %s.", token);
*agrpPtr = parseSubnetAddress(token);
if(*agrpPtr == NULL) {
free(tmpPtr->name);
free(tmpPtr);
my_log(LOG_ERR, 0, "Unable to parse subnet address.");
} else {
(*agrpPtr)->allow = false;
agrpPtr = &(*agrpPtr)->next;
}
}

@ -121,13 +121,6 @@ void acceptIgmp(int recvlen) {
src = ip->ip_src.s_addr;
dst = ip->ip_dst.s_addr;
/* filter local multicast 239.255.255.250 */
if (dst == htonl(0xEFFFFFFA))
{
my_log(LOG_NOTICE, 0, "The IGMP message was local multicast. Ignoring.");
return;
}
/*
* this is most likely a message from the kernel indicating that
* a new src grp pair message has arrived and so, it would be

@ -78,9 +78,12 @@ int upStreamIfIdx[MAX_UPS_VIFS];
*/
int main( int ArgCn, char *ArgVc[] ) {
int c;
int c, devnull = -1;
bool NotAsDaemon = false;
struct Config *config = NULL;
struct passwd *pw = NULL;
srand(time(NULL) * getpid());
// Parse the commandline options and setup basic settings..
@ -140,18 +143,46 @@ int main( int ArgCn, char *ArgVc[] ) {
break;
}
// Open /dev/null before chrooting.
if (!NotAsDaemon) {
devnull = open("/dev/null", O_RDWR);
if (devnull == -1)
my_log(LOG_ERR, 0, "unable to open /dev/null");
}
config = getCommonConfig();
if (config->user[0]) {
pw = getpwnam(config->user);
if (pw == NULL)
my_log(LOG_ERR, 0, "unknown user %s", config->user);
}
if (config->chroot[0])
if (chroot(config->chroot) != 0 || chdir("/") != 0)
my_log(LOG_ERR, 0, "unable to chroot to %s",
config->chroot);
if (pw != NULL)
if (setgroups(1, &pw->pw_gid) != 0 ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0 ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
my_log(LOG_ERR, 0, "unable to drop privileges to %s",
config->user);
if ( !NotAsDaemon ) {
// Only daemon goes past this line...
if (fork()) exit(0);
// Detach daemon from terminal
if ( close( 0 ) < 0 || close( 1 ) < 0 || close( 2 ) < 0
|| open( "/dev/null", 0 ) != 0 || dup2( 0, 1 ) < 0 || dup2( 0, 2 ) < 0
|| setpgid( 0, 0 ) < 0
) {
if ( close( 0 ) < 0 || close( 1 ) < 0 || close( 2 ) < 0 ||
dup2( devnull, 0 ) < 0 || dup2( devnull, 1 ) < 0 ||
dup2( devnull, 2 ) < 0 || setpgid( 0, 0 ) < 0 ) {
my_log( LOG_ERR, errno, "failed to detach daemon" );
}
if (devnull > 2)
close(devnull);
}
// Go to the main loop.

@ -49,6 +49,9 @@
#include <fcntl.h>
#include <stdbool.h>
#include <time.h>
#include <grp.h>
#include <limits.h>
#include <pwd.h>
#include <sys/socket.h>
#include <sys/un.h>
@ -142,6 +145,7 @@ struct SubnetList {
uint32_t subnet_addr;
uint32_t subnet_mask;
struct SubnetList *next;
bool allow;
};
struct IfDesc {
@ -178,6 +182,8 @@ struct Config {
// Set if not detect new interface for down stream.
unsigned short defaultInterfaceState; // 0: disable, 2: downstream
//~ aimwang added done
char chroot[PATH_MAX];
char user[LOGIN_NAME_MAX];
};
// Holds the indeces of the upstream IF...

@ -83,22 +83,33 @@ void acceptGroupReport(uint32_t src, uint32_t group) {
my_log(LOG_DEBUG, 0, "Should insert group %s (from: %s) to route table. Vif Ix : %d",
inetFmt(group,s1), inetFmt(src,s2), sourceVif->index);
// If we don't have a whitelist we insertRoute and done
// If we don't have a black- and whitelist we insertRoute and done
if(sourceVif->allowedgroups == NULL)
{
insertRoute(group, sourceVif->index, src);
return;
}
// Check if this Request is legit on this interface
struct SubnetList *sn;
for(sn = sourceVif->allowedgroups; sn != NULL; sn = sn->next)
bool allow_list = false;
struct SubnetList *match = NULL;
struct SubnetList *sn;
for(sn = sourceVif->allowedgroups; sn != NULL; sn = sn->next) {
// Check if there is a whitelist
if (sn->allow)
allow_list = true;
if((group & sn->subnet_mask) == sn->subnet_addr)
{
// The membership report was OK... Insert it into the route table..
insertRoute(group, sourceVif->index, src);
return;
match = sn;
}
if((!allow_list && match == NULL) ||
(allow_list && match != NULL && match->allow)) {
// The membership report was OK... Insert it into the route table..
insertRoute(group, sourceVif->index, src);
return;
}
my_log(LOG_INFO, 0, "The group address %s may not be requested from this interface. Ignoring.", inetFmt(group, s1));
my_log(LOG_INFO, 0, "The group address %s may not be requested from this interface. Ignoring.", inetFmt(group, s1));
} else {
// Log the state of the interface the report was received on.
my_log(LOG_INFO, 0, "Mebership report was received on %s. Ignoring.",

@ -157,18 +157,25 @@ static void sendJoinLeaveUpstream(struct RouteTable* route, int join) {
my_log(LOG_ERR, 0 ,"FATAL: Unable to get Upstream IF.");
}
// Check if there is a white list for the upstram VIF
// Check if there is a black- or whitelist for the upstram VIF
if (upstrIf->allowedgroups != NULL) {
uint32_t group = route->group;
struct SubnetList* sn;
bool allow_list = false;
struct SubnetList *match = NULL;
struct SubnetList *sn;
uint32_t group = route->group;
// Check if this Request is legit to be forwarded to upstream
for(sn = upstrIf->allowedgroups; sn != NULL; sn = sn->next)
for(sn = upstrIf->allowedgroups; sn != NULL; sn = sn->next) {
// Check if there is a whitelist
if (sn->allow)
allow_list = true;
if((group & sn->subnet_mask) == sn->subnet_addr)
// Forward is OK...
break;
match = sn;
}
if (sn == NULL) {
// Keep in sync with request.c, note the negation
if(!((!allow_list && match == NULL) ||
(allow_list && match != NULL && match->allow))) {
my_log(LOG_INFO, 0, "The group address %s may not be forwarded upstream. Ignoring.", inetFmt(group, s1));
return;
}

Loading…
Cancel
Save