Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package smcroute for openSUSE:Factory checked in at 2022-12-03 10:04:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/smcroute (Old) and /work/SRC/openSUSE:Factory/.smcroute.new.1835 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "smcroute" Sat Dec 3 10:04:03 2022 rev:9 rq:1039756 version:2.5.6 Changes: -------- --- /work/SRC/openSUSE:Factory/smcroute/smcroute.changes 2021-11-21 23:52:46.122139466 +0100 +++ /work/SRC/openSUSE:Factory/.smcroute.new.1835/smcroute.changes 2022-12-03 10:04:16.899455387 +0100 @@ -1,0 +2,7 @@ +Mon Nov 28 17:57:31 UTC 2022 - Martin Hauke <mar...@gmx.de> + +- Update to version 2.5.6 + * Add smcroutectl batch support. + * Fix removing group config. + +------------------------------------------------------------------- Old: ---- smcroute-2.5.5.tar.gz New: ---- smcroute-2.5.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ smcroute.spec ++++++ --- /var/tmp/diff_new_pack.ArvIZO/_old 2022-12-03 10:04:17.499458721 +0100 +++ /var/tmp/diff_new_pack.ArvIZO/_new 2022-12-03 10:04:17.503458743 +0100 @@ -1,8 +1,8 @@ # # spec file for package smcroute # -# Copyright (c) 2021 SUSE LLC -# Copyright (c) 2018-2021, Martin Hauke <mar...@gmx.de> +# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2018-2022, Martin Hauke <mar...@gmx.de> # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ Name: smcroute -Version: 2.5.5 +Version: 2.5.6 Release: 0 Summary: Static multicast routing for UNIX License: GPL-3.0-only ++++++ smcroute-2.5.5.tar.gz -> smcroute-2.5.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/.github/workflows/build.yml new/smcroute-2.5.6/.github/workflows/build.yml --- old/smcroute-2.5.5/.github/workflows/build.yml 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/.github/workflows/build.yml 2022-11-28 08:00:09.000000000 +0100 @@ -29,7 +29,7 @@ sudo modprobe ip_gre sudo apt-get -y update sudo apt-get -y install pkg-config libsystemd-dev libcap-dev tshark iptables valgrind - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Configure # Build in a sub-directory so we can safely set a+w on all # directories. Needed for `make check` since it runs with @@ -67,7 +67,7 @@ sudo chmod a+rw /var/run/xtables.lock make check || (cat test/test-suite.log; false) - name: Upload Test Results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: smcroute-test-${{ matrix.compiler }} path: test/* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/.github/workflows/coverity.yml new/smcroute-2.5.6/.github/workflows/coverity.yml --- old/smcroute-2.5.5/.github/workflows/coverity.yml 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/.github/workflows/coverity.yml 2022-11-28 08:00:09.000000000 +0100 @@ -15,7 +15,7 @@ coverity: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Fetch latest Coverity Scan MD5 id: var env: @@ -27,7 +27,7 @@ export MD5=$(cat coverity-latest.tar.gz.md5) echo "Got MD5 $MD5" echo ::set-output name=md5::${MD5} - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: cache with: path: coverity-latest.tar.gz @@ -76,7 +76,7 @@ --form description="${PROJECT_NAME} $(git rev-parse HEAD)" \ https://scan.coverity.com/builds?project=${COVERITY_PROJ} - name: Upload build.log - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: coverity-build.log path: cov-int/build-log.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/.github/workflows/release.yml new/smcroute-2.5.6/.github/workflows/release.yml --- old/smcroute-2.5.5/.github/workflows/release.yml 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/.github/workflows/release.yml 2022-11-28 08:00:09.000000000 +0100 @@ -7,38 +7,11 @@ jobs: release: - name: Create GitHub release - runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/') - outputs: - upload_url: ${{ steps.create_release.outputs.upload_url }} - release_id: ${{ steps.create_release.outputs.id }} - steps: - - uses: actions/checkout@v2 - - name: Extract ChangeLog entry ... - # Hack to extract latest entry for body_path below - run: | - awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \ - |head -n -1 > release.md - cat release.md - - name: Create release ... - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: SMCRoute v${{ github.ref }} - body_path: release.md - draft: false - prerelease: false - tarball: name: Build and upload release tarball - needs: release if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Installing dependencies ... run: | sudo modprobe ip_gre @@ -55,10 +28,13 @@ ls -lF ../ mkdir -p artifacts/ mv ../*.tar.* artifacts/ - - name: Upload release artifacts ... - uses: skx/github-action-publish-binaries@release-0.15 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Extract ChangeLog entry ... + run: | + awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \ + |head -n -1 > release.md + cat release.md + - uses: ncipollo/release-action@v1 with: - releaseId: ${{ needs.release.outputs.release_id }} - args: artifacts/* + name: SMCRoute v${{ github.ref_name }} + bodyFile: "release.md" + artifacts: "artifacts/*" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/ChangeLog.md new/smcroute-2.5.6/ChangeLog.md --- old/smcroute-2.5.5/ChangeLog.md 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/ChangeLog.md 2022-11-28 08:00:09.000000000 +0100 @@ -3,6 +3,36 @@ All notable changes to the project are documented in this file. +[v2.5.6][] - 2022-11-28 +----------------------- + +Despite the new `smcroutectl` batch mode feature, this is primarily a +bug fix release. Most notably #183 and #187. + +### Changes +- Add `smcroutectl` batch support, issue #189. Based on the IPC support + added in issue #185, by Alexey Smirnov: + + ~$ sudo smcroutectl -b <<-EOF + join eth0 225.1.2.3 + add eth0 192.168.1.42 225.1.2.3 eth1 eth2 + rem eth1 225.3.4.5 eth3 + leave eth1 225.3.4.5 + EOF + ~$ + +### Fixes +- Fix #178: invalid systemd daemon type Simple/Notify vs simple/notify +- Fix #179: typo in wildcard routes section of README +- Fix #180: minor typo in file and directory names in documentation +- Fix #183: casting in IPC code hides error handling of `recv()` +- Fix #186: NULL pointer dereference in `utimensat()` replacement + function. Found accidentally by Alexey Smirnov. Only triggered on + systems that don't have a native `utimensat()` in their C-library, or + if you try to build SMCRoute without using its own build system ... +- Fix #187: strange behavior joining/leaving the same group +- Fix #192: typo in README + [v2.5.5][] - 2021-11-21 ----------------------- @@ -617,7 +647,8 @@ [mrdisc]: https://github.com/troglobit/mrdisc [RFC4286]: https://tools.ietf.org/html/rfc4286 -[UNRELEASED]: https://github.com/troglobit/smcroute/compare/2.5.5...HEAD +[UNRELEASED]: https://github.com/troglobit/smcroute/compare/2.5.6...HEAD +[v2.5.6]: https://github.com/troglobit/smcroute/compare/2.5.5...2.5.6 [v2.5.5]: https://github.com/troglobit/smcroute/compare/2.5.4...2.5.5 [v2.5.4]: https://github.com/troglobit/smcroute/compare/2.5.3...2.5.4 [v2.5.3]: https://github.com/troglobit/smcroute/compare/2.5.2...2.5.3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/README.md new/smcroute-2.5.6/README.md --- old/smcroute-2.5.5/README.md 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/README.md 2022-11-28 08:00:09.000000000 +0100 @@ -88,7 +88,7 @@ to run the daemon in the foreground, as required by modern init daemons like systemd and [Finit][]. -When started from systemd, `smcrouted` rusn with the `-n -s` options, +When started from systemd, `smcrouted` runs with the `-n -s` options, i.e. supervised in the foreground and uses syslog for logging output. The default log level is `INFO`, this can be adjusted using the file `/etc/default/smcroute`: @@ -246,7 +246,7 @@ phyint eth0 enable mrdisc phyint eth1 enable - phyint eth1 enable + phyint eth2 enable mgroup from eth0 group 225.1.2.3 mroute from eth0 group 225.1.2.3 to eth1 eth2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/configure.ac new/smcroute-2.5.6/configure.ac --- old/smcroute-2.5.5/configure.ac 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/configure.ac 2022-11-28 08:00:09.000000000 +0100 @@ -2,13 +2,14 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT(SMCRoute, 2.5.5, https://github.com/troglobit/smcroute/issues, smcroute, https://troglobit.com/smcroute.html) +AC_INIT([SMCRoute], [2.5.6], [https://github.com/troglobit/smcroute/issues], + [smcroute], [https://troglobit.com/smcroute.html]) AC_CONFIG_AUX_DIR(aux) AM_INIT_AUTOMAKE([1.11 foreign]) AM_SILENT_RULES([yes]) AC_CONFIG_SRCDIR([src/smcrouted.c]) -AC_CONFIG_HEADER([config.h]) +AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile man/Makefile src/Makefile test/Makefile smcroute.service]) # Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR() @@ -22,16 +23,25 @@ AC_PROG_INSTALL # The pidfile() code needs asprintf(), which relies on -D_GNU_SOURCE -AC_GNU_SOURCE +AC_USE_SYSTEM_EXTENSIONS # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE +AC_TYPE_MODE_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UID_T +AC_TYPE_UINT8_T +AC_TYPE_UINT16_T AC_TYPE_UINT32_T # Checks for library functions. AC_FUNC_FORK -AC_CHECK_FUNCS([atexit dup2 memset select socket strchr strerror strrchr asprintf]) +AC_FUNC_CHOWN +AC_FUNC_MALLOC +AC_CHECK_FUNCS([atexit clock_gettime dup2 memset select setenv socket strchr \ + strdup strerror strncasecmp strrchr asprintf]) # Check for usually missing API's AC_REPLACE_FUNCS([strlcpy strlcat tempfile utimensat]) @@ -59,11 +69,10 @@ [with_systemd=auto]) # Checks for header files. -AC_HEADER_STDC -AC_CHECK_HEADERS([arpa/inet.h fcntl.h glob.h ifaddrs.h linux/sockios.h net/if.h \ - netinet/in.h netinet/in_var.h net/route.h sys/capability.h \ - sys/ioctl.h sys/param.h sys/prctl.h sys/socket.h sys/stat.h \ - sys/time.h sys/types.h syslog.h termios.h unistd.h], [], [],[ +AC_CHECK_HEADERS([arpa/inet.h fcntl.h glob.h ifaddrs.h limits.h linux/sockios.h \ + net/if.h netinet/in.h netinet/in_var.h net/route.h paths.h stddef.h \ + sys/capability.h sys/ioctl.h sys/param.h sys/prctl.h sys/socket.h \ + sys/stat.h sys/time.h sys/types.h syslog.h termios.h unistd.h], [], [],[ #ifdef HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif @@ -104,8 +113,8 @@ AS_IF([test "x$with_libsystemd" != "xno"], [ AC_DEFINE([HAVE_LIBSYSTEMD], [1], [Define to 1 if you have libsystemd-dev]) - AC_SUBST([DAEMON_TYPE], "Notify")], [ - AC_SUBST([DAEMON_TYPE], "Simple")]) + AC_SUBST([DAEMON_TYPE], "notify")], [ + AC_SUBST([DAEMON_TYPE], "simple")]) AM_CONDITIONAL([HAVE_LIBSYSTEMD], [test "x$with_libsystemd" != "xno"]) # Check if we need -lpthread (building statically) and -lrt (older GLIBC) @@ -154,14 +163,14 @@ # Mac OS does not (yet) support SOCK_CLOEXEC AC_CACHE_CHECK([for SOCK_CLOEXEC support], [ac_cv_sock_cloexec], - [AC_TRY_RUN([ + [AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include <sys/types.h> #include <sys/socket.h> int main() { return socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0) == -1; -}], [ac_cv_sock_cloexec=yes], [ac_cv_sock_cloexec=no], [ac_cv_sock_cloexec=no])]) +}]])],[ac_cv_sock_cloexec=yes],[ac_cv_sock_cloexec=no],[ac_cv_sock_cloexec=no])]) AS_IF([test "$ac_cv_sock_cloexec" = "yes" ], AC_DEFINE([HAVE_SOCK_CLOEXEC], 1, [Define if the SOCK_CLOEXEC flag is supported])) @@ -177,6 +186,9 @@ # install" into account, unfortunately. test "x$prefix" = xNONE && prefix=$ac_default_prefix test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' +SYSCONFDIR=`eval echo $sysconfdir` +SYSCONFDIR=`eval echo $SYSCONFDIR` +AC_SUBST(SYSCONFDIR) SBINDIR=`eval echo $sbindir` SBINDIR=`eval echo $SBINDIR` AC_SUBST(SBINDIR) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/lib/malloc.c new/smcroute-2.5.6/lib/malloc.c --- old/smcroute-2.5.5/lib/malloc.c 1970-01-01 01:00:00.000000000 +0100 +++ new/smcroute-2.5.6/lib/malloc.c 2022-11-28 08:00:09.000000000 +0100 @@ -0,0 +1,20 @@ +#if HAVE_CONFIG_H +# include <config.h> +#endif +#undef malloc + +#include <sys/types.h> + +void *malloc (); + +/* + * Allocate an N-byte block of memory from the heap. + * If N is zero, allocate a 1-byte block. + */ +void *rpl_malloc (size_t n) +{ + if (n == 0) + n = 1; + + return malloc (n); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/lib/utimensat.c new/smcroute-2.5.6/lib/utimensat.c --- old/smcroute-2.5.5/lib/utimensat.c 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/lib/utimensat.c 2022-11-28 08:00:09.000000000 +0100 @@ -21,18 +21,28 @@ #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif +#include <time.h> #include <sys/time.h> /* lutimes(), utimes(), utimensat() */ -int utimensat(int dirfd, const char *pathname, const struct timespec ts[2], int flags) +int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { - int ret = -1; + struct timespec ts[2]; struct timeval tv[2]; + int ret = -1; if (dirfd != 0) { errno = ENOTSUP; return -1; } + if (!times) { + clock_gettime(CLOCK_REALTIME, &ts[0]); + ts[1] = ts[0]; + } else { + ts[0] = times[0]; + ts[1] = times[1]; + } + TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]); TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]); @@ -45,3 +55,37 @@ return ret; } + +#ifdef UNITTEST +#include <err.h> +#include <stdio.h> +#include <unistd.h> + +int main(int argc, char *argv[]) +{ + char *fn; + + if (argc < 2) + errx(1, "Usage: touch FILENAME"); + fn = argv[1]; + + if (access(fn, F_OK)) { + FILE *fp; + + fp = fopen(fn, "w"); + if (!fp) + err(1, "Failed creating %s", fn); + fclose(fp); + } + utimensat(0, fn, NULL, 0); + + return 0; +} +#endif +/** + * Local Variables: + * compile-command: "gcc -W -Wall -Wextra -I.. -DUNITTEST -o touch utimensat.c" + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/man/smcroute.conf.5 new/smcroute-2.5.6/man/smcroute.conf.5 --- old/smcroute-2.5.5/man/smcroute.conf.5 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/man/smcroute.conf.5 2022-11-28 08:00:09.000000000 +0100 @@ -22,15 +22,15 @@ .Pp On most systems the configuration file(s) are available in: .Bl -tag -offset indent -.It Pa /etc/smcrotue.conf +.It Pa /etc/smcroute.conf The traditional location, with all routes, group joins, and interfaces. -.It Pa /etc/smcrotue.d/*.conf +.It Pa /etc/smcroute.d/*.conf Recently an .Cm include directive was added to .Nm , which allows for including other files. By convention -.Pa /etc/smcrotue.d/ +.Pa /etc/smcroute.d/ has been selected as the default in the bundled example .Nm . See more about the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/man/smcroutectl.8 new/smcroute-2.5.6/man/smcroutectl.8 --- old/smcroute-2.5.5/man/smcroutectl.8 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/man/smcroutectl.8 2022-11-28 08:00:09.000000000 +0100 @@ -1,5 +1,5 @@ .\" -*- nroff -*- -.Dd August 15, 2021 +.Dd November 28, 2021 .Dt SMCROUTECTL 8 SMM .Os .Sh NAME @@ -8,7 +8,7 @@ .Xr smcrouted 8 .Sh SYNOPSIS .Nm smcroutectl -.Op Fl dptv +.Op Fl bdptv .Op Fl i Ar NAME .Op Fl u Ar FILE .Op Ar COMMAND @@ -36,6 +36,16 @@ .Nm options are available: .Bl -tag -width Ds +.It Fl b +Batch mode, read commands from stdin. +.Bd -unfilled -offset indent +$ sudo smcroutectl -b <<-EOF + join eth0 225.1.2.3 + add eth0 192.168.1.42 225.1.2.3 eth1 eth2 + rem eth1 225.3.4.5 eth3 + leave eth1 225.3.4.5 + EOF +.Ed .It Fl d Enable detailed output in show commands. .It Fl i Ar NAME @@ -56,6 +66,10 @@ .Cm show command output. No ANSI control characters are used, not even for probing screen width. +.It Fl t +Skip table headings entirely in +.Cm show +command output. .It Fl u Ar FILE UNIX domain socket path, used for the IPC between .Nm smcrouted @@ -69,10 +83,6 @@ .Nm is configured at build time, see .Sx FILES . -.It Fl t -Skip table headings entirely in -.Cm show -command output. .El .Sh OPERATION The diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/man/smcrouted.8 new/smcroute-2.5.6/man/smcrouted.8 --- old/smcroute-2.5.5/man/smcrouted.8 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/man/smcrouted.8 2022-11-28 08:00:09.000000000 +0100 @@ -1,5 +1,5 @@ .\" -*- nroff -*- -.Dd August 15, 2021 +.Dd November 28, 2021 .Dt SMCROUTED 8 SMM .Os .Sh NAME @@ -59,28 +59,6 @@ .Sh OPTIONS The following command line options are available: .Bl -tag -width Ds -.It Fl n -Run daemon in foreground, do not detach from controlling terminal -.It Fl N -By default -.Nm -enables multicast routing on all available, and multicast capable, -interfaces in the system. These interfaces are enumerated as VIFs, -virtual interfaces, of which most UNIX systems have a very limited -amount, usually 32. This daemon option inverts the behavior so no -interfaces are enabled by default. Useful on systems with many -interfaces, where multicast routing only makes use of a few. -.Pp -The config file setting -.Ar phyint IFNAME enable -is required to enable the required interfaces. -.It Fl f Ar FILE -Alternate configuration file, default -.Pa /etc/smcroute.conf -.It Fl F Ar FILE -Check configuration file syntax, use -.Fl l Ar LEVEL -to increase verbosity. Returns non-zero on error. .It Fl c Ar SEC Flush unused dynamic (*,G) multicast routes every .Ar SEC @@ -116,6 +94,15 @@ .Nm has loaded/reloaded all static multicast routes from the configuration file, or when a source-less (ANY) rule has been installed. +.It Fl f Ar FILE +Alternate configuration file, default +.Pa /etc/smcroute.conf +.It Fl F Ar FILE +Check configuration file syntax, use +.Fl l Ar LEVEL +to increase verbosity. Returns non-zero on error. +.It Fl h +Show summary of command line options and exit. .It Fl i Ar NAME Set daemon identity. Used to create unique PID, IPC socket, and configuration file names, as well as set the syslog identity. E.g., @@ -147,6 +134,21 @@ Default 20 sec. This option is only available when .Nm is built with mrdisc support (Linux, and IPv4, only). RFC4286. +.It Fl n +Run daemon in foreground, do not detach from controlling terminal +.It Fl N +By default +.Nm +enables multicast routing on all available, and multicast capable, +interfaces in the system. These interfaces are enumerated as VIFs, +virtual interfaces, of which most UNIX systems have a very limited +amount, usually 32. This daemon option inverts the behavior so no +interfaces are enabled by default. Useful on systems with many +interfaces, where multicast routing only makes use of a few. +.Pp +The config file setting +.Ar phyint IFNAME enable +is required to enable the required interfaces. .It Fl p Ar USER Op :GROUP Drop root privileges to USER:GROUP after start and retain CAP_NET_ADMIN capabilities only. The :GROUP is optional. This option is only diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/smcroute.service.in new/smcroute-2.5.6/smcroute.service.in --- old/smcroute-2.5.5/smcroute.service.in 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/smcroute.service.in 2022-11-28 08:00:09.000000000 +0100 @@ -4,14 +4,14 @@ Documentation=man:smcroute.conf Documentation=man:smcroutectl Documentation=file:@DOCDIR@/README.md -# ConditionPathExists=/etc/smcroute.conf +# ConditionPathExists=@SYSCONFDIR@/smcroute.conf After=network-online.target Requires=network-online.target [Service] Type=@DAEMON_TYPE@ -EnvironmentFile=-@sysconfdir@/default/smcroute -ExecStart=@SBINDIR@/smcrouted -n -s $SMCROUTED_OPTS +EnvironmentFile=-@SYSCONFDIR@/default/smcroute +ExecStart=@SBINDIR@/smcrouted -n -s $SMCROUTED_OPTS $SMCROUTED_ARGS ExecReload=@SBINDIR@/smcroutectl reload NotifyAccess=main diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/src/iface.c new/smcroute-2.5.6/src/iface.c --- old/smcroute-2.5.5/src/iface.c 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/src/iface.c 2022-11-28 08:00:09.000000000 +0100 @@ -437,7 +437,7 @@ inw = iface_ifname_maxlen(); if (inw < (int)strlen(p)) - inw = (int)strlen(p); + inw = (int)strlen(p); snprintf(line, sizeof(line), " INDEX %-*s VIF MIF=\n", inw, p); ipc_send(sd, line, strlen(line)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/src/ipc.c new/smcroute-2.5.6/src/ipc.c --- old/smcroute-2.5.5/src/ipc.c 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/src/ipc.c 2022-11-28 08:00:09.000000000 +0100 @@ -43,38 +43,84 @@ static struct sockaddr_un sun; static int ipc_socket = -1; +/* + * max word count in one command: + * smcroutectl add in1 source group out1 out2 .. out32 + */ +#define CMD_MAX_WORDS (MAXVIFS + 3) + /* Receive command from the smcroutectl */ static void ipc_read(int sd) { + /* since command len must be limited by the max number of oifs + preallocate ipc_msg only once in advance */ + char msg_buf[sizeof(struct ipc_msg) + CMD_MAX_WORDS * sizeof(char *)]; char buf[MX_CMDPKT_SZ]; - struct ipc_msg *msg; + const char* buf_ptr; + ssize_t rx = 0, rx_curr; + int first_call = 1; memset(buf, 0, sizeof(buf)); - msg = (struct ipc_msg *)ipc_receive(sd, buf, sizeof(buf)); - if (!msg) { - /* Skip logging client disconnects */ - if (errno != ECONNRESET) - smclog(LOG_WARNING, "Failed receiving IPC message from client: %s", strerror(errno)); - return; - } - if (msg_do(sd, msg)) { - if (EINVAL == errno) - smclog(LOG_WARNING, "Unknown or malformed IPC message '%c' from client.", msg->cmd); - errno = 0; - ipc_send(sd, log_message, strlen(log_message) + 1); - } else { - ipc_send(sd, "", 1); - } + /* + * since client message would be big enough and couldn't fit + * into buffer we have to make multiple iterations to receive + * all data + */ + while (1) { + rx_curr = ipc_receive(sd, buf + rx, sizeof(buf) - rx, first_call); + first_call = 0; + if (rx_curr <= 0) { + if (errno == EAGAIN) /* no more data from client */ + return; + if (errno != ECONNRESET) /* Skip logging client disconnects */ + smclog(LOG_WARNING, "Failed receiving IPC message from client: %s", strerror(errno)); + return; + } + rx += rx_curr; + + /* Make sure to always have at least one NUL, for strlen() */ + buf[rx] = 0; - free(msg); + buf_ptr = buf; + while (rx > 0) { + struct ipc_msg* msg = (struct ipc_msg*)msg_buf; + + /* extract one command at a time */ + if (ipc_parse(buf_ptr, rx, msg)) { + if (EAGAIN == errno) { + /* + * need more data from client? move last unused bytes (if any) to + * the begging of the buffer and lets try to receive more data + */ + memmove(buf, buf_ptr, rx); + break; + } + smclog(LOG_WARNING, "Failed to parse IPC message from client: %s", strerror(errno)); + return; + } + + if (msg_do(sd, msg)) { + if (EINVAL == errno) + smclog(LOG_WARNING, "Unknown or malformed IPC message '%c' from client.", msg->cmd); + errno = 0; + ipc_send(sd, log_message, strlen(log_message) + 1); + } else { + ipc_send(sd, "", 1); + } + + /* shift to the next command if any and reduce remaining bytes in buffer */ + buf_ptr += msg->len; + rx -= msg->len; + } + } } static void ipc_accept(int sd, void *arg) { - int client; socklen_t socklen = 0; + int client; (void)arg; client = accept(sd, NULL, &socklen); @@ -149,7 +195,7 @@ * Returns: * Number of bytes successfully sent, or -1 with @errno on failure. */ -int ipc_send(int sd, char *buf, size_t len) +int ipc_send(int sd, const char *buf, size_t len) { if (write(sd, buf, len) != (ssize_t)len) return -1; @@ -162,67 +208,80 @@ * @sd: Client socket from ipc_accept() * @buf: Buffer for message * @len: Size of @buf in bytes + * @first_call: non-zero set on first read after accept, 0 - subsequent calls * - * Reads a message from the IPC socket and stores in @buf, respecting + * Reads a message(s) from the IPC socket and stores in @buf, respecting * the size @len. Connects and resets connection as necessary. * * Returns: - * Pointer to a successfuly read command packet in @buf, or %NULL on error. + * Size of a successfuly read command packet in @buf, or 0 on error. */ -void *ipc_receive(int sd, char *buf, size_t len) +ssize_t ipc_receive(int sd, char *buf, size_t len, int first_call) { - size_t sz; + ssize_t sz; + /* since we can call this multiple times during receive of multipart + command lets pass `don't wait` flag to not block forever + when client finish transmission */ + int flags = first_call ? 0 : MSG_DONTWAIT; - sz = recv(sd, buf, len - 1, 0); - if (!sz) { + sz = recv(sd, buf, len - 1, flags); + if (!sz) errno = ECONNRESET; - return NULL; - } + + return sz; +} + +/** + * ipc_server_parse - Parse IPC message(s) from client + * @buf: Buffer of message(s) + * @sz: Size of @buf in bytes + * @msg_buf: Preallocated ipc_msg + * + * Parse message(s) from the IPC socket, respecting + * the size @sz. + * + * Returns: + * POSIX OK(0) on a successfuly read command in @buf, or non-zero on error. + */ +int ipc_parse(const char *buf, size_t sz, void* msg_buf) +{ + struct ipc_msg* msg; /* successful read */ if (sz >= sizeof(struct ipc_msg)) { - struct ipc_msg *msg = (struct ipc_msg *)buf; + memcpy(msg_buf, buf, sizeof(struct ipc_msg)); + msg = (struct ipc_msg*)msg_buf; - /* Make sure to always have at least one NUL, for strlen() */ - buf[sz] = 0; - - if (sz == msg->len) { - char *ptr; + /* enough bytes to extract just one message? */ + if (sz >= msg->len) { size_t i, count; + const char *ptr; - /* Upper bound: smcroutectl add in1 source group out1 out2 .. out32 */ count = msg->count; - if (count > (MAXVIFS + 3)) { + if (count > CMD_MAX_WORDS) { errno = EINVAL; - return NULL; + return 1; } - msg = malloc(sizeof(struct ipc_msg) + msg->count * sizeof(char *)); - if (!msg) - return NULL; - - memcpy(msg, buf, sizeof(struct ipc_msg)); - ptr = buf + offsetof(struct ipc_msg, argv); for (i = 0; i < count; i++) { /* Verify ptr, attacker may set too large msg->count */ - if (ptr >= (buf + len)) { - free(msg); + if (ptr >= (buf + msg->len)) { errno = EBADMSG; - return NULL; + return 1; } - msg->argv[i] = ptr; + msg->argv[i] = (char*)ptr; ptr += strlen(ptr) + 1; } - msg->count = count; - return msg; + return 0; } } + /* we've parsed all commands or not enough bytes to parse next */ errno = EAGAIN; - return NULL; + return 1; } /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/src/ipc.h new/smcroute-2.5.6/src/ipc.h --- old/smcroute-2.5.5/src/ipc.h 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/src/ipc.h 2022-11-28 08:00:09.000000000 +0100 @@ -7,8 +7,9 @@ int ipc_init (char *path); void ipc_exit (void); -int ipc_send (int sd, char *buf, size_t len); -void *ipc_receive (int sd, char *buf, size_t len); +int ipc_send (int sd, const char *buf, size_t len); +ssize_t ipc_receive(int sd, char *buf, size_t len, int first_call); +int ipc_parse (const char *buf, size_t sz, void *msg_buf); #endif /* SMCROUTE_IPC_H_ */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/src/mcgroup.c new/smcroute-2.5.6/src/mcgroup.c --- old/smcroute-2.5.5/src/mcgroup.c 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/src/mcgroup.c 2022-11-28 08:00:09.000000000 +0100 @@ -372,7 +372,7 @@ } if (!cmd) { - TAILQ_REMOVE(&kern_list, mcg, link); + TAILQ_REMOVE(&conf_list, mcg, link); free_mc_sock(mcg->sd); free(mcg); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/src/mrdisc.c new/smcroute-2.5.6/src/mrdisc.c --- old/smcroute-2.5.5/src/mrdisc.c 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/src/mrdisc.c 2022-11-28 08:00:09.000000000 +0100 @@ -84,8 +84,8 @@ /* Checksum routine for Internet Protocol family headers */ static unsigned short in_cksum(unsigned short *addr, int len) { - unsigned short *w = addr; unsigned short answer = 0; + unsigned short *w = addr; int nleft = len; int sum = 0; @@ -122,9 +122,9 @@ static int inet_send(int sd, uint8_t type, uint8_t interval) { - ssize_t num; - struct igmp igmp; struct sockaddr dest; + struct igmp igmp; + ssize_t num; memset(&igmp, 0, sizeof(igmp)); igmp.igmp_type = type; @@ -143,10 +143,10 @@ /* If called with interval=0, only read() */ static int inet_recv(int sd, uint8_t interval) { + struct igmp *igmp; char buf[1530]; - ssize_t num; struct ip *ip; - struct igmp *igmp; + ssize_t num; memset(buf, 0, sizeof(buf)); num = read(sd, buf, sizeof(buf)); @@ -165,11 +165,11 @@ static int inet_open(char *ifname) { - char loop; - int sd, val, rc; - struct ifreq ifr; - struct ip_mreqn mreq; unsigned char ra[4] = { IPOPT_RA, 0x04, 0x00, 0x00 }; + struct ip_mreqn mreq; + struct ifreq ifr; + int sd, val, rc; + char loop; sd = socket_create(AF_INET, SOCK_RAW, IPPROTO_IGMP, mrdisc_recv, NULL); if (sd < 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/src/smcroutectl.c new/smcroute-2.5.6/src/smcroutectl.c --- old/smcroute-2.5.5/src/smcroutectl.c 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/src/smcroutectl.c 2022-11-28 08:00:09.000000000 +0100 @@ -44,7 +44,9 @@ static char *sock_file = NULL; static char *prognm = NULL; static int heading = 1; +static int detail = 0; static int plain = 0; +static int help = 0; struct arg { char *name; @@ -55,6 +57,7 @@ char *example; /* optional */ int has_detail; } args[] = { + { NULL, 0, 'b', NULL, "Batch mode, read commands from stdin", NULL, 0 }, { NULL, 0, 'd', NULL, "Detailed output in show command", NULL, 0 }, { NULL, 1, 'i', "NAME", "Identity of routing daemon instance, default: " PACKAGE, "foo", 0 }, { NULL, 1, 'I', "NAME", NULL, NULL, 0 }, /* Alias, compat with older versions */ @@ -391,64 +394,15 @@ return 0; } -static char *progname(const char *arg0) +static int parse(int pos, int argc, char *argv[]) { - char *nm; - - nm = strrchr(arg0, '/'); - if (nm) - nm++; - else - nm = (char *)arg0; - - return nm; -} - -int main(int argc, char *argv[]) -{ - int help = 0, detail = 0; - int c, i, pos = 1, status = 0; struct arg *cmd = NULL; + int status = 0; + int c; - prognm = progname(argv[0]); - while ((c = getopt(argc, argv, "dhI:i:ptu:v")) != EOF) { - switch (c) { - case 'd': - detail++; - break; - - case 'h': - help++; - break; - - case 'I': /* compat with previous versions */ - case 'i': - ident = optarg; - break; - - case 'p': - plain = 1; - break; - - case 't': - heading = 0; - break; - - case 'u': - sock_file = optarg; - break; - - case 'v': - return version(); - - default: - return usage(1); - } - } - - pos = optind; while (pos < argc && !cmd) { char *arg = argv[pos]; + int i; for (i = 0; args[i].val; i++) { char *nm = args[i].name; @@ -511,6 +465,95 @@ return ipc_command(c, &argv[pos], argc - pos); } +static int batch(void) +{ + char line[512]; + int rc = 0; + + while (fgets(line, sizeof(line), stdin)) { + char *ptr, *token, *args[10]; + int num = 0; + + ptr = chomp(line); + if (ptr[0] == '#') + continue; + + while (num < 9 && (token = strsep(&ptr, " \t"))) + args[num++] = token; + + if (!num) + continue; + + rc += parse(0, num, args); + } + + return rc; +} + +static char *progname(const char *arg0) +{ + char *nm; + + nm = strrchr(arg0, '/'); + if (nm) + nm++; + else + nm = (char *)arg0; + + return nm; +} + +int main(int argc, char *argv[]) +{ + int batch_mode = 0; + int c; + + prognm = progname(argv[0]); + while ((c = getopt(argc, argv, "bdhI:i:ptu:v")) != EOF) { + switch (c) { + case 'b': + batch_mode = 1; + break; + + case 'd': + detail++; + break; + + case 'h': + help++; + break; + + case 'I': /* compat with previous versions */ + case 'i': + ident = optarg; + break; + + case 'p': + plain = 1; + break; + + case 't': + heading = 0; + break; + + case 'u': + sock_file = optarg; + break; + + case 'v': + return version(); + + default: + return usage(1); + } + } + + if (batch_mode) + return batch(); + + return parse(optind, argc, argv); +} + /** * Local Variables: * indent-tabs-mode: t diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/test/Makefile.am new/smcroute-2.5.6/test/Makefile.am --- old/smcroute-2.5.5/test/Makefile.am 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/test/Makefile.am 2022-11-28 08:00:09.000000000 +0100 @@ -1,4 +1,4 @@ -EXTRA_DIST = adv.sh basic.sh bridge.sh dyn.sh expire.sh gre.sh ipv6.sh +EXTRA_DIST = adv.sh basic.sh batch.sh bridge.sh dyn.sh expire.sh gre.sh ipv6.sh EXTRA_DIST += include.sh isolated.sh join.sh joinlen.sh lib.sh lost.sh EXTRA_DIST += multi.sh mem.sh mrcache.sh mrcache6.sh mrdisc.sh poison.sh EXTRA_DIST += reload.sh reload6.sh vlan.sh vrfy.sh @@ -9,6 +9,7 @@ TESTS = expire.sh TESTS += adv.sh TESTS += basic.sh +TESTS += batch.sh TESTS += bridge.sh TESTS += dyn.sh TESTS += gre.sh diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/test/README.md new/smcroute-2.5.6/test/README.md --- old/smcroute-2.5.5/test/README.md 2021-11-21 09:38:26.000000000 +0100 +++ new/smcroute-2.5.6/test/README.md 2022-11-28 08:00:09.000000000 +0100 @@ -19,16 +19,17 @@ To run the tests: - ~$ cd src/smcroute - ~/src/smcroute$ ./autogen.sh - ~/src/smcroute$ ./configure --enable-test - ~/src/smcroute$ make -j9 - ~/src/smcroute$ make check + ~$ sudo modprobe ip_gre # if you have sudo capabilities + ~$ cd src/smcroute + ~/src/smcroute$ ./autogen.sh + ~/src/smcroute$ ./configure --enable-test --enable-mrdisc + ~/src/smcroute$ make -j9 + ~/src/smcroute$ make check Each unit test is standalone. To manually run select tests: ~/src/smcroute$ cd test/ - ~/src/smcroute/test$ unshare -mrun ./testname.sh + ~/src/smcroute/test$ unshare -mrun ./testname.sh The tools `ping` and `tshark` are used to create and listen to multicast streams "routed by" SMCRoute. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.5.5/test/batch.sh new/smcroute-2.5.6/test/batch.sh --- old/smcroute-2.5.5/test/batch.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/smcroute-2.5.6/test/batch.sh 2022-11-28 08:00:09.000000000 +0100 @@ -0,0 +1,37 @@ +#!/bin/sh +# Verify batch mode, we just want to see the daemon accepting the +# batched commands. + +# shellcheck source=/dev/null +. "$(dirname "$0")/lib.sh" + +print "Creating world ..." +topo basic + +# IP world ... +ip addr add 10.0.0.1/24 dev a1 +ip addr add 20.0.0.1/24 dev a2 +ip addr add 2001:1::1/64 dev a1 +ip addr add 2001:2::1/64 dev a2 +ip -br a + +print "Starting smcrouted ..." +../src/smcrouted -f "/tmp/$NM/conf" -n -N -P "/tmp/$NM/pid" -l debug -u "/tmp/$NM/sock" & +sleep 1 + +print "Joining groups (batch)" +../src/smcroutectl -u "/tmp/$NM/sock" -b <<-EOF + join a1 10.0.0.11 225.1.1.1 + join a2 225.2.2.2 + join a1 fc00::2 ff04::111 + join a2 ff2e::22 + EOF + +output=$(../src/smcroutectl -pu "/tmp/$NM/sock" show groups) +echo "$output" +[ "$(echo "$output" | grep 225.1.1.1 | sed 's/[[:space:]]*//g')" = "(10.0.0.11,225.1.1.1)a1" ] || FAIL "225.1.1.1" +[ "$(echo "$output" | grep 225.2.2.2 | sed 's/[[:space:]]*//g')" = "(*,225.2.2.2)a2" ] || FAIL "225.2.2.2" +[ "$(echo "$output" | grep ff04::111 | sed 's/[[:space:]]*//g')" = "(fc00::2,ff04::111)a1" ] || FAIL "ff04::111" +[ "$(echo "$output" | grep ff2e::22 | sed 's/[[:space:]]*//g')" = "(*,ff2e::22)a2" ] || FAIL "ff2e::22" + +OK