Hello community, here is the log from the commit of package smcroute for openSUSE:Factory checked in at 2018-11-26 10:21:27 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/smcroute (Old) and /work/SRC/openSUSE:Factory/.smcroute.new.19453 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "smcroute" Mon Nov 26 10:21:27 2018 rev:2 rq:648973 version:2.4.3 Changes: -------- --- /work/SRC/openSUSE:Factory/smcroute/smcroute.changes 2018-07-02 23:31:27.605397304 +0200 +++ /work/SRC/openSUSE:Factory/.smcroute.new.19453/smcroute.changes 2018-11-26 10:22:38.193568393 +0100 @@ -1,0 +2,39 @@ +Wed Nov 14 13:02:17 UTC 2018 - Tomáš Chvátal <[email protected]> + +- Remove ip_route.h for the license clash + +------------------------------------------------------------------- +Sat Nov 10 17:51:15 UTC 2018 - [email protected] + +- Update to version 2.4.3 + Changes + * Add strlcat() replacement from OpenBSD, use instead of strcat() + * smcrouted should never log to system console, proposed by Westermo + Fixes + * smcrouted fails to join multicast groups on interfaces that do not + yet have an IP address when smcrouted starts up, or when it receives + SIGHUP, e.g. DHCP client interfaces. This patch release adds a timer + refresh of interface addresses that retries multicast group joins + until an address is set. This is similar to issue #55, but does not + handle interfaces that do not exist yet. + * Make sure Linux alias interfaces (baseif:num) are registered as + baseif. Westermo found that use of alias interfaces cause multiple + VIFs to be registered for the same base interface causing multicast + routes to use the wrong inbound or outbound VIF. Alias interfaces + use the same underlying physical interface so only one VIF needed. + * Fix display of route counters and column alignment + * Simplify utimensat() replacement, AT_SYMLINK_NOFOLLOW unused + +------------------------------------------------------------------- +Mon Sep 10 20:09:44 UTC 2018 - [email protected] + +- Update to version 2.4.2 + Changes + * Add wrapper script smcroute for use with old style startup scripts + * Add symlinks to man pages for smcrouted.8 and smcroutectl.8 + * Update SysV init script, daemon now called smcrouted + Fixes + * Fix #96: A .conf line may be missing final newline, this is fine + * Spellcheck smcroute.conf example + +------------------------------------------------------------------- Old: ---- smcroute-2.4.1.tar.gz New: ---- smcroute-2.4.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ smcroute.spec ++++++ --- /var/tmp/diff_new_pack.yqWW0i/_old 2018-11-26 10:22:38.685567814 +0100 +++ /var/tmp/diff_new_pack.yqWW0i/_new 2018-11-26 10:22:38.685567814 +0100 @@ -1,6 +1,7 @@ # # spec file for package smcroute # +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2018, Martin Hauke <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -12,12 +13,12 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # Name: smcroute -Version: 2.4.1 +Version: 2.4.3 Release: 0 Summary: Static multicast routing for UNIX License: GPL-3.0-only @@ -47,9 +48,14 @@ %setup -q sed -i 's|@DOCDIR@|%{_docdir}/smcroute/|g' smcroute.service.in +# remove file not used by Linux with incompatible Apple license +rm src/ip_mroute.h + %build autoreconf -fiv -%configure --with-systemd +%configure \ + --with-systemd \ + --disable-silent-rules make %{?_smp_mflags} %install @@ -79,9 +85,12 @@ %license COPYING %{_sbindir}/smcroutectl %{_sbindir}/smcrouted +%{_sbindir}/smcroute %{_sbindir}/rcsmcroute %config %{_sysconfdir}/smcroute.conf %{_mandir}/man8/smcroute.8%{?ext_man} +%{_mandir}/man8/smcroutectl.8%{?ext_man} +%{_mandir}/man8/smcrouted.8%{?ext_man} %{_unitdir}/%{name}.service %changelog ++++++ smcroute-2.4.1.tar.gz -> smcroute-2.4.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/.gitignore new/smcroute-2.4.3/.gitignore --- old/smcroute-2.4.1/.gitignore 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/.gitignore 2018-11-07 01:34:48.000000000 +0100 @@ -20,8 +20,9 @@ install-sh mcsender missing -smcroute smcrouted smcroutectl smcroute.service stamp-h1 +*.tar.* +.dirstamp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/ChangeLog.md new/smcroute-2.4.3/ChangeLog.md --- old/smcroute-2.4.1/ChangeLog.md 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/ChangeLog.md 2018-11-07 01:34:48.000000000 +0100 @@ -3,6 +3,46 @@ All notable changes to the project are documented in this file. +[v2.4.3][] +---------- + +The Lyon release. + +### Changes +- Add `strlcat()` replacement from OpenBSD, use instead of `strcat()` +- `smcrouted` should never log to system console, proposed by Westermo + +### Fixes +- `smcrouted` fails to join multicast groups on interfaces that do not + yet have an IP address when `smcrouted` starts up, or when it receives + `SIGHUP`, e.g. DHCP client interfaces. This patch release adds a timer + refresh of interface addresses that retries multicast group joins until + an address is set. This is similar to issue #55, but does not handle + interfaces that do not exist yet +- Make sure Linux alias interfaces (baseif:num) are registered as + baseif. Westermo found that use of alias interfaces cause multiple + VIFs to be registered for the same base interface causing multicast + routes to use the wrong inbound or outbound VIF. Alias interfaces + use the same underlying physical interface so only one VIF needed +- Fix display of route counters and column alignment +- Minor spelling fixes, found by Debian +- Add missing status command to SysV init script, found by Debian +- Simplify `utimensat()` replacement, `AT_SYMLINK_NOFOLLOW` unused + + +[v2.4.2][] - 2018-09-09 +----------------------- + +### Changes +- Add wrapper script `smcroute` for use with old style startup scripts +- Add symlinks to man pages for `smcrouted.8 and` `smcroutectl.8` +- Update SysV init script, daemon now called `smcrouted` + +### Fixes +- Fix #96: A `.conf` line may be missing final newline, this is fine +- Spellcheck `smcroute.conf` example +- Fix Lintian warning (Debian) for unbreakable line in man page + [v2.4.1][] - 2018-06-16 ----------------------- @@ -433,7 +473,9 @@ [mrdisc]: https://github.com/troglobit/mrdisc [RFC4286]: https://tools.ietf.org/html/rfc4286 -[UNRELEASED]: https://github.com/troglobit/smcroute/compare/2.4.1...HEAD +[UNRELEASED]: https://github.com/troglobit/smcroute/compare/2.4.3...HEAD +[v2.4.2]: https://github.com/troglobit/smcroute/compare/2.4.2...2.4.3 +[v2.4.2]: https://github.com/troglobit/smcroute/compare/2.4.1...2.4.2 [v2.4.1]: https://github.com/troglobit/smcroute/compare/2.4.1...2.4.1 [v2.4.0]: https://github.com/troglobit/smcroute/compare/2.3.1...2.4.0 [v2.3.1]: https://github.com/troglobit/smcroute/compare/2.3.0...2.3.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/Makefile.am new/smcroute-2.4.3/Makefile.am --- old/smcroute-2.4.1/Makefile.am 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/Makefile.am 2018-11-07 01:34:48.000000000 +0100 @@ -1,9 +1,12 @@ ## SMCRoute - A static multicast routing tool -*-Makefile-*- ACLOCAL_AMFLAGS = -I m4 DISTCHECK_CONFIGURE_FLAGS = --with-systemd=$$dc_install_base/$(systemd) + SUBDIRS = src DISTCLEANFILES = *~ DEADJOE semantic.cache *.gdb *.elf core core.* *.d +dist_sbin_SCRIPTS = smcroute dist_man8_MANS = smcroute.8 +SYMLINKS = smcrouted.8 smcroutectl.8 doc_DATA = README.md COPYING smcroute.conf EXTRA_DIST = README.md AUTHORS ChangeLog.md autogen.sh smcroute.conf smcroute.init @@ -11,6 +14,19 @@ systemd_DATA = smcroute.service endif +# Hook in install to add smcroute.8 --> smcrouted.8, smcroutectl.8 symlinks +install-data-hook: + @for file in $(SYMLINKS); do \ + link=$(DESTDIR)$(man8dir)/$$file; \ + test -e $$link && continue; \ + $(LN_S) $(dist_man8_MANS) $$link; \ + done + +uninstall-hook: + @for file in $(SYMLINKS); do \ + $(RM) $(DESTDIR)$(mandir)/$$file; \ + done + ## Generate detached signature file (ascii-armored), like OpenVPN does GPG = gpg gpg-dist: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/README.md new/smcroute-2.4.3/README.md --- old/smcroute-2.4.1/README.md 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/README.md 2018-11-07 01:34:48.000000000 +0100 @@ -86,8 +86,8 @@ **Note:** To test the above you can use ping from another device. The multicast should be visible as long as your IP# matches the source above and you ping 225.1.2.3 -- **REMEMBER TO SET THE TTL >1** - - $ ping -I eth0 -t 2 225.1.2.3 + + ping -I eth0 -t 2 225.1.2.3 The TTL is what usually bites people first trying out multicast routing. Most TCP/IP stacks default to a TTL of 1 for multicast frames, e.g. ping @@ -100,12 +100,15 @@ because the TTL is the only thing that helps prevent routing loops! On Linux the following `iptables` command can be used to change the TTL: - # iptables -t mangle -A PREROUTING -i eth0 -d 225.1.2.3 -j TTL --ttl-inc 1 + iptables -t mangle -A PREROUTING -i eth0 -d 225.1.2.3 -j TTL --ttl-inc 1 + +Some commands, like this one, must usually be run with root privileges +or the correct set of capabilities. ### Action Scripts - # smcrouted -e /path/to/script + smcrouted -e /path/to/script With `-e CMD` a user script or command can be called when `smcrouted` receives a `SIGHUP` or installs a multicast route to the kernel. This @@ -115,7 +118,7 @@ ### Many Interfaces - # smcrouted -N + smcrouted -N With the `-N` command line option SMCRoute does *not* prepare all system interfaces for multicast routing. Very useful if your system has a lot @@ -135,8 +138,8 @@ its support for multiple multicast routing tables. In such setups it may be useful to change the default identity of SMCRoute: - # smcrouted -I mrt1 -t 1 - # smcrouted -I mrt2 -t 2 + smcrouted -I mrt1 -t 1 + smcrouted -I mrt2 -t 2 The `-I NAME` option alters the default syslog name, config file, PID file, and client socket file name used. In the first instance above, @@ -154,19 +157,19 @@ SMCRoute also has a client interface to interact with the daemon: - # smcroutectl join eth0 225.1.2.3 - # smcroutectl add eth0 192.168.1.42 225.1.2.3 eth1 eth2 + smcroutectl join eth0 225.1.2.3 + smcroutectl add eth0 192.168.1.42 225.1.2.3 eth1 eth2 If the daemon runs with a different identity the client needs to be called using the same identity: - # smcrouted -I mrt - # smcroutectl -I mrt show + smcrouted -I mrt + smcroutectl -I mrt show There are more commands. See the man page or the online help for details: - # smcroutectl help + smcroutectl help **Note:** Root privileges are required by default for `smcroutectl` due to the IPC socket permissions. @@ -248,22 +251,34 @@ ### Configure & Build -As of SMCRoute v2.2, the `libcap` library is used to gain full privilege -separation using POSIX capabilities. At startup this library is used to -drop full root privileges, retaining only `CAP_NET_ADMIN` for managing -the multicast routes. Use `--without-libcap` to disable this feature. - -**Note:** On RHEL/CentOS 6 you must `configure --without-libcap` - - $ ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var - $ make -j5 - $ sudo make install-strip +The GNU Configure & Build system use `/usr/local` as the default install +prefix. In many cases this is useful, but this means the configuration +files and cache files will also use that same prefix. Most users have +come to expect those files in `/etc/` and `/var/run/` and configure has +a few useful options that are recommended to use: + + ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var + make -j5 + sudo make install-strip + +### Privilege Separation + +As of SMCRoute v2.2 support for privilege separation using the `libcap` +library was added. It is used to drop full root privileges at startup, +retaining only `CAP_NET_ADMIN` for managing the multicast routes. + +The build system searches for the `libcap` library and header file(s). +Bith `libcap-dev` and `pkg-config` are required. + +**Note:** Although support is automatically detected, the build system + will issue a warning if `libcap` is missing. This can be + silenced with `configure --without-libcap` ### Integration with systemd -For systemd integration you need to install `pkg-config`, which helps -the SMCRoute build system figure out the systemd paths. When installed -simply call `systemctl` to enable and start `smcrouted`: +For systemd integration `libsystemd-dev` and `pkg-config` are required. +When the unit file is installed, `systemctl` can be used to enable and +start `smcrouted`: $ sudo systemctl enable smcroute.service $ sudo systemctl start smcroute.service @@ -278,7 +293,7 @@ following `LDFLAGS=` *after* the configure script. You may also need to add `LIBS=...`, which will depend on your particular system: - $ ./configure LDFLAGS="-static" ... + ./configure LDFLAGS="-static" ... ### Building from GIT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/configure.ac new/smcroute-2.4.3/configure.ac --- old/smcroute-2.4.1/configure.ac 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/configure.ac 2018-11-07 01:34:48.000000000 +0100 @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT(SMCRoute, 2.4.1, https://github.com/troglobit/smcroute/issues, smcroute, http://troglobit.com/smcroute.html) +AC_INIT(SMCRoute, 2.4.3, https://github.com/troglobit/smcroute/issues, smcroute, http://troglobit.com/smcroute.html) AM_INIT_AUTOMAKE([1.11 foreign dist-xz]) AM_SILENT_RULES([yes]) @@ -17,6 +17,7 @@ # Checks for programs. AC_PROG_CC +AC_PROG_LN_S AC_PROG_INSTALL # The pidfile() code needs asprintf(), which relies on -D_GNU_SOURCE @@ -32,7 +33,7 @@ AC_CHECK_FUNCS([atexit dup2 memset select socket strchr strerror strrchr asprintf]) # Check for usually missing API's -AC_REPLACE_FUNCS([strlcpy utimensat]) +AC_REPLACE_FUNCS([strlcpy strlcat utimensat]) AC_CONFIG_LIBOBJ_DIR([lib]) # Check for sun_len in struct sockaddr_un diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/lib/strlcat.c new/smcroute-2.4.3/lib/strlcat.c --- old/smcroute-2.4.1/lib/strlcat.c 1970-01-01 01:00:00.000000000 +0100 +++ new/smcroute-2.4.3/lib/strlcat.c 2018-11-07 01:34:48.000000000 +0100 @@ -0,0 +1,55 @@ +/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <[email protected]> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/lib/utimensat.c new/smcroute-2.4.3/lib/utimensat.c --- old/smcroute-2.4.1/lib/utimensat.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/lib/utimensat.c 2018-11-07 01:34:48.000000000 +0100 @@ -1,20 +1,18 @@ /* Replacement in case utimensat(2) is missing * - * Copyright (C) 2017 Joachim Nilsson <[email protected]> + * Copyright (C) 2017-2018 Joachim Nilsson <[email protected]> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" @@ -38,17 +36,12 @@ TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]); TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]); +#ifdef AT_SYMLINK_NOFOLLOW if ((flags & AT_SYMLINK_NOFOLLOW) == AT_SYMLINK_NOFOLLOW) ret = lutimes(pathname, tv); else +#endif ret = utimes(pathname, tv); return ret; } - -/** - * Local Variables: - * indent-tabs-mode: t - * c-file-style: "linux" - * End: - */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/smcroute new/smcroute-2.4.3/smcroute --- old/smcroute-2.4.1/smcroute 1970-01-01 01:00:00.000000000 +0100 +++ new/smcroute-2.4.3/smcroute 2018-11-07 01:34:48.000000000 +0100 @@ -0,0 +1,59 @@ +#!/bin/sh +# Compatibility wrapper for users with old startup scripts +# Written by Joachim Nilsson, placed in the public domain + +OP=$1 +shift + +case "$OP" in + -d) + smcrouted $* + ;; + -h) + echo "Usage: smcroute [OPTIONS] [ARGS]" + echo + echo " -d Start daemon" + echo " -k Kill a running daemon" + echo + echo " -h This help text" + echo " -v Show version" + echo + echo " -a ARGS Add a multicast route" + echo " -r ARGS Remove a multicast route" + echo + echo " -j ARGS Join a multicast group" + echo " -l ARGS Leave a multicast group" + echo + echo " <------------- INBOUND --------------> <----- OUTBOUND ------>" + echo " -a <IFNAME> <SOURCE-IP> <MULTICAST-GROUP> <IFNAME> [<IFNAME> ...]" + echo " -r <IFNAME> <SOURCE-IP> <MULTICAST-GROUP>" + echo + echo " -j <IFNAME> <MULTICAST-GROUP>" + echo " -l <IFNAME> <MULTICAST-GROUP>" + echo + echo "NOTE: This is a compatibility wrapper script for SMCRoute. Intended for" + echo " use with old style startup scripts. It is recommended to migrate" + echo " to /etc/smcroute.conf, see the smcroute(8) man page for help." + return 0 + ;; + -k) + smcroutectl kill + ;; + -v) + smcroutectl version + ;; + -a) + smcroutectl add $* + ;; + -r) + smcroutectl remove $* + ;; + -j) + smcroutectl join $* + ;; + *) + echo "Unknown command or option to the SMCRoute compatiblity wrapper script." + echo "See the smcroute(8) man page for help on available commands." + return 1 + ;; +esac diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/smcroute.8 new/smcroute-2.4.3/smcroute.8 --- old/smcroute-2.4.1/smcroute.8 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/smcroute.8 2018-11-07 01:34:48.000000000 +0100 @@ -20,14 +20,16 @@ .Op Fl dtv .Op Fl I Ar NAME .Op Ar COMMAND -.Oo Ao add | rem Ac Ao ROUTE Ac Oc Oo Ao join | leave Ac Ao GROUP Ac Oc .Pp .Nm smcroutectl -.Op help | flush | kill | restart | version | show [groups|routes] +.Ao help | flush | kill | restart | version Ac .Nm smcroutectl -.Oo \ add | \ \ rem Oc Ao IFNAME Ac Oo SOURCE Oc Ar GROUP[/LEN] IFNAME Op IFNAME ... +.Ao show Ac +.Op groups | routes .Nm smcroutectl -.Oo join | leave Oc Ao IFNAME Ac Oo SOURCE Oc Ar GROUP +.Ao add \ | \ \ rem Ac Ao IFNAME Ac Oo SOURCE Oc Ar GROUP[/LEN] IFNAME Op IFNAME ... +.Nm smcroutectl +.Ao join | leave Ac Ao IFNAME Ac Oo SOURCE Oc Ar GROUP .Sh DESCRIPTION .Nm is both a daemon and command line tool to manipulate the multicast diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/smcroute.conf new/smcroute-2.4.3/smcroute.conf --- old/smcroute-2.4.1/smcroute.conf 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/smcroute.conf 2018-11-07 01:34:48.000000000 +0100 @@ -9,9 +9,12 @@ # NOTE: Use of the mgroup command should be avoided if possible. # Instead configure "router ports" or similar on the switches # or bridges on your LAN. This to have them direct all the -# multicast to your router, or direct select groups they have +# multicast to your router, or select groups if they have # such capabilities. Usually MAC multicast filters exist. # +# Some switch manufacturers support mrdisc, RFC4286, which +# SMCRoute can use to advertise itself on source interfaces. +# # The UNIX kernel usually limits the number of multicast groups # a socket/client can join. In Linux, 20 mgroup lines can be # configured by default, but this can be changed with sysctl: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/smcroute.init new/smcroute-2.4.3/smcroute.init --- old/smcroute-2.4.1/smcroute.init 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/smcroute.init 2018-11-07 01:34:48.000000000 +0100 @@ -9,17 +9,17 @@ # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Static multicast router daemon -# Description: SMCRoute is a tool to manipulate the multicast routes -# of the Linux kernel. It can be used as an alternative -# to dynamic multicast routers like mrouted in situation -# where static multicast routes should be maintained -# and/or no proper IGMP signaling exists. +# Description: SMCRoute is a daemon and command line tool to manipulate +# the multicast routing table of a UNIX kernel. It can be +# used as an alternative to dynamic multicast routers like +# pimd or mrouted in situations where static routes should +# be maintained and/or no proper IGMP signaling exists. ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/smcroute -DAEMON_OPTS=-d -NAME=smcroute +DAEMON=/usr/sbin/smcrouted +DAEMON_OPTS= +NAME=smcrouted DESC="static multicast router daemon" test -x $DAEMON || exit 0 @@ -72,6 +72,9 @@ stop start ;; + status) + status_of_proc "$DAEMON" "$DESC" && exit 0 || exit $? + ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|force-reload}" >&2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/conf.c new/smcroute-2.4.3/src/conf.c --- old/smcroute-2.4.1/src/conf.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/conf.c 2018-11-07 01:34:48.000000000 +0100 @@ -29,8 +29,11 @@ #include "mcgroup.h" #define MAX_LINE_LEN 512 +#define DEBUG(fmt, args...) \ + smclog(LOG_DEBUG, "%s:%02d: " fmt, conf, lineno, ##args) #define WARN(fmt, args...) \ smclog(LOG_WARNING, "%s:%02d: " fmt, conf, lineno, ##args) + static const char *conf = NULL; static char *pop_token(char **line) @@ -52,7 +55,7 @@ end = token; while (*end && !isspace((int)*end)) end++; - if (*end == 0 || end == token) { + if (end == token) { *line = NULL; return NULL; } @@ -307,6 +310,7 @@ char *group = NULL; char *dest[32]; + DEBUG("Read line: '%s'", line); while ((token = pop_token(&line))) { /* Strip comments. */ if (match("#", token)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/ifvc.c new/smcroute-2.4.3/src/ifvc.c --- old/smcroute-2.4.1/src/ifvc.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/ifvc.c 2018-11-07 01:34:48.000000000 +0100 @@ -33,33 +33,35 @@ #include "log.h" #include "ifvc.h" +#include "mcgroup.h" +#include "timer.h" #include "util.h" static unsigned int num_ifaces = 0, num_ifaces_alloc = 0; static struct iface *iface_list = NULL; /** - * iface_init - Setup vector of active interfaces + * iface_update - Periodic check of new interfaces or addresses + * @refresh: Only update interface addresses * - * Builds up a vector with active system interfaces. Must be called - * before any other interface functions in this module! + * This functions is not only called by iface_init() at startup or + * SIGHUP, it is also called periodically to check if known ifaces + * have changed or gained an IP address. This is required because + * on Linux (and possibly other UNICES too) it is not possible to + * join a multicast group without an address (YMMV). + * + * Note: + * For now we only return %TRUE for interface updates. + * + * Returns: + * %TRUE(1), at least one interface added or updated, otherwise + * %FALSE(0) if there was no change. */ -void iface_init(void) +int iface_update(int refresh) { - struct iface *iface; struct ifaddrs *ifaddr, *ifa; - - num_ifaces = 0; - - if (iface_list) - free(iface_list); - - num_ifaces_alloc = 1; - iface_list = calloc(num_ifaces_alloc, sizeof(struct iface)); - if (!iface_list) { - smclog(LOG_ERR, "Failed allocating space for interfaces: %s", strerror(errno)); - exit(255); - } + struct iface *iface; + int change = 0; if (getifaddrs(&ifaddr) == -1) { smclog(LOG_ERR, "Failed retrieving interface addresses: %s", strerror(errno)); @@ -69,11 +71,16 @@ for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { /* Check if already added? */ if ((iface = iface_find_by_name(ifa->ifa_name))) { - if (!iface->inaddr.s_addr && ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) + if (!iface->inaddr.s_addr && ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { iface->inaddr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + change = 1; + } continue; } + if (refresh) + continue; + /* Allocate more space? */ if (num_ifaces == num_ifaces_alloc) { num_ifaces_alloc *= 2; @@ -107,6 +114,46 @@ iface->threshold = DEFAULT_THRESHOLD; } freeifaddrs(ifaddr); + + return change; +} + +/** + * iface_init - Setup vector of active interfaces + * + * Builds up a vector with active system interfaces. Must be called + * before any other interface functions in this module! + */ +void iface_init(void) +{ + num_ifaces = 0; + + if (iface_list) + free(iface_list); + + num_ifaces_alloc = 1; + iface_list = calloc(num_ifaces_alloc, sizeof(struct iface)); + if (!iface_list) { + smclog(LOG_ERR, "Failed allocating space for interfaces: %s", strerror(errno)); + exit(255); + } + + iface_update(0); + + /* In case of addresses being added later ... */ + if (timer_add(5, iface_refresh, NULL) < 0 && errno != EEXIST) + smclog(LOG_WARNING, "failed creating iface refresh timer: %s", strerror(errno)); +} + +void iface_refresh(void *arg) +{ + (void)arg; + + if (!iface_update(1)) + return; + + if (mcgroup_refresh()) + timer_del(iface_refresh, arg); } /** @@ -134,20 +181,34 @@ unsigned int i; struct iface *iface; struct iface *candidate = NULL; + char *nm, *ptr; if (!ifname) return NULL; + nm = strdup(ifname); + if (!nm) + return NULL; + + /* Alias interfaces should use the same VIF/MIF as parent */ + ptr = strchr(nm, ':'); + if (ptr) + *ptr = 0; + for (i = 0; i < num_ifaces; i++) { iface = &iface_list[i]; - if (!strcmp(ifname, iface->name)) { - if (iface->vif >= 0) + if (!strcmp(nm, iface->name)) { + if (iface->vif >= 0) { + free(nm); return iface; + } candidate = iface; } } + free(nm); + return candidate; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/ifvc.h new/smcroute-2.4.3/src/ifvc.h --- old/smcroute-2.4.1/src/ifvc.h 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/ifvc.h 2018-11-07 01:34:48.000000000 +0100 @@ -25,6 +25,7 @@ }; void iface_init (void); +void iface_refresh (void *arg); void iface_exit (void); struct iface *iface_iterator (int first); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/ipc.c new/smcroute-2.4.3/src/ipc.c --- old/smcroute-2.4.1/src/ipc.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/ipc.c 2018-11-07 01:34:48.000000000 +0100 @@ -52,13 +52,13 @@ if (!msg) { /* Skip logging client disconnects */ if (errno != ECONNRESET) - smclog(LOG_WARNING, "Failed receving IPC message from client: %s", strerror(errno)); + smclog(LOG_WARNING, "Failed receiving IPC message from client: %s", strerror(errno)); return; } if (msg_do(sd, msg)) { if (EINVAL == errno) - smclog(LOG_WARNING, "Unkown or malformed IPC message '%c' from client.", msg->cmd); + 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 { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/mcgroup.c new/smcroute-2.4.3/src/mcgroup.c --- old/smcroute-2.4.1/src/mcgroup.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/mcgroup.c 2018-11-07 01:34:48.000000000 +0100 @@ -52,6 +52,11 @@ */ LIST_HEAD(, mgroup) mgroup_static_list = LIST_HEAD_INITIALIZER(); +/* + * Failed joins due to no-ip-address on iface yet ... + */ +LIST_HEAD(, mgroup) mgroup_retry_list = LIST_HEAD_INITIALIZER(); + static int mcgroup4_socket = -1; #ifdef HAVE_LINUX_FILTER_H @@ -67,6 +72,7 @@ }; #endif /* HAVE_LINUX_FILTER_H */ + static struct iface *match_valid_iface(const char *ifname, struct ifmatch *state) { struct iface *iface = iface_match_by_name(ifname, state); @@ -77,7 +83,7 @@ return iface; } -static void list_add(struct iface *iface, struct in_addr source, struct in_addr group) +static void list_add(struct iface *iface, struct in_addr source, struct in_addr group, int fail) { struct mgroup *entry; @@ -91,7 +97,11 @@ entry->inbound = iface->vif; entry->source = source; entry->group = group; - LIST_INSERT_HEAD(&mgroup_static_list, entry, link); + + if (fail) + LIST_INSERT_HEAD(&mgroup_retry_list, entry, link); + else + LIST_INSERT_HEAD(&mgroup_static_list, entry, link); } static void list_rem(struct iface *iface, struct in_addr source, struct in_addr group) @@ -126,35 +136,105 @@ } } -static int mcgroup_join_leave_ipv4(int sd, int cmd, const char *ifname, struct in_addr group) +static int join_leave_ipv4(int sd, int cmd, struct iface *iface, struct in_addr group) { - int opt, ret = 0; struct ip_mreq mreq; - struct iface *iface; + int opt, retry = 0; + + if (!cmd) { + cmd = 'j'; + retry = 1; + } + + if (cmd == 'j') + opt = IP_ADD_MEMBERSHIP; + else + opt = IP_DROP_MEMBERSHIP; + + mreq.imr_multiaddr.s_addr = group.s_addr; + mreq.imr_interface.s_addr = iface->inaddr.s_addr; + if (setsockopt(sd, IPPROTO_IP, opt, &mreq, sizeof(mreq))) { + char grp[16]; + + if (retry) + return 1; + + inet_ntop(AF_INET, &group, grp, sizeof(grp)); + if (EADDRNOTAVAIL == errno && cmd == 'l') + smclog(LOG_DEBUG, "failed leave (*,%s), not a member", grp); + else if (EADDRINUSE == errno && cmd == 'j') + smclog(LOG_DEBUG, "failed join (*,%s), already member", grp); + else if (ENODEV == errno && cmd == 'j') + smclog(LOG_ERR, "failed join (*,%s) on %s, no interface address.", grp, iface); + else + smclog(LOG_ERR, "failed %s (*,%s) on iface %s. Error %d: %s", + cmd == 'j' ? "join" : "leave", grp, iface->name, errno, strerror(errno)); + + return 1; + } + + return 0; +} + +static int join_leave_ssm_ipv4(int sd, int cmd, struct iface *iface, struct in_addr source, struct in_addr group) +{ + struct ip_mreq_source mreqsrc; + int opt, retry = 0; + + if (!cmd) { + cmd = 'j'; + retry = 1; + } + + if (cmd == 'j') + opt = IP_ADD_SOURCE_MEMBERSHIP; + else + opt = IP_DROP_SOURCE_MEMBERSHIP; + + mreqsrc.imr_multiaddr.s_addr = group.s_addr; + mreqsrc.imr_sourceaddr.s_addr = source.s_addr; + mreqsrc.imr_interface.s_addr = iface->inaddr.s_addr; + if (setsockopt(sd, IPPROTO_IP, opt, &mreqsrc, sizeof(mreqsrc))) { + char *src, grp[16]; + + if (retry) + return 1; + + src = inet_ntoa(source); + inet_ntop(AF_INET, &group, grp, sizeof(grp)); + + if (EADDRNOTAVAIL == errno && cmd == 'j') + smclog(LOG_DEBUG, "failed join (%s,%s), already member", src, grp); + else if (EADDRNOTAVAIL == errno && cmd == 'l') + smclog(LOG_DEBUG, "failed leave (%s,%s), not a member from that source", src, grp); + else if (EINVAL == errno && cmd == 'l') + smclog(LOG_DEBUG, "failed leave (%s,%s), not a member", src, grp); + else + smclog(LOG_WARNING, "failed %s (%s,%s) on iface %s. Error %d: %s", + cmd == 'j' ? "join" : "leave", src, grp, iface->name, errno, strerror(errno)); + + return 1; + } + + return 0; +} + +static int mcgroup_join_leave_ipv4(int sd, int cmd, const char *ifname, struct in_addr group) +{ struct ifmatch state; struct in_addr any_src; + struct iface *iface; + int ret = 0; any_src.s_addr = htonl(INADDR_ANY); iface_match_init(&state); while ((iface = match_valid_iface(ifname, &state))) { - if (cmd == 'j') { - list_add(iface, any_src, group); - opt = IP_ADD_MEMBERSHIP; - } else { + ret += join_leave_ipv4(sd, cmd, iface, group); + + if (cmd == 'j') + list_add(iface, any_src, group, ret); + else list_rem(iface, any_src, group); - opt = IP_DROP_MEMBERSHIP; - } - mreq.imr_multiaddr.s_addr = group.s_addr; - mreq.imr_interface.s_addr = iface->inaddr.s_addr; - if (setsockopt(sd, IPPROTO_IP, opt, &mreq, sizeof(mreq))) { - if (EADDRNOTAVAIL == errno && cmd == 'l') - smclog(LOG_DEBUG, "failed leaving group, not a member of %s", inet_ntoa(group)); - else if (EADDRINUSE == errno && cmd == 'j') - smclog(LOG_DEBUG, "failed joining group, already member of %s", inet_ntoa(group)); - else - smclog(LOG_DEBUG, "failed group %s: %s", cmd == 'j' ? "join" : "leave", strerror(errno)); - ret = 1; - } } if (!state.match_count) @@ -169,34 +249,18 @@ smclog(LOG_WARNING, "Source specific join/leave not supported, ignoring source %s", inet_ntoa(source)); return mcgroup_join_leave_ipv4(sd, cmd, ifname, group); #else - int opt, ret = 0; - struct ip_mreq_source mreqsrc; struct iface *iface; struct ifmatch state; + int ret = 0; iface_match_init(&state); while ((iface = match_valid_iface(ifname, &state))) { - if (cmd == 'j') { - list_add(iface, source, group); - opt = IP_ADD_SOURCE_MEMBERSHIP; - } else { + ret += join_leave_ssm_ipv4(sd, cmd, iface, source, group); + + if (cmd == 'j') + list_add(iface, source, group, ret); + else list_rem(iface, source, group); - opt = IP_DROP_SOURCE_MEMBERSHIP; - } - mreqsrc.imr_multiaddr.s_addr = group.s_addr; - mreqsrc.imr_sourceaddr.s_addr = source.s_addr; - mreqsrc.imr_interface.s_addr = iface->inaddr.s_addr; - if (setsockopt(sd, IPPROTO_IP, opt, &mreqsrc, sizeof(mreqsrc))) { - if (EADDRNOTAVAIL == errno && cmd == 'j') - smclog(LOG_DEBUG, "failed join, already member of %s", inet_ntoa(group)); - else if (EADDRNOTAVAIL == errno && cmd == 'l') - smclog(LOG_DEBUG, "failed leave, not a member of %s from that source", inet_ntoa(group)); - else if (EINVAL == errno && cmd == 'l') - smclog(LOG_DEBUG, "failed leave, not a member of %s", inet_ntoa(group)); - else - smclog(LOG_WARNING, "failed %s: %s", cmd == 'j' ? "join" : "leave", strerror(errno)); - ret = 1; - } } if (!state.match_count) @@ -256,7 +320,54 @@ LIST_REMOVE(entry, link); free(entry); } +} + +/* + * Retry join of previously failed joins, called by iface_update() + */ +static void mcgroup4_retry(void) +{ + struct in_addr any_src; + struct mgroup *entry, *tmp; + + any_src.s_addr = htonl(INADDR_ANY); + + LIST_FOREACH_SAFE(entry, &mgroup_retry_list, link, tmp) { + struct iface *iface; + char grp[16]; + int is_any = 0; + int rc; + + iface = iface_find_by_vif(entry->inbound); + if (!iface) + continue; + + if (!memcmp(&entry->source, &any_src, sizeof(any_src))) { + is_any = 1; + rc = join_leave_ipv4(mcgroup4_socket, 0, iface, entry->group); + } else + rc = join_leave_ssm_ipv4(mcgroup4_socket, 0, iface, entry->source, entry->group); + if (rc) + continue; + + inet_ntop(AF_INET, &entry->group, grp, sizeof(grp)); + smclog(LOG_NOTICE, "successful join (%s,%s) on iface %s.", + is_any ? "*" : inet_ntoa(entry->source), grp, iface->name, + errno, strerror(errno)); + + /* Move to list of joined groups */ + LIST_REMOVE(entry, link); + LIST_INSERT_HEAD(&mgroup_static_list, entry, link); + } +} + +int mcgroup_refresh(void) +{ + mcgroup4_retry(); + if (LIST_EMPTY(&mgroup_retry_list)) + return 1; + return 0; } #ifdef HAVE_IPV6_MULTICAST_HOST diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/mcgroup.h new/smcroute-2.4.3/src/mcgroup.h --- old/smcroute-2.4.1/src/mcgroup.h 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/mcgroup.h 2018-11-07 01:34:48.000000000 +0100 @@ -2,6 +2,8 @@ #ifndef SMCROUTE_MCGROUP_H_ #define SMCROUTE_MCGROUP_H_ +int mcgroup_refresh (void); + int mcgroup4_join (const char *ifname, struct in_addr source, struct in_addr group); int mcgroup4_leave (const char *ifname, struct in_addr source, struct in_addr group); void mcgroup4_disable (void); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/mrdisc.c new/smcroute-2.4.3/src/mrdisc.c --- old/smcroute-2.4.1/src/mrdisc.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/mrdisc.c 2018-11-07 01:34:48.000000000 +0100 @@ -74,7 +74,7 @@ int mrdisc_init(int period) { interval = period; - if (timer_add(interval, mrdisc_send, NULL) < 0) { + if (timer_add(interval, mrdisc_send, NULL) < 0 && errno != EEXIST) { smclog(LOG_ERR, "Failed starting mrdisc announcement timer."); return -1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/mroute.c new/smcroute-2.4.3/src/mroute.c --- old/smcroute-2.4.1/src/mroute.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/mroute.c 2018-11-07 01:34:48.000000000 +0100 @@ -561,8 +561,8 @@ return 0; } -/* - * Query kernel for install MFC entry usage statistics +/* + * Query kernel for route usage statistics */ static int get_stats4(struct mroute4 *route, unsigned long *pktcnt, unsigned long *bytecnt, unsigned long *wrong_if) { @@ -1204,12 +1204,12 @@ snprintf(buf, sizeof(buf), "%-34s %-16s", sg, i->name); if (detail) { - char stats[25]; + char stats[30]; unsigned long p = 0, b = 0; get_stats4(r, &p, &b, NULL); - snprintf(stats, sizeof(stats), " %10.10lu %10.10lu ", p, b); - strcat(buf, stats); + snprintf(stats, sizeof(stats), " %10lu %10lu ", p, b); + strlcat(buf, stats, sizeof(buf)); } for (vif = 0; vif < MAX_MC_VIFS; vif++) { @@ -1223,9 +1223,9 @@ continue; snprintf(tmp, sizeof(tmp), " %s", i->name); - strcat(buf, tmp); + strlcat(buf, tmp, sizeof(buf)); } - strcat(buf, "\n"); + strlcat(buf, "\n", sizeof(buf)); if (ipc_send(sd, buf, strlen(buf)) < 0) { smclog(LOG_ERR, "Failed sending reply to client: %s", strerror(errno)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/pidfile.c new/smcroute-2.4.3/src/pidfile.c --- old/smcroute-2.4.1/src/pidfile.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/pidfile.c 2018-11-07 01:34:48.000000000 +0100 @@ -47,14 +47,20 @@ static char *pidfile_path = NULL; static pid_t pidfile_pid = 0; -static void pidfile_cleanup(void); - const char *__pidfile_path = LOCALSTATEDIR "/run"; const char *__pidfile_name = NULL; extern char *prognm; -int -pidfile(const char *basename, uid_t uid, gid_t gid) +static void pidfile_cleanup(void) +{ + if (pidfile_path != NULL && pidfile_pid == getpid()) { + (void) unlink(pidfile_path); + free(pidfile_path); + pidfile_path = NULL; + } +} + +int pidfile_create(const char *basename, uid_t uid, gid_t gid) { int save_errno; int atexit_already; @@ -70,7 +76,7 @@ if (pidfile_path != NULL) { if (!access(pidfile_path, R_OK) && pid == pidfile_pid) { utimensat(0, pidfile_path, NULL, 0); - return (0); + return 0; } free(pidfile_path); pidfile_path = NULL; @@ -80,10 +86,10 @@ if (basename[0] != '/') { if (asprintf(&pidfile_path, "%s/%s.pid", __pidfile_path, basename) == -1) - return (-1); + return -1; } else { if (asprintf(&pidfile_path, "%s", basename) == -1) - return (-1); + return -1; } smclog(LOG_DEBUG, "Creating PID file %s", pidfile_path); @@ -92,7 +98,7 @@ free(pidfile_path); pidfile_path = NULL; errno = save_errno; - return (-1); + return -1; } if (fprintf(f, "%ld\n", (long)pid) <= 0 || fflush(f) != 0) { @@ -102,20 +108,20 @@ free(pidfile_path); pidfile_path = NULL; errno = save_errno; - return (-1); + return -1; } (void) fclose(f); __pidfile_name = pidfile_path; if (chown(pidfile_path, uid, gid)) - return (-1); + return -1; /* * LITE extension, no need to set up another atexit() handler * if user only called us to update the mtime of the PID file */ if (atexit_already) - return (0); + return 0; pidfile_pid = pid; if (atexit(pidfile_cleanup) < 0) { @@ -125,18 +131,8 @@ pidfile_path = NULL; pidfile_pid = 0; errno = save_errno; - return (-1); + return -1; } - return (0); -} - -static void -pidfile_cleanup(void) -{ - if (pidfile_path != NULL && pidfile_pid == getpid()) { - (void) unlink(pidfile_path); - free(pidfile_path); - pidfile_path = NULL; - } + return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/smcroutectl.c new/smcroute-2.4.3/src/smcroutectl.c --- old/smcroute-2.4.1/src/smcroutectl.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/smcroutectl.c 2018-11-07 01:34:48.000000000 +0100 @@ -149,7 +149,7 @@ if (count && argv[0][0] == 'g') snprintf(line, sizeof(line), "\e[7m%-34s %-16s", g, i); else if (detail) - snprintf(line, sizeof(line), "\e[7m%-34s %-16s %10s %10s %-8s", r, i, p, b, o); + snprintf(line, sizeof(line), "\e[7m%-34s %-16s %10s %10s %-8s", r, i, p, b, o); else snprintf(line, sizeof(line), "\e[7m%-34s %-16s %-8s", r, i, o); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/smcrouted.c new/smcroute-2.4.3/src/smcrouted.c --- old/smcroute-2.4.1/src/smcrouted.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/smcrouted.c 2018-11-07 01:34:48.000000000 +0100 @@ -98,7 +98,7 @@ conf_read(conf_file, do_vifs); /* Acknowledge client SIGHUP/reload by touching the pidfile */ - pidfile(NULL, uid, gid); + pidfile_create(NULL, uid, gid); } /* @@ -176,14 +176,14 @@ } /* - * Build list of multicast-capable physical interfaces + * Timer API needs to be initilized before mroute4_enable() */ - iface_init(); + timer_init(); /* - * Timer API needs to be initilized before mroute4_enable() + * Build list of multicast-capable physical interfaces */ - timer_init(); + iface_init(); if (mroute4_enable(do_vifs, table_id, cache_tmo)) { if (errno == EADDRINUSE) @@ -214,8 +214,8 @@ conf_read(conf_file, do_vifs); /* Everything setup, notify any clients by creating the pidfile */ - if (pidfile(pid_file, uid, gid)) - smclog(LOG_WARNING, "Failed create/chown pidfile: %s", strerror(errno)); + if (pidfile_create(pid_file, uid, gid)) + smclog(LOG_WARNING, "Failed create/chown PID file: %s", strerror(errno)); /* Drop root privileges before entering the server loop */ cap_drop_root(uid, gid); @@ -333,7 +333,7 @@ int main(int argc, char *argv[]) { int c; - int log_opts = LOG_CONS | LOG_PID; + int log_opts = LOG_NDELAY | LOG_PID; prognm = progname(argv[0]); while ((c = getopt(argc, argv, "c:d:e:f:hI:l:m:nNp:P:st:v")) != EOF) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/timer.c new/smcroute-2.4.3/src/timer.c --- old/smcroute-2.4.1/src/timer.c 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/timer.c 2018-11-07 01:34:48.000000000 +0100 @@ -27,6 +27,7 @@ #include "log.h" #include "queue.h" #include "socket.h" +#include "timer.h" /* * TODO @@ -35,6 +36,7 @@ */ struct timer { LIST_ENTRY(timer) link; + int active; /* Set to 0 to delete */ int period; /* period time in seconds */ struct timespec timeout; @@ -77,6 +79,21 @@ return b; } +static struct timer *find(void (*cb), void *arg) +{ + struct timer *entry; + + LIST_FOREACH(entry, &tl, link) { + if (entry->cb != cb || entry->arg != arg) + continue; + + return entry; + } + + return NULL; +} + + static int start(struct timespec *now) { struct timer *next, *entry; @@ -102,19 +119,24 @@ { char dummy; struct timespec now; - struct timer *entry; + struct timer *entry, *tmp; (void)arg; if (read(sd, &dummy, 1) < 0) smclog(LOG_DEBUG, "Failed read(pipe): %s", strerror(errno)); clock_gettime(CLOCK_MONOTONIC, &now); - LIST_FOREACH(entry, &tl, link) { + LIST_FOREACH_SAFE(entry, &tl, link, tmp) { if (expired(entry, &now)) { if (entry->cb) entry->cb(entry->arg); set(entry, &now); } + + if (!entry->active) { + LIST_REMOVE(entry, link); + free(entry); + } } start(&now); @@ -165,6 +187,12 @@ struct timer *t; struct timespec now; + t = find(cb, arg); + if (t && t->active) { + errno = EEXIST; + return -1; + } + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) return -1; @@ -172,6 +200,7 @@ if (!t) return -1; + t->active = 1; t->period = period; t->cb = cb; t->arg = arg; @@ -183,6 +212,24 @@ return start(&now); } +/* + * delete a timer + */ +int timer_del(void (*cb)(void *), void *arg) +{ + struct timer *entry; + + entry = find(cb, arg); + if (!entry) + return 1; + + /* Mark for deletion and issue a new run */ + entry->active = 0; + handler(0); + + return 0; +} + /** * Local Variables: * indent-tabs-mode: t diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/timer.h new/smcroute-2.4.3/src/timer.h --- old/smcroute-2.4.1/src/timer.h 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/timer.h 2018-11-07 01:34:48.000000000 +0100 @@ -3,6 +3,8 @@ #define SMCROUTE_TIMER_H_ int timer_init (void); + int timer_add (int period, void (*cb)(void *), void *arg); +int timer_del (void (*cb)(void *), void *arg); #endif /* SMCROUTE_TIMER_H_ */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/smcroute-2.4.1/src/util.h new/smcroute-2.4.3/src/util.h --- old/smcroute-2.4.1/src/util.h 2018-06-16 13:40:28.000000000 +0200 +++ new/smcroute-2.4.3/src/util.h 2018-11-07 01:34:48.000000000 +0100 @@ -18,12 +18,18 @@ #define NELEMS(array) (sizeof(array) / sizeof(array[0])) #endif -int pidfile(const char *basename, uid_t uid, gid_t gid); +int pidfile_create(const char *basename, uid_t uid, gid_t gid); + #ifndef HAVE_UTIMENSAT int utimensat(int dirfd, const char *pathname, const struct timespec ts[2], int flags); #endif + #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t len); #endif +#ifndef HAVE_STRLCAT +size_t strlcat(char *dst, const char *src, size_t dsize); +#endif + #endif /* SMCROUTE_UTIL_H_ */
