├── debian ├── compat ├── docs ├── dirs ├── mrouted.docs ├── source │ ├── format │ └── lintian-overrides ├── mrouted.examples ├── mrinfo.install ├── mtrace.install ├── map-mbone.install ├── mrouted.install ├── .gitignore ├── rules ├── README.debian ├── control ├── init.d ├── copyright └── changelog ├── doc ├── README.md ├── RPF.jpg ├── PRUNING.jpg ├── FLOODING.jpg ├── GRAFTING.jpg ├── dvmrp-simple.png ├── LINKS ├── AUTHORS ├── DVMRP.md ├── configure ├── Makefile └── panos-text.ps ├── lib ├── .gitignore ├── utimensat.c ├── strlcpy.c ├── strlcat.c ├── strtonum.c └── pidfile.c ├── LICENSE ├── autogen.sh ├── test ├── .gitignore ├── Makefile.am ├── single.sh ├── three.sh ├── tunnel.sh └── shared.sh ├── .github ├── FUNDING.yml ├── workflows │ ├── container.yml │ ├── release.yml │ ├── coverity.yml │ └── build.yml ├── CODE-OF-CONDUCT.md └── CONTRIBUTING.md ├── src ├── .gitignore ├── pathnames.h ├── Makefile.am ├── igmpv2.h ├── route.h ├── igmpv3.h ├── common.c ├── log.c ├── ipip.c ├── pev.h ├── prune.h ├── inet.c ├── icmp.c ├── dvmrp.h └── config.c ├── man ├── Makefile.am ├── map-mbone.8 ├── mrinfo.8 └── mrouted.8 ├── .gitignore ├── mrouted.service.in ├── Dockerfile ├── Makefile.am ├── mrouted.conf ├── configure.ac └── README.md /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README 2 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | DVMRP.md -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/sbin 2 | etc 3 | -------------------------------------------------------------------------------- /debian/mrouted.docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) -------------------------------------------------------------------------------- /debian/mrouted.examples: -------------------------------------------------------------------------------- 1 | mrouted.conf 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troglobit/mrouted/HEAD/LICENSE -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf -W portability -visfm 4 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | .deps/* 2 | *.log 3 | *.o 4 | *.trs 5 | mping 6 | -------------------------------------------------------------------------------- /debian/mrinfo.install: -------------------------------------------------------------------------------- 1 | usr/sbin/mrinfo 2 | usr/share/man/man8/mrinfo.8 3 | -------------------------------------------------------------------------------- /debian/mtrace.install: -------------------------------------------------------------------------------- 1 | usr/sbin/mtrace 2 | usr/share/man/man8/mtrace.8 3 | -------------------------------------------------------------------------------- /doc/RPF.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troglobit/mrouted/HEAD/doc/RPF.jpg -------------------------------------------------------------------------------- /debian/map-mbone.install: -------------------------------------------------------------------------------- 1 | usr/sbin/map-mbone 2 | usr/share/man/man8/map-mbone.8 3 | -------------------------------------------------------------------------------- /doc/PRUNING.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troglobit/mrouted/HEAD/doc/PRUNING.jpg -------------------------------------------------------------------------------- /doc/FLOODING.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troglobit/mrouted/HEAD/doc/FLOODING.jpg -------------------------------------------------------------------------------- /doc/GRAFTING.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troglobit/mrouted/HEAD/doc/GRAFTING.jpg -------------------------------------------------------------------------------- /doc/dvmrp-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troglobit/mrouted/HEAD/doc/dvmrp-simple.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [troglobit] 4 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.map 3 | map-mbone 4 | mroutectl 5 | mrouted 6 | mrinfo 7 | mtrace 8 | cfparse.c 9 | -------------------------------------------------------------------------------- /debian/source/lintian-overrides: -------------------------------------------------------------------------------- 1 | mrouted source: empty-debian-diff 2 | mrouted source: native-package-with-dash-version 3 | -------------------------------------------------------------------------------- /man/Makefile.am: -------------------------------------------------------------------------------- 1 | dist_man5_MANS = mrouted.conf.5 2 | dist_man8_MANS = mrouted.8 mroutectl.8 map-mbone.8 mrinfo.8 mtrace.8 3 | -------------------------------------------------------------------------------- /debian/mrouted.install: -------------------------------------------------------------------------------- 1 | lib/systemd/system/mrouted.service 2 | usr/sbin/mrouted 3 | usr/sbin/mroutectl 4 | usr/share/man/man8/mrouted.8 5 | usr/share/man/man8/mroutectl.8 6 | -------------------------------------------------------------------------------- /debian/.gitignore: -------------------------------------------------------------------------------- 1 | *.substvars 2 | *.log 3 | .debhelper/* 4 | mrouted/* 5 | mrinfo/* 6 | map-mbone/* 7 | mtrace/* 8 | tmp/* 9 | files 10 | autoreconf.* 11 | mrouted*.debhelper 12 | -------------------------------------------------------------------------------- /doc/LINKS: -------------------------------------------------------------------------------- 1 | mstat etc: 2 | http://imj.ucsb.edu/mdh/tooldetail.html 3 | 4 | mtrace@sf.net 5 | http://kb.pert.geant.net/PERTKB/MulticastTraceroute 6 | http://sourceforge.net/projects/mtrace/ 7 | 8 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # Uncomment this to turn on verbose mode. 3 | #export DH_VERBOSE=1 4 | 5 | # See dpkg-buildflags(1) manpage 6 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 7 | 8 | %: 9 | dh $@ --with autoreconf,systemd 10 | 11 | override_dh_installchangelogs: 12 | dh_installchangelogs ChangeLog.md 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | .dirstamp 3 | .gdb_history 4 | *~ 5 | *.bak 6 | *-stamp 7 | aux/ 8 | ID 9 | GPATH 10 | GRTAGS 11 | GSYMS 12 | GTAGS 13 | Makefile 14 | Makefile.in 15 | aclocal.m4 16 | autom4te.cache 17 | build-stamp 18 | compile 19 | config.h 20 | config.h.in 21 | config.log 22 | config.status 23 | configure 24 | depcomp 25 | install-sh 26 | missing 27 | mrouted.service 28 | stamp-h1 29 | ylwrap 30 | -------------------------------------------------------------------------------- /doc/AUTHORS: -------------------------------------------------------------------------------- 1 | Current Maintainer(s): 2 | * Joachim Wiberg 3 | 4 | Original Author(s): 5 | * David Waitzman, while at BBN Technologies 6 | * Craig Partridge, BBN Technologies 7 | * Steve Deering 8 | * Ajit Thyagarajan 9 | * Bill Fenner 10 | * David Thaler (SNMP Support) 11 | * Daniel Zappala (RSRR Support) 12 | 13 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = lib.sh mping.c pod.sh shared.sh single.sh three.sh 2 | CLEANFILES = *~ *.trs *.log 3 | 4 | noinst_PROGRAMS = mping 5 | mping_SOURCES = mping.c 6 | 7 | TEST_EXTENSIONS = .sh 8 | TESTS_ENVIRONMENT = unshare -mrun --map-auto 9 | 10 | TESTS = pod.sh 11 | TESTS += shared.sh 12 | TESTS += single.sh 13 | TESTS += three.sh 14 | TESTS += tunnel.sh 15 | -------------------------------------------------------------------------------- /mrouted.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Multicast routing daemon, mrouted 3 | Documentation=man:mrouted 4 | Documentation=man:mrouted.conf 5 | Documentation=man:mroutectl 6 | Documentation=file:@DOCDIR@/README.md 7 | Documentation=https://github.com/troglobit/mrouted 8 | # ConditionPathExists=@SYSCONFDIR@/mrouted.conf 9 | After=network-online.target 10 | Requires=network-online.target 11 | 12 | [Service] 13 | Type=simple 14 | ExecStartPre=-/sbin/modprobe ipip 15 | EnvironmentFile=-@SYSCONFDIR@/default/mrouted 16 | ExecStart=@SBINDIR@/mrouted --foreground --syslog $MROUTED_OPTS $MROUTED_ARGS 17 | 18 | [Install] 19 | WantedBy=multi-user.target 20 | -------------------------------------------------------------------------------- /src/pathnames.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | #ifndef MROUTED_PATHNAMES_H_ 10 | #define MROUTED_PATHNAMES_H_ 11 | 12 | #include 13 | 14 | #define _PATH_MROUTED_CONF SYSCONFDIR "/%s.conf" 15 | #define _PATH_MROUTED_GENID PRESERVEDIR "/%s.genid" 16 | #define _PATH_MROUTED_RUNDIR RUNSTATEDIR 17 | #define _PATH_MROUTED_SOCK RUNSTATEDIR "/%s.sock" 18 | 19 | #endif /* MROUTED_PATHNAMES_H_ */ 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # You probably don't want to use this, becuase mrouted need the actual 2 | # interfaces in its network namespace to work, meaning you wont see them 3 | # anymore on the host side ... 4 | FROM alpine:latest 5 | 6 | # Build depends 7 | RUN apk add --no-cache git gcc musl-dev linux-headers make pkgconfig \ 8 | automake autoconf bison flex 9 | 10 | COPY . /tmp/mrouted 11 | RUN git clone --depth=1 file:///tmp/mrouted /root/mrouted 12 | WORKDIR /root/mrouted 13 | 14 | RUN ./autogen.sh && \ 15 | ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \ 16 | --without-systemd \ 17 | make && \ 18 | make install-strip 19 | 20 | FROM alpine:latest 21 | COPY --from=0 /usr/sbin/mrouted /usr/sbin/mrouted 22 | 23 | CMD [ "/usr/sbin/mrouted" ] 24 | -------------------------------------------------------------------------------- /debian/README.debian: -------------------------------------------------------------------------------- 1 | mrouted for Debian 2 | ------------------ 3 | 4 | If you are not running a stock Debian kernel, you need to enable multicast and 5 | multicast-routing in your kernel: 6 | 7 | CONFIG_IP_MULTICAST=y 8 | CONFIG_IP_MROUTE=y 9 | 10 | If you want to use multiple routing tables, available in modern kernels, you 11 | also need to have the following option. 12 | 13 | CONFIG_IP_MROUTE_MULTIPLE_TABLES=y 14 | 15 | Please note, however, that you also need to create routing rules directing 16 | packets to the table. This example uses routing table ID 123: 17 | 18 | ip mrule add iif eth0 lookup 123 19 | ip mrule add oif eth0 lookup 123 20 | 21 | If you want to build a multicast tunnel via an unicast connection, you have to 22 | enable support for IP-IP tunneling as well: 23 | 24 | CONFIG_NET_IPIP=m (or =y) 25 | 26 | The default configuration of mrouted is to route between two and more 27 | interfaces. For more details see the manpage. 28 | 29 | -- Joachim Wiberg , Sun, 19 Sep 2021 00:01:32 +0200 30 | -------------------------------------------------------------------------------- /.github/workflows/container.yml: -------------------------------------------------------------------------------- 1 | name: Container Claus 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | tags: 8 | - '[0-9]+.[0-9]+*' 9 | 10 | jobs: 11 | docker: 12 | runs-on: ubuntu-latest 13 | permissions: 14 | packages: write 15 | contents: read 16 | env: 17 | MAKEFLAGS: -j3 18 | IMAGE_NAME: mrouted 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Build image 22 | run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" 23 | - name: Log in to registry 24 | run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin 25 | - name: Push image 26 | run: | 27 | IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME 28 | # Change all uppercase to lowercase 29 | IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') 30 | # Strip git ref prefix from version 31 | VERSION=$(echo "${{ github.ref_name }}" | sed -e 's,.*/\(.*\),\1,') 32 | # Use Docker `latest` tag convention 33 | [ "$VERSION" == "master" ] && VERSION=latest 34 | echo IMAGE_ID=$IMAGE_ID 35 | echo VERSION=$VERSION 36 | docker tag $IMAGE_NAME $IMAGE_ID:$VERSION 37 | docker push $IMAGE_ID:$VERSION 38 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | # For replacement functions in lib/ 2 | AUTOMAKE_OPTIONS = subdir-objects 3 | 4 | # -D_GNU_SOURCE Use GNU extensions, where possible 5 | # -D_BSD_SOURCE Use functions derived from 4.3 BSD Unix rather than POSIX.1 6 | # In GLIBC >= v2.20 this is replaced with -D_DEFAULT_SOURCE, 7 | # but to build on older GLIBC systems we now need both ... 8 | AM_CPPFLAGS = -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_GNU_SOURCE -I$(top_srcdir)/include 9 | AM_CPPFLAGS += -DSYSCONFDIR=\"@sysconfdir@\" -DRUNSTATEDIR=\"@runstatedir@\" -DPRESERVEDIR=\"@localstatedir@/lib\" 10 | if LINUX 11 | AM_CPPFLAGS += -DIOCTL_OK_ON_RAW_SOCKET 12 | endif 13 | AM_CFLAGS = -W -Wall -Wextra -Wno-unused -Wno-unused-parameter 14 | 15 | sbin_PROGRAMS = mrouted mroutectl map-mbone mrinfo mtrace 16 | mrouted_SOURCES = main.c common.c cfparse.y config.c \ 17 | defs.h dvmrp.h \ 18 | igmp.c igmpv2.h igmpv3.h \ 19 | icmp.c ipc.c ipip.c inet.c \ 20 | kern.c log.c \ 21 | pathnames.h queue.h \ 22 | pev.c pev.h \ 23 | prune.c prune.h \ 24 | route.c route.h \ 25 | vif.c vif.h 26 | mrouted_CPPFLAGS = -DREGISTER_HANDLER $(AM_CPPFLAGS) 27 | mrouted_LDADD = $(LIBS) $(LIBOBJS) 28 | 29 | mroutectl_SOURCES = mroutectl.c common.c defs.h 30 | mroutectl_LDADD = $(LIBS) $(LIBOBJS) 31 | 32 | map_mbone_SOURCES = mapper.c defs.h igmp.c igmpv2.h inet.c kern.c 33 | map_mbone_LDADD = $(LIBS) $(LIBOBJS) 34 | 35 | mrinfo_SOURCES = mrinfo.c defs.h igmp.c igmpv2.h inet.c kern.c 36 | mrinfo_LDADD = $(LIBS) $(LIBOBJS) 37 | 38 | mtrace_SOURCES = mtrace.c defs.h igmp.c igmpv2.h inet.c kern.c 39 | mtrace_LDADD = $(LIBS) $(LIBOBJS) 40 | 41 | -------------------------------------------------------------------------------- /lib/utimensat.c: -------------------------------------------------------------------------------- 1 | /* Replacement in case utimensat(2) is missing 2 | * 3 | * Copyright (C) 2017-2020 Joachim Wiberg 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #include "config.h" 19 | #include 20 | #ifdef HAVE_FCNTL_H 21 | #include 22 | #endif 23 | #include /* lutimes(), utimes(), utimensat() */ 24 | 25 | int utimensat(int dirfd, const char *pathname, const struct timespec ts[2], int flags) 26 | { 27 | int ret = -1; 28 | struct timeval tv[2]; 29 | 30 | if (dirfd != 0) { 31 | errno = ENOTSUP; 32 | return -1; 33 | } 34 | 35 | TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]); 36 | TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]); 37 | 38 | if ((flags & AT_SYMLINK_NOFOLLOW) == AT_SYMLINK_NOFOLLOW) 39 | ret = lutimes(pathname, tv); 40 | else 41 | ret = utimes(pathname, tv); 42 | 43 | return ret; 44 | } 45 | 46 | /** 47 | * Local Variables: 48 | * indent-tabs-mode: t 49 | * c-file-style: "linux" 50 | * End: 51 | */ 52 | -------------------------------------------------------------------------------- /lib/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | /* 23 | * Copy string src to buffer dst of size dsize. At most dsize-1 24 | * chars will be copied. Always NUL terminates (unless dsize == 0). 25 | * Returns strlen(src); if retval >= dsize, truncation occurred. 26 | */ 27 | size_t 28 | strlcpy(char *dst, const char *src, size_t dsize) 29 | { 30 | const char *osrc = src; 31 | size_t nleft = dsize; 32 | 33 | /* Copy as many bytes as will fit. */ 34 | if (nleft != 0) { 35 | while (--nleft != 0) { 36 | if ((*dst++ = *src++) == '\0') 37 | break; 38 | } 39 | } 40 | 41 | /* Not enough room in dst, add NUL and traverse rest of src. */ 42 | if (nleft == 0) { 43 | if (dsize != 0) 44 | *dst = '\0'; /* NUL-terminate dst */ 45 | while (*src++) 46 | ; 47 | } 48 | 49 | return(src - osrc - 1); /* count does not include NUL */ 50 | } 51 | -------------------------------------------------------------------------------- /src/igmpv2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | * 9 | * 10 | * igmpv2.h,v 3.8.4.1 1997/11/18 23:25:58 fenner Exp 11 | */ 12 | 13 | /* 14 | * Constants for IGMP Version 2. Several of these, especially the 15 | * robustness variable, should be variables and not constants. 16 | */ 17 | #define IGMP_ROBUSTNESS_DEFAULT 2 18 | #define IGMP_QUERY_INTERVAL_DEFAULT 125 19 | #define IGMP_QUERY_RESPONSE_INTERVAL 10 20 | #define IGMP_GROUP_MEMBERSHIP_INTERVAL (igmp_robustness * \ 21 | igmp_query_interval + \ 22 | igmp_response_interval) 23 | #define IGMP_OTHER_QUERIER_PRESENT_INTERVAL (igmp_robustness * \ 24 | igmp_query_interval + \ 25 | igmp_response_interval / 2) 26 | /* Round to the nearest TIMER_INTERVAL */ 27 | #define IGMP_STARTUP_QUERY_INTERVAL (((igmp_query_interval / 4) \ 28 | / TIMER_INTERVAL) * TIMER_INTERVAL) 29 | #define IGMP_STARTUP_QUERY_COUNT igmp_robustness 30 | #define IGMP_LAST_MEMBER_INTERVAL_DEFAULT 1 31 | #define IGMP_LAST_MEMBER_QUERY_COUNT igmp_robustness 32 | 33 | /* 34 | * OLD_AGE_THRESHOLD is the number of IGMP_QUERY_INTERVAL's to remember the 35 | * presence of an IGMPv1 group member. According to the IGMPv2 specification, 36 | * routers remember this presence for [Robustness Variable] * [Query Interval] + 37 | * [Query Response Interval]. However, OLD_AGE_THRESHOLD is in units of 38 | * [Query Interval], so doesn't have sufficient resolution to represent 39 | * [Query Response Interval]. When the timer mechanism gets an efficient 40 | * method of refreshing timers, this should get fixed. 41 | */ 42 | #define OLD_AGE_THRESHOLD igmp_robustness 43 | -------------------------------------------------------------------------------- /lib/strlcat.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | /* 23 | * Appends src to string dst of size dsize (unlike strncat, dsize is the 24 | * full size of dst, not space left). At most dsize-1 characters 25 | * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). 26 | * Returns strlen(src) + MIN(dsize, strlen(initial dst)). 27 | * If retval >= dsize, truncation occurred. 28 | */ 29 | size_t 30 | strlcat(char *dst, const char *src, size_t dsize) 31 | { 32 | const char *odst = dst; 33 | const char *osrc = src; 34 | size_t n = dsize; 35 | size_t dlen; 36 | 37 | /* Find the end of dst and adjust bytes left but don't go past end. */ 38 | while (n-- != 0 && *dst != '\0') 39 | dst++; 40 | dlen = dst - odst; 41 | n = dsize - dlen; 42 | 43 | if (n-- == 0) 44 | return(dlen + strlen(src)); 45 | while (*src != '\0') { 46 | if (n != 0) { 47 | *dst++ = *src; 48 | n--; 49 | } 50 | src++; 51 | } 52 | *dst = '\0'; 53 | 54 | return(dlen + (src - osrc)); /* count does not include NUL */ 55 | } 56 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | doc_DATA = README.md ChangeLog.md LICENSE mrouted.conf 2 | EXTRA_DIST = README.md ChangeLog.md LICENSE mrouted.conf 3 | DISTCLEANFILES = *~ DEADJOE semantic.cache *.gdb *.elf core core.* *.d 4 | SUBDIRS = src man 5 | EXTRADEBS = mrinfo*_$(VERSION)* mtrace*_$(VERSION)* map-mbone*_$(VERSION)* 6 | 7 | if ENABLE_TEST 8 | SUBDIRS += test 9 | endif 10 | 11 | if SYSTEMD 12 | systemd_DATA = mrouted.service 13 | endif 14 | 15 | ## Generate .deb package 16 | package: 17 | @debuild -uc -us -B --lintian-opts --profile debian -i -I --show-overrides 18 | 19 | ## Check if tagged in git 20 | release-hook: 21 | @if [ "x`git tag -l $(PACKAGE_VERSION)|grep $(PACKAGE_VERSION)`" = "x" ]; then \ 22 | echo; \ 23 | printf "\e[1m\e[41mCannot find release tag $(PACKAGE_VERSION)\e[0m\n"; \ 24 | printf "\e[1m\e[5mDo release anyway?\e[0m "; read yorn; \ 25 | if [ "$$yorn" != "y" -a "$$yorn" != "Y" ]; then \ 26 | printf "OK, aborting release.\n"; \ 27 | exit 1; \ 28 | fi; \ 29 | echo; \ 30 | else \ 31 | echo; \ 32 | printf "\e[1m\e[42mFound GIT release tag $(PACKAGE_VERSION)\e[0m\n"; \ 33 | printf "\e[1m\e[44m>>Remember to push tags!\e[0m\n"; \ 34 | echo; \ 35 | fi 36 | 37 | ## Target to run when building a release 38 | release: release-hook distcheck 39 | @for file in $(DIST_ARCHIVES); do \ 40 | md5sum $$file > ../$$file.md5; \ 41 | sha256sum $$file > ../$$file.sha256; \ 42 | done 43 | @mv $(DIST_ARCHIVES) ../ 44 | @echo 45 | @echo "Resulting release files =========================================================================" 46 | @for file in $(DIST_ARCHIVES); do \ 47 | printf "%-32s Distribution tarball\n" $$file; \ 48 | printf "%-32s " $$file.md5; cat ../$$file.md5 | cut -f1 -d' '; \ 49 | printf "%-32s " $$file.sha256; cat ../$$file.sha256 | cut -f1 -d' '; \ 50 | done 51 | 52 | DISTCHECK_CONFIGURE_FLAGS = --with-systemd=$$dc_install_base/$(systemd) 53 | -------------------------------------------------------------------------------- /.github/CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all 5 | people who contribute through reporting issues, posting feature 6 | requests, updating documentation, submitting pull requests or patches, 7 | and other activities. 8 | 9 | We are committed to making participation in this project a 10 | harassment-free experience for everyone, regardless of level of 11 | experience, gender, gender identity and expression, sexual orientation, 12 | disability, personal appearance, body size, race, ethnicity, age, 13 | religion, or nationality. 14 | 15 | Examples of unacceptable behavior by participants include: 16 | 17 | * The use of sexualized language or imagery 18 | * Personal attacks 19 | * Trolling or insulting/derogatory comments 20 | * Public or private harassment 21 | * Publishing other's private information, such as physical or electronic 22 | addresses, without explicit permission 23 | * Other unethical or unprofessional conduct. 24 | 25 | Project maintainers have the right and responsibility to remove, edit, 26 | or reject comments, commits, code, wiki edits, issues, and other 27 | contributions that are not aligned to this Code of Conduct. By adopting 28 | this Code of Conduct, project maintainers commit themselves to fairly 29 | and consistently applying these principles to every aspect of managing 30 | this project. Project maintainers who do not follow or enforce the Code 31 | of Conduct may be permanently removed from the project team. 32 | 33 | This code of conduct applies both within project spaces and in public 34 | spaces when an individual is representing the project or its community. 35 | 36 | Instances of abusive, harassing, or otherwise unacceptable behavior may 37 | be reported by opening an issue or contacting one or more of the project 38 | maintainers. 39 | 40 | This Code of Conduct is adapted from the [Contributor Covenant][1], 41 | [version 1.2.0][2]. 42 | 43 | [1]: http://contributor-covenant.org 44 | [2]: http://contributor-covenant.org/version/1/2/0/ 45 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release General 2 | 3 | on: 4 | push: 5 | tags: 6 | - '[0-9]+.[0-9]+*' 7 | 8 | jobs: 9 | release: 10 | name: Build and upload release tarball 11 | if: startsWith(github.ref, 'refs/tags/') 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Installing dependencies ... 16 | run: | 17 | sudo apt-get -y update 18 | sudo apt-get -y install pkg-config libsystemd-dev 19 | - name: Setting release variables ... 20 | id: build 21 | run: | 22 | ver=${GITHUB_REF#refs/tags/} 23 | echo "ver=${ver}" >> $GITHUB_OUTPUT 24 | if echo $ver | grep -qE '^[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha|-beta|-rc)[0-9]*$'; then 25 | echo "pre=true" >> $GITHUB_OUTPUT 26 | else 27 | echo "pre=false" >> $GITHUB_OUTPUT 28 | fi 29 | if echo $ver | grep -qE '^[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then 30 | echo "latest=true" >> $GITHUB_OUTPUT 31 | else 32 | echo "latest=false" >> $GITHUB_OUTPUT 33 | fi 34 | - name: Creating Makefiles ... 35 | run: | 36 | ./autogen.sh 37 | ./configure 38 | - name: Enable unprivileged userns (unshare) 39 | run: | 40 | sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0 41 | - name: Build release ... 42 | run: | 43 | make release || (cat test/test-suite.log; false) 44 | ls -lF ../ 45 | mkdir -p artifacts/ 46 | mv ../*.tar.* artifacts/ 47 | - name: Extract ChangeLog entry ... 48 | run: | 49 | awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \ 50 | |head -n -1 > release.md 51 | cat release.md 52 | - uses: ncipollo/release-action@v1 53 | with: 54 | name: mrouted v${{ github.ref_name }} 55 | prerelease: ${{ steps.build.outputs.pre }} 56 | makeLatest: ${{ steps.build.outputs.latest }} 57 | bodyFile: "release.md" 58 | artifacts: "artifacts/*" 59 | -------------------------------------------------------------------------------- /lib/strtonum.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2004 Ted Unangst and Todd Miller 5 | * All rights reserved. 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #define INVALID 1 25 | #define TOOSMALL 2 26 | #define TOOLARGE 3 27 | 28 | /* Not defined in GLIBC */ 29 | #ifndef LLONG_MAX 30 | # define LLONG_MAX 0x7fffffffffffffffLL 31 | #endif 32 | 33 | #ifndef LLONG_MIN 34 | # define LLONG_MIN (-0x7fffffffffffffffLL-1) 35 | #endif 36 | 37 | long long 38 | strtonum(const char *numstr, long long minval, long long maxval, 39 | const char **errstrp) 40 | { 41 | long long ll = 0; 42 | char *ep; 43 | int error = 0; 44 | struct errval { 45 | const char *errstr; 46 | int err; 47 | } ev[4] = { 48 | { NULL, 0 }, 49 | { "invalid", EINVAL }, 50 | { "too small", ERANGE }, 51 | { "too large", ERANGE }, 52 | }; 53 | 54 | ev[0].err = errno; 55 | errno = 0; 56 | if (minval > maxval) 57 | error = INVALID; 58 | else { 59 | ll = strtoll(numstr, &ep, 10); 60 | if (numstr == ep || *ep != '\0') 61 | error = INVALID; 62 | else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) 63 | error = TOOSMALL; 64 | else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) 65 | error = TOOLARGE; 66 | } 67 | if (errstrp != NULL) 68 | *errstrp = ev[error].errstr; 69 | errno = ev[error].err; 70 | if (error) 71 | ll = 0; 72 | 73 | return (ll); 74 | } 75 | -------------------------------------------------------------------------------- /mrouted.conf: -------------------------------------------------------------------------------- 1 | # mrouted.conf,v 3.8 1995/11/29 22:40:47 fenner Rel 2 | # 3 | # This is the configuration file for "mrouted", an IP multicast router. 4 | # mrouted looks for it in "/etc/mrouted.conf". 5 | # 6 | # NOTE: any phyint commands MUST precede any tunnel commands 7 | # NOTE: the mask-len is the no. of leading 1's in the mask 8 | # NOTE: rate_limit is in kilobits, and defaults to 500 for tunnels 9 | # 10 | 11 | # name / 12 | #name LOCAL 239.255.0.0/16 13 | #name EE 239.254.0.0/16 # i.e. the EE dept wants local groups 14 | 15 | # Life time in seconds for a graft, [60, ..], default 300. 16 | #cache-lifetime 300 17 | 18 | # Query interval can be [1,1024], default 125. Recommended not go below 10 19 | #igmp-query-interval 125 20 | 21 | # Last member query interval [1,1024], default 1. The igmp-robustness 22 | # setting controls the last member query count. 23 | #igmp-query-last-member-interval 1 24 | 25 | # Robustness can be [2,10], default 2. Recommended to use 2 26 | #igmp-robustness 2 27 | 28 | # IP Option Router Alert is enabled by default 29 | #no router-alert 30 | 31 | # By default mrouted runs on all multicast capable interfaces. Use this 32 | # command to disable all phyints by defaullt, and then the below form to 33 | # selectively enable each interface to run on. 34 | #no phyint 35 | 36 | # phyint [enable | disable] [igmpv1 | igmpv2 | igmpv3] 37 | # [metric ] [threshold ] [rate-limit ] 38 | # [boundary (|/)] 39 | # [altnet (/|)] 40 | # [static-group ] [join-group ] 41 | # 42 | # Example of use of named boundary 43 | #phyint le1 boundary EE # le1 is our interface to comp sci, 44 | # # keep them away from our local groups 45 | 46 | # tunnel [srcrt] 47 | # [metric ] [threshold ] [rate-limit ] 48 | # [boundary (|/)] 49 | #tunnel 128.4.0.77 128.4.0.8 metric 1 threshold 64 rate-limit 500 # <-- REPLACE 50 | # boundary LOCAL 51 | # 52 | # You might want to specify a boundary on your tunnel to the outside world, 53 | # as above. 54 | 55 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: mrouted 2 | Section: net 3 | Priority: optional 4 | Maintainer: Joachim Wiberg 5 | Build-Depends: debhelper (>= 10), bison | byacc | btyacc, pkg-config, systemd 6 | Standards-Version: 4.3.0 7 | Homepage: https://troglobit.com/mrouted.shtml 8 | Vcs-Browser: https://github.com/troglobit/mrouted 9 | Vcs-Git: https://github.com/troglobit/mrouted.git 10 | 11 | Package: mrouted 12 | Architecture: any 13 | Depends: ${shlibs:Depends}, ${misc:Depends} 14 | Description: Simple multicast routing for UNIX 15 | mrouted is the original implementation of the DVMRP multicast routing 16 | protocol, RFC 1075. 17 | . 18 | mrouted is *simple* to use. DVMRP is derived from RIP, which means it 19 | works stand-alone without any extra network setup required. You can get 20 | up and running in a matter of minutes. Use the built-in IP-in-IP 21 | tunneling support, or GRE, to traverse Internet or intranets. 22 | 23 | Package: mrinfo 24 | Architecture: any 25 | Depends: ${shlibs:Depends}, ${misc:Depends} 26 | Description: Display configuration info from a multicast router 27 | mrinfo displays configuration information about DVMRP routers. It does 28 | this by sending ASK_NEIGHBORS IGMP messages to the specified router. 29 | . 30 | If the router responds, its version number and a list of all neighboring 31 | multicast routers is included in the response. mrinfo then proceeds to 32 | request additional information, such as metrics, thresholds and flags. 33 | 34 | Package: mtrace 35 | Architecture: any 36 | Depends: ${shlibs:Depends}, ${misc:Depends} 37 | Description: Print multicast path from a source to a receiver 38 | Assessing problems in the distribution of IP multicast traffic 39 | can be difficult. mtrace utilizes a tracing feature implemented 40 | in DVMRP multicast routers, mrouted version 3.3 and later, that is 41 | accessed via an extension to the IGMP protocol. A trace query is 42 | passed hop-by-hop along the reverse path from the receiver to the 43 | source, ollecting hop addresses, packet counts, and routing error 44 | conditions along the path, and then the response is returned to 45 | the requestor. 46 | 47 | Package: map-mbone 48 | Architecture: any 49 | Depends: ${shlibs:Depends}, ${misc:Depends} 50 | Description: Multicast connection mapper 51 | map-mbone attempts to display all multicast routers reachable from 52 | the current multicast router. Like mrinfo it sends ASK_NEIGHBORS 53 | IGMP messages to discover available DVMRP, mrouted, routers. 54 | 55 | -------------------------------------------------------------------------------- /src/route.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | #ifndef MROUTED_ROUTE_H_ 10 | #define MROUTED_ROUTE_H_ 11 | 12 | #include "defs.h" 13 | #include "queue.h" 14 | 15 | /* 16 | * Routing Table Entry, one per subnet from which a multicast could originate. 17 | * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.) 18 | * 19 | * The Routing Table is stored as a doubly-linked list of these structures, 20 | * ordered by decreasing value of rt_originmask and, secondarily, by 21 | * decreasing value of rt_origin within each rt_originmask value. 22 | * This data structure is efficient for generating route reports, whether 23 | * full or partial, for processing received full reports, for clearing the 24 | * CHANGED flags, and for periodically advancing the timers in all routes. 25 | * It is not so efficient for updating a small number of routes in response 26 | * to a partial report. In a stable topology, the latter are rare; if they 27 | * turn out to be costing a lot, we can add an auxiliary hash table for 28 | * faster access to arbitrary route entries. 29 | */ 30 | struct rtentry { 31 | TAILQ_ENTRY(rtentry) rt_link; /* link to next/prev vif */ 32 | uint32_t rt_origin; /* subnet origin of multicasts */ 33 | uint32_t rt_originmask; /* subnet mask for origin */ 34 | uint16_t rt_originwidth; /* # bytes of origin subnet number */ 35 | uint8_t rt_metric; /* cost of route back to origin */ 36 | uint8_t rt_flags; /* RTF_ flags defined below */ 37 | uint32_t rt_gateway; /* first-hop gateway back to origin */ 38 | vifi_t rt_parent; /* incoming vif (ie towards origin) */ 39 | vifbitmap_t rt_children; /* outgoing children vifs */ 40 | uint32_t *rt_dominants; /* per vif dominant gateways */ 41 | nbrbitmap_t rt_subordinates; /* bitmap of subordinate gateways */ 42 | nbrbitmap_t rt_subordadv; /* recently advertised subordinates */ 43 | uint32_t rt_timer; /* for timing out the route entry */ 44 | struct gtable *rt_groups; /* link to active groups */ 45 | }; 46 | 47 | #define RTF_CHANGED 0x01 /* route changed but not reported */ 48 | #define RTF_HOLDDOWN 0x04 /* this route is in holddown */ 49 | 50 | #define ALL_ROUTES 0 /* possible arguments to report() */ 51 | #define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */ 52 | 53 | #define RT_FMT(r, s) inet_fmts((r)->rt_origin, (r)->rt_originmask, s, sizeof(s)) 54 | 55 | #endif /* MROUTED_ROUTE_H_ */ 56 | -------------------------------------------------------------------------------- /.github/workflows/coverity.yml: -------------------------------------------------------------------------------- 1 | name: Coverity Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'dev' 7 | 8 | env: 9 | PROJECT_NAME: mrouted 10 | CONTACT_EMAIL: troglobit@gmail.com 11 | COVERITY_NAME: troglobit-mrouted 12 | COVERITY_PROJ: troglobit%2Fmrouted 13 | 14 | jobs: 15 | coverity: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Fetch latest Coverity Scan MD5 20 | id: var 21 | env: 22 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 23 | run: | 24 | wget -q https://scan.coverity.com/download/cxx/linux64 \ 25 | --post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \ 26 | -O coverity-latest.tar.gz.md5 27 | echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT 28 | - uses: actions/cache@v4 29 | id: cache 30 | with: 31 | path: coverity-latest.tar.gz 32 | key: ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }} 33 | restore-keys: | 34 | ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }} 35 | ${{ runner.os }}-coverity- 36 | ${{ runner.os }}-coverity 37 | - name: Download Coverity Scan 38 | env: 39 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 40 | run: | 41 | if [ ! -f coverity-latest.tar.gz ]; then 42 | wget -q https://scan.coverity.com/download/cxx/linux64 \ 43 | --post-data "token=$TOKEN&project=${COVERITY_PROJ}" \ 44 | -O coverity-latest.tar.gz 45 | else 46 | echo "Latest Coverity Scan available from cache :-)" 47 | md5sum coverity-latest.tar.gz 48 | fi 49 | mkdir coverity 50 | tar xzf coverity-latest.tar.gz --strip 1 -C coverity 51 | - name: Install dependencies 52 | run: | 53 | sudo apt-get -y update 54 | sudo apt-get -y install pkg-config libsystemd-dev 55 | - name: Configure 56 | run: | 57 | ./autogen.sh 58 | ./configure --prefix= 59 | - name: Build 60 | run: | 61 | export PATH=`pwd`/coverity/bin:$PATH 62 | cov-build --dir cov-int make 63 | - name: Submit results to Coverity Scan 64 | env: 65 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 66 | run: | 67 | tar czvf ${PROJECT_NAME}.tgz cov-int 68 | curl \ 69 | --form project=${COVERITY_NAME} \ 70 | --form token=$TOKEN \ 71 | --form email=${CONTACT_EMAIL} \ 72 | --form file=@${PROJECT_NAME}.tgz \ 73 | --form version=trunk \ 74 | --form description="${PROJECT_NAME} $(git rev-parse HEAD)" \ 75 | https://scan.coverity.com/builds?project=${COVERITY_PROJ} 76 | - name: Upload build.log 77 | uses: actions/upload-artifact@v4 78 | with: 79 | name: coverity-build.log 80 | path: cov-int/build-log.txt 81 | -------------------------------------------------------------------------------- /debian/init.d: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: mrouted 4 | # Required-Start: $remote_fs $syslog $network 5 | # Required-Stop: $remote_fs $syslog $network 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Multicast routing daemon, mrouted 9 | # Description: The original dynamic multicast routing daemon, mrouted 10 | ### END INIT INFO 11 | . /lib/lsb/init-functions 12 | 13 | PATH=/bin:/usr/bin:/sbin:/usr/sbin 14 | DESC="Multicast routing daemon" 15 | NAME=mrouted 16 | 17 | DAEMON=/usr/sbin/mrouted 18 | PIDFILE=/var/run/mrouted.pid 19 | SCRIPTNAME=/etc/init.d/$NAME 20 | 21 | # Exit if the package is not installed 22 | [ -x "$DAEMON" ] || exit 0 23 | 24 | # Read configuration variable file if it is present 25 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 26 | 27 | # Define LSB log_* functions. 28 | . /lib/lsb/init-functions 29 | 30 | do_start() 31 | { 32 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $MROUTED_OPTIONS 33 | } 34 | 35 | do_signal() 36 | { 37 | start-stop-daemon --stop --quiet --signal $1 $2 --pidfile $PIDFILE --exec $DAEMON 38 | } 39 | 40 | do_stop() 41 | { 42 | do_signal TERM --oknodo 43 | } 44 | 45 | do_reload() 46 | { 47 | do_signal HUP 48 | } 49 | 50 | # mrouted has native support for ip-ip tunnels 51 | load_module() 52 | { 53 | lsmod |grep ipip >/dev/null 54 | if [ $? -ne 0 ]; then 55 | modprobe ipip 2> /dev/null || true 56 | fi 57 | } 58 | 59 | case "$1" in 60 | start) 61 | log_daemon_msg "Starting $DESC" "$NAME" 62 | load_module 63 | do_start 64 | case "$?" in 65 | 0) log_end_msg 0 ;; 66 | 1) log_progress_msg "already started" 67 | log_end_msg 0 ;; 68 | *) log_end_msg 1 ;; 69 | esac 70 | ;; 71 | 72 | stop) 73 | log_daemon_msg "Stopping $DESC" "$NAME" 74 | do_stop 75 | case "$?" in 76 | 0) log_end_msg 0 ;; 77 | 1) log_progress_msg "already stopped" 78 | log_end_msg 0 ;; 79 | *) log_end_msg 1 ;; 80 | esac 81 | ;; 82 | 83 | reload) 84 | log_daemon_msg "Reloading $DESC" "$NAME" 85 | do_reload 86 | case "$?" in 87 | 0) log_end_msg 0 ;; 88 | 1) log_progress_msg "not running" 89 | log_end_msg 1 ;; 90 | *) log_end_msg 1 ;; 91 | esac 92 | ;; 93 | 94 | restart|force-reload) 95 | $0 stop 96 | $0 start 97 | ;; 98 | 99 | try-restart) 100 | $0 status >/dev/null 2>&1 && $0 restart 101 | ;; 102 | 103 | status) 104 | status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $? 105 | ;; 106 | 107 | *) 108 | echo "Usage: $SCRIPTNAME {start|stop|reload|restart|force-reload|try-restart|status}" >&2 109 | exit 3 110 | ;; 111 | esac 112 | 113 | : 114 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Bob the Builder 2 | 3 | # Run on all branches, including all pull requests, except the 'dev' 4 | # branch since that's where we run Coverity Scan (limited tokens/day) 5 | on: 6 | push: 7 | branches: 8 | - '**' 9 | - '!dev' 10 | pull_request: 11 | branches: 12 | - '**' 13 | 14 | jobs: 15 | build: 16 | # Verify we can build on latest Ubuntu with both gcc and clang 17 | name: ${{ matrix.compiler }} 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | compiler: [gcc, clang] 22 | fail-fast: false 23 | env: 24 | MAKEFLAGS: -j3 25 | CC: ${{ matrix.compiler }} 26 | steps: 27 | - name: Install dependencies 28 | run: | 29 | sudo modprobe ipip 30 | sudo apt-get -y update 31 | sudo apt-get -y install pkg-config libsystemd-dev bird2 ethtool keepalived tshark tree 32 | - uses: actions/checkout@v4 33 | - name: Configure 34 | # Build in a sub-directory so we can safely set a+w on all 35 | # directories. Needed for `make check` since it runs with 36 | # root dropped and wants to write .trs and .log files. 37 | run: | 38 | ./autogen.sh 39 | ./configure --prefix= --enable-test 40 | - name: Build 41 | run: | 42 | make V=1 43 | - name: Install 44 | run: | 45 | DESTDIR=~/tmp make install-strip 46 | tree ~/tmp 47 | ldd ~/tmp/sbin/mrouted 48 | size ~/tmp/sbin/mrouted 49 | ldd ~/tmp/sbin/mroutectl 50 | size ~/tmp/sbin/mroutectl 51 | sudo ~/tmp/sbin/mrouted -p ~/tmp/foo.pid -u ~/tmp/foo.sock 52 | sleep 1 53 | ~/tmp/sbin/mrouted -h 54 | sudo ~/tmp/sbin/mroutectl -u ~/tmp/foo.sock -h 55 | sudo ~/tmp/sbin/mroutectl -u ~/tmp/foo.sock 56 | sudo ~/tmp/sbin/mroutectl -u ~/tmp/foo.sock kill 57 | - name: Enable unprivileged userns (unshare) 58 | run: | 59 | sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0 60 | - name: Run unit tests 61 | run: | 62 | make check || (cat test/test-suite.log; false) 63 | - name: Upload Test Results 64 | uses: actions/upload-artifact@v4 65 | with: 66 | name: mrouted-test-${{ matrix.compiler }} 67 | path: test/* 68 | debian: 69 | # Verify that Debian packages can be built 70 | name: Debian Package 71 | runs-on: ubuntu-latest 72 | container: debian:stable 73 | steps: 74 | - uses: actions/checkout@v4 75 | - name: Installing dependencies 76 | run: | 77 | apt-get update 78 | apt-get install -y build-essential bison flex autoconf automake pkg-config \ 79 | libsystemd-dev systemd dpkg-dev debhelper devscripts 80 | - name: Building Debian package 81 | run: | 82 | ./autogen.sh 83 | ./configure 84 | make distcheck 85 | make package 86 | cat ../mrouted*.changes 87 | -------------------------------------------------------------------------------- /src/igmpv3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998-2001 3 | * University of Southern California/Information Sciences Institute. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the project nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef MROUTED_IGMPV3_H_ 32 | #define MROUTED_IGMPV3_H_ 33 | 34 | /* 35 | * IGMPv3 report modes. 36 | */ 37 | #ifndef IGMP_MODE_IS_INCLUDE 38 | #define IGMP_DO_NOTHING 0 /* don't send a record */ 39 | #define IGMP_MODE_IS_INCLUDE 1 /* MODE_IN */ 40 | #define IGMP_MODE_IS_EXCLUDE 2 /* MODE_EX */ 41 | #define IGMP_CHANGE_TO_INCLUDE_MODE 3 /* TO_IN */ 42 | #define IGMP_CHANGE_TO_EXCLUDE_MODE 4 /* TO_EX */ 43 | #define IGMP_ALLOW_NEW_SOURCES 5 /* ALLOW_NEW */ 44 | #define IGMP_BLOCK_OLD_SOURCES 6 /* BLOCK_OLD */ 45 | #endif 46 | 47 | struct igmpv3_query { 48 | uint8_t type; 49 | uint8_t code; 50 | uint16_t csum; 51 | uint32_t group; 52 | #if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN) 53 | uint8_t qrv:3, 54 | suppress:1, 55 | resv:4; 56 | #else 57 | uint8_t resv:4, 58 | suppress:1, 59 | qrv:3; 60 | #endif 61 | uint8_t qqic; 62 | uint16_t nsrcs; 63 | uint32_t srcs[0]; 64 | }; 65 | 66 | struct igmpv3_grec { 67 | uint8_t grec_type; 68 | uint8_t grec_auxwords; 69 | uint16_t grec_nsrcs; 70 | uint32_t grec_mca; 71 | uint32_t grec_src[0]; 72 | }; 73 | 74 | #define IGMP_GRPREC_HDRLEN 8 75 | #define IGMP_V3_GROUP_RECORD_MIN_SIZE 8 76 | 77 | struct igmpv3_report { 78 | uint8_t type; 79 | uint8_t resv1; 80 | uint16_t csum; 81 | uint16_t resv2; 82 | uint16_t ngrec; 83 | struct igmpv3_grec grec[0]; 84 | }; 85 | 86 | #ifndef IGMP_V3_REPORT_MINLEN 87 | #define IGMP_V3_REPORT_MINLEN 8 88 | #define IGMP_V3_REPORT_MAXRECS 65535 89 | #endif 90 | 91 | #endif /* MROUTED_IGMPV3_H_ */ 92 | 93 | /** 94 | * Local Variables: 95 | * indent-tabs-mode: t 96 | * c-file-style: "cc-mode" 97 | * End: 98 | */ 99 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | #include "defs.h" 10 | 11 | struct debugnm debugnames[] = { 12 | { "packet", DEBUG_PKT, 2 }, 13 | { "pkt", DEBUG_PKT, 3 }, 14 | { "pruning", DEBUG_PRUNE, 1 }, 15 | { "prunes", DEBUG_PRUNE, 1 }, 16 | { "routing", DEBUG_ROUTE, 1 }, 17 | { "routes", DEBUG_ROUTE, 1 }, 18 | { "route-detail", DEBUG_RTDETAIL, 6 }, 19 | { "rtdetail", DEBUG_RTDETAIL, 2 }, 20 | { "neighbors", DEBUG_PEER, 1 }, 21 | { "peers", DEBUG_PEER, 2 }, 22 | { "kernel", DEBUG_KERN, 2 }, 23 | { "cache", DEBUG_CACHE, 1 }, 24 | { "timer", DEBUG_TIMEOUT, 2 }, 25 | { "interface", DEBUG_IF, 2 }, 26 | { "vif", DEBUG_IF, 1 }, 27 | { "membership", DEBUG_MEMBER, 1 }, 28 | { "groups", DEBUG_MEMBER, 1 }, 29 | { "traceroute", DEBUG_TRACE, 2 }, 30 | { "mtrace", DEBUG_TRACE, 2 }, 31 | { "igmp", DEBUG_IGMP, 1 }, 32 | { "icmp", DEBUG_ICMP, 2 }, 33 | { "all", DEBUG_ALL, 1 }, 34 | { "3", DEBUG_ALL, 1 } /* compat. */ 35 | }; 36 | 37 | int debug_list(int mask, char *buf, size_t len) 38 | { 39 | struct debugnm *d; 40 | uint32_t last = 0; 41 | size_t i; 42 | 43 | memset(buf, 0, len); 44 | for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) { 45 | if (!(mask & d->level)) 46 | continue; 47 | 48 | if (last == d->level) 49 | continue; 50 | last = d->level; 51 | 52 | if (mask != (int)DEBUG_ALL) 53 | mask &= ~d->level; 54 | 55 | strlcat(buf, d->name, len); 56 | 57 | if (mask && i + 1 < ARRAY_LEN(debugnames)) 58 | strlcat(buf, ", ", len); 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | void debug_print(void) 65 | { 66 | char buf[768]; 67 | 68 | if (!debug_list(DEBUG_ALL, buf, sizeof(buf))) { 69 | char line[82] = " "; 70 | char *ptr; 71 | 72 | ptr = strtok(buf, " "); 73 | while (ptr) { 74 | char *sys = ptr; 75 | char buf[20]; 76 | 77 | ptr = strtok(NULL, " "); 78 | 79 | /* Flush line */ 80 | if (strlen(line) + strlen(sys) + 3 >= sizeof(line)) { 81 | puts(line); 82 | strlcpy(line, " ", sizeof(line)); 83 | } 84 | 85 | if (ptr) 86 | snprintf(buf, sizeof(buf), "%s ", sys); 87 | else 88 | snprintf(buf, sizeof(buf), "%s", sys); 89 | 90 | strlcat(line, buf, sizeof(line)); 91 | } 92 | 93 | puts(line); 94 | } 95 | } 96 | 97 | int debug_parse(char *arg) 98 | { 99 | struct debugnm *d; 100 | size_t i, len; 101 | char *next = NULL; 102 | int sys = 0; 103 | 104 | if (!arg || !strlen(arg) || strstr(arg, "none")) 105 | return sys; 106 | 107 | while (arg) { 108 | next = strchr(arg, ','); 109 | if (next) 110 | *next++ = '\0'; 111 | 112 | len = strlen(arg); 113 | for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) { 114 | if (len >= d->nchars && strncmp(d->name, arg, len) == 0) 115 | break; 116 | } 117 | 118 | if (i == ARRAY_LEN(debugnames)) { 119 | fprintf(stderr, "Unknown debug level: %s\n", arg); 120 | return DEBUG_PARSE_ERR; 121 | } 122 | 123 | sys |= d->level; 124 | arg = next; 125 | } 126 | 127 | return sys; 128 | } 129 | 130 | /** 131 | * Local Variables: 132 | * indent-tabs-mode: t 133 | * c-file-style: "cc-mode" 134 | * End: 135 | */ 136 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: mrouted 3 | Upstream-Contact: troglobit@gmail.com 4 | Source: https://github.com/troglobit/mrouted 5 | 6 | Files: * 7 | Copyright: 2002 The Board of Trustees of the Leland Stanford Junior University 8 | Comment: This project was made fully open source by Standford in March 2003 9 | thanks to the effort by the OpenBSD project. For the full story, see 10 | the commit log for the LICENSE file in the OpenBSD CVS repository: 11 | http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/mrouted/LICENSE 12 | License: MROUTED 13 | 14 | Files: src/pev.[ch] 15 | Copyright: Free software under the UNLICENSE 16 | License: public-domain 17 | 18 | Files: src/ipc.c src/mroutectl.c 19 | Copyright: 2018-2020 Joachim Wiberg 20 | License: BSD-3-clause 21 | 22 | Files: lib/strlcpy.c 23 | Copyright: 1998, 2015 Todd C. Miller 24 | License: ISC 25 | 26 | Files: lib/strlcat.c 27 | Copyright: 1998, 2015 Todd C. Miller 28 | License: ISC 29 | 30 | Files: lib/strtonum.c 31 | Copyright: 2004 Ted Unangst and Todd Miller 32 | License: ISC 33 | 34 | Files: lib/pidfile.c 35 | Copyright: 1999 The NetBSD Foundation, Inc. 36 | License: BSD-2-clause 37 | 38 | Files: lib/utimensat.c 39 | Copyright: 2017-2020 Joachim Wiberg 40 | License: ISC 41 | 42 | Files: debian/* 43 | Comment: mrouted was repackaged by Joachim Wiberg 44 | on Mon, 17 Aug 2010 08:32:02 +0100 based on an earlier (failed) 45 | attempt by Christoph Martin on 46 | Mon, 1 Mar 1999 21:36:23 +0100, which was dropped by Debian: 47 | http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=288112 48 | Copyright: 2010-2020 Joachim Wiberg 49 | License: ISC 50 | 51 | License: MROUTED 52 | Permission is hereby granted to STANFORD's rights, free of charge, to any 53 | person obtaining a copy of this Software and associated documentation files 54 | ( "MROUTED"), to deal in MROUTED without restriction, including without 55 | limitation the rights to use, copy, modify, merge, publish, distribute, 56 | sublicense, and/or sell copies of MROUTED , and to permit persons to whom 57 | MROUTED is furnished to do so, subject to the following conditions: 58 | 1) The above copyright notice and this permission notice shall be 59 | included in all copies or substantial portions of the MROUTED . 60 | 2) Neither the STANFORD name nor the names of its contributors may be 61 | used in any promotional advertising or other promotional materials to be 62 | disseminated to the public or any portion thereof nor to use the name of 63 | any STANFORD faculty member, employee, or student, or any trademark, 64 | service mark, trade name, or symbol of STANFORD or Stanford Hospitals and 65 | Clinics, nor any that is associated with any of them, without STANFORD's 66 | prior written consent. Any use of STANFORD's name shall be limited to 67 | statements of fact and shall not imply endorsement of any products or 68 | services. 69 | 3) MROUTED IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 70 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 71 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 72 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 73 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 74 | FROM, OUT OF OR IN CONNECTION WITH MROUTED OR THE USE OR OTHER DEALINGS IN 75 | THE MROUTED. 76 | Comment: The license is 3-clause BSD style license, but is not word-for-word 77 | compatible. Non-printable, or 8-bit, characters have been replaced. 78 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | 10 | #define SYSLOG_NAMES 11 | #include "defs.h" 12 | #include 13 | 14 | #define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */ 15 | #define LOG_SHUT_UP 600 /* shut up for 10 minutes */ 16 | 17 | #ifndef INTERNAL_NOPRI 18 | #define INTERNAL_NOPRI 0x10 19 | #endif 20 | 21 | CODE prionm[] = 22 | { 23 | { "none", INTERNAL_NOPRI }, /* INTERNAL */ 24 | { "crit", LOG_CRIT }, 25 | { "alert", LOG_ALERT }, 26 | { "panic", LOG_EMERG }, 27 | { "error", LOG_ERR }, 28 | { "warning", LOG_WARNING }, 29 | { "notice", LOG_NOTICE }, 30 | { "info", LOG_INFO }, 31 | { "debug", LOG_DEBUG }, 32 | { NULL, -1 } 33 | }; 34 | 35 | int loglevel = LOG_NOTICE; 36 | 37 | static char *log_name = PACKAGE_NAME; 38 | 39 | 40 | int log_str2lvl(char *level) 41 | { 42 | int i; 43 | 44 | for (i = 0; prionm[i].c_name; i++) { 45 | size_t len = MIN(strlen(prionm[i].c_name), strlen(level)); 46 | 47 | if (!strncasecmp(prionm[i].c_name, level, len)) 48 | return prionm[i].c_val; 49 | } 50 | 51 | return atoi(level); 52 | } 53 | 54 | const char *log_lvl2str(int val) 55 | { 56 | int i; 57 | 58 | for (i = 0; prionm[i].c_name; i++) { 59 | if (prionm[i].c_val == val) 60 | return prionm[i].c_name; 61 | } 62 | 63 | return "unknown"; 64 | } 65 | 66 | int log_list(char *buf, size_t len) 67 | { 68 | int i; 69 | 70 | memset(buf, 0, len); 71 | for (i = 0; prionm[i].c_name; i++) { 72 | if (i > 0) 73 | strlcat(buf, ", ", len); 74 | strlcat(buf, prionm[i].c_name, len); 75 | } 76 | 77 | return 0; 78 | } 79 | 80 | 81 | 82 | /* 83 | * Open connection to syslog daemon and set initial log level 84 | */ 85 | void log_init(char *ident) 86 | { 87 | log_name = ident; 88 | if (!use_syslog) 89 | return; 90 | 91 | openlog(ident, LOG_PID, LOG_DAEMON); 92 | setlogmask(LOG_UPTO(loglevel)); 93 | } 94 | 95 | 96 | /* 97 | * Log errors and other messages to the system log daemon and to stderr, 98 | * according to the severity of the message and the current debug level. 99 | * For errors of severity LOG_ERR or worse, terminate the program. 100 | */ 101 | void logit(int severity, int syserr, const char *format, ...) 102 | { 103 | static char fmt[211] = "warning - "; 104 | const struct tm *thyme; 105 | struct timeval now; 106 | time_t now_sec; 107 | va_list ap; 108 | char *msg; 109 | 110 | va_start(ap, format); 111 | vsnprintf(&fmt[10], sizeof(fmt) - 10, format, ap); 112 | va_end(ap); 113 | msg = (severity == LOG_WARNING) ? fmt : &fmt[10]; 114 | 115 | if (!use_syslog) { 116 | if (severity > loglevel) 117 | return; 118 | 119 | /* Only OK use-case for unsafe gettimeofday(), logging. */ 120 | gettimeofday(&now, NULL); 121 | now_sec = now.tv_sec; 122 | thyme = localtime(&now_sec); 123 | // if (!debug) 124 | fprintf(stderr, "%s: ", log_name); 125 | fprintf(stderr, "%02d:%02d:%02d.%03d %s", thyme->tm_hour, 126 | thyme->tm_min, thyme->tm_sec, (int)(now.tv_usec / 1000), msg); 127 | if (syserr == 0) 128 | fprintf(stderr, "\n"); 129 | else 130 | fprintf(stderr, ": %s\n", strerror(syserr)); 131 | 132 | goto end; 133 | } 134 | 135 | if (syserr != 0) { 136 | errno = syserr; 137 | syslog(severity, "%s: %s", msg, strerror(errno)); 138 | } else 139 | syslog(severity, "%s", msg); 140 | 141 | end: 142 | if (severity <= LOG_ERR) 143 | exit(1); 144 | } 145 | 146 | /** 147 | * Local Variables: 148 | * indent-tabs-mode: t 149 | * c-file-style: "cc-mode" 150 | * End: 151 | */ 152 | -------------------------------------------------------------------------------- /doc/DVMRP.md: -------------------------------------------------------------------------------- 1 | DVMRP Overview 2 | ============== 3 | 4 | Reverse Path Forwarding 5 | ----------------------- 6 | 7 | ![](RPF.jpg "RPF illustrated") 8 | 9 | DVMRP uses Reverse Path Forwarding[^1] (RPF) to determine the best 10 | (shortest) path back to the source. The router examines all packets 11 | received as input to make sure that both source address and interface 12 | are in the routing table. It looks up the source address in the 13 | forwarding table[^2] and compares that entry with the receiving entry 14 | (RFP check). If the interface and entry do not match or are not in the 15 | table, then the packets are discarded. If there is a match, then the 16 | router forwards the packets. 17 | 18 | 19 | Flood & Prune 20 | ------------- 21 | 22 | ![](FLOODING.jpg "Flooding illustrated") 23 | 24 | Periodically, the source performs what is known as flooding in order to 25 | push datagrams downstream. Initially, DVMRP routers assume that every 26 | node on the connected subnets wants to receive data. Along with the 27 | datagrams, a packet called the *route report* is transmitted (across a 28 | time interval). All the routes known by a given router is sent to all 29 | adjacent routers. By using IGMP[^3], the routers are aware of which 30 | hosts are connected to the subnets. On receiving the *route reports*, a 31 | router selects the best adjacent router through which it can reach the 32 | given source network. 33 | 34 | ![](PRUNING.jpg "Pruning illustrated") 35 | 36 | After registering that router as the *upstream neighbor*, a *dependency* 37 | is expressed to the router for receiving packets. Upon receiving this 38 | *dependency*, the receiving router registers the expressed *dependency* 39 | as its *dependent downstream neighbor*. 40 | 41 | Hence, an optimal multicast spanning tree is constructed. On receiving 42 | a multicast packet, a router accepts that packet for forwarding if and 43 | only if the packet is received from the UPSTREAM NEIGHBOR. Otherwise, 44 | it will be dropped. 45 | 46 | Then, the list of the *dependent downstream neighbor* is verified and 47 | the Lower Layer protocols forwards the packets to the specific 48 | neighbors. If there are no *dependent downstream neighbors*, *prune 49 | messages* are sent to the *upstream neighbor*, requesting that the 50 | router should stop sending packets from the specified source network for 51 | a specified amount of time. 52 | 53 | ![](GRAFTING.jpg "Grafting illustrated") 54 | 55 | Thus, datagrams will no longer be transmitted along that path (cutting 56 | down on the bandwidth being used). After a prune interval, packets will 57 | be flooded downstream again, along the shortest path trees. 58 | 59 | If any other routers expresses some dependencies, *graft messages* are 60 | sent to that *upstream neighbor*. Upon receiving an acknowledgment, 61 | *graftack messages* are expected back. On receiving a *graft message* 62 | from a *downstream neighbor*, multicast packets will be sent on that 63 | interface. 64 | 65 | The above procedures of Pruning and Grafting could initiate a similar 66 | action in the receiving routers. This means that unnecesary data 67 | traffic will be reduced in the network, which is the advantage of DVMRP. 68 | 69 | 70 | [^1]: *Reverse Path Forwarding:* the algorithm used to determine the 71 | best route back to a source. The router examines all packets 72 | received as inputs to make sure that both source interface and 73 | address are in the table. It looks those up in the routing table 74 | and compares them. If there is a match then accept the packets, else 75 | discard. 76 | 77 | [^2]: *Forwarding table:* the table maintained in a router that lets it 78 | make decisions on how to forward packets. The process of building 79 | up the forwarding table is called routing. Thus the forwarding 80 | table is sometimes called a routing table. 81 | 82 | [^3]: *Internet Group Membership Protocol*, allows hosts on a LAN to 83 | signal routers that they would like to subscribe to a multicast 84 | group to receive a data stream. Routers in turn use IGMP to 85 | determine which interfaces to flood multicast packets to and which 86 | multicast groups are on which interfaces. 87 | -------------------------------------------------------------------------------- /test/single.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Verifies operation in a single router setup: 3 | # - forwardng multicast between two emulated end devices 4 | # - IGMP v3 Query on both LANs 5 | 6 | # shellcheck source=/dev/null 7 | . "$(dirname "$0")/lib.sh" 8 | 9 | # Requires ethtool to disable UDP checksum offloading 10 | print "Check deps ..." 11 | check_dep ethtool 12 | check_dep tshark 13 | 14 | print "Creating world ..." 15 | left="/tmp/$NM/a1" 16 | right="/tmp/$NM/a2" 17 | touch "$left" "$right" 18 | PID=$$ 19 | 20 | echo "$left" > "/tmp/$NM/mounts" 21 | echo "$right" >> "/tmp/$NM/mounts" 22 | 23 | lif=$(basename "$left") 24 | rif=$(basename "$right") 25 | 26 | # Disabling UDP checksum offloading, frames are leaving kernel space 27 | # on these VETH pairs. (Silence noisy ethtool output) 28 | unshare --net="$left" -- ip link set lo up 29 | nsenter --net="$left" -- ip link add eth0 type veth peer "$lif" 30 | nsenter --net="$left" -- ethtool --offload eth0 tx off >/dev/null 31 | nsenter --net="$left" -- ethtool --offload eth0 rx off >/dev/null 32 | nsenter --net="$left" -- ip link set "$lif" netns $PID 33 | ethtool --offload "$lif" tx off >/dev/null 34 | ethtool --offload "$lif" rx off >/dev/null 35 | nsenter --net="$left" -- ip link set eth0 up 36 | ip link set "$lif" up 37 | 38 | unshare --net="$right" -- ip link set lo up 39 | nsenter --net="$right" -- ip link add eth0 type veth peer "$rif" 40 | nsenter --net="$right" -- ethtool --offload eth0 tx off >/dev/null 41 | nsenter --net="$right" -- ethtool --offload eth0 rx off >/dev/null 42 | nsenter --net="$right" -- ip link set "$rif" netns $PID 43 | ethtool --offload "$rif" tx off >/dev/null 44 | ethtool --offload "$rif" rx off >/dev/null 45 | nsenter --net="$right" -- ip link set eth0 up 46 | ip link set "$rif" up 47 | 48 | ip addr add 10.0.0.1/24 dev a1 49 | nsenter --net="$left" -- ip addr add 10.0.0.10/24 dev eth0 50 | nsenter --net="$left" -- ip route add default via 10.0.0.1 51 | 52 | ip addr add 20.0.0.1/24 dev a2 53 | nsenter --net="$right" -- ip addr add 20.0.0.10/24 dev eth0 54 | nsenter --net="$right" -- ip route add default via 20.0.0.1 55 | 56 | ip -br l 57 | ip -br a 58 | 59 | print "Creating config ..." 60 | cat < "/tmp/$NM/conf" 61 | no phyint 62 | phyint $lif enable 63 | phyint $rif enable 64 | EOF 65 | cat "/tmp/$NM/conf" 66 | 67 | print "Starting collectors ..." 68 | nsenter --net="$left" -- tshark -lni eth0 -w "/tmp/$NM/left.pcap" 2>/dev/null & 69 | echo $! >> "/tmp/$NM/PIDs" 70 | nsenter --net="$right" -- tshark -lni eth0 -w "/tmp/$NM/right.pcap" 2>/dev/null & 71 | echo $! >> "/tmp/$NM/PIDs" 72 | sleep 1 73 | 74 | print "Starting mrouted ..." 75 | ../src/mrouted -i solo -f "/tmp/$NM/conf" -n -p "/tmp/$NM/pid" -l debug -u "/tmp/$NM/sock" & 76 | 77 | print "Starting emitter ..." 78 | nsenter --net="$right" -- ./mping -qr -i eth0 -t 3 -W 30 225.1.2.3 & 79 | echo $! >> "/tmp/$NM/PIDs" 80 | sleep 1 81 | 82 | if ! nsenter --net="$left" -- ./mping -s -i eth0 -t 3 -c 10 -w 30 225.1.2.3; then 83 | show_mroute 84 | ../src/mroutectl -u "/tmp/$NM/sock" 85 | echo "Failed routing, expected at least 10 multicast ping replies" 86 | FAIL 87 | fi 88 | 89 | ../src/mroutectl -u "/tmp/$NM/sock" show compat detail 90 | 91 | kill_pids 92 | 93 | print "Analyzing left.pcap ..." 94 | lines1=$(tshark -n -r "/tmp/$NM/left.pcap" 2>/dev/null | grep "DVMRP 50 V3 Probe" | tee "/tmp/$NM/result" | wc -l) 95 | lines2=$(tshark -n -r "/tmp/$NM/left.pcap" 2>/dev/null | grep "IGMPv3 50 Membership Query" | tee -a "/tmp/$NM/result" | wc -l) 96 | cat "/tmp/$NM/result" 97 | echo " => $lines1 DVMRP, expected 1" 98 | echo " => $lines2 IGMP Query, expected 1" 99 | # shellcheck disable=SC2086 disable=SC2166 100 | [ $lines1 -ge 1 -a $lines2 -ge 1 ] || FAIL 101 | 102 | print "Analyzing right.pcap ..." 103 | lines1=$(tshark -n -r "/tmp/$NM/right.pcap" 2>/dev/null | grep "DVMRP 50 V3 Probe" | tee "/tmp/$NM/result" | wc -l) 104 | lines2=$(tshark -n -r "/tmp/$NM/right.pcap" 2>/dev/null | grep "IGMPv3 50 Membership Query" | tee -a "/tmp/$NM/result" | wc -l) 105 | cat "/tmp/$NM/result" 106 | echo " => $lines1 DVMRP, expected 1" 107 | echo " => $lines2 IGMP Query, expected 1" 108 | # shellcheck disable=SC2086 disable=SC2166 109 | [ $lines1 -ge 1 -a $lines2 -ge 1 ] || FAIL 110 | 111 | OK 112 | -------------------------------------------------------------------------------- /lib/pidfile.c: -------------------------------------------------------------------------------- 1 | /* Updated by troglobit for libite/finit/uftpd projects 2016/07/04 */ 2 | /* $OpenBSD: pidfile.c,v 1.11 2015/06/03 02:24:36 millert Exp $ */ 3 | /* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */ 4 | 5 | /*- 6 | * Copyright (c) 1999 The NetBSD Foundation, Inc. 7 | * All rights reserved. 8 | * 9 | * This code is derived from software contributed to The NetBSD Foundation 10 | * by Jason R. Thorpe. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions 14 | * are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #include /* utimensat() */ 35 | #include /* utimensat() on *BSD */ 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include "pathnames.h" 42 | 43 | static char *pidfile_path = NULL; 44 | static pid_t pidfile_pid = 0; 45 | 46 | static void pidfile_cleanup(void); 47 | 48 | const char *__pidfile_path = _PATH_MROUTED_RUNDIR; 49 | const char *__pidfile_name = NULL; 50 | 51 | int 52 | pidfile(const char *basename) 53 | { 54 | int save_errno; 55 | int atexit_already; 56 | pid_t pid; 57 | FILE *f; 58 | 59 | pid = getpid(); 60 | atexit_already = 0; 61 | 62 | if (pidfile_path != NULL) { 63 | if (!access(pidfile_path, R_OK) && pid == pidfile_pid) { 64 | utimensat(0, pidfile_path, NULL, 0); 65 | return (0); 66 | } 67 | free(pidfile_path); 68 | pidfile_path = NULL; 69 | __pidfile_name = NULL; 70 | atexit_already = 1; 71 | } 72 | 73 | if (basename[0] != '/') { 74 | if (asprintf(&pidfile_path, "%s/%s.pid", __pidfile_path, basename) == -1) 75 | return (-1); 76 | } else { 77 | if (asprintf(&pidfile_path, "%s", basename) == -1) 78 | return (-1); 79 | } 80 | 81 | if ((f = fopen(pidfile_path, "w")) == NULL) { 82 | save_errno = errno; 83 | free(pidfile_path); 84 | pidfile_path = NULL; 85 | errno = save_errno; 86 | return (-1); 87 | } 88 | 89 | if (fprintf(f, "%ld\n", (long)pid) <= 0 || fflush(f) != 0) { 90 | save_errno = errno; 91 | (void) fclose(f); 92 | (void) unlink(pidfile_path); 93 | free(pidfile_path); 94 | pidfile_path = NULL; 95 | errno = save_errno; 96 | return (-1); 97 | } 98 | (void) fclose(f); 99 | __pidfile_name = pidfile_path; 100 | 101 | /* 102 | * LITE extension, no need to set up another atexit() handler 103 | * if user only called us to update the mtime of the PID file 104 | */ 105 | if (atexit_already) 106 | return (0); 107 | 108 | pidfile_pid = pid; 109 | if (atexit(pidfile_cleanup) < 0) { 110 | save_errno = errno; 111 | (void) unlink(pidfile_path); 112 | free(pidfile_path); 113 | pidfile_path = NULL; 114 | pidfile_pid = 0; 115 | errno = save_errno; 116 | return (-1); 117 | } 118 | 119 | return (0); 120 | } 121 | 122 | static void 123 | pidfile_cleanup(void) 124 | { 125 | if (pidfile_path != NULL && pidfile_pid == getpid()) { 126 | (void) unlink(pidfile_path); 127 | free(pidfile_path); 128 | pidfile_path = NULL; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.61]) 2 | AC_INIT([mrouted], [4.6], [https://github.com/troglobit/mrouted/issues],, 3 | [https://troglobit.com/projects/mrouted/]) 4 | AC_CONFIG_AUX_DIR(aux) 5 | AM_INIT_AUTOMAKE([1.11 foreign]) 6 | AM_SILENT_RULES([yes]) 7 | 8 | AC_CONFIG_SRCDIR([src/main.c]) 9 | AC_CONFIG_HEADERS([config.h]) 10 | AC_CONFIG_FILES([Makefile man/Makefile src/Makefile test/Makefile mrouted.service]) 11 | 12 | # Check for standard programs, headers, and functions 13 | AC_PROG_CC 14 | AC_PROG_INSTALL 15 | AC_PROG_YACC 16 | 17 | # Required to check for libsystemd-dev 18 | PKG_PROG_PKG_CONFIG 19 | 20 | # Check for linux/netlink.h is only to be able to define LINUX below 21 | AC_CHECK_HEADERS([fcntl.h ifaddrs.h sys/ioctl.h sys/time.h linux/netlink.h termios.h]) 22 | AC_CHECK_HEADERS([net/if.h netinet/igmp.h], [], [], [ 23 | #include 24 | #ifdef STDC_HEADERS 25 | # include 26 | # include 27 | #else 28 | # ifdef HAVE_STDLIB_H 29 | # include 30 | # endif 31 | #endif 32 | #ifdef HAVE_SYS_SOCKET_H 33 | # include 34 | #endif 35 | #include 36 | #include ]) 37 | 38 | # Check if some func is not in libc 39 | AC_CHECK_LIB([util], [pidfile]) 40 | 41 | # Check for required functions in libc 42 | AC_CHECK_FUNCS([atexit getifaddrs]) 43 | 44 | # Check for usually missing API's, which we can replace 45 | AC_REPLACE_FUNCS([pidfile strlcpy strlcat strtonum utimensat]) 46 | AC_CONFIG_LIBOBJ_DIR([lib]) 47 | 48 | AC_ARG_ENABLE(test, 49 | AS_HELP_STRING([--enable-test], [enable tests, requries unshare, tshark, etc.]), 50 | enable_test="$enableval", enable_test="no") 51 | 52 | AC_ARG_WITH([systemd], 53 | [AS_HELP_STRING([--with-systemd=DIR], [Directory for systemd service files])],, 54 | [with_systemd=auto]) 55 | 56 | # Create config.h from selected features and fallback defautls 57 | AS_IF([test "x$with_systemd" = "xyes" -o "x$with_systemd" = "xauto"], [ 58 | def_systemd=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) 59 | AS_IF([test "x$def_systemd" = "x"], 60 | [AS_IF([test "x$with_systemd" = "xyes"], 61 | [AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])]) 62 | with_systemd=no], [with_systemd="$def_systemd"])]) 63 | AS_IF([test "x$with_systemd" != "xno"], 64 | [AC_SUBST([systemddir], [$with_systemd])]) 65 | 66 | AM_CONDITIONAL(BSD, [test "x$ac_cv_header_net_if_dl_h" = "xyes"]) 67 | AM_CONDITIONAL(LINUX, [test "x$ac_cv_header_linux_netlink_h" = "xyes"]) 68 | AM_CONDITIONAL(SYSTEMD, [test "x$with_systemd" != "xno"]) 69 | AM_CONDITIONAL(ENABLE_TEST, [test "x$enable_test" != "xno"]) 70 | 71 | # Expand $sbindir early, into $SBINDIR, for systemd unit file 72 | # NOTE: This does *not* take prefix/exec_prefix override at "make 73 | # install" into account, unfortunately. 74 | test "x$prefix" = xNONE && prefix=$ac_default_prefix 75 | test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' 76 | DOCDIR=`eval echo $docdir` 77 | DOCDIR=`eval echo $DOCDIR` 78 | AC_SUBST(DOCDIR) 79 | SYSCONFDIR=`eval echo $sysconfdir` 80 | SYSCONFDIR=`eval echo $SYSCONFDIR` 81 | AC_SUBST(SYSCONFDIR) 82 | SBINDIR=`eval echo $sbindir` 83 | SBINDIR=`eval echo $SBINDIR` 84 | AC_SUBST(SBINDIR) 85 | 86 | # Workaround for as-of-yet unreleased runstatedir support, planned for 87 | # autoconf 2.70, which some major distros have backported. 88 | AS_IF([test -z "$runstatedir"], runstatedir="$localstatedir/run") 89 | AC_SUBST(runstatedir) 90 | 91 | # Generate all files 92 | AC_OUTPUT 93 | 94 | cat < **Tip:** Adapt your code to what the surrounding code looks like! 27 | 28 | mrouted is written in C. C is an old language and sometimes that age is 29 | clearly visible. The current maintainer has tried to (re)enforce a 30 | consistent and more modern C style, without having to completly 31 | re-indent the whole code base. 32 | 33 | First of all, lines are allowed to be longer than 72 characters these 34 | days. In fact, there exist no enforced maximum, but keeping it around 35 | 100 chars is good practice. 36 | 37 | mrouted use leading four spaces in functions and structs. The next level 38 | use eight spaces, but the original authors used tab for that level. A 39 | `switch()` has its `case` statements indented four spaces ... but then 40 | it is more or less [KNF][]. 41 | 42 | In Emacs this coding style can be achieved by using the following 43 | footer applied to a C file: 44 | 45 | /** 46 | * Local Variables: 47 | * indent-tabs-mode: t 48 | * c-file-style: "cc-mode" 49 | * End: 50 | */ 51 | 52 | The current maintainer has considered shifting the original coding 53 | style to FULL [KNF][] several times, but decided against changing 54 | to keep with the intent of the original authors. 55 | 56 | 57 | Commit Messages 58 | --------------- 59 | 60 | Commit messages exist to track *why* a change was made. Try to be as 61 | clear and concise as possible in your commit messages, and always, be 62 | proud of your work and set up a proper GIT identity for your commits: 63 | 64 | git config --global user.name "Jane Doe" 65 | git config --global user.email jane.doe@example.com 66 | 67 | Example commit message from the [Pro Git][gitbook] online book, notice 68 | how `git commit -s` is used to automatically add a `Signed-off-by`: 69 | 70 | Brief, but clear and concise summary of changes 71 | 72 | More detailed explanatory text, if necessary. Wrap it to about 72 73 | characters or so. In some contexts, the first line is treated as 74 | the subject of an email and the rest of the text as the body. The 75 | blank line separating the ummary from the body is critical (unless 76 | you omit the body entirely); tools like rebase can get confused if 77 | you run the two together. 78 | 79 | Further paragraphs come after blank lines. 80 | 81 | - Bullet points are okay, too 82 | 83 | - Typically a hyphen or asterisk is used for the bullet, preceded 84 | by a single space, with blank lines in between, but conventions 85 | vary here 86 | 87 | Signed-off-by: Jane Doe 88 | 89 | 90 | Target Systems 91 | -------------- 92 | 93 | mrouted mainly targets modern UNIX systems and has been tested on both 94 | Debian and Ubuntu for Linux, FreeBSD, and NetBSD. Please consider these 95 | targets when submitting changes. If you cannot test on them do this, be 96 | prepared that your feature/fix will likely be delayed by the maintainer, 97 | who will attempt to test and in some cases port the feature for you. 98 | 99 | 100 | Code of Conduct 101 | --------------- 102 | 103 | It is expected of everyone engaging in the project to, in the words of 104 | Bill & Ted; [be excellent to each other][conduct]. 105 | 106 | 107 | [github]: https://github.com/troglobit/mrouted/ 108 | [KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form 109 | [gitbook]: https://git-scm.com/book/ch5-2.html 110 | [conduct]: CODE-OF-CONDUCT.md 111 | -------------------------------------------------------------------------------- /src/ipip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | 10 | #include "defs.h" 11 | 12 | /* 13 | * Exported variables. 14 | */ 15 | #ifdef notyet 16 | int raw_socket; /* socket for raw network I/O */ 17 | #endif 18 | /* 19 | *XXX For now, we just use the IGMP socket to send packets. 20 | * This is legal in BSD, because the protocol # is not checked 21 | * on raw sockets. The k_* interfaces need to gain a socket 22 | * argument so that we can call them on the raw_socket also. 23 | */ 24 | #define raw_socket igmp_socket 25 | 26 | /* 27 | * Private variables. 28 | */ 29 | static int rawid = 0; 30 | 31 | /* 32 | * Open and initialize the raw socket. 33 | */ 34 | void init_ipip(void) 35 | { 36 | #ifdef notyet 37 | if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 38 | logit(LOG_ERR, errno, "Raw IP socket"); 39 | #endif 40 | } 41 | 42 | /* 43 | * Allocate and fill in static IP header for encapsulating on a tunnel. 44 | */ 45 | void init_ipip_on_vif(struct uvif *v) 46 | { 47 | struct ip *ip; 48 | 49 | if (v->uv_encap_hdr) 50 | return; 51 | 52 | ip = v->uv_encap_hdr = calloc(1, sizeof(struct ip)); 53 | if (!ip) { 54 | logit(LOG_ERR, errno, "Out of memory when setting up IPIP tunnel"); 55 | return; /* Never reached */ 56 | } 57 | 58 | /* 59 | * Fields zeroed that aren't filled in later: 60 | * - IP ID (let the kernel fill it in) 61 | * - Offset (we don't send fragments) 62 | * - Checksum (let the kernel fill it in) 63 | */ 64 | memset(ip, 0, sizeof(struct ip)); 65 | ip->ip_v = IPVERSION; 66 | ip->ip_hl = sizeof(struct ip) >> 2; 67 | ip->ip_tos = 0xc0; /* Internet Control */ 68 | ip->ip_ttl = MAXTTL; /* applies to unicasts only */ 69 | ip->ip_p = IPPROTO_IPIP; 70 | ip->ip_src.s_addr = v->uv_lcl_addr; 71 | ip->ip_dst.s_addr = v->uv_rmt_addr; 72 | } 73 | 74 | /* 75 | * Call build_igmp() to build an IGMP message in the output packet buffer. 76 | * Then fill in the fields of the IP packet that build_igmp() left for the 77 | * kernel to fill in, and encapsulate the original packet with the 78 | * pre-created ip header for this vif. 79 | */ 80 | void send_ipip(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen, struct uvif *v) 81 | { 82 | struct msghdr msg; 83 | struct iovec iov[2]; 84 | struct sockaddr_in sdst; 85 | struct ip *ip; 86 | 87 | build_igmp(src, dst, type, code, group, datalen); 88 | ip = (struct ip *)send_buf; 89 | ip->ip_id = htons(rawid++); 90 | ip->ip_sum = 0; 91 | ip->ip_sum = inet_cksum((uint16_t *)ip, ip->ip_hl << 2); 92 | 93 | ip = v->uv_encap_hdr; 94 | ip->ip_len = 2 * MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; 95 | #ifndef HAVE_IP_HDRINCL_BSD_ORDER 96 | ip->ip_len = htons(ip->ip_len); 97 | #endif 98 | 99 | memset(&sdst, 0, sizeof(sdst)); 100 | sdst.sin_family = AF_INET; 101 | #ifdef HAVE_SA_LEN 102 | sdst.sin_len = sizeof(sdst); 103 | #endif 104 | sdst.sin_addr = ip->ip_dst; 105 | 106 | iov[0].iov_base = (caddr_t)v->uv_encap_hdr; 107 | iov[0].iov_len = sizeof(struct ip); 108 | iov[1].iov_base = (caddr_t)send_buf; 109 | iov[1].iov_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; 110 | 111 | memset(&msg, 0, sizeof(msg)); 112 | msg.msg_name = (caddr_t)&sdst; 113 | msg.msg_namelen = sizeof(sdst); 114 | msg.msg_iov = iov; 115 | msg.msg_iovlen = 2; 116 | if (sendmsg(raw_socket, &msg, 0) < 0) { 117 | switch (errno) { 118 | case ENETUNREACH: 119 | case ENETDOWN: 120 | check_vif_state(); 121 | break; 122 | default: 123 | logit(LOG_WARNING, errno, "sendmsg to %s on %s", 124 | inet_fmt(sdst.sin_addr.s_addr, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2))); 125 | break; 126 | } 127 | } 128 | 129 | IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code)) 130 | logit(LOG_DEBUG, 0, "SENT %s from %-15s to %s encaped to %s", 131 | igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" : 132 | inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)), 133 | inet_fmt(sdst.sin_addr.s_addr, s3, sizeof(s3))); 134 | } 135 | 136 | /** 137 | * Local Variables: 138 | * indent-tabs-mode: t 139 | * c-file-style: "cc-mode" 140 | * End: 141 | */ 142 | -------------------------------------------------------------------------------- /man/map-mbone.8: -------------------------------------------------------------------------------- 1 | .\" $OpenBSD: map-mbone.8,v 1.13 2007/05/31 19:20:25 jmc Exp $ 2 | .\" $NetBSD: map-mbone.8,v 1.2 1995/10/03 23:16:53 thorpej Exp $ 3 | .\" 4 | .\" Mapper for connections between MRouteD multicast routers. 5 | .\" Written by Pavel Curtis 6 | .\" 7 | .\" Copyright (c) 1992, 2001 Xerox Corporation. All rights reserved. 8 | .\" 9 | .\" Redistribution and use in source and binary forms, with or without 10 | .\" modification, are permitted provided that the following conditions are met: 11 | .\" 12 | .\" Redistributions of source code must retain the above copyright notice, 13 | .\" this list of conditions and the following disclaimer. 14 | .\" 15 | .\" Redistributions in binary form must reproduce the above copyright notice, 16 | .\" this list of conditions and the following disclaimer in the documentation 17 | .\" and/or other materials provided with the distribution. 18 | .\" 19 | .\" Neither name of the Xerox, PARC, nor the names of its contributors may be 20 | .\" used to endorse or promote products derived from this software 21 | .\" without specific prior written permission. 22 | .\" 23 | .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 | .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR 27 | .\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28 | .\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 | .\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30 | .\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 | .\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 | .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 33 | .\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | .\" 35 | .Dd $Mdocdate: May 31 2007 $ 36 | .Dt MAP-MBONE 8 SMM 37 | .Os 38 | .Sh NAME 39 | .Nm map-mbone 40 | .Nd Multicast connection mapper 41 | .Sh SYNOPSIS 42 | .Nm map-mbone 43 | .Op Fl fgn 44 | .Op Fl d Ar level 45 | .Op Fl r Ar count 46 | .Op Fl t Ar seconds 47 | .Op Ar starting_router 48 | .Sh DESCRIPTION 49 | .Nm 50 | attempts to display all multicast routers that are reachable from the multicast 51 | router 52 | .Ar starting_router . 53 | If not specified on the command line, 54 | .Ar starting_router 55 | is 56 | .Dq localhost . 57 | .Nm 58 | must be run as root. 59 | .Pp 60 | .Nm 61 | sends an 62 | .Dv ASK_NEIGHBORS 63 | .Tn IGMP 64 | message to 65 | .Ar starting_router . 66 | A response contains the 67 | multicast version number 68 | of 69 | .Ar starting_router 70 | and the addresses of 71 | all its neighboring multicast routers. 72 | If the multicast version number is recent, then 73 | .Nm 74 | requests additional information such as metrics, thresholds, and flags. 75 | .Pp 76 | If a recursive search has been requested (see 77 | .Fl f ) , 78 | .Nm 79 | repeats the above operation for each new 80 | multicast router in the list of neighbors and 81 | continues the process until no new multicast routers are reported. 82 | .Pp 83 | The options are as follows: 84 | .Pp 85 | .Bl -tag -width "-t seconds" 86 | .It Fl d Ar level 87 | Sets the debug level to 88 | .Ar level . 89 | When the debug level is greater than 90 | 0, additional debugging messages are printed to stderr. 91 | Regardless of 92 | the debug level, an error condition will always write an error message and will 93 | cause 94 | .Nm 95 | to terminate. 96 | Non-zero debug levels are: 97 | .Bl -enum -offset indent 98 | .It 99 | Print packet warnings, plus level 0 messages. 100 | .It 101 | Print notifications of down networks, plus level 1 messages. 102 | .It 103 | Print notifications of all packet timeouts, plus level 2 messages. 104 | .El 105 | .Pp 106 | Default is 0. 107 | .It Fl f 108 | Causes a recursive (flooding) search. 109 | If no 110 | .Ar starting_router 111 | is specified, a recursive search is always performed. 112 | .It Fl g 113 | Sets graphing format to GraphEd format. 114 | .It Fl n 115 | Disables DNS lookup for the names of the multicast routers. 116 | .It Fl r Ar count 117 | Sets the neighbor query retry limit to 118 | .Ar count . 119 | Default is 1. 120 | .It Fl t Ar seconds 121 | Sets the number of seconds to wait for a neighbor query 122 | reply before retrying to 123 | .Ar seconds . 124 | Default is 2. 125 | .El 126 | .Sh SEE ALSO 127 | .Xr mrinfo 8 , 128 | .Xr mrouted 8 , 129 | .Xr mtrace 8 130 | .Sh AUTHORS 131 | Pavel Curtis 132 | -------------------------------------------------------------------------------- /doc/configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | 4 | OS=`uname` 5 | CFG=config.mk 6 | TMP=`mktemp` 7 | 8 | heading() 9 | { 10 | echo "# This makefile snippet is generated by the mrouted configure script." > $CFG 11 | echo >> $CFG 12 | echo "# Initial definitions ..." >> $CFG 13 | echo "# -D_GNU_SOURCE Use GNU extensions, where possible" >> $CFG 14 | echo "# -D_BSD_SOURCE Use functions derived from 4.3 BSD Unix rather than POSIX.1" >> $CFG 15 | echo "# In GLIBC >= v2.20 this is replaced with -D_DEFAULT_SOURCE " >> $CFG 16 | echo "DEFS = -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_GNU_SOURCE" >> $CFG 17 | echo "# EXTRA_OBJS = For locally provided objects missing on some platforms, e.g., strlcpy.o" >> $CFG 18 | echo "# EXTRA_LIBS = For platform specific libraries, e.g., -lutil" >> $CFG 19 | echo >> $CFG 20 | echo "# $OS specific settings ..." >> $CFG 21 | } 22 | 23 | usage() 24 | { 25 | echo "Run this script to configure mrouted for your operating system." 26 | echo 27 | echo "Usage: $0 [ARG]" 28 | echo 29 | echo " --with-includes=PATH Use this if the multicast header files are not in the" 30 | echo " standard location on your system. E.g., /sys" 31 | echo 32 | echo "Report any bugs to https://github.com/troglobit/mrouted/issues" 33 | echo 34 | 35 | exit 1 36 | } 37 | 38 | echo > $TMP 39 | echo "# Enabled features ..." >> $TMP 40 | 41 | while [ "$*" != "" ]; do 42 | opt=`expr "$1" : "--\([^=]*\)=.*"` 43 | arg=`expr "$1" : "--[^=]*=\(.*\)"` 44 | if [ -z "$opt" ]; then 45 | opt=`expr "$1" : "--\(.*\)"` 46 | fi 47 | shift 48 | 49 | case $opt in 50 | with-includes) 51 | echo "INCLUDES += -I$arg" >> $TMP 52 | ;; 53 | 54 | help) 55 | usage 56 | ;; 57 | 58 | *) 59 | echo "Unknown option: $opt" 60 | usage 61 | ;; 62 | esac 63 | done 64 | 65 | ## BSDI -D__bsdi__ is defined by the OS 66 | #INCLUDES = 67 | #DEFS += 68 | #EXTRA_OBJS = strlcpy.o pidfile.o strtonum.o 69 | 70 | ## SunOS, OSF1, gcc 71 | #INCLUDES = 72 | #DEFS += -DSunOS=43 73 | #EXTRA_OBJS = strlcpy.o pidfile.o strtonum.o 74 | 75 | ## SunOS, OSF1, cc 76 | #INCLUDES = 77 | #DEFS += -DSunOS=43 78 | #EXTRA_OBJS = strlcpy.o pidfile.o strtonum.o 79 | 80 | ## IRIX 81 | #INCLUDES = 82 | #DEFS += -D_BSD_SIGNALS -DIRIX 83 | #EXTRA_OBJS = strlcpy.o pidfile.o strtonum.o 84 | 85 | ## Solaris 2.5, gcc 86 | #INCLUDES = 87 | #DEFS += -DSUNOS5 -DSunOS=55 88 | ## Solaris 2.5, cc 89 | #INCLUDES = 90 | #DEFS += -DSUNOS5 -DSunOS=55 91 | ## Solaris 2.6 92 | #INCLUDES = 93 | #DEFS += -DSUNOS5 -DSunOS=56 94 | ## Solaris 2.x 95 | #EXTRA_OBJS = strlcpy.o pidfile.o strtonum.o 96 | #EXTRA_LIBS = -L/usr/ucblib -lucb -L/usr/lib -lsocket -lnsl 97 | 98 | # For uClibc based Linux systems, add -DHAVE_STRLCPY to DEFS 99 | case $OS in 100 | Linux) 101 | heading 102 | echo "INCLUDES =" >> $CFG 103 | echo "DEFS += -DIOCTL_OK_ON_RAW_SOCKET" >> $CFG 104 | echo "EXTRA_OBJS = strlcpy.o pidfile.o strtonum.o" >> $CFG 105 | echo "EXTRA_LIBS =" >> $CFG 106 | ;; 107 | 108 | FreeBSD) 109 | heading 110 | echo "INCLUDES =" >> $CFG 111 | echo "DEFS += -DHAVE_STRTONUM -DHAVE_STRLCPY" >> $CFG 112 | echo "EXTRA_OBJS = pidfile.o" >> $CFG 113 | echo "EXTRA_LIBS =" >> $CFG 114 | ;; 115 | 116 | NetBSD) 117 | heading 118 | echo "INCLUDES =" >> $CFG 119 | echo "DEFS += -DHAVE_STRLCPY -DHAVE_PIDFILE" >> $CFG 120 | echo "EXTRA_OBJS = strtonum.o" >> $CFG 121 | echo "EXTRA_LIBS = -lutil" >> $CFG 122 | ;; 123 | 124 | OpenBSD) 125 | heading 126 | echo "INCLUDES =" >> $CFG 127 | echo "DEFS += -DHAVE_STRTONUM -DHAVE_STRLCPY -DHAVE_PIDFILE" >> $CFG 128 | echo "EXTRA_OBJS =" >> $CFG 129 | echo "EXTRA_LIBS = -lutil" >> $CFG 130 | ;; 131 | 132 | *) 133 | rm $CFG 134 | echo "$OS is currently unsupported. Help out at https://github.com/troglobit/mrouted/" 135 | exit 1 136 | ;; 137 | esac 138 | 139 | cat $TMP >> $CFG 140 | rm $TMP 141 | 142 | exit 0 143 | 144 | -------------------------------------------------------------------------------- /src/pev.h: -------------------------------------------------------------------------------- 1 | /* This is free and unencumbered software released into the public domain. */ 2 | 3 | /* 4 | * All pev callback run in regular process context, even signal 5 | * callbacks. All callbacks gets the socket, signal, or timer id, 6 | * as the first argument, in addition to the optional argument. 7 | * 8 | * static void signal_cb(int signo, void *arg); 9 | * static void socket_cb(int sd, void *arg); 10 | * static void timer_cb(int id, void *arg); 11 | * 12 | * NOTE: pev < v2.0 passed the timeout value as the first argument 13 | * to timer_cb(). Now the first arugment is the timer id. 14 | */ 15 | 16 | #ifndef PEV_H_ 17 | #define PEV_H_ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | /* 24 | * Call this before creating any signal, socket, or timer callbacks. 25 | */ 26 | int pev_init (void); 27 | 28 | /* 29 | * Call this from a callback to exit the event loop. 30 | * The status is what is returned from pev_run(). 31 | */ 32 | int pev_exit (int status); 33 | 34 | /* 35 | * The event loop itself. Call after pev_init() and all the signal, 36 | * socket, or timer callbacks have been created. Returns the status 37 | * given to pev_exit(). 38 | */ 39 | int pev_run (void); 40 | 41 | /* 42 | * Signal callbacks are identified by signal number, only one callback 43 | * per signal. Signals are serialized like timers, which use SIGALRM, 44 | * using a pipe. Delete by giving id returned from pev_sig_add() 45 | */ 46 | int pev_sig_add (int signo, void (*cb)(int, void *), void *arg); 47 | int pev_sig_del (int id); 48 | 49 | /* 50 | * Destructor callback, called when deleting a signal event (pev_sig_del). 51 | * Useful for deallocating heap allocated arg data. 52 | */ 53 | int pev_sig_set_cb_del (int id, void (*cb)(void *)); 54 | 55 | /* 56 | * Socket or file descriptor callback by sd/fd, only one callback per 57 | * descriptor. API changes to CLOEXEC and NONBLOCK. Delete by id 58 | * returned from pev_sock_add() 59 | */ 60 | int pev_sock_add (int sd, void (*cb)(int, void *), void *arg); 61 | int pev_sock_del (int id); 62 | 63 | /* 64 | * Same as pev_sock_add() but creates/closes socket as well. 65 | * Delete by id returned from pev_sock_open() 66 | */ 67 | int pev_sock_open (int domain, int type, int proto, void (*cb)(int, void *), void *arg); 68 | int pev_sock_close (int id); 69 | 70 | /* 71 | * Destructor callback, called when deleting a socket event (pev_sock_del or 72 | * pev_sock_close). Useful for deallocating heap allocated arg data. 73 | */ 74 | int pev_sock_set_cb_del (int id, void (*cb)(void *)); 75 | 76 | 77 | /* 78 | * TIMER API 79 | * 80 | * The scheduling granularity of timers is subject to limits in your 81 | * operating system timer resolution. 82 | * 83 | * Periodic timers use SIGALRM via the POSIX setitimer() API, which 84 | * may affect the use of sleep(), usleep(), and alarm() APIs in your 85 | * application. See your respective OS for details. 86 | */ 87 | 88 | /* 89 | * Add or delete a timer. When creating a new timer, the timeout and 90 | * period arguments are in microseconds. The callback used to get the 91 | * timeout value as its first argument, but this was changed in v2.0 to 92 | * instead pass the timer id so callback easily can do pev_timer_set(). 93 | * The timer id is also returned by the add function. 94 | * 95 | * For one-shot timers, set period = 0 and timeout to the delay before 96 | * the callback should be called. 97 | * 98 | * For periodic timers, set period != 0. The timeout may be set to 99 | * zero (timeout=0) for periodic tasks, this means the first call will 100 | * be after period microseconds. The timeout value is only used for 101 | * the first call. 102 | */ 103 | int pev_timer_add (int timeout, int period, void (*cb)(int, void *), void *arg); 104 | int pev_timer_del (int id); 105 | 106 | /* 107 | * Reset timeout of one-shot timer. When a one-shot timer has fired 108 | * it goes inert. Calling pev_timer_set() rearms the timer. 109 | * 110 | * Remember, the timeout argument is in microseconds. 111 | * 112 | * An active timer has a non-zero timeout, this can be checked with 113 | * the pev_timer_get() call. This also applies to periodic timers, 114 | * with the exception of the first initial timeout, the call always 115 | * returns the period value. 116 | */ 117 | int pev_timer_set (int id, int timeout); 118 | int pev_timer_get (int id); 119 | 120 | /* 121 | * Destructor callback, called when deleting a timer (pev_timer_del). 122 | * Useful for deallocating heap allocated arg data. 123 | */ 124 | int pev_timer_set_cb_del (int id, void (*cb)(void *)); 125 | 126 | #endif /* PEV_H_ */ 127 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for mrouted, a multicast router, and its auxiliary -*-Makefile-*- 2 | # programs: map-mbone, mrinfo and mtrace. 3 | # 4 | 5 | # VERSION ?= $(shell git tag -l | tail -1) 6 | VERSION ?= 3.9.8 7 | NAME = mrouted 8 | CONFIG = $(NAME).conf 9 | EXECS = mrouted map-mbone mrinfo mtrace 10 | PKG = $(NAME)-$(VERSION) 11 | ARCHIVE = $(PKG).tar.bz2 12 | 13 | ROOTDIR ?= $(dir $(shell pwd)) 14 | RM ?= rm -f 15 | CC ?= $(CROSS)gcc 16 | 17 | prefix ?= /usr/local 18 | sysconfdir ?= /etc 19 | datadir = $(prefix)/share/doc/mrouted 20 | mandir = $(prefix)/share/man/man8 21 | 22 | # This magic trick looks like a comment, but works on BSD PMake 23 | #include 24 | include config.mk 25 | 26 | IGMP_SRCS = igmp.c inet.c kern.c 27 | IGMP_OBJS = igmp.o inet.o kern.o 28 | 29 | ROUTER_OBJS = config.o cfparse.o main.o route.o vif.o prune.o callout.o \ 30 | icmp.o ipip.o vers.o $(EXTRA_OBJS) 31 | ROUTER_SRCS = $(ROUTER_OBJS:.o=.c) 32 | MAPPER_OBJS = mapper.o $(EXTRA_OBJS) 33 | MRINFO_OBJS = mrinfo.o $(EXTRA_OBJS) 34 | MTRACE_OBJS = mtrace.o $(EXTRA_OBJS) 35 | #MSTAT_OBJS = mstat.o $(EXTRA_OBJS) 36 | 37 | ## Common 38 | CFLAGS += $(MCAST_INCLUDE) $(INCLUDES) $(DEFS) $(USERCOMPILE) 39 | CFLAGS += -O2 -W -Wall -Wextra 40 | #CFLAGS += -O -g 41 | LDLIBS = $(EXTRA_LIBS) 42 | LDFLAGS += -Wl,-Map,$@.map 43 | OBJS = $(IGMP_OBJS) $(ROUTER_OBJS) $(MAPPER_OBJS) $(MRINFO_OBJS) \ 44 | $(MTRACE_OBJS) $(MSTAT_OBJS) 45 | SRCS = $(OBJS:.o=.c) 46 | MANS = $(addsuffix .8,$(EXECS)) 47 | DISTFILES = README.md AUTHORS LICENSE ChangeLog.md 48 | 49 | LINT = splint 50 | LINTFLAGS = $(MCAST_INCLUDE) $(filter-out -W -Wall -Werror, $(CFLAGS)) -posix-lib -weak -skipposixheaders 51 | 52 | all: $(EXECS) $(MSTAT) 53 | 54 | .y.c: 55 | @printf " YACC $@\n" 56 | @$(YACC) $< 57 | -@mv y.tab.c $@ || mv $(<:.y=.tab.c) $@ 58 | 59 | .c.o: 60 | @printf " CC $@\n" 61 | @$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< 62 | 63 | install: $(EXECS) 64 | @install -d $(DESTDIR)$(prefix)/sbin 65 | @install -d $(DESTDIR)$(sysconfdir) 66 | @install -d $(DESTDIR)$(datadir) 67 | @install -d $(DESTDIR)$(mandir) 68 | @for file in $(EXECS); do \ 69 | install -m 0755 $$file $(DESTDIR)$(prefix)/sbin/$$file; \ 70 | done 71 | @install -b -m 0644 $(CONFIG) $(DESTDIR)$(sysconfdir)/$(CONFIG) 72 | @for file in $(DISTFILES); do \ 73 | install -m 0644 $$file $(DESTDIR)$(datadir)/$$file; \ 74 | done 75 | @for file in $(MANS); do \ 76 | install -m 0644 $$file $(DESTDIR)$(mandir)/$$file; \ 77 | done 78 | 79 | uninstall: 80 | -@for file in $(EXECS); do \ 81 | $(RM) $(DESTDIR)$(prefix)/sbin/$$file; \ 82 | done 83 | -@$(RM) $(DESTDIR)$(sysconfdir)/$(CONFIG) 84 | -@$(RM) -r $(DESTDIR)$(datadir) 85 | -@for file in $(MANS); do \ 86 | $(RM) $(DESTDIR)$(mandir)/$$file; \ 87 | done 88 | 89 | mrouted: $(IGMP_OBJS) $(ROUTER_OBJS) $(CMULIBS) 90 | @printf " LINK $@\n" 91 | @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(IGMP_OBJS) $(ROUTER_OBJS) $(LDLIBS) 92 | 93 | vers.c: Makefile 94 | @echo $(VERSION) | sed -e 's/.*/char todaysversion[]="&";/' > vers.c 95 | 96 | map-mbone: $(IGMP_OBJS) $(MAPPER_OBJS) 97 | @printf " LINK $@\n" 98 | @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(IGMP_OBJS) $(MAPPER_OBJS) $(LDLIBS) 99 | 100 | mrinfo: $(IGMP_OBJS) $(MRINFO_OBJS) 101 | @printf " LINK $@\n" 102 | @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(IGMP_OBJS) $(MRINFO_OBJS) $(LDLIBS) 103 | 104 | mtrace: $(IGMP_OBJS) $(MTRACE_OBJS) 105 | @printf " LINK $@\n" 106 | @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(IGMP_OBJS) $(MTRACE_OBJS) $(LDLIBS) 107 | 108 | mstat: $(MSTAT_OBJS) $(CMULIBS) 109 | @printf " LINK $@\n" 110 | @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(MSTAT_OBJS) $(LDLIBS) 111 | 112 | # Runs Clang scan-build on the whole tree 113 | check: clean 114 | @scan-build $(MAKE) all 115 | 116 | clean: 117 | -@$(RM) $(OBJS) $(EXECS) 118 | 119 | distclean: 120 | -@$(RM) $(OBJS) core $(EXECS) vers.c cfparse.c *.o *.map .*.d *.out tags TAGS 121 | 122 | dist: 123 | @echo "Building bzip2 tarball of $(PKG) in parent dir..." 124 | git archive --format=tar --prefix=$(PKG)/ $(VERSION) | bzip2 >../$(ARCHIVE) 125 | @(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5) 126 | 127 | build-deb: 128 | gbp buildpackage --git-ignore-new --git-ignore-branch --git-no-create-orig --git-upstream-branch=master 129 | 130 | lint: 131 | @$(LINT) $(LINTFLAGS) $(SRCS) 132 | 133 | tags: $(IGMP_SRCS) $(ROUTER_SRCS) 134 | @ctags $(IGMP_SRCS) $(ROUTER_SRCS) 135 | 136 | cflow: 137 | @cflow $(MCAST_INCLUDE) $(IGMP_SRCS) $(ROUTER_SRCS) > cflow.out 138 | 139 | cflow2: 140 | @cflow -ix $(MCAST_INCLUDE) $(IGMP_SRCS) $(ROUTER_SRCS) > cflow2.out 141 | 142 | rcflow: 143 | @cflow -r $(MCAST_INCLUDE) $(IGMP_SRCS) $(ROUTER_SRCS) > rcflow.out 144 | 145 | rcflow2: 146 | @cflow -r -ix $(MCAST_INCLUDE) $(IGMP_SRCS) $(ROUTER_SRCS) > rcflow2.out 147 | 148 | TAGS: 149 | @etags $(SRCS) 150 | 151 | -------------------------------------------------------------------------------- /src/prune.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | 10 | #ifndef MROUTED_PRUNE_H_ 11 | #define MROUTED_PRUNE_H_ 12 | 13 | /* 14 | * Group table 15 | * 16 | * Each group entry is a member of two doubly-linked lists: 17 | * 18 | * a) A list hanging off of the routing table entry for this source (rt_groups) 19 | * sorted by group address under the routing entry (gt_next, gt_prev) 20 | * b) An independent list pointed to by kernel_table, which is a list of 21 | * active source,group's (gt_gnext, gt_gprev). 22 | * 23 | */ 24 | struct gtable { 25 | struct gtable *gt_next; /* pointer to the next entry */ 26 | struct gtable *gt_prev; /* back pointer for linked list */ 27 | struct gtable *gt_gnext; /* fwd pointer for group list */ 28 | struct gtable *gt_gprev; /* rev pointer for group list */ 29 | uint32_t gt_mcastgrp; /* multicast group associated */ 30 | vifbitmap_t gt_scope; /* scoped interfaces */ 31 | uint8_t gt_ttls[MAXVIFS]; /* ttl vector for forwarding */ 32 | vifbitmap_t gt_grpmems; /* forw. vifs for src, grp */ 33 | int gt_prsent_timer; /* prune timer for this group */ 34 | int gt_timer; /* timer for this group entry */ 35 | time_t gt_ctime; /* time of entry creation */ 36 | uint8_t gt_grftsnt; /* graft sent/retransmit timer */ 37 | nbrbitmap_t gt_prunes; /* bitmap of neighbors who pruned */ 38 | struct stable *gt_srctbl; /* source table */ 39 | struct ptable *gt_pruntbl; /* prune table */ 40 | struct rtentry *gt_route; /* parent route */ 41 | int gt_rexmit_timer; /* timer for prune retransmission */ 42 | int gt_prune_rexmit; /* time til prune retransmission */ 43 | }; 44 | 45 | /* 46 | * Source table 47 | * 48 | * When source-based prunes exist, there will be a struct ptable here as well. 49 | */ 50 | struct stable 51 | { 52 | struct stable *st_next; /* pointer to the next entry */ 53 | uint32_t st_origin; /* host origin of multicasts */ 54 | uint32_t st_pktcnt; /* packet count for src-grp entry */ 55 | uint32_t st_savpkt; /* saved pkt cnt when no krnl entry */ 56 | time_t st_ctime; /* kernel entry creation time */ 57 | }; 58 | 59 | /* 60 | * structure to store incoming prunes. Can hang off of either group or source. 61 | */ 62 | struct ptable 63 | { 64 | struct ptable *pt_next; /* pointer to the next entry */ 65 | uint32_t pt_router; /* router that sent this prune */ 66 | vifi_t pt_vifi; /* vif prune received on */ 67 | uint32_t pt_index; /* neighbor index of router */ 68 | int pt_timer; /* timer for prune */ 69 | }; 70 | 71 | #define MIN_PRUNE_LIFE TIMER_INTERVAL /* min prune lifetime to bother with */ 72 | 73 | /* 74 | * The packet format for a traceroute request. 75 | */ 76 | struct tr_query { 77 | uint32_t tr_src; /* traceroute source */ 78 | uint32_t tr_dst; /* traceroute destination */ 79 | uint32_t tr_raddr; /* traceroute response address */ 80 | #if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN) 81 | struct { 82 | uint32_t qid : 24; /* traceroute query id */ 83 | uint32_t ttl : 8; /* traceroute response ttl */ 84 | } q; 85 | #else 86 | struct { 87 | uint32_t ttl : 8; /* traceroute response ttl */ 88 | uint32_t qid : 24; /* traceroute query id */ 89 | } q; 90 | #endif /* BYTE_ORDER */ 91 | }; 92 | 93 | #define tr_rttl q.ttl 94 | #define tr_qid q.qid 95 | 96 | /* 97 | * Traceroute response format. A traceroute response has a tr_query at the 98 | * beginning, followed by one tr_resp for each hop taken. 99 | */ 100 | struct tr_resp { 101 | uint32_t tr_qarr; /* query arrival time */ 102 | uint32_t tr_inaddr; /* incoming interface address */ 103 | uint32_t tr_outaddr; /* outgoing interface address */ 104 | uint32_t tr_rmtaddr; /* parent address in source tree */ 105 | uint32_t tr_vifin; /* input packet count on interface */ 106 | uint32_t tr_vifout; /* output packet count on interface */ 107 | uint32_t tr_pktcnt; /* total incoming packets for src-grp */ 108 | uint8_t tr_rproto; /* routing protocol deployed on router */ 109 | uint8_t tr_fttl; /* ttl required to forward on outvif */ 110 | uint8_t tr_smask; /* subnet mask for src addr */ 111 | uint8_t tr_rflags; /* forwarding error codes */ 112 | }; 113 | 114 | /* defs within mtrace */ 115 | #define QUERY 1 116 | #define RESP 2 117 | #define QLEN sizeof(struct tr_query) 118 | #define RLEN sizeof(struct tr_resp) 119 | 120 | /* fields for tr_rflags (forwarding error codes) */ 121 | #define TR_NO_ERR 0 122 | #define TR_WRONG_IF 1 123 | #define TR_PRUNED 2 124 | #define TR_OPRUNED 3 125 | #define TR_SCOPED 4 126 | #define TR_NO_RTE 5 127 | #define TR_NO_FWD 7 128 | #define TR_NO_SPACE 0x81 129 | #define TR_OLD_ROUTER 0x82 130 | 131 | /* fields for tr_rproto (routing protocol) */ 132 | #define PROTO_DVMRP 1 133 | #define PROTO_MOSPF 2 134 | #define PROTO_PIM 3 135 | #define PROTO_CBT 4 136 | 137 | #define MASK_TO_VAL(x, i) { \ 138 | uint32_t _x = ntohl(x); \ 139 | (i) = 1; \ 140 | while ((_x) <<= 1) \ 141 | (i)++; \ 142 | } 143 | 144 | #define VAL_TO_MASK(x, i) \ 145 | x = i ? htonl(~((1 << (32 - (i))) - 1)) : 0 146 | 147 | #define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv) 148 | 149 | #endif /* MROUTED_PRUNE_H_ */ 150 | -------------------------------------------------------------------------------- /man/mrinfo.8: -------------------------------------------------------------------------------- 1 | .\" $OpenBSD: mrinfo.8,v 1.12 2007/05/31 19:20:25 jmc Exp $ 2 | .\" $NetBSD: mrinfo.8,v 1.2 1995/10/03 23:20:39 thorpej Exp $ 3 | .\" 4 | .\" Written Wed Mar 24 1993 by Van Jacobson (adapted from the 5 | .\" multicast mapper written by Pavel Curtis). 6 | .\" 7 | .\" The lawyers insist we include the following UC copyright notice. 8 | .\" The mapper from which this is derived contained a Xerox copyright 9 | .\" notice which follows the UC one. Try not to get depressed noting 10 | .\" that the legal gibberish is larger than the program. 11 | .\" 12 | .\" Copyright (c) 1993 Regents of the University of California. 13 | .\" All rights reserved. 14 | .\" 15 | .\" Redistribution and use in source and binary forms, with or without 16 | .\" modification, are permitted provided that the following conditions 17 | .\" are met: 18 | .\" 1. Redistributions of source code must retain the above copyright 19 | .\" notice, this list of conditions and the following disclaimer. 20 | .\" 2. Redistributions in binary form must reproduce the above copyright 21 | .\" notice, this list of conditions and the following disclaimer in the 22 | .\" documentation and/or other materials provided with the distribution. 23 | .\" 3. All advertising materials mentioning features or use of this software 24 | .\" must display the following acknowledgement: 25 | .\" This product includes software developed by the Computer Systems 26 | .\" Engineering Group at Lawrence Berkeley Laboratory. 27 | .\" 4. Neither the name of the University nor of the Laboratory may be used 28 | .\" to endorse or promote products derived from this software without 29 | .\" specific prior written permission. 30 | .\" 31 | .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 32 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 35 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 | .\" SUCH DAMAGE. 42 | .\" --------------------------------- 43 | .\" Copyright (c) 1992, 2001 Xerox Corporation. All rights reserved. 44 | .\" 45 | .\" Redistribution and use in source and binary forms, with or without 46 | .\" modification, are permitted provided that the following conditions are met: 47 | .\" 48 | .\" Redistributions of source code must retain the above copyright notice, 49 | .\" this list of conditions and the following disclaimer. 50 | .\" 51 | .\" Redistributions in binary form must reproduce the above copyright notice, 52 | .\" this list of conditions and the following disclaimer in the documentation 53 | .\" and/or other materials provided with the distribution. 54 | .\" 55 | .\" Neither name of the Xerox, PARC, nor the names of its contributors may be 56 | .\" used to endorse or promote products derived from this software 57 | .\" without specific prior written permission. 58 | .\" 59 | .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 60 | .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 61 | .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 62 | .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR 63 | .\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 64 | .\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 65 | .\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 66 | .\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 67 | .\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 68 | .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 69 | .\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 70 | .\" 71 | .Dd $Mdocdate: May 31 2007 $ 72 | .Dt MRINFO 8 SMM 73 | .Os 74 | .Sh NAME 75 | .Nm mrinfo 76 | .Nd displays configuration info from a multicast router 77 | .Sh SYNOPSIS 78 | .Nm mrinfo 79 | .Op Fl hn 80 | .Op Fl d Ar level 81 | .Op Fl r Ar count 82 | .Op Fl t Ar seconds 83 | .Ar router 84 | .Sh DESCRIPTION 85 | .Nm 86 | attempts to display the configuration information from the specified multicast capable 87 | .Ar router . 88 | .Pp 89 | .Nm 90 | uses the ASK_NEIGHBORS IGMP message to query the specified multicast 91 | router. 92 | If the router responds, the version number and a list of their 93 | neighboring multicast router addresses is part of the response. 94 | If the responding router has a recent multicast version number, then 95 | .Nm 96 | requests additional information such as metrics, thresholds, 97 | and flags from the multicast router. 98 | Once the specified multicast router responds, 99 | the configuration is displayed to the standard output. 100 | .Pp 101 | The options are as follows: 102 | .Bl -tag -width timeout_levelxyz 103 | .It Fl h 104 | Print a help message and exit. 105 | .It Fl n 106 | Use numerical address instead of a symbolic host name. 107 | .It Fl d Ar level 108 | sets the debug level. 109 | When the debug level is greater than the default value of 0, 110 | additional debugging messages are printed. 111 | Regardless of the debug level, 112 | an error condition will always write an error message and cause 113 | .Nm 114 | to terminate. 115 | Non-zero debug levels have the following effects (printed to stderr): 116 | .Pp 117 | .Bl -tag -width 1n -compact -offset indent 118 | .It 1 119 | packet warnings. 120 | .It 2 121 | all level 1 messages plus notifications of down networks. 122 | .It 3 123 | all level 2 messages plus notifications of all packet timeouts. 124 | .El 125 | .It Fl r Ar count 126 | sets the neighbor query retry count limit. 127 | The default is to do 3 retries. 128 | .It Fl t Ar seconds 129 | sets the timeout in number of seconds to wait for a neighbor query reply. 130 | The default timeout is 4 seconds. 131 | .El 132 | .Sh EXAMPLES 133 | .Bd -literal 134 | # mrinfo mbone.phony.dom.net 135 | 127.148.176.10 (mbone.phony.dom.net) [version 3.3]: 136 | 127.148.176.10 -> 0.0.0.0 (?) [1/1/querier] 137 | 127.148.176.10 -> 127.0.8.4 (mbone2.phony.dom.net) [1/45/tunnel] 138 | 127.148.176.10 -> 105.1.41.9 (momoney.com) [1/32/tunnel/down] 139 | 127.148.176.10 -> 143.192.152.119 (mbone.dipu.edu) [1/32/tunnel] 140 | .Ed 141 | .Pp 142 | For each neighbor of the queried multicast router, the IP of the queried router 143 | is displayed, followed by the IP and name of the neighbor. 144 | In square brackets the metric (cost of connection) 145 | and threshold (multicast ttl) is displayed. 146 | If the queried multicast router has a newer version number, the type (tunnel, 147 | srcrt) and status (disabled, down) of the connection is displayed. 148 | .Sh SEE ALSO 149 | .Xr map-mbone 8 , 150 | .Xr mrouted 8 , 151 | .Xr mtrace 8 152 | .Sh AUTHORS 153 | .An Van Jacobson 154 | -------------------------------------------------------------------------------- /src/inet.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include "defs.h" 14 | 15 | /* 16 | * Exported variables. 17 | */ 18 | char s1[MAX_INET_BUF_LEN]; /* buffers to hold the string representations */ 19 | char s2[MAX_INET_BUF_LEN]; /* of IP addresses, to be passed to inet_fmt() */ 20 | char s3[MAX_INET_BUF_LEN]; /* or inet_fmts(). */ 21 | char s4[MAX_INET_BUF_LEN]; 22 | 23 | 24 | /* 25 | * Verify that a given IP address is a valid multigast group 26 | */ 27 | int inet_valid_group(uint32_t naddr) 28 | { 29 | uint32_t addr; 30 | 31 | addr = ntohl(naddr); 32 | 33 | return IN_MULTICAST(addr); 34 | } 35 | 36 | /* 37 | * Verify that a given IP address is credible as a host address. 38 | * (Without a mask, cannot detect addresses of the form {subnet,0} or 39 | * {subnet,-1}.) 40 | */ 41 | int inet_valid_host(uint32_t naddr) 42 | { 43 | uint32_t addr; 44 | 45 | addr = ntohl(naddr); 46 | 47 | return (!(IN_MULTICAST(addr) || 48 | IN_BADCLASS (addr) || 49 | (addr & 0xff000000) == 0)); 50 | } 51 | 52 | /* 53 | * Verify that a given netmask is plausible; 54 | * make sure that it is a series of 1's followed by 55 | * a series of 0's with no discontiguous 1's. 56 | */ 57 | int inet_valid_mask(uint32_t mask) 58 | { 59 | if (~(((mask & -mask) - 1) | mask) != 0) { 60 | /* Mask is not contiguous */ 61 | return FALSE; 62 | } 63 | 64 | return TRUE; 65 | } 66 | 67 | /* 68 | * Verify that a given subnet number and mask pair are credible. 69 | * 70 | * With CIDR, almost any subnet and mask are credible. mrouted still 71 | * can't handle aggregated class A's, so we still check that, but 72 | * otherwise the only requirements are that the subnet address is 73 | * within the [ABC] range and that the host bits of the subnet 74 | * are all 0. 75 | */ 76 | int inet_valid_subnet(uint32_t nsubnet, uint32_t nmask) 77 | { 78 | uint32_t subnet, mask; 79 | 80 | subnet = ntohl(nsubnet); 81 | mask = ntohl(nmask); 82 | 83 | if ((subnet & mask) != subnet) 84 | return FALSE; 85 | 86 | if (subnet == 0) 87 | return mask == 0; 88 | 89 | if (IN_CLASSA(subnet)) { 90 | if (mask < 0xff000000 || 91 | (subnet & 0xff000000) == 0x7f000000 || 92 | (subnet & 0xff000000) == 0x00000000) 93 | return FALSE; 94 | } else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) { 95 | /* Above Class C address space */ 96 | return FALSE; 97 | } 98 | 99 | if (subnet & ~mask) { 100 | /* Host bits are set in the subnet */ 101 | return FALSE; 102 | } 103 | 104 | if (!inet_valid_mask(mask)) { 105 | /* Netmask is not contiguous */ 106 | return FALSE; 107 | } 108 | 109 | return TRUE; 110 | } 111 | 112 | 113 | /* 114 | * Convert an IP address to name 115 | */ 116 | char *inet_name(uint32_t addr, int numeric) 117 | { 118 | static char host[NI_MAXHOST]; 119 | struct sockaddr_in sin; 120 | struct sockaddr *sa; 121 | struct in_addr in; 122 | int rc; 123 | 124 | if (addr == 0) 125 | return "local"; 126 | 127 | if (numeric) { 128 | in.s_addr = addr; 129 | return inet_ntoa(in); 130 | } 131 | 132 | sin.sin_family = AF_INET; 133 | sin.sin_addr.s_addr = addr; 134 | sa = (struct sockaddr *)&sin; 135 | 136 | rc = getnameinfo(sa, sizeof(sin), host, sizeof(host), NULL, 0, 0); 137 | if (rc) 138 | return NULL; 139 | 140 | return host; 141 | } 142 | 143 | 144 | /* 145 | * Convert an IP address in uint32_t (network) format into a printable string. 146 | */ 147 | char *inet_fmt(uint32_t addr, char *s, size_t len) 148 | { 149 | uint8_t *a; 150 | 151 | a = (uint8_t *)&addr; 152 | snprintf(s, len, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); 153 | 154 | return s; 155 | } 156 | 157 | 158 | /* 159 | * Convert an IP subnet number in uint32_t (network) format into a printable 160 | * string including the netmask as a number of bits. 161 | */ 162 | char *inet_fmts(uint32_t addr, uint32_t mask, char *s, size_t len) 163 | { 164 | uint8_t *a, *m; 165 | int bits; 166 | 167 | if ((addr == 0) && (mask == 0)) { 168 | snprintf(s, len, "default"); 169 | return s; 170 | } 171 | a = (uint8_t *)&addr; 172 | m = (uint8_t *)&mask; 173 | bits = 33 - ffs(ntohl(mask)); 174 | 175 | if (m[3] != 0) snprintf(s, len, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3], 176 | bits); 177 | else if (m[2] != 0) snprintf(s, len, "%u.%u.%u/%d", a[0], a[1], a[2], bits); 178 | else if (m[1] != 0) snprintf(s, len, "%u.%u/%d", a[0], a[1], bits); 179 | else snprintf(s, len, "%u/%d", a[0], bits); 180 | 181 | return s; 182 | } 183 | 184 | /* 185 | * Convert the printable string representation of an IP address into the 186 | * uint32_t (network) format. Return 0xffffffff on error. (To detect the 187 | * legal address with that value, you must explicitly compare the string 188 | * with "255.255.255.255".) 189 | */ 190 | uint32_t inet_parse(char *s, int n) 191 | { 192 | uint32_t a = 0; 193 | uint32_t a0 = 0, a1 = 0, a2 = 0, a3 = 0; 194 | int i; 195 | char c; 196 | 197 | i = sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c); 198 | if (i < n || i > 4 || a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255) 199 | return 0xffffffff; 200 | 201 | ((uint8_t *)&a)[0] = a0; 202 | ((uint8_t *)&a)[1] = a1; 203 | ((uint8_t *)&a)[2] = a2; 204 | ((uint8_t *)&a)[3] = a3; 205 | 206 | return a; 207 | } 208 | 209 | 210 | /* 211 | * inet_cksum extracted from: 212 | * P I N G . C 213 | * 214 | * Author - 215 | * Mike Muuss 216 | * U. S. Army Ballistic Research Laboratory 217 | * December, 1983 218 | * Modified at Uc Berkeley 219 | * 220 | * (ping.c) Status - 221 | * Public Domain. Distribution Unlimited. 222 | * 223 | * I N _ C K S U M 224 | * 225 | * Checksum routine for Internet Protocol family headers (C Version) 226 | * 227 | */ 228 | uint16_t inet_cksum(uint16_t *addr, uint32_t len) 229 | { 230 | int nleft = (int)len; 231 | uint16_t *w = addr; 232 | uint16_t answer = 0; 233 | uint32_t sum = 0; 234 | 235 | /* 236 | * Our algorithm is simple, using a 32 bit accumulator (sum), 237 | * we add sequential 16 bit words to it, and at the end, fold 238 | * back all the carry bits from the top 16 bits into the lower 239 | * 16 bits. 240 | */ 241 | while (nleft > 1) { 242 | sum += *w++; 243 | nleft -= 2; 244 | } 245 | 246 | /* mop up an odd byte, if necessary */ 247 | if (nleft == 1) { 248 | *(uint8_t *) (&answer) = *(uint8_t *)w ; 249 | sum += answer; 250 | } 251 | 252 | /* 253 | * add back carry outs from top 16 bits to low 16 bits 254 | */ 255 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 256 | sum += (sum >> 16); /* add carry */ 257 | return (uint16_t)~sum; /* truncate to 16 bits */ 258 | } 259 | 260 | /** 261 | * Local Variables: 262 | * indent-tabs-mode: t 263 | * c-file-style: "cc-mode" 264 | * End: 265 | */ 266 | -------------------------------------------------------------------------------- /src/icmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | 10 | #include "defs.h" 11 | 12 | static int icmp_socket; 13 | static int sock_id; 14 | 15 | static void icmp_handler(int, void *); 16 | static char * icmp_name(struct icmp *); 17 | 18 | void init_icmp(void) 19 | { 20 | if ((icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) 21 | logit(LOG_ERR, errno, "ICMP socket"); 22 | 23 | sock_id = pev_sock_add(icmp_socket, icmp_handler, NULL); 24 | 25 | IF_DEBUG(DEBUG_ICMP) 26 | logit(LOG_DEBUG, 0, "registering icmp socket fd %d", icmp_socket); 27 | } 28 | 29 | static void icmp_handler(int fd, void *arg) 30 | { 31 | uint8_t icmp_buf[RECV_BUF_SIZE]; 32 | struct sockaddr_in from; 33 | socklen_t fromlen = sizeof(from); 34 | int iphdrlen, ipdatalen; 35 | struct icmp *icmp; 36 | struct uvif *uv; 37 | struct ip *ip; 38 | uint32_t src; 39 | ssize_t len; 40 | vifi_t vifi; 41 | 42 | memset(icmp_buf, 0, sizeof(icmp_buf)); 43 | while ((len = recvfrom(fd, icmp_buf, sizeof(icmp_buf), 0, (struct sockaddr *)&from, &fromlen)) < 0) { 44 | if (errno == EINTR) 45 | continue; 46 | 47 | logit(LOG_WARNING, errno, "ICMP"); 48 | return; 49 | } 50 | 51 | ip = (struct ip *)icmp_buf; 52 | iphdrlen = ip->ip_hl << 2; 53 | 54 | /* Sanity check resulting header size */ 55 | if (iphdrlen > 60) { 56 | logit(LOG_WARNING, 0, "Received an invadlid ICMP frame."); 57 | return; 58 | } 59 | 60 | #ifdef HAVE_IP_HDRINCL_BSD_ORDER 61 | ipdatalen = ip->ip_len - iphdrlen; 62 | #else 63 | ipdatalen = ntohs(ip->ip_len) - iphdrlen; 64 | #endif 65 | 66 | if (iphdrlen + ipdatalen != len) { 67 | /* Malformed ICMP, just return. */ 68 | IF_DEBUG(DEBUG_ICMP) { 69 | logit(LOG_DEBUG, 0, "hdr %d data %d != rcv %zd", iphdrlen, ipdatalen, len); 70 | } 71 | 72 | return; 73 | } 74 | 75 | if (ipdatalen < ICMP_MINLEN + (int)sizeof(struct ip)) { 76 | /* Not enough data for us to be interested in it. */ 77 | return; 78 | } 79 | 80 | src = ip->ip_src.s_addr; 81 | icmp = (struct icmp *)(icmp_buf + iphdrlen); 82 | IF_DEBUG(DEBUG_ICMP) { 83 | logit(LOG_DEBUG, 0, "got ICMP type %d from %s", 84 | icmp->icmp_type, inet_fmt(src, s1, sizeof(s1))); 85 | } 86 | 87 | /* 88 | * Eventually: 89 | * have registry of ICMP listeners, by type, code and ICMP_ID 90 | * (and maybe fields of the original packet too -- maybe need a 91 | * generalized packet filter!) to allow ping and traceroute 92 | * from the monitoring tool. 93 | */ 94 | switch (icmp->icmp_type) { 95 | case ICMP_UNREACH: 96 | case ICMP_TIMXCEED: 97 | /* Look at returned packet to see if it's us sending on a tunnel */ 98 | ip = &icmp->icmp_ip; 99 | if (ip->ip_p != IPPROTO_IGMP && ip->ip_p != IPPROTO_IPIP) 100 | return; 101 | 102 | UVIF_FOREACH(vifi, uv) { 103 | if (ip->ip_src.s_addr == uv->uv_lcl_addr && 104 | ip->ip_dst.s_addr == uv->uv_dst_addr) { 105 | char *p; 106 | int n; 107 | /* 108 | * I sent this packet on this vif. 109 | */ 110 | n = ++uv->uv_icmp_warn; 111 | while (n && !(n & 1)) 112 | n >>= 1; 113 | if (n == 1 && ((p = icmp_name(icmp)) != NULL)) 114 | logit(LOG_WARNING, 0, "Received ICMP %s from %s %s %s on vif %d", 115 | p, inet_fmt(src, s1, sizeof(s1)), "for traffic sent to", 116 | inet_fmt(ip->ip_dst.s_addr, s2, sizeof(s2)), 117 | vifi); 118 | 119 | break; 120 | } 121 | } 122 | break; 123 | } 124 | } 125 | 126 | /* 127 | * Return NULL for ICMP informational messages. 128 | * Return string describing the error for ICMP errors. 129 | */ 130 | static char *icmp_name(struct icmp *icmp) 131 | { 132 | static char retval[30]; 133 | 134 | switch (icmp->icmp_type) { 135 | case ICMP_UNREACH: 136 | switch (icmp->icmp_code) { 137 | case ICMP_UNREACH_NET: 138 | return "network unreachable"; 139 | case ICMP_UNREACH_HOST: 140 | return "host unreachable"; 141 | case ICMP_UNREACH_PROTOCOL: 142 | return "protocol unreachable"; 143 | case ICMP_UNREACH_PORT: 144 | return "port unreachable"; 145 | case ICMP_UNREACH_NEEDFRAG: 146 | return "needs fragmentation"; 147 | case ICMP_UNREACH_SRCFAIL: 148 | return "source route failed"; 149 | #ifndef ICMP_UNREACH_NET_UNKNOWN 150 | #define ICMP_UNREACH_NET_UNKNOWN 6 151 | #endif 152 | case ICMP_UNREACH_NET_UNKNOWN: 153 | return "network unknown"; 154 | #ifndef ICMP_UNREACH_HOST_UNKNOWN 155 | #define ICMP_UNREACH_HOST_UNKNOWN 7 156 | #endif 157 | case ICMP_UNREACH_HOST_UNKNOWN: 158 | return "host unknown"; 159 | #ifndef ICMP_UNREACH_ISOLATED 160 | #define ICMP_UNREACH_ISOLATED 8 161 | #endif 162 | case ICMP_UNREACH_ISOLATED: 163 | return "source host isolated"; 164 | #ifndef ICMP_UNREACH_NET_PROHIB 165 | #define ICMP_UNREACH_NET_PROHIB 9 166 | #endif 167 | case ICMP_UNREACH_NET_PROHIB: 168 | return "network access prohibited"; 169 | #ifndef ICMP_UNREACH_HOST_PROHIB 170 | #define ICMP_UNREACH_HOST_PROHIB 10 171 | #endif 172 | case ICMP_UNREACH_HOST_PROHIB: 173 | return "host access prohibited"; 174 | #ifndef ICMP_UNREACH_TOSNET 175 | #define ICMP_UNREACH_TOSNET 11 176 | #endif 177 | case ICMP_UNREACH_TOSNET: 178 | return "bad TOS for net"; 179 | #ifndef ICMP_UNREACH_TOSHOST 180 | #define ICMP_UNREACH_TOSHOST 12 181 | #endif 182 | case ICMP_UNREACH_TOSHOST: 183 | return "bad TOS for host"; 184 | #ifndef ICMP_UNREACH_FILTER_PROHIB 185 | #define ICMP_UNREACH_FILTER_PROHIB 13 186 | #endif 187 | case ICMP_UNREACH_FILTER_PROHIB: 188 | return "prohibited by filter"; 189 | #ifndef ICMP_UNREACH_HOST_PRECEDENCE 190 | #define ICMP_UNREACH_HOST_PRECEDENCE 14 191 | #endif 192 | case ICMP_UNREACH_HOST_PRECEDENCE: 193 | return "host precedence violation"; 194 | #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF 195 | #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 196 | #endif 197 | case ICMP_UNREACH_PRECEDENCE_CUTOFF: 198 | return "precedence cutoff"; 199 | default: 200 | snprintf(retval, sizeof(retval), "unreachable code %d", icmp->icmp_code); 201 | return retval; 202 | } 203 | case ICMP_SOURCEQUENCH: 204 | return "source quench"; 205 | case ICMP_REDIRECT: 206 | return NULL; /* XXX */ 207 | case ICMP_TIMXCEED: 208 | switch (icmp->icmp_code) { 209 | case ICMP_TIMXCEED_INTRANS: 210 | return "time exceeded in transit"; 211 | case ICMP_TIMXCEED_REASS: 212 | return "time exceeded in reassembly"; 213 | default: 214 | snprintf(retval, sizeof(retval), "time exceeded code %d", icmp->icmp_code); 215 | return retval; 216 | } 217 | case ICMP_PARAMPROB: 218 | switch (icmp->icmp_code) { 219 | #ifndef ICMP_PARAMPROB_OPTABSENT 220 | #define ICMP_PARAMPROB_OPTABSENT 1 221 | #endif 222 | case ICMP_PARAMPROB_OPTABSENT: 223 | return "required option absent"; 224 | default: 225 | snprintf(retval, sizeof(retval), "parameter problem code %d", icmp->icmp_code); 226 | return retval; 227 | } 228 | } 229 | return NULL; 230 | } 231 | 232 | /** 233 | * Local Variables: 234 | * indent-tabs-mode: t 235 | * c-file-style: "cc-mode" 236 | * End: 237 | */ 238 | -------------------------------------------------------------------------------- /src/dvmrp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | * 9 | * 10 | * dvmrp.h,v 3.8.4.5 1997/11/18 23:25:57 fenner Exp 11 | */ 12 | 13 | /* 14 | * A DVMRP message consists of an IP header + an IGMP header + (for some types) 15 | * zero or more bytes of data. 16 | * 17 | * For REPORT messages, the data is route information; the route information 18 | * consists of one or more lists of the following form: 19 | * 20 | * (mask, (origin, metric), (origin, metric), ...) 21 | * 22 | * where: 23 | * 24 | * "mask" is the subnet mask for all the origins in the list. 25 | * It is always THREE bytes long, containing the low-order 26 | * three bytes of the mask (the high-order byte is always 27 | * 0xff and therefore need not be transmitted). 28 | * 29 | * "origin" is the number of a subnet from which multicast datagrams 30 | * may originate. It is from one to four bytes long, 31 | * depending on the value of "mask": 32 | * if all bytes of the mask are zero 33 | * the subnet number is one byte long 34 | * else if the low-order two bytes of the mask are zero 35 | * the subnet number is two bytes long 36 | * else if the lowest-order byte of the mask is zero 37 | * the subnet number is three bytes long, 38 | * else 39 | * the subnet number is four bytes long. 40 | * 41 | * "metric" is a one-byte value consisting of two subfields: 42 | * - the high-order bit is a flag which, when set, indicates 43 | * the last (origin, metric) pair of a list. 44 | * - the low-order seven bits contain the routing metric for 45 | * the corresponding origin, relative to the sender of the 46 | * DVMRP report. The metric may have the value of UNREACHABLE 47 | * added to it as a "split horizon" indication (so called 48 | * "poisoned reverse"). 49 | * 50 | * Within a list, the origin subnet numbers must be in ascending order, and 51 | * the lists themselves are in order of increasing mask value. A message may 52 | * not exceed 576 bytes, the default maximum IP reassembly size, including 53 | * the IP and IGMP headers; the route information may be split across more 54 | * than one message if necessary, by terminating a list in one message and 55 | * starting a new list in the next message (repeating the same mask value, 56 | * if necessary). 57 | * 58 | * For NEIGHBORS messages, the data is neighboring-router information 59 | * consisting of one or more lists of the following form: 60 | * 61 | * (local-addr, metric, threshold, ncount, neighbor, neighbor, ...) 62 | * 63 | * where: 64 | * 65 | * "local-addr" is the sending router's address as seen by the neighbors 66 | * in this list; it is always four bytes long. 67 | * "metric" is a one-byte unsigned value, the TTL `cost' of forwarding 68 | * packets to any of the neighbors on this list. 69 | * "threshold" is a one-byte unsigned value, a lower bound on the TTL a 70 | * packet must have to be forwarded to any of the neighbors on 71 | * this list. 72 | * "ncount" is the number of neighbors in this list. 73 | * "neighbor" is the address of a neighboring router, four bytes long. 74 | * 75 | * As with REPORT messages, NEIGHBORS messages should not exceed 576 bytes, 76 | * including the IP and IGMP headers; split longer messages by terminating the 77 | * list in one and continuing in another, repeating the local-addr, etc., if 78 | * necessary. 79 | * 80 | * For NEIGHBORS2 messages, the data is identical to NEIGHBORS except 81 | * there is a flags byte before the neighbor count: 82 | * 83 | * (local-addr, metric, threshold, flags, ncount, neighbor, neighbor, ...) 84 | */ 85 | 86 | /* 87 | * DVMRP message types (carried in the "code" field of an IGMP header) 88 | */ 89 | #define DVMRP_PROBE 1 /* for finding neighbors */ 90 | #define DVMRP_REPORT 2 /* for reporting some or all routes */ 91 | #define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */ 92 | /* of this router's neighbors. */ 93 | #define DVMRP_NEIGHBORS 4 /* response to such a request */ 94 | #define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */ 95 | #define DVMRP_NEIGHBORS2 6 96 | #define DVMRP_PRUNE 7 /* prune message */ 97 | #define DVMRP_GRAFT 8 /* graft message */ 98 | #define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */ 99 | #define DVMRP_INFO_REQUEST 10 /* information request */ 100 | #define DVMRP_INFO_REPLY 11 /* information reply */ 101 | 102 | /* 103 | * 'flags' byte values in DVMRP_NEIGHBORS2 reply. 104 | */ 105 | #define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */ 106 | #define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */ 107 | #define DVMRP_NF_PIM 0x04 /* neighbor is a PIM neighbor */ 108 | #define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ 109 | #define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ 110 | #define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */ 111 | #define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */ 112 | 113 | /* 114 | * Request/reply types for info queries/replies 115 | */ 116 | #define DVMRP_INFO_VERSION 1 /* version string */ 117 | #define DVMRP_INFO_NEIGHBORS 2 /* neighbors2 data */ 118 | 119 | /* 120 | * Limit on length of route data 121 | */ 122 | #define MAX_IP_PACKET_LEN 576 123 | #define MIN_IP_HEADER_LEN 20 124 | #define IP_HEADER_RAOPT_LEN (router_alert ? 24 : 20) 125 | #define MAX_IP_HEADER_LEN 60 126 | #define MAX_DVMRP_DATA_LEN \ 127 | ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN ) 128 | 129 | /* 130 | * Various protocol constants (all times in seconds) 131 | */ 132 | 133 | /* NetBSD 6.1, for instance, does not have IPOPT_RA defined. */ 134 | #ifndef IPOPT_RA 135 | #define IPOPT_RA 148 136 | #endif 137 | /* address for multicast DVMRP msgs */ 138 | #define INADDR_DVMRP_GROUP (uint32_t)0xe0000004 /* 224.0.0.4 */ 139 | /* 140 | * The IGMPv2 defines INADDR_ALLRTRS_GROUP, but earlier 141 | * ones don't, so we define it conditionally here. 142 | */ 143 | #ifndef INADDR_ALLRTRS_GROUP 144 | /* address for multicast mtrace msg */ 145 | #define INADDR_ALLRTRS_GROUP (uint32_t)0xe0000002 /* 224.0.0.2 */ 146 | #endif 147 | 148 | #ifndef INADDR_ALLRPTS_GROUP 149 | #define INADDR_ALLRPTS_GROUP ((in_addr_t)0xe0000016) /* 224.0.0.22, IGMPv3 */ 150 | #endif 151 | 152 | #ifndef INADDR_MAX_LOCAL_GROUP 153 | #define INADDR_MAX_LOCAL_GROUP (uint32_t)0xe00000ff /* 224.0.0.255 */ 154 | #endif 155 | 156 | #define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */ 157 | /* (This is the timer interrupt */ 158 | /* interval; all times must be */ 159 | /* multiples of this value.) */ 160 | 161 | #define ROUTE_REPORT_INTERVAL 60 /* periodic route report interval */ 162 | #define ROUTE_SWITCH_TIME 140 /* time to switch to equivalent gw */ 163 | #define ROUTE_EXPIRE_TIME 200 /* time to mark route invalid */ 164 | #define ROUTE_DISCARD_TIME 340 /* time to garbage collect route */ 165 | 166 | #define LEAF_CONFIRMATION_TIME 200 /* time to consider subnet a leaf */ 167 | 168 | #define NEIGHBOR_PROBE_INTERVAL 10 /* periodic neighbor probe interval */ 169 | #define NEIGHBOR_EXPIRE_TIME 30 /* time to consider neighbor gone */ 170 | #define OLD_NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */ 171 | 172 | #define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */ 173 | #define DEFAULT_METRIC 1 /* default subnet/tunnel metric */ 174 | #define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */ 175 | 176 | #define MAX_RATE_LIMIT 100000 /* max rate limit */ 177 | #define DEFAULT_PHY_RATE_LIMIT 0 /* default phyint rate limit */ 178 | #define DEFAULT_TUN_RATE_LIMIT 0 /* default tunnel rate limit */ 179 | 180 | #define DEFAULT_CACHE_LIFETIME 300 /* kernel route entry discard time */ 181 | #define MIN_CACHE_LIFETIME 60 /* minimum allowed cache lifetime */ 182 | #define AVERAGE_PRUNE_LIFETIME 7200 /* average lifetime of prunes sent */ 183 | #define MIN_PRUNE_LIFETIME 120 /* minimum allowed prune lifetime */ 184 | #define GRAFT_TIMEOUT_VAL 5 /* retransmission time for grafts */ 185 | #define PRUNE_REXMIT_VAL 3 /* initial time for prune rexmission*/ 186 | -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The mrouted program is covered by the license in the accompanying file 3 | * named "LICENSE". Use of the mrouted program represents acceptance of 4 | * the terms and conditions listed in that file. 5 | * 6 | * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | * Leland Stanford Junior University. 8 | */ 9 | 10 | #include 11 | #include "defs.h" 12 | 13 | static TAILQ_HEAD(, uvif) vifs = TAILQ_HEAD_INITIALIZER(vifs); 14 | 15 | void config_set_ifflag(uint32_t flag) 16 | { 17 | struct uvif *uv; 18 | 19 | TAILQ_FOREACH(uv, &vifs, uv_link) 20 | uv->uv_flags |= flag; 21 | } 22 | 23 | struct uvif *config_find_ifname(char *nm) 24 | { 25 | struct uvif *uv; 26 | 27 | if (!nm) { 28 | errno = EINVAL; 29 | return NULL; 30 | } 31 | 32 | TAILQ_FOREACH(uv, &vifs, uv_link) { 33 | if (!strcmp(uv->uv_name, nm)) 34 | return uv; 35 | } 36 | 37 | return NULL; 38 | } 39 | 40 | struct uvif *config_find_ifaddr(in_addr_t addr) 41 | { 42 | struct uvif *uv; 43 | 44 | TAILQ_FOREACH(uv, &vifs, uv_link) { 45 | if (!(uv->uv_flags & VIFF_TUNNEL) && addr == uv->uv_lcl_addr) 46 | return uv; 47 | } 48 | 49 | return NULL; 50 | } 51 | 52 | struct uvif *config_init_tunnel(in_addr_t lcl_addr, in_addr_t rmt_addr, uint32_t flags) 53 | { 54 | const char *ifname; 55 | struct ifreq ifr; 56 | struct uvif *uv; 57 | 58 | uv = config_find_ifaddr(lcl_addr); 59 | if (!uv) { 60 | errno = ENOTMINE; 61 | return NULL; 62 | } 63 | ifname = uv->uv_name; 64 | 65 | if (((ntohl(lcl_addr) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { 66 | errno = ELOOPBACK; 67 | return NULL; 68 | } 69 | 70 | if (config_find_ifaddr(rmt_addr)) { 71 | errno = ERMTLOCAL; 72 | return NULL; 73 | } 74 | 75 | TAILQ_FOREACH(uv, &vifs, uv_link) { 76 | if (uv->uv_flags & VIFF_DISABLED) 77 | continue; 78 | 79 | if (uv->uv_flags & VIFF_TUNNEL) { 80 | if (rmt_addr == uv->uv_rmt_addr) { 81 | errno = EDUPLICATE; 82 | return NULL; 83 | } 84 | 85 | continue; 86 | } 87 | 88 | if ((rmt_addr & uv->uv_subnetmask) == uv->uv_subnet) { 89 | logit(LOG_INFO, 0, 90 | "Unnecessary tunnel to %s, same subnet as interface %s", 91 | inet_fmt(rmt_addr, s1, sizeof(s1)), uv->uv_name); 92 | return NULL; 93 | } 94 | } 95 | 96 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 97 | if (ioctl(udp_socket, SIOCGIFFLAGS, &ifr) < 0) { 98 | logit(LOG_INFO, errno, "failed SIOCGIFFLAGS on %s", ifr.ifr_name); 99 | return NULL; 100 | } 101 | 102 | uv = calloc(1, sizeof(struct uvif)); 103 | if (!uv) { 104 | logit(LOG_ERR, errno, "failed allocating memory for iflist"); 105 | return NULL; 106 | } 107 | 108 | zero_vif(uv, 1); 109 | uv->uv_flags = VIFF_TUNNEL | flags; 110 | uv->uv_flags |= VIFF_OTUNNEL; /* XXX */ 111 | uv->uv_lcl_addr = lcl_addr; 112 | uv->uv_rmt_addr = rmt_addr; 113 | uv->uv_dst_addr = rmt_addr; 114 | strlcpy(uv->uv_name, ifr.ifr_name, sizeof(uv->uv_name)); 115 | 116 | uv->uv_ifindex = if_nametoindex(uv->uv_name); 117 | if (!uv->uv_ifindex) 118 | logit(LOG_ERR, errno, "Failed reading ifindex for %s", uv->uv_name); 119 | 120 | if (!(ifr.ifr_flags & IFF_UP)) { 121 | uv->uv_flags |= VIFF_DOWN; 122 | vifs_down = TRUE; 123 | } 124 | 125 | TAILQ_INSERT_TAIL(&vifs, uv, uv_link); 126 | 127 | return uv; 128 | } 129 | 130 | /* 131 | * Ignore any kernel interface that is disabled, or connected to the 132 | * same subnet as one already installed in the uvifs[] array. 133 | */ 134 | static vifi_t check_vif(struct uvif *v) 135 | { 136 | struct uvif *uv; 137 | vifi_t vifi; 138 | 139 | UVIF_FOREACH(vifi, uv) { 140 | if (v->uv_flags & VIFF_TUNNEL) 141 | continue; 142 | 143 | if (v->uv_flags & VIFF_DISABLED) { 144 | logit(LOG_DEBUG, 0, "Skipping %s, disabled", v->uv_name); 145 | return NO_VIF; 146 | } 147 | 148 | if ((v->uv_lcl_addr & uv->uv_subnetmask) == uv->uv_subnet || 149 | (uv->uv_subnet & v->uv_subnetmask) == v->uv_subnet) { 150 | logit(LOG_WARNING, 0, "ignoring %s, same subnet as %s", 151 | v->uv_name, uv->uv_name); 152 | return NO_VIF; 153 | } 154 | 155 | /* 156 | * Same interface, but cannot have multiple VIFs on the same 157 | * interface so add as secondary IP address (altnet) for RPF 158 | */ 159 | if (strcmp(v->uv_name, uv->uv_name) == 0) { 160 | struct phaddr *ph; 161 | 162 | ph = calloc(1, sizeof(*ph)); 163 | if (!ph) { 164 | logit(LOG_ERR, errno, "Failed allocating altnet on %s", uv->uv_name); 165 | break; 166 | } 167 | 168 | logit(LOG_INFO, 0, "Installing %s subnet %s as an altnet on %s", 169 | v->uv_name, 170 | inet_fmts(v->uv_subnet, v->uv_subnetmask, s2, sizeof(s2)), 171 | uv->uv_name); 172 | 173 | ph->pa_subnet = v->uv_subnet; 174 | ph->pa_subnetmask = v->uv_subnetmask; 175 | ph->pa_subnetbcast = v->uv_subnetbcast; 176 | 177 | ph->pa_next = uv->uv_addrs; 178 | uv->uv_addrs = ph; 179 | return NO_VIF; 180 | } 181 | } 182 | 183 | return vifi; 184 | } 185 | 186 | void config_vifs_correlate(void) 187 | { 188 | struct listaddr *al, *al_tmp; 189 | struct uvif *uv, *v, *tmp; 190 | vifi_t vifi; 191 | 192 | TAILQ_FOREACH_SAFE(v, &vifs, uv_link, tmp) { 193 | vifi = check_vif(v); 194 | if (vifi == NO_VIF || install_uvif(v)) { 195 | TAILQ_REMOVE(&vifs, v, uv_link); 196 | free(v); 197 | continue; 198 | } 199 | 200 | if (v->uv_flags & VIFF_TUNNEL) 201 | logit(LOG_INFO, 0, "Installing tunnel %s from %s to %s as VIF #%u, rate %d pps", 202 | v->uv_name, inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)), 203 | inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)), 204 | vifi, v->uv_rate_limit); 205 | else 206 | logit(LOG_INFO, 0, "Installing %s (%s on subnet %s) as VIF #%u, rate %d pps", 207 | v->uv_name, inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)), 208 | inet_fmts(v->uv_subnet, v->uv_subnetmask, s2, sizeof(s2)), 209 | vifi, v->uv_rate_limit); 210 | } 211 | 212 | /* 213 | * XXX: one future extension may be to keep this for adding/removing 214 | * dynamic interfaces at runtime. Now we re-init and let SIGHUP 215 | * rebuild it to recheck since we tear down all vifs anyway. 216 | */ 217 | TAILQ_INIT(&vifs); 218 | } 219 | 220 | /* 221 | * Query the kernel to find network interfaces that are multicast-capable 222 | * and install them in the uvifs array. 223 | */ 224 | void config_vifs_from_kernel(void) 225 | { 226 | in_addr_t addr, mask, subnet; 227 | struct ifaddrs *ifa, *ifap; 228 | struct uvif *uv; 229 | vifi_t vifi; 230 | int flags; 231 | 232 | if (getifaddrs(&ifap) < 0) 233 | logit(LOG_ERR, errno, "getifaddrs"); 234 | 235 | /* 236 | * Loop through all of the interfaces. 237 | */ 238 | for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 239 | /* 240 | * Ignore any interface for an address family other than IP. 241 | */ 242 | if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET) 243 | continue; 244 | 245 | /* 246 | * Ignore loopback interfaces and interfaces that do not support 247 | * multicast. 248 | */ 249 | flags = ifa->ifa_flags; 250 | if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) 251 | continue; 252 | 253 | /* 254 | * Perform some sanity checks on the address and subnet, ignore any 255 | * interface whose address and netmask do not define a valid subnet. 256 | */ 257 | addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; 258 | mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr; 259 | subnet = addr & mask; 260 | if (!inet_valid_subnet(subnet, mask) || (addr != subnet && addr == (subnet & ~mask))) { 261 | logit(LOG_WARNING, 0, "ignoring %s, has invalid address (%s) and/or mask (%s)", 262 | ifa->ifa_name, inet_fmt(addr, s1, sizeof(s1)), inet_fmt(mask, s2, sizeof(s2))); 263 | continue; 264 | } 265 | 266 | uv = calloc(1, sizeof(struct uvif)); 267 | if (!uv) { 268 | logit(LOG_ERR, errno, "failed allocating memory for iflist"); 269 | return; 270 | } 271 | 272 | zero_vif(uv, 0); 273 | 274 | strlcpy(uv->uv_name, ifa->ifa_name, sizeof(uv->uv_name)); 275 | uv->uv_lcl_addr = addr; 276 | uv->uv_subnet = subnet; 277 | uv->uv_subnetmask = mask; 278 | uv->uv_subnetbcast = subnet | ~mask; 279 | 280 | if (ifa->ifa_flags & IFF_POINTOPOINT) 281 | uv->uv_flags |= VIFF_REXMIT_PRUNES; 282 | 283 | /* 284 | * On Linux we can enumerate vifs using ifindex, 285 | * no need for an IP address. Also used for the 286 | * VIF lookup in find_vif() 287 | */ 288 | uv->uv_ifindex = if_nametoindex(uv->uv_name); 289 | if (!uv->uv_ifindex) 290 | logit(LOG_ERR, errno, "Failed reading ifindex for %s", uv->uv_name); 291 | /* 292 | * If the interface is not yet up, set the vifs_down flag to 293 | * remind us to check again later. 294 | */ 295 | if (!(flags & IFF_UP)) { 296 | uv->uv_flags |= VIFF_DOWN; 297 | vifs_down = TRUE; 298 | } 299 | 300 | TAILQ_INSERT_TAIL(&vifs, uv, uv_link); 301 | } 302 | 303 | freeifaddrs(ifap); 304 | } 305 | 306 | /** 307 | * Local Variables: 308 | * indent-tabs-mode: t 309 | * c-file-style: "cc-mode" 310 | * End: 311 | */ 312 | -------------------------------------------------------------------------------- /doc/panos-text.ps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-2.0 2 | %%Creator: LBL whiteboard 3 | %%Pages: (atend) 4 | %%EndComments 5 | userdict /_$iv$save save put 6 | 7 | /sf { % scale /fontName => - (set current font) 8 | {findfont} stopped {pop /Courier findfont} if 9 | exch scalefont setfont 10 | } bind def 11 | 12 | /rf { % orient scale /fontname => - (set current font) 13 | {findfont} stopped {pop /Courier findfont} if 14 | exch scalefont exch matrix rotate 15 | makefont setfont 16 | } bind def 17 | 18 | /ws { 19 | 4 index 6 4 roll moveto sub 20 | 2 index stringwidth pop sub 21 | exch div 0 8#40 4 3 roll 22 | widthshow 23 | } bind def 24 | 25 | /as { 26 | 4 index 6 4 roll moveto sub 27 | 2 index stringwidth pop sub 28 | exch div 0 3 2 roll 29 | ashow 30 | } bind def 31 | 32 | %%EndProlog 33 | %%Page: "ucacgev:1" 1 34 | -0 -0 translate 35 | 0 setgray 36 | 19 /Helvetica-Bold sf 37 | 5.004 740(mrouted -- set up and administration)5 318.042 ws 38 | 5.004 715( )1 10.008 ws 39 | 5.004 690( )1 10.008 ws 40 | 5.004 665(o JOINING the MBone)3 192.024 ws 41 | 5.004 640( )1 10.008 ws 42 | 5.004 615( the multicast routing s/w:)5 233.046 ws 43 | 5.004 590( - mrouted ftp://ftp.parc.xerox.com/pub/net-research/ipmulti/)16 583.146 ws 44 | 5.004 565( - CISCO IOS 11.x ftp://ftp-eng.cisco.com/ipmulticast.html)12 530.136 ws 45 | 5.004 540( - pimd http://catarina.usc.edu/ahelmy/pimsm-implem/)19 545.184 ws 46 | 5.004 515( - gated http://www.gated.org/)18 333.09 ws 47 | 5.004 490( )1 10.008 ws 48 | 5.004 465( the protocols)3 129.024 ws 49 | 5.004 440( - DVMRP)9 121.032 ws 50 | 5.004 415( - PIM)9 88.038 ws 51 | 5.004 390( + IGMP)9 106.56 ws 52 | 5.004 365( )1 10.008 ws 53 | 5.004 340( references)2 106.056 ws 54 | 5.004 315( Deering S., Cheriton D., "Multicast Routing in Datagram )16 524.646 ws 55 | 45.036 290(internetworks and Extended LANs", )4 356.634 ws 56 | 45.036 265(ACM Transactions on Computer Systems, Vol. 8, No. 2 May 1990)10 596.196 ws 57 | 5.004 240( )1 10.008 ws 58 | 5.004 215( RFC1058 C.Hedrick "Routing Information Protocol", June 1988)14 580.212 ws 59 | 5.004 190( )1 10.008 ws 60 | 5.004 165( T.Pusateri "Distance Vector Multicast Routing Protocol", )14 534.204 ws 61 | 45.036 140(Work in Progress, August 1997)4 311.112 ws 62 | 5.004 115( )1 10.008 ws 63 | 5.004 90( mrouted man page)10 206.064 ws 64 | showpage 65 | %%Page: "ucacgev:2" 2 66 | -0 -0 translate 67 | 0 setgray 68 | 19 /Helvetica-Bold sf 69 | 5.004 740(o mrouted \(multicast routing daemon\))4 330.03 ws 70 | 5.004 715( )1 10.008 ws 71 | 5.004 690( ftp://ftp.parc.xerox.com/pub/net-research/ipmulti/)8 465.12 ws 72 | 5.004 665( )1 10.008 ws 73 | 5.004 640( - version:)9 126.054 ws 74 | 5.004 615( mrouted3.8, 3.8.2 \(SNMP support, RSRR\))14 404.1 ws 75 | 5.004 590( mrouted3.9-beta2 \(route filtering\) **)13 357.084 ws 76 | 5.004 565( )1 10.008 ws 77 | 5.004 540( - Platforms :)10 150.048 ws 78 | 5.004 515( sparc-solaris2, i386-bsd, sgi-irix6, sparc-sunos41x)13 486.234 ws 79 | 5.004 490( )1 10.008 ws 80 | 5.004 465( - kernel multicast support)11 265.086 ws 81 | 5.004 440( FreeBSD already there in new releases)21 416.214 ws 82 | 5.004 415( Solaris 2.5.1 multicast patches from:)21 403.182 ws 83 | 5.004 390( ftp://playground.sun.com/pub/multicast/)24 468.144 ws 84 | 5.004 365( standard in 2.6 \(?\))19 240.102 ws 85 | showpage 86 | %%Page: "ucacgev:3" 3 87 | -0 -0 translate 88 | 0 setgray 89 | 19 /Helvetica-Bold sf 90 | 5.004 740(o Distance Vector & Reverse Path Multicasting Concepts)7 491.13 ws 91 | 45.036 690(- Basic Concept)2 181.062 ws 92 | 45.036 665( Every router has a table with all networks )13 429.192 ws 93 | 45.036 640( and their respective distance.)8 323.154 ws 94 | 45.036 615( )5 70.056 ws 95 | 45.036 590( D\(i,j\) metric of best route from i to j)14 375.102 ws 96 | 45.036 565( d\(i,k\) metric to reach neighbor k)11 349.128 ws 97 | 45.036 540( )5 70.056 ws 98 | 45.036 515( D\(i,i\) = 0 all i)10 195.156 ws 99 | 45.036 490( D\(i,j\) = min_k [d\(i,k\) + D\(k,j\)])10 308.106 ws 100 | 45.036 440(- Keywords)1 142.056 ws 101 | 45.036 415( Routes:)2 122.04 ws 102 | 45.036 390( RR \(Route Reports\))7 237.042 ws 103 | 45.036 365( network/netmask metric)6 276.12 ws 104 | 45.036 340( Route Updates)6 197.064 ws 105 | 45.036 315( Dependencies:)2 183.078 ws 106 | 45.036 290( upstream, downstream \(parent/child in tree rooted )11 505.152 ws 107 | 85.068 265(at the source\))2 203.094 ws 108 | 45.036 240( Poison Reverse)6 205.11 ws 109 | 45.036 215( leafs)5 111.078 ws 110 | 45.036 190( Operations: )2 156.06 ws 111 | 45.036 165( Graft, Prune, Flood,)7 238.086 ws 112 | 45.036 140( Forwarding Cache Entries)3 273.096 ws 113 | 5.004 115( )1 10.008 ws 114 | showpage 115 | %%Page: "ucacgev:4" 4 116 | -0 -0 translate 117 | 0 setgray 118 | 19 /Helvetica-Bold sf 119 | 5.004 765( )8 45.036 ws 120 | 45.036 740(- multicast VS unicast routing)4 299.088 ws 121 | 5.004 715( in the mrouted case multicast routing depends on the)18 514.134 ws 122 | 5.004 690( unicast routing but DVMRP has its own routing table.)18 510.102 ws 123 | 5.004 665( )1 10.008 ws 124 | 5.004 640( - how the multicast distribution tree \(wrt S,G\) is created)17 519.138 ws 125 | 5.004 615( Reverse Path Forwarding \(the shortest path !!from the)17 518.112 ws 126 | 5.004 590( receiver back to the source, routing assymetry\(?\)\))16 483.174 ws 127 | 45.036 540(Pathologies inherent to distance vector routing)5 449.118 ws 128 | 45.036 490( Route flaps,)3 158.058 ws 129 | 45.036 465( Black Holes, )4 167.094 ws 130 | 45.036 440( Counting to infinity)4 220.032 ws 131 | 45.036 415( Convergence delays)3 230.112 ws 132 | showpage 133 | %%Page: "ucacgev:5" 5 134 | -0 -0 translate 135 | 0 setgray 136 | 19 /Helvetica-Bold sf 137 | 5.004 740(o Steps involved in setting up mrouted )7 342.072 ws 138 | 5.004 715( )1 10.008 ws 139 | 5.004 690( - where to run mrouted \(local MBone POP\))15 407.088 ws 140 | 5.004 665( more than one mrouted on the same Ethernet \(?\))24 502.128 ws 141 | 5.004 640( encapsulation/members on the same interface)20 481.194 ws 142 | 5.004 615( )1 10.008 ws 143 | 5.004 590( - what the remote tunnel endpoint \(IP address\))15 442.098 ws 144 | 5.004 565( )1 10.008 ws 145 | 5.004 540( - what network interfaces are used by the tunnels:)16 473.148 ws 146 | 5.004 515( point to point links \(e.g ATM PVCs\))22 385.092 ws 147 | 5.004 490( shared medium \(e.g Ethernet\))19 339.12 ws 148 | 5.004 465( )1 10.008 ws 149 | 5.004 440( - static route \(to host or interface for p2p links\))18 450.108 ws 150 | 45.036 415( \(man route\) )4 159.048 ws 151 | 5.004 390( links reserved only for multicast traffic)15 386.154 ws 152 | 5.004 365( )1 10.008 ws 153 | 5.004 340( - determine IP connectivity/routing \(ping/traceroute\))13 494.118 ws 154 | 5.004 315( )1 10.008 ws 155 | 5.004 290( - create /etc/mrouted.conf)10 265.086 ws 156 | 5.004 265( )1 10.008 ws 157 | 5.004 240( - run mrouted \(with appropriate debug option if needed\))16 522.072 ws 158 | showpage 159 | %%Page: "ucacgev:6" 6 160 | -0 -0 translate 161 | 0 setgray 162 | 19 /Helvetica-Bold sf 163 | 5.004 740(o Administration)1 148.014 ws 164 | 5.004 715( )1 10.008 ws 165 | 5.004 690( how to configure/start/stop/debug)4 306.036 ws 166 | 5.004 665( )1 10.008 ws 167 | 5.004 640( - manually or on system start-up \(e.g rc.local\))15 434.142 ws 168 | 5.004 615( )1 10.008 ws 169 | 5.004 590( - debugging options \( -d option \))14 322.02 ws 170 | 5.004 565( packet, prunes, routes, peers, cache, timeout)21 471.204 ws 171 | 5.004 540( interface, membership, traceroute, igmp)19 428.166 ws 172 | 5.004 515( )1 10.008 ws 173 | 5.004 490( - signals)9 118.062 ws 174 | 5.004 465( HUP, INT, TERM, USR1, USR2)20 339.102 ws 175 | 5.004 440( )1 10.008 ws 176 | 5.004 415( - files)10 97.056 ws 177 | 5.004 390( /etc/mrouted.conf)8 196.056 ws 178 | 5.004 365( /etc/mrouted.pid)8 185.058 ws 179 | 5.004 340( /tmp/mrouted.dump \(/var/run in FreeBSD\))11 399.078 ws 180 | 5.004 315( /tmp/mrouted.cache)8 216.072 ws 181 | 5.004 290( )1 10.008 ws 182 | 5.004 265( - commands, tools)10 204.066 ws 183 | 5.004 240( mtrace, mrinfo, mstat, \(mview\))15 325.116 ws 184 | 5.004 215( ping, netstat, ifconfig, route, tcpdump)16 388.08 ws 185 | 45.036 190( traceroute)4 153.072 ws 186 | 5.004 165( )1 10.008 ws 187 | 5.004 140( - , , , , )13 525.24 ws 188 | 5.004 115( )1 10.008 ws 189 | showpage 190 | %%Page: "ucacgev:7" 7 191 | -0 -0 translate 192 | 0 setgray 193 | 19 /Helvetica-Bold sf 194 | 5.004 740( - filtering)9 122.04 ws 195 | 5.004 715( "input" or "input and output")16 313.164 ws 196 | 5.004 690( )15 348.228 ws 197 | 5.004 665( )1 10.008 ws 198 | 5.004 640( - administrative scoping)10 252.09 ws 199 | 5.004 615( )12 168.084 ws 200 | 5.004 590( )1 10.008 ws 201 | 5.004 565( - other configuration options)11 291.042 ws 202 | 5.004 540( , , , )15 559.296 ws 203 | 5.004 515( )1 10.008 ws 204 | 5.004 490( - monitoring)9 150.03 ws 205 | 5.004 465( )1 10.008 ws 206 | showpage 207 | %%Trailer 208 | _$iv$save restore 209 | %%Pages: 7 210 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simple Multicast Routing for UNIX 2 | ================================= 3 | [![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan] 4 | 5 | Simple overview of what DVMRP is 6 | 7 | Table of Contents 8 | ----------------- 9 | 10 | * [Introduction](#introduction) 11 | * [Running](#running) 12 | * [Configuration](#configuration) 13 | * [Build & Install](#build--install) 14 | * [Building from GIT](#building-from-git) 15 | * [Contributing](#contributing) 16 | * [Origin & References](#origin--references) 17 | 18 | 19 | Introduction 20 | ------------ 21 | 22 | mrouted is the original implementation of the DVMRP multicast routing 23 | protocol, [RFC 1075][]. It only works with IPv4 networks. For more 24 | advanced setups, the [pimd project](https://github.com/troglobit/pimd) 25 | or [pimd-dense project](https://github.com/troglobit/pimd-dense), for 26 | IPv6 the [pim6sd project](https://github.com/troglobit/pim6sd) may be of 27 | interest. 28 | 29 | mrouted is *simple* to use. DVMRP is derived from RIP, which means it 30 | works stand-alone without any extra network setup required. You can get 31 | up and running in a matter of minutes. Use the built-in [IP-in-IP][] 32 | tunneling support, or GRE, to traverse Internet or intranets. 33 | 34 | mrouted is developed on Linux and works as-is out of the box. Other 35 | UNIX variants should also work, but are not as thoroughly tested. 36 | 37 | Manual pages available online: 38 | 39 | * [mrouted(8)][] 40 | * [mroutectl(8)][] 41 | * [mrouted.conf(5)][] 42 | 43 | 44 | Running 45 | ------- 46 | 47 | mrouted does not require a `.conf` file. When it starts up it probes 48 | all available interfaces and starts peering with any DVMRP capable 49 | neighbor. Multicast is forwarded to end-devices that *join* a group 50 | using IGMPv1, IGMPv2, or IGMPv3. For LANs where there may be hosts that 51 | do not speak IGMP, or where certain groups should always be forwarded, a 52 | `static-group` setting is available in `mrouted.conf`. 53 | 54 | Use [mgen(1)][], [mcjoin(1)][], or [iperf](https://iperf.fr/) to send 55 | IGMP join packets and multicast data on the LAN to test your multicast 56 | routing setup. Use the `mroutectl` tool to query a running `mrouted` 57 | for status. 58 | 59 | > **NOTE:** Beware of the TTL value in the IP header of your multicast 60 | > data. It defaults to 1 on most operating systems, which 61 | > means nothing will be routed by default! 62 | 63 | For the native mrouted tunnel to work in Linux based systems, you need 64 | to have the "ipip" kernel module loaded or as built-in: 65 | 66 | modprobe ipip 67 | 68 | Alternatively, you may of course also set up GRE tunnels between your 69 | multicast capable routers. 70 | 71 | If you have *many* interfaces on your system you may want to look into 72 | the `no phyint` setting in [mroute.conf(5)][]. Linux users may also 73 | need to adjust `/proc/sys/net/ipv4/igmp_max_memberships` to a value 74 | larger than the default 20. mrouted needs 3x the number of interfaces 75 | (vifs) for the relevant control protocol groups. The kernel (Linux & 76 | BSD) *maximum* number of interfaces to use for multicast routing is 32. 77 | 78 | **Note:** mrouted must run with sufficient capabilities, or as root. 79 | 80 | 81 | Configuration 82 | ------------- 83 | 84 | mrouted reads its configuration file from `/etc/mrouted.conf`, if it 85 | exists. You can override the default by specifying an alternate file 86 | when invoking mrouted: 87 | 88 | mrouted -f /path/file.conf 89 | 90 | mrouted can be reconfigured at runtime like any regular UNIX daemon with 91 | `SIGHUP`, or `mroutectl restart`, to activate changes made to its 92 | configuration file. The PID is saved in the file `/run/mrouted.pid` for 93 | your scripting needs. 94 | 95 | By default, mrouted configures itself to act as a multicast router on 96 | all multicast capable interfaces. Hence, you do not need to explicitly 97 | configure it, unless you need to setup tunnel links, change the default 98 | operating parameters, disable multicast routing over a specific physical 99 | interfaces, or have dynamic interfaces. 100 | 101 | **Note:** you need to have IP Multicast Routing enabled in the kernel 102 | as well. How this is achieved is outside the scope of this README. 103 | 104 | For more help, see the [mrouted(8)][] and [mrouted.conf(5)][] man pages. 105 | 106 | 107 | Build & Install 108 | --------------- 109 | 110 | ### Debian/Ubuntu 111 | 112 | curl -sS https://deb.troglobit.com/pubkey.gpg | sudo apt-key add - 113 | echo "deb [arch=amd64] https://deb.troglobit.com/debian stable main" | sudo tee /etc/apt/sources.list.d/troglobit.list 114 | sudo apt-get update && sudo apt-get install mrouted 115 | 116 | ### Building from Source 117 | 118 | Download the latest official *versioned* mrouted release. Official 119 | releases contain all the necessary files, unlike building from GIT. 120 | mrouted has no external dependencies except for a standard C library. 121 | 122 | * https://github.com/troglobit/mrouted/releases 123 | 124 | The configure script and Makefile supports de facto standard settings 125 | and environment variables such as `--prefix=PATH` and `DESTDIR=` for the 126 | install process. For example, to install mrouted to `/usr`, instead of 127 | the default `/usr/local`, and redirect install to a package directory in 128 | `/tmp`: 129 | 130 | ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var 131 | make 132 | make DESTDIR=/tmp/mrouted-4.0-1 install-strip 133 | 134 | **Note:** On some systems `--runstatedir` may not be available in the 135 | configure script, try `--localstatedir=/var` instead. 136 | 137 | 138 | Building from GIT 139 | ----------------- 140 | 141 | If you want to contribute, or simply just try out the latest but 142 | unreleased features, then you need to know a few things about the 143 | [GNU build system][buildsystem]: 144 | 145 | - `configure.ac` and a per-directory `Makefile.am` are key files 146 | - `configure` and `Makefile.in` are generated from `autogen.sh` 147 | - `Makefile` is generated by `configure` script 148 | 149 | To build from GIT you first need to clone the repository and run the 150 | `autogen.sh` script. This requires `automake` and `autoconf` to be 151 | installed on your system. 152 | 153 | git clone https://github.com/troglobit/mrouted.git 154 | cd mrouted/ 155 | ./autogen.sh 156 | ./configure && make 157 | 158 | GIT sources are a moving target and are not recommended for production 159 | systems, unless you know what you are doing! 160 | 161 | 162 | Contributing 163 | ------------ 164 | 165 | The basic functionality has been tested thoroughly over the years, but 166 | that does not mean mrouted is bug free. Please report bugs, feature 167 | requests, patches and pull requests at [GitHub][repo]. 168 | 169 | 170 | Origin & References 171 | ------------------- 172 | 173 | The mrouted routing daemon was developed by David Waitzman, Craig 174 | Partridge, Steve Deering, Ajit Thyagarajan, Bill Fenner, David Thaler 175 | and Daniel Zappala. With contributions by many others. 176 | 177 | The last release by Mr. Fenner was 3.9-beta3 on April 26 1999 and 178 | mrouted has been in "beta" status since then. Several prominent UNIX 179 | operating systems, such as AIX, Solaris, HP-UX, BSD/OS, NetBSD, FreeBSD, 180 | OpenBSD as well as most GNU/Linux based distributions have used that 181 | beta as a de facto stable release, with (mostly) minor patches for 182 | system adaptations. Over time however many dropped support, but Debian 183 | and OpenBSD kept it under their wings. 184 | 185 | In March 2003 [OpenBSD](http://www.openbsd.org/), led by the fearless 186 | Theo de Raadt, managed to convince Stanford to release mrouted under a 187 | [fully free license][License], the [3-clause BSD license][BSD License]. 188 | Unfortunately, and despite the license issue being corrected by OpenBSD, 189 | in February 2005 [Debian dropped mrouted][1] as an "obsolete protocol". 190 | 191 | For a long time the OpenBSD team remained the sole guardian of this 192 | project. In 2010 [Joachim Wiberg](https://troglobit.com) revived 193 | mrouted on [GitHub][repo] based on the last release by Bill Fenner, the 194 | `mrouted-3.9beta3+IOS12.tar.gz` tarball. This project has integrated 195 | all (?) known patches and continuously track the OpenBSD project, which 196 | is based on the 3.8 release, for any relevant fixes. 197 | 198 | [1]: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=288112 199 | [License]: http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/mrouted/LICENSE 200 | [License Badge]: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg 201 | [BSD License]: http://en.wikipedia.org/wiki/BSD_licenses 202 | [RFC 1075]: http://tools.ietf.org/html/rfc1075 203 | [IP-in-IP]: https://en.wikipedia.org/wiki/IP_in_IP 204 | [buildsystem]: https://airs.com/ian/configure/ 205 | [mgen(1)]: https://www.nrl.navy.mil/itd/ncs/products/mgen 206 | [mcjoin(1)]: https://github.com/troglobit/mcjoin/ 207 | [mrouted(8)]: https://man.troglobit.com/man8/mrouted.8.html 208 | [mroutectl(8)]: https://man.troglobit.com/man8/mroutectl.8.html 209 | [mrouted.conf(5)]: https://man.troglobit.com/man5/mrouted.conf.5.html 210 | [repo]: https://github.com/troglobit/mrouted/ 211 | [GitHub]: https://github.com/troglobit/mrouted/actions/workflows/build.yml/ 212 | [GitHub Status]: https://github.com/troglobit/mrouted/actions/workflows/build.yml/badge.svg 213 | [Coverity Scan]: https://scan.coverity.com/projects/3320 214 | [Coverity Status]: https://scan.coverity.com/projects/3320/badge.svg 215 | -------------------------------------------------------------------------------- /test/three.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Three routers in a row, end devices on each end. Every router and 3 | # end device in a network namespace to circumvent one-address per 4 | # subnet in Linux 5 | # 6 | # NS1 NS2 NS3 NS4 NS5 7 | # [ED1:eth0]--[eth1:R1:eth2]---[eth3:R2:eth4]---[eth5:R3:eth6]---[eth0:ED2] 8 | # 10.0.0.0/24 10.0.1.0/24 10.0.2.0/24 10.0.3.0/24 9 | 10 | # shellcheck source=/dev/null 11 | . "$(dirname "$0")/lib.sh" 12 | 13 | # Requires OSPF (bird) to build the unicast rpf tree 14 | print "Check deps ..." 15 | check_dep ethtool 16 | check_dep tshark 17 | check_dep bird 18 | 19 | print "Creating world ..." 20 | NS1="/tmp/$NM/NS1" 21 | NS2="/tmp/$NM/NS2" 22 | NS3="/tmp/$NM/NS3" 23 | NS4="/tmp/$NM/NS4" 24 | NS5="/tmp/$NM/NS5" 25 | touch "$NS1" "$NS2" "$NS3" "$NS4" "$NS5" 26 | 27 | echo "$NS1" > "/tmp/$NM/mounts" 28 | echo "$NS2" >> "/tmp/$NM/mounts" 29 | echo "$NS3" >> "/tmp/$NM/mounts" 30 | echo "$NS4" >> "/tmp/$NM/mounts" 31 | echo "$NS5" >> "/tmp/$NM/mounts" 32 | 33 | unshare --net="$NS1" -- ip link set lo up 34 | unshare --net="$NS2" -- ip link set lo up 35 | unshare --net="$NS3" -- ip link set lo up 36 | unshare --net="$NS4" -- ip link set lo up 37 | unshare --net="$NS5" -- ip link set lo up 38 | 39 | # Creates a VETH pair, one end named eth0 and the other is eth7: 40 | # 41 | # created /tmp/foo eth0 eth7 1.2.3.4/24 1.2.3.1 42 | # 43 | # Disabling UDP checksum offloading with ethtool, frames are leaving 44 | # kernel space on these VETH pairs. (Silence noisy ethtool output) 45 | created() 46 | { 47 | in=$2 48 | if echo "$3" | grep -q '@'; then 49 | ut=$(echo "$3" | cut -f1 -d@) 50 | id=$(echo "$3" | cut -f2 -d@) 51 | else 52 | ut=$3 53 | fi 54 | 55 | echo "Creating device interfaces $in and $ut ..." 56 | nsenter --net="$1" -- ip link add "$in" type veth peer "$ut" 57 | nsenter --net="$1" -- ip link set "$in" up 58 | 59 | nsenter --net="$1" -- ip addr add "$4" broadcast + dev "$2" 60 | nsenter --net="$1" -- ip route add default via "$5" 61 | 62 | for iface in "$in" "$ut"; do 63 | nsenter --net="$1" -- ethtool --offload "$iface" tx off >/dev/null 64 | nsenter --net="$1" -- ethtool --offload "$iface" rx off >/dev/null 65 | done 66 | 67 | if [ -n "$id" ]; then 68 | echo "$1 moving $ut to netns PID $id" 69 | nsenter --net="$1" -- ip link set "$ut" netns "$id" 70 | fi 71 | 72 | return $! 73 | } 74 | 75 | creater() 76 | { 77 | if echo "$2" |grep -q ':'; then 78 | x=$(echo "$2" | cut -f1 -d:) 79 | b=$(echo "$2" | cut -f2 -d:) 80 | echo "1) Found x=$x and b=$b ..." 81 | a=$(echo "$x" | cut -f1 -d@) 82 | p=$(echo "$x" | cut -f2 -d@) 83 | echo "1) Found a=$a and p=$p ..." 84 | echo "Creating router interfaces $a and $b ..." 85 | nsenter --net="$1" -- ip link add "$a" type veth peer "$b" 86 | for iface in "$a" "$b"; do 87 | nsenter --net="$1" -- ethtool --offload "$iface" tx off >/dev/null 88 | nsenter --net="$1" -- ethtool --offload "$iface" rx off >/dev/null 89 | done 90 | echo "$1 moving $a to netns PID $p" 91 | nsenter --net="$1" -- ip link set "$a" netns "$p" 92 | else 93 | b=$2 94 | fi 95 | 96 | echo "Bringing up $a with addr $4" 97 | nsenter --net="$1" -- ip link set "$b" up 98 | nsenter --net="$1" -- ip addr add "$4" broadcast + dev "$b" 99 | 100 | if echo "$3" |grep -q ':'; then 101 | a=$(echo "$3" | cut -f1 -d:) 102 | x=$(echo "$3" | cut -f2 -d:) 103 | echo "2) Found x=$x and b=$b ..." 104 | b=$(echo "$x" | cut -f1 -d@) 105 | p=$(echo "$x" | cut -f2 -d@) 106 | echo "2) Found a=$a and p=$p ..." 107 | echo "Creating router interfaces $a and $b ..." 108 | nsenter --net="$1" -- ip link add "$a" type veth peer "$b" 109 | for iface in "$a" "$b"; do 110 | nsenter --net="$1" -- ethtool --offload "$iface" tx off >/dev/null 111 | nsenter --net="$1" -- ethtool --offload "$iface" rx off >/dev/null 112 | done 113 | echo "$1 moving $b to netns PID $p" 114 | nsenter --net="$1" -- ip link set "$b" netns "$p" 115 | else 116 | a=$3 117 | fi 118 | 119 | echo "Bringing up $a with addr $5" 120 | nsenter --net="$1" -- ip link set "$a" up 121 | nsenter --net="$1" -- ip addr add "$5" broadcast + dev "$a" 122 | } 123 | 124 | dvmrp_routes() 125 | { 126 | dprint "R1 DVMRP Routes" 127 | nsenter --net="$NS2" -- ../src/mroutectl -pt -u "/tmp/$NM/r1.sock" -d show routes 128 | dprint "R2 DVMRP Routes" 129 | nsenter --net="$NS3" -- ../src/mroutectl -pt -u "/tmp/$NM/r2.sock" -d show routes 130 | dprint "R3 DVMRP Routes" 131 | nsenter --net="$NS4" -- ../src/mroutectl -pt -u "/tmp/$NM/r3.sock" -d show routes 132 | } 133 | 134 | dvmrp_status() 135 | { 136 | dprint "DVMRP Status $NS2" 137 | nsenter --net="$NS2" -- ../src/mroutectl -u "/tmp/$NM/r1.sock" show compat detail 138 | dprint "DVMRP Status $NS3" 139 | nsenter --net="$NS3" -- ../src/mroutectl -u "/tmp/$NM/r2.sock" show compat detail 140 | dprint "DVMRP Status $NS4" 141 | nsenter --net="$NS4" -- ../src/mroutectl -u "/tmp/$NM/r3.sock" show compat detail 142 | } 143 | 144 | dvmrp_neigh() 145 | { 146 | dprint "R1 DVMRP Neighbors" 147 | nsenter --net="$NS2" -- ../src/mroutectl -pt -u "/tmp/$NM/r1.sock" -d show neighbor 148 | dprint "R2 DVMRP Neighbors" 149 | nsenter --net="$NS3" -- ../src/mroutectl -pt -u "/tmp/$NM/r2.sock" -d show neighbor 150 | dprint "R3 DVMRP Neighbors" 151 | nsenter --net="$NS4" -- ../src/mroutectl -pt -u "/tmp/$NM/r3.sock" -d show neighbor 152 | } 153 | 154 | has_neigh() 155 | { 156 | nm=$(basename "$2" .sock) 157 | neighbors=$(nsenter --net="$1" -- \ 158 | ../src/mroutectl -pt -u "$2" -d show neighbor \ 159 | | awk 'NF && $4 == "G" { print $1 }') 160 | shift 2 161 | 162 | while [ $# -gt 0 ]; do 163 | if ! echo "$neighbors" | grep -wq "$1"; then 164 | echo "$nm: missing neighbor $1" 165 | return 1 166 | fi 167 | shift 168 | done 169 | 170 | return 0 171 | } 172 | 173 | dvmrp_peer() 174 | { 175 | has_neigh "$NS2" "/tmp/$NM/r1.sock" 10.0.1.2 || return 1 176 | has_neigh "$NS3" "/tmp/$NM/r2.sock" 10.0.1.1 10.0.2.2 || return 1 177 | has_neigh "$NS4" "/tmp/$NM/r3.sock" 10.0.2.1 || return 1 178 | } 179 | 180 | dprint "Creating $NS2 router ..." 181 | nsenter --net="$NS2" -- sleep 5 & 182 | pid2=$! 183 | dprint "Creating $NS4 router ..." 184 | nsenter --net="$NS4" -- sleep 5 & 185 | pid4=$! 186 | 187 | dprint "Creating NS1 ED with eth1 in PID $pid2" 188 | created "$NS1" eth0 eth1@"$pid2" 10.0.0.10/24 10.0.0.1 189 | 190 | dprint "Creating NS3 router with eth3 in PID $pid2 and eth5 in PID $pid4" 191 | creater "$NS3" eth2@"$pid2":eth3 eth4:eth5@"$pid4" 10.0.1.2/24 10.0.2.1/24 192 | 193 | dprint "Creating NS5 ED with eth6 in PID $pid4" 194 | created "$NS5" eth0 eth6@"$pid4" 10.0.3.10/24 10.0.3.1 195 | 196 | creater "$NS2" eth1 eth2 10.0.0.1/24 10.0.1.1/24 197 | creater "$NS4" eth5 eth6 10.0.2.2/24 10.0.3.1/24 198 | 199 | dprint "$NS1" 200 | nsenter --net="$NS1" -- ip -br l 201 | nsenter --net="$NS1" -- ip -br a 202 | dprint "$NS2" 203 | nsenter --net="$NS2" -- ip -br l 204 | nsenter --net="$NS2" -- ip -br a 205 | dprint "$NS3" 206 | nsenter --net="$NS3" -- ip -br l 207 | nsenter --net="$NS3" -- ip -br a 208 | dprint "$NS4" 209 | nsenter --net="$NS4" -- ip -br l 210 | nsenter --net="$NS4" -- ip -br a 211 | dprint "$NS5" 212 | nsenter --net="$NS5" -- ip -br l 213 | nsenter --net="$NS5" -- ip -br a 214 | 215 | print "Creating OSPF config ..." 216 | cat < "/tmp/$NM/bird.conf" 217 | protocol device { 218 | } 219 | protocol direct { 220 | ipv4; 221 | } 222 | protocol kernel { 223 | ipv4 { 224 | export all; 225 | }; 226 | learn; 227 | } 228 | protocol ospf { 229 | ipv4 { 230 | import all; 231 | }; 232 | area 0 { 233 | interface "eth*" { 234 | type broadcast; 235 | hello 1; 236 | wait 3; 237 | dead 5; 238 | }; 239 | }; 240 | } 241 | EOF 242 | cat "/tmp/$NM/bird.conf" 243 | 244 | print "Starting Bird OSPF ..." 245 | nsenter --net="$NS2" -- bird -c "/tmp/$NM/bird.conf" -d -s "/tmp/$NM/r1-bird.sock" & 246 | echo $! >> "/tmp/$NM/PIDs" 247 | nsenter --net="$NS3" -- bird -c "/tmp/$NM/bird.conf" -d -s "/tmp/$NM/r2-bird.sock" & 248 | echo $! >> "/tmp/$NM/PIDs" 249 | nsenter --net="$NS4" -- bird -c "/tmp/$NM/bird.conf" -d -s "/tmp/$NM/r3-bird.sock" & 250 | echo $! >> "/tmp/$NM/PIDs" 251 | 252 | print "Starting mrouted ..." 253 | LVL=info 254 | nsenter --net="$NS2" -- ../src/mrouted -i NS2 -n -p "/tmp/$NM/r1.pid" -l $LVL -d all -u "/tmp/$NM/r1.sock" & 255 | echo $! >> "/tmp/$NM/PIDs" 256 | nsenter --net="$NS3" -- ../src/mrouted -i NS3 -n -p "/tmp/$NM/r2.pid" -l $LVL -d all -u "/tmp/$NM/r2.sock" & 257 | echo $! >> "/tmp/$NM/PIDs" 258 | nsenter --net="$NS4" -- ../src/mrouted -i NS4 -n -p "/tmp/$NM/r3.pid" -l $LVL -d all -u "/tmp/$NM/r3.sock" & 259 | echo $! >> "/tmp/$NM/PIDs" 260 | 261 | # Wait for routers to peer 262 | print "Waiting for OSPF routers to peer (30 sec) ..." 263 | tenacious 30 nsenter --net="$NS1" -- ping -qc 1 -W 1 10.0.3.10 >/dev/null 264 | dprint "OK" 265 | 266 | print "Waiting for DVMRP routers to peer (30 sec) ..." 267 | tenacious 30 dvmrp_peer 268 | dprint "OK" 269 | 270 | # dprint "OSPF State & Routing Table $NS2:" 271 | # nsenter --net="$NS2" -- echo "show ospf state" | birdc -s "/tmp/$NM/r1-bird.sock" 272 | # nsenter --net="$NS2" -- echo "show ospf int" | birdc -s "/tmp/$NM/r1-bird.sock" 273 | # nsenter --net="$NS2" -- echo "show ospf neigh" | birdc -s "/tmp/$NM/r1-bird.sock" 274 | # nsenter --net="$NS2" -- ip route 275 | 276 | # dprint "OSPF State & Routing Table $NS3:" 277 | # nsenter --net="$NS4" -- echo "show ospf state" | birdc -s "/tmp/$NM/r2-bird.sock" 278 | # nsenter --net="$NS4" -- echo "show ospf int" | birdc -s "/tmp/$NM/r2-bird.sock" 279 | # nsenter --net="$NS3" -- echo "show ospf neigh" | birdc -s "/tmp/$NM/r2-bird.sock" 280 | # nsenter --net="$NS3" -- ip route 281 | 282 | # dprint "OSPF State & Routing Table $NS4:" 283 | # nsenter --net="$NS4" -- echo "show ospf state" | birdc -s "/tmp/$NM/r3-bird.sock" 284 | # nsenter --net="$NS4" -- echo "show ospf int" | birdc -s "/tmp/$NM/r3-bird.sock" 285 | # nsenter --net="$NS4" -- echo "show ospf neigh" | birdc -s "/tmp/$NM/r3-bird.sock" 286 | # nsenter --net="$NS4" -- ip route 287 | 288 | print "Starting emitter ..." 289 | nsenter --net="$NS5" -- ./mping -qr -i eth0 -t 5 -W 30 225.1.2.3 & 290 | echo $! >> "/tmp/$NM/PIDs" 291 | sleep 1 292 | 293 | if ! nsenter --net="$NS1" -- ./mping -s -i eth0 -t 5 -c 10 -w 30 225.1.2.3; then 294 | dprint "DVMRP Status $NS2" 295 | nsenter --net="$NS2" -- ../src/mroutectl -u "/tmp/$NM/r1.sock" show compat detail 296 | dprint "DVMRP Status $NS3" 297 | nsenter --net="$NS3" -- ../src/mroutectl -u "/tmp/$NM/r2.sock" show compat detail 298 | dprint "DVMRP Status $NS4" 299 | nsenter --net="$NS4" -- ../src/mroutectl -u "/tmp/$NM/r3.sock" show compat detail 300 | echo "Failed routing, expected at least 10 multicast ping replies" 301 | FAIL 302 | fi 303 | 304 | OK 305 | -------------------------------------------------------------------------------- /test/tunnel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Three routers in a row, end devices on each end. Every virtual 3 | # device/router live in their own network namespace. Only R1 and R3 run 4 | # mrouted and tunnel all multicast over the built-in IP-IP tunnel. 5 | # 6 | # NS1 NS2 NS3 NS4 NS5 7 | # [ED1:eth0]--[eth1:R1:eth2]---[eth3:R2:eth4]---[eth5:R3:eth6]---[eth0:ED2] 8 | # 10.0.0.0/24 10.0.1.0/24 10.0.2.0/24 10.0.3.0/24 9 | 10 | # shellcheck source=/dev/null 11 | . "$(dirname "$0")/lib.sh" 12 | 13 | # Requires OSPF (bird) to build the unicast rpf tree 14 | print "Check deps ..." 15 | check_dep grep -q ipip /proc/modules 16 | check_dep ethtool 17 | check_dep tshark 18 | check_dep bird 19 | 20 | print "Creating world ..." 21 | NS1="/tmp/$NM/NS1" 22 | NS2="/tmp/$NM/NS2" 23 | NS3="/tmp/$NM/NS3" 24 | NS4="/tmp/$NM/NS4" 25 | NS5="/tmp/$NM/NS5" 26 | touch "$NS1" "$NS2" "$NS3" "$NS4" "$NS5" 27 | 28 | echo "$NS1" > "/tmp/$NM/mounts" 29 | echo "$NS2" >> "/tmp/$NM/mounts" 30 | echo "$NS3" >> "/tmp/$NM/mounts" 31 | echo "$NS4" >> "/tmp/$NM/mounts" 32 | echo "$NS5" >> "/tmp/$NM/mounts" 33 | 34 | unshare --net="$NS1" -- ip link set lo up 35 | unshare --net="$NS2" -- ip link set lo up 36 | unshare --net="$NS3" -- ip link set lo up 37 | unshare --net="$NS4" -- ip link set lo up 38 | unshare --net="$NS5" -- ip link set lo up 39 | 40 | # Creates a VETH pair, one end named eth0 and the other is eth7: 41 | # 42 | # created /tmp/foo eth0 eth7 1.2.3.4/24 1.2.3.1 43 | # 44 | # Disabling UDP checksum offloading with ethtool, frames are leaving 45 | # kernel space on these VETH pairs. (Silence noisy ethtool output) 46 | created() 47 | { 48 | in=$2 49 | if echo "$3" | grep -q '@'; then 50 | ut=$(echo "$3" | cut -f1 -d@) 51 | id=$(echo "$3" | cut -f2 -d@) 52 | else 53 | ut=$3 54 | fi 55 | 56 | echo "Creating device interfaces $in and $ut ..." 57 | nsenter --net="$1" -- ip link add "$in" type veth peer "$ut" 58 | nsenter --net="$1" -- ip link set "$in" up 59 | 60 | nsenter --net="$1" -- ip addr add "$4" broadcast + dev "$2" 61 | nsenter --net="$1" -- ip route add default via "$5" 62 | 63 | for iface in "$in" "$ut"; do 64 | nsenter --net="$1" -- ethtool --offload "$iface" tx off >/dev/null 65 | nsenter --net="$1" -- ethtool --offload "$iface" rx off >/dev/null 66 | done 67 | 68 | if [ -n "$id" ]; then 69 | echo "$1 moving $ut to netns PID $id" 70 | nsenter --net="$1" -- ip link set "$ut" netns "$id" 71 | fi 72 | 73 | return $! 74 | } 75 | 76 | creater() 77 | { 78 | if echo "$2" |grep -q ':'; then 79 | x=$(echo "$2" | cut -f1 -d:) 80 | b=$(echo "$2" | cut -f2 -d:) 81 | echo "1) Found x=$x and b=$b ..." 82 | a=$(echo "$x" | cut -f1 -d@) 83 | p=$(echo "$x" | cut -f2 -d@) 84 | echo "1) Found a=$a and p=$p ..." 85 | echo "Creating router interfaces $a and $b ..." 86 | nsenter --net="$1" -- ip link add "$a" type veth peer "$b" 87 | for iface in "$a" "$b"; do 88 | nsenter --net="$1" -- ethtool --offload "$iface" tx off >/dev/null 89 | nsenter --net="$1" -- ethtool --offload "$iface" rx off >/dev/null 90 | done 91 | echo "$1 moving $a to netns PID $p" 92 | nsenter --net="$1" -- ip link set "$a" netns "$p" 93 | else 94 | b=$2 95 | fi 96 | 97 | echo "Bringing up $a with addr $4" 98 | nsenter --net="$1" -- ip link set "$b" up 99 | nsenter --net="$1" -- ip addr add "$4" broadcast + dev "$b" 100 | 101 | if echo "$3" |grep -q ':'; then 102 | a=$(echo "$3" | cut -f1 -d:) 103 | x=$(echo "$3" | cut -f2 -d:) 104 | echo "2) Found x=$x and b=$b ..." 105 | b=$(echo "$x" | cut -f1 -d@) 106 | p=$(echo "$x" | cut -f2 -d@) 107 | echo "2) Found a=$a and p=$p ..." 108 | echo "Creating router interfaces $a and $b ..." 109 | nsenter --net="$1" -- ip link add "$a" type veth peer "$b" 110 | for iface in "$a" "$b"; do 111 | nsenter --net="$1" -- ethtool --offload "$iface" tx off >/dev/null 112 | nsenter --net="$1" -- ethtool --offload "$iface" rx off >/dev/null 113 | done 114 | echo "$1 moving $b to netns PID $p" 115 | nsenter --net="$1" -- ip link set "$b" netns "$p" 116 | else 117 | a=$3 118 | fi 119 | 120 | echo "Bringing up $a with addr $5" 121 | nsenter --net="$1" -- ip link set "$a" up 122 | nsenter --net="$1" -- ip addr add "$5" broadcast + dev "$a" 123 | } 124 | 125 | dprint "Creating $NS2 router ..." 126 | nsenter --net="$NS2" -- sleep 5 & 127 | pid2=$! 128 | dprint "Creating $NS4 router ..." 129 | nsenter --net="$NS4" -- sleep 5 & 130 | pid4=$! 131 | 132 | dprint "Creating NS1 ED with eth1 in PID $pid2" 133 | created "$NS1" eth0 eth1@"$pid2" 10.0.0.10/24 10.0.0.1 134 | 135 | dprint "Creating NS3 router with eth3 in PID $pid2 and eth5 in PID $pid4" 136 | creater "$NS3" eth2@"$pid2":eth3 eth4:eth5@"$pid4" 10.0.1.2/24 10.0.2.1/24 137 | 138 | dprint "Creating NS5 ED with eth6 in PID $pid4" 139 | created "$NS5" eth0 eth6@"$pid4" 10.0.3.10/24 10.0.3.1 140 | 141 | creater "$NS2" eth1 eth2 10.0.0.1/24 10.0.1.1/24 142 | creater "$NS4" eth5 eth6 10.0.2.2/24 10.0.3.1/24 143 | 144 | dprint "$NS1" 145 | nsenter --net="$NS1" -- ip -br l 146 | nsenter --net="$NS1" -- ip -br a 147 | dprint "$NS2" 148 | nsenter --net="$NS2" -- ip -br l 149 | nsenter --net="$NS2" -- ip -br a 150 | dprint "$NS3" 151 | nsenter --net="$NS3" -- ip -br l 152 | nsenter --net="$NS3" -- ip -br a 153 | dprint "$NS4" 154 | nsenter --net="$NS4" -- ip -br l 155 | nsenter --net="$NS4" -- ip -br a 156 | dprint "$NS5" 157 | nsenter --net="$NS5" -- ip -br l 158 | nsenter --net="$NS5" -- ip -br a 159 | 160 | print "Creating OSPF config ..." 161 | cat < "/tmp/$NM/bird.conf" 162 | protocol device { 163 | } 164 | protocol direct { 165 | ipv4; 166 | } 167 | protocol kernel { 168 | ipv4 { 169 | export all; 170 | }; 171 | learn; 172 | } 173 | protocol ospf { 174 | ipv4 { 175 | import all; 176 | }; 177 | area 0 { 178 | interface "eth*" { 179 | type broadcast; 180 | hello 1; 181 | wait 3; 182 | dead 5; 183 | }; 184 | }; 185 | } 186 | EOF 187 | cat "/tmp/$NM/bird.conf" 188 | 189 | print "Starting Bird OSPF ..." 190 | nsenter --net="$NS2" -- bird -c "/tmp/$NM/bird.conf" -d -s "/tmp/$NM/r1-bird.sock" & 191 | echo $! >> "/tmp/$NM/PIDs" 192 | nsenter --net="$NS3" -- bird -c "/tmp/$NM/bird.conf" -d -s "/tmp/$NM/r2-bird.sock" & 193 | echo $! >> "/tmp/$NM/PIDs" 194 | nsenter --net="$NS4" -- bird -c "/tmp/$NM/bird.conf" -d -s "/tmp/$NM/r3-bird.sock" & 195 | echo $! >> "/tmp/$NM/PIDs" 196 | # sleep 1 197 | 198 | print "Disabling rp_filter on routers ..." 199 | nsenter --net="$NS2" -- sysctl -w net.ipv4.conf.all.rp_filter=0 200 | nsenter --net="$NS3" -- sysctl -w net.ipv4.conf.all.rp_filter=0 201 | nsenter --net="$NS4" -- sysctl -w net.ipv4.conf.all.rp_filter=0 202 | 203 | print "Creating mrouted.conf for R1 ..." 204 | cat < "/tmp/$NM/r1.conf" 205 | no phyint 206 | phyint eth1 enable 207 | #phyint eth2 enable 208 | tunnel 10.0.1.1 10.0.2.2 metric 1 rate-limit 0 209 | EOF 210 | cat "/tmp/$NM/r1.conf" 211 | 212 | print "Creating mrouted.conf for R3 ..." 213 | cat < "/tmp/$NM/r3.conf" 214 | no phyint 215 | #phyint eth5 enable 216 | phyint eth6 enable 217 | tunnel 10.0.2.2 10.0.1.1 metric 1 rate-limit 0 218 | EOF 219 | cat "/tmp/$NM/r3.conf" 220 | 221 | print "Starting mrouted ..." 222 | nsenter --net="$NS2" -- ../src/mrouted -i NS2 -n -p "/tmp/$NM/r1.pid" -f "/tmp/$NM/r1.conf" -l debug -d all -u "/tmp/$NM/r1.sock" & 223 | echo $! >> "/tmp/$NM/PIDs" 224 | nsenter --net="$NS4" -- ../src/mrouted -i NS4 -n -p "/tmp/$NM/r3.pid" -f "/tmp/$NM/r3.conf" -l debug -d all -u "/tmp/$NM/r3.sock" & 225 | echo $! >> "/tmp/$NM/PIDs" 226 | # sleep 1 227 | 228 | # Wait for routers to peer 229 | print "Waiting for OSPF routers to peer (30 sec) ..." 230 | tenacious 30 nsenter --net="$NS1" -- ping -qc 1 -W 1 10.0.3.10 >/dev/null 231 | dprint "OK" 232 | 233 | #dprint "DVMRP Status $NS2" 234 | #nsenter --net="$NS2" -- ../src/mroutectl -u "/tmp/$NM/r1.sock" show compat detail 235 | #dprint "DVMRP Status $NS4" 236 | #nsenter --net="$NS4" -- ../src/mroutectl -u "/tmp/$NM/r3.sock" show compat detail 237 | # echo 238 | # echo 239 | # print "Sleeping 10 sec to allow mrouted instances to peer ..." 240 | # sleep 10 241 | # dprint "DVMRP Status $NS2" 242 | # nsenter --net="$NS2" -- ../src/mroutectl -u "/tmp/$NM/r1.sock" show compat detail 243 | # nsenter --net="$NS2" -- ../src/mroutectl -u "/tmp/$NM/r1.sock" show routes 244 | # dprint "DVMRP Status $NS4" 245 | # nsenter --net="$NS4" -- ../src/mroutectl -u "/tmp/$NM/r3.sock" show compat detail 246 | # nsenter --net="$NS4" -- ../src/mroutectl -u "/tmp/$NM/r3.sock" show routes 247 | # dprint "OK" 248 | 249 | # print "Checking VIFs ..." 250 | # nsenter --net="$NS2" -- cat /proc/net/ip_mr_vif 251 | # nsenter --net="$NS4" -- cat /proc/net/ip_mr_vif 252 | 253 | 254 | # dprint "OSPF State & Routing Table $NS2:" 255 | # nsenter --net="$NS2" -- echo "show ospf state" | birdc -s "/tmp/$NM/r1-bird.sock" 256 | # nsenter --net="$NS2" -- echo "show ospf int" | birdc -s "/tmp/$NM/r1-bird.sock" 257 | # nsenter --net="$NS2" -- echo "show ospf neigh" | birdc -s "/tmp/$NM/r1-bird.sock" 258 | # nsenter --net="$NS2" -- ip route 259 | 260 | # dprint "OSPF State & Routing Table $NS3:" 261 | # nsenter --net="$NS4" -- echo "show ospf state" | birdc -s "/tmp/$NM/r2-bird.sock" 262 | # nsenter --net="$NS4" -- echo "show ospf int" | birdc -s "/tmp/$NM/r2-bird.sock" 263 | # nsenter --net="$NS3" -- echo "show ospf neigh" | birdc -s "/tmp/$NM/r2-bird.sock" 264 | # nsenter --net="$NS3" -- ip route 265 | 266 | # dprint "OSPF State & Routing Table $NS4:" 267 | # nsenter --net="$NS4" -- echo "show ospf state" | birdc -s "/tmp/$NM/r3-bird.sock" 268 | # nsenter --net="$NS4" -- echo "show ospf int" | birdc -s "/tmp/$NM/r3-bird.sock" 269 | # nsenter --net="$NS4" -- echo "show ospf neigh" | birdc -s "/tmp/$NM/r3-bird.sock" 270 | # nsenter --net="$NS4" -- ip route 271 | 272 | # For debugging 273 | nsenter --net="$NS2" -- tshark -lni eth2 -w "/tmp/$NM/r1.pcap" 2>/dev/null & 274 | echo $! >> "/tmp/$NM/PIDs" 275 | nsenter --net="$NS3" -- tshark -lni eth3 -w "/tmp/$NM/r2.pcap" 2>/dev/null & 276 | echo $! >> "/tmp/$NM/PIDs" 277 | nsenter --net="$NS4" -- tshark -lni eth5 -w "/tmp/$NM/r3.pcap" 2>/dev/null & 278 | echo $! >> "/tmp/$NM/PIDs" 279 | nsenter --net="$NS5" -- tshark -lni eth0 -w "/tmp/$NM/ed2.pcap" 2>/dev/null & 280 | echo $! >> "/tmp/$NM/PIDs" 281 | 282 | print "Starting emitter ..." 283 | nsenter --net="$NS5" -- ./mping -qr -i eth0 -t 5 -W 30 225.1.2.3 & 284 | echo $! >> "/tmp/$NM/PIDs" 285 | sleep 1 286 | 287 | if ! nsenter --net="$NS1" -- ./mping -s -i eth0 -t 5 -c 10 -w 30 225.1.2.3; then 288 | dprint "DVMRP Status $NS2" 289 | nsenter --net="$NS2" -- cat /proc/net/ip_mr_vif 290 | nsenter --net="$NS2" -- cat /proc/net/ip_mr_cache 291 | nsenter --net="$NS2" -- ../src/mroutectl -u "/tmp/$NM/r1.sock" show compat detail 292 | dprint "DVMRP Status $NS4" 293 | nsenter --net="$NS4" -- cat /proc/net/ip_mr_vif 294 | nsenter --net="$NS4" -- cat /proc/net/ip_mr_cache 295 | nsenter --net="$NS4" -- ../src/mroutectl -u "/tmp/$NM/r3.sock" show compat detail 296 | echo "Failed routing, expected at least 10 multicast ping replies" 297 | FAIL 298 | fi 299 | 300 | OK 301 | -------------------------------------------------------------------------------- /test/shared.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Two routers with shared segments 3 | # 4 | # 10.0.0.0/24 10.0.1.0/24 5 | # 6 | # .--- eth1:R1:eth2 ---. 7 | # / \ 8 | # / \ 9 | # ED1 ---br0 br1--- ED2 10 | # \ / 11 | # \ / 12 | # '--- eth3:R2:eth4 ---' 13 | # 14 | # 15 | 16 | # shellcheck source=/dev/null 17 | . "$(dirname "$0")/lib.sh" 18 | 19 | # Requires OSPF (bird) to build the unicast rpf tree 20 | print "Check deps ..." 21 | check_dep ethtool 22 | check_dep tshark 23 | check_dep bird 24 | check_dep keepalived 25 | 26 | print "Creating world ..." 27 | R1="/tmp/$NM/R1" 28 | R2="/tmp/$NM/R2" 29 | ED1="/tmp/$NM/ED1" 30 | ED2="/tmp/$NM/ED2" 31 | touch "$R1" "$R2" "$ED1" "$ED2" 32 | 33 | echo "$R1" > "/tmp/$NM/mounts" 34 | echo "$R2" >> "/tmp/$NM/mounts" 35 | echo "$ED1" >> "/tmp/$NM/mounts" 36 | echo "$ED2" >> "/tmp/$NM/mounts" 37 | 38 | unshare --net="$R1" -- ip link set lo up 39 | unshare --net="$R2" -- ip link set lo up 40 | unshare --net="$ED1" -- ip link set lo up 41 | unshare --net="$ED2" -- ip link set lo up 42 | 43 | 44 | # Creates a VETH pair, one end named eth0 and the other is eth7: 45 | # 46 | # created /tmp/foo eth0 eth7 1.2.3.4/24 1.2.3.1 47 | # 48 | # Disabling UDP checksum offloading with ethtool, frames are leaving 49 | # kernel space on these VETH pairs. (Silence noisy ethtool output) 50 | created() 51 | { 52 | in=$2 53 | if echo "$3" | grep -q '@'; then 54 | ut=$(echo "$3" | cut -f1 -d@) 55 | id=$(echo "$3" | cut -f2 -d@) 56 | else 57 | ut=$3 58 | fi 59 | 60 | echo "Creating device interfaces $in and $ut ..." 61 | nsenter --net="$1" -- ip link add "$in" type veth peer "$ut" 62 | nsenter --net="$1" -- ip link set "$in" up 63 | 64 | nsenter --net="$1" -- ip addr add "$4" broadcast + dev "$2" 65 | nsenter --net="$1" -- ip route add default via "$5" 66 | 67 | for iface in "$in" "$ut"; do 68 | nsenter --net="$1" -- ethtool --offload "$iface" tx off >/dev/null 69 | nsenter --net="$1" -- ethtool --offload "$iface" rx off >/dev/null 70 | done 71 | 72 | nsenter --net="$1" -- sysctl -w net.ipv6.conf.all.disable_ipv6=1 73 | if [ -n "$id" ]; then 74 | echo "$1 moving $ut to netns PID $id" 75 | nsenter --net="$1" -- ip link set "$ut" netns "$id" 76 | fi 77 | 78 | return $! 79 | } 80 | 81 | # Syntax: 82 | # a:b 83 | # a@pid:b 84 | # a:b@pid 85 | # 86 | # Unsupported: 87 | # a@pid:b@pid 88 | create_vpair() 89 | { 90 | ns=$1 91 | pair=$2 92 | addr=$3 93 | 94 | # a:b with possible @ to denote that either side should move @ pid netns 95 | if echo "$pair" |grep -q ':'; then 96 | echo "$ns: veth pair $pair ============================" 97 | x=$(echo "$pair" | cut -f1 -d:) 98 | y=$(echo "$pair" | cut -f2 -d:) 99 | echo "Found x=$x and y=$y ..." 100 | 101 | if echo "$x" | grep -q '@'; then 102 | a=$(echo "$x" | cut -f1 -d@) 103 | p=$(echo "$x" | cut -f2 -d@) 104 | b=$y 105 | elif echo "$y" | grep -q '@'; then 106 | a=$(echo "$y" | cut -f1 -d@) 107 | p=$(echo "$y" | cut -f2 -d@) 108 | b=$x 109 | fi 110 | 111 | echo " Found a=$a and p=$p, with b=$b ..." 112 | 113 | echo " creating interfaces $a and $b ..." 114 | nsenter --net="$ns" -- ip link add "$a" type veth peer "$b" 115 | for iface in "$a" "$b"; do 116 | nsenter --net="$ns" -- ethtool --offload "$iface" tx off >/dev/null 117 | nsenter --net="$ns" -- ethtool --offload "$iface" rx off >/dev/null 118 | done 119 | echo " moving $a to netns PID $p" 120 | nsenter --net="$ns" -- ip link set "$a" netns "$p" 121 | else 122 | # Not a pair, an after-the-fact set-address on an interface 123 | b=$pair 124 | fi 125 | 126 | nsenter --net="$ns" -- sysctl -w net.ipv6.conf.all.disable_ipv6=1 127 | 128 | echo " Bringing up $b with addr $addr" 129 | nsenter --net="$ns" -- ip link set "$b" up 130 | nsenter --net="$ns" -- ip addr add "$addr" broadcast + dev "$b" 131 | } 132 | 133 | creater() 134 | { 135 | create_vpair $1 $2 $4 136 | create_vpair $1 $3 $5 137 | } 138 | 139 | dprint "Creating end-devices ..." 140 | nsenter --net="$ED1" -- sleep 5 & 141 | pid0=$! 142 | nsenter --net="$ED2" -- sleep 5 & 143 | pid3=$! 144 | 145 | create_vpair "$ED1" eth0:eth0b@"$pid0" 10.0.0.10/24 146 | nsenter --net="$ED1" -- ip route add default via 10.0.0.1 147 | 148 | create_vpair "$ED2" eth0:eth0b@"$pid0" 10.0.1.10/24 149 | nsenter --net="$ED2" -- ip route add default via 10.0.1.1 150 | 151 | dprint "Creating R1 router with eth1b in PID $pid0 and eth2 in PID $pid3" 152 | creater "$R1" eth1b@"$pid0":eth1 eth2:eth2b@"$pid3" 10.0.0.2/24 10.0.1.2/24 153 | 154 | dprint "Creating R2 router with eth1b in PID $pid0 and eth4 in PID $pid3" 155 | creater "$R2" eth3b@"$pid0":eth3 eth4:eth4b@"$pid3" 10.0.0.3/24 10.0.1.3/24 156 | 157 | dprint "Finalizing $ED1 end-device ..." 158 | nsenter --net="$ED1" -- ip link set eth0 up 159 | nsenter --net="$ED1" -- ip link set eth0b up 160 | nsenter --net="$ED1" -- ip link set eth1b up 161 | nsenter --net="$ED1" -- ip link set eth3b up 162 | nsenter --net="$ED1" -- ip link add br0 type bridge 163 | nsenter --net="$ED1" -- ip link set br0 up 164 | nsenter --net="$ED1" -- ip link set eth0b master br0 165 | nsenter --net="$ED1" -- ip link set eth1b master br0 166 | nsenter --net="$ED1" -- ip link set eth3b master br0 167 | 168 | dprint "Finalizing $ED2 end-device ..." 169 | nsenter --net="$ED2" -- ip link set eth0 up 170 | nsenter --net="$ED2" -- ip link set eth0b up 171 | nsenter --net="$ED2" -- ip link set eth2b up 172 | nsenter --net="$ED2" -- ip link set eth4b up 173 | nsenter --net="$ED2" -- ip link add br0 type bridge 174 | nsenter --net="$ED2" -- ip link set br0 up 175 | nsenter --net="$ED2" -- ip link set eth0b master br0 176 | nsenter --net="$ED2" -- ip link set eth2b master br0 177 | nsenter --net="$ED2" -- ip link set eth4b master br0 178 | 179 | print "$R1: starting up VRRP ..." 180 | cat < "/tmp/$NM/keep-r1.conf" 181 | vrrp_instance left { 182 | state MASTER 183 | interface eth1 184 | virtual_router_id 51 185 | priority 255 186 | advert_int 1 187 | virtual_ipaddress { 188 | 10.0.0.1/24 189 | } 190 | } 191 | vrrp_instance right { 192 | state MASTER 193 | interface eth2 194 | virtual_router_id 52 195 | priority 255 196 | advert_int 1 197 | virtual_ipaddress { 198 | 10.0.1.1/24 199 | } 200 | } 201 | vrrp_sync_group r1 { 202 | group { 203 | left 204 | right 205 | } 206 | } 207 | EOF 208 | cat "/tmp/$NM/keep-r1.conf" 209 | 210 | nsenter --net="$R1" -- keepalived -P -p "/tmp/$NM/keep-r1.pid" -r "/tmp/$NM/vrrp-r1.pid" -f "/tmp/$NM/keep-r1.conf" -l -D -n & 211 | echo $! >> "/tmp/$NM/PIDs" 212 | 213 | print "$R2: starting up VRRP ..." 214 | cat < "/tmp/$NM/keep-r2.conf" 215 | vrrp_instance left { 216 | state BACKUP 217 | interface eth3 218 | virtual_router_id 51 219 | priority 254 220 | advert_int 1 221 | virtual_ipaddress { 222 | 10.0.0.1/24 223 | } 224 | } 225 | vrrp_instance right { 226 | state BACKUP 227 | interface eth4 228 | virtual_router_id 52 229 | priority 254 230 | advert_int 1 231 | virtual_ipaddress { 232 | 10.0.1.1/24 233 | } 234 | } 235 | vrrp_sync_group r2 { 236 | group { 237 | left 238 | right 239 | } 240 | } 241 | EOF 242 | cat "/tmp/$NM/keep-r2.conf" 243 | 244 | nsenter --net="$R2" -- keepalived -P -p "/tmp/$NM/keep-r2.pid" -r "/tmp/$NM/vrrp-r2.pid" -f "/tmp/$NM/keep-r2.conf" -l -D -n & 245 | echo $! >> "/tmp/$NM/PIDs" 246 | 247 | print "Creating OSPF config ..." 248 | cat < "/tmp/$NM/bird.conf" 249 | protocol device { 250 | } 251 | protocol direct { 252 | ipv4; 253 | } 254 | protocol kernel { 255 | ipv4 { 256 | export all; 257 | }; 258 | learn; 259 | } 260 | protocol ospf { 261 | ipv4 { 262 | import all; 263 | }; 264 | area 0 { 265 | interface "eth*" { 266 | type broadcast; 267 | hello 1; 268 | wait 3; 269 | dead 5; 270 | }; 271 | }; 272 | } 273 | EOF 274 | cat "/tmp/$NM/bird.conf" 275 | 276 | print "Starting Bird OSPF ..." 277 | nsenter --net="$R1" -- bird -c "/tmp/$NM/bird.conf" -d -s "/tmp/$NM/r1-bird.sock" & 278 | echo $! >> "/tmp/$NM/PIDs" 279 | nsenter --net="$R2" -- bird -c "/tmp/$NM/bird.conf" -d -s "/tmp/$NM/r2-bird.sock" & 280 | echo $! >> "/tmp/$NM/PIDs" 281 | # sleep 1 282 | 283 | print "Starting mrouted ..." 284 | nsenter --net="$R1" -- ../src/mrouted -i R1 -n -p "/tmp/$NM/r1.pid" -l debug -u "/tmp/$NM/r1.sock" & 285 | echo $! >> "/tmp/$NM/PIDs" 286 | nsenter --net="$R2" -- ../src/mrouted -i R2 -n -p "/tmp/$NM/r2.pid" -l debug -u "/tmp/$NM/r2.sock" & 287 | echo $! >> "/tmp/$NM/PIDs" 288 | # sleep 1 289 | 290 | # print "Router link states" 291 | # dprint "$ED1" 292 | # nsenter --net="$ED1" -- ip -br l 293 | # nsenter --net="$ED1" -- ip -br a 294 | # nsenter --net="$ED1" -- bridge link 295 | # dprint "$R1" 296 | # nsenter --net="$R1" -- ip -br l 297 | # nsenter --net="$R1" -- ip -br a 298 | # dprint "$R2" 299 | # nsenter --net="$R2" -- ip -br l 300 | # nsenter --net="$R2" -- ip -br a 301 | # dprint "$ED2" 302 | # nsenter --net="$ED2" -- ip -br l 303 | # nsenter --net="$ED2" -- ip -br a 304 | # nsenter --net="$ED2" -- bridge link 305 | 306 | # print "Routing tables on end-devices" 307 | # dprint "$ED1" 308 | # nsenter --net="$ED1" -- ip -br r 309 | # nsenter --net="$ED1" -- bridge fdb show 310 | # nsenter --net="$ED1" -- ping -c 10 -W 1 10.0.0.1 311 | # nsenter --net="$ED1" -- ip neigh 312 | # dprint "$ED2" 313 | # nsenter --net="$ED2" -- ip -br r 314 | # nsenter --net="$ED2" -- bridge fdb show 315 | # nsenter --net="$ED2" -- ping -c 10 -W 1 10.0.1.1 316 | # nsenter --net="$ED2" -- ip neigh 317 | 318 | # Wait for routers to peer 319 | print "Waiting for OSPF routers to peer (30 sec) ..." 320 | # sleep 10 321 | # dprint "R1 <-> R2" 322 | tenacious 30 nsenter --net="$R1" -- ping -qc 1 -W 1 10.0.1.2 >/dev/null 323 | dprint "OK" 324 | 325 | print "Verifying end-to-end unicast connectivity (30 sec) ..." 326 | tenacious 30 nsenter --net="$ED1" -- ping -qc 1 -W 1 10.0.1.10 >/dev/null 327 | dprint "OK" 328 | 329 | print "Starting emitter ..." 330 | nsenter --net="$ED2" -- ./mping -qr -i eth0 -t 5 -W 30 225.1.2.3 & 331 | echo $! >> "/tmp/$NM/PIDs" 332 | sleep 1 333 | 334 | if ! nsenter --net="$ED1" -- ./mping -s -i eth0 -t 5 -c 10 -w 30 225.1.2.3; then 335 | dprint "DVMRP Status $R1" 336 | nsenter --net="$R1" -- ../src/mroutectl -u "/tmp/$NM/r1.sock" show compat detail 337 | dprint "DVMRP Status $R2" 338 | nsenter --net="$R2" -- ../src/mroutectl -u "/tmp/$NM/r2.sock" show compat detail 339 | dprint "DVMRP Status $R3" 340 | nsenter --net="$R3" -- ../src/mroutectl -u "/tmp/$NM/r3.sock" show compat detail 341 | dprint "DVMRP Status $R4" 342 | nsenter --net="$R4" -- ../src/mroutectl -u "/tmp/$NM/r4.sock" show compat detail 343 | echo "Failed routing, expected at least 10 multicast ping replies" 344 | FAIL 345 | fi 346 | 347 | OK 348 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | mrouted (4.6) stable; urgency=low 2 | 3 | * Issue #56: ensure group timers are stopped when stopping interfaces 4 | * Issue #56: replace homegrown timer and socket handling with pev v2.0. 5 | The existing timer implementation was too imprecise and jittered 6 | several seconds between query intervals 7 | * Issue #64: fix compiler warnings when building with 64-bit 'time_t' 8 | targeting 32-bit platforms (only affects logging and status output) 9 | * Fix 'mroutectl show routes', locally connected routes never expire 10 | * Skip timeout of subordinates at startup 11 | * Minor compiler warnings on non-Linux systems 12 | * Check interface status and update internal state on more error 13 | codes instead of logging 'sendto()' or 'sendmsg()' failure 14 | * Revert change in 'TIMER_INTERVAL' from v4.0, update interval is 15 | now 5 seconds instead of 2 16 | * Removed internal log rate limiter, demystifies behavior and greatly 17 | simplifies the code 18 | * Log interface names with their assigned VIF number to ease debugging 19 | * Speed up peering by sending route reports as soon as one-way peering 20 | has been established 21 | * Updates to logging, clarifying source 0.0.0.0 of routes as "us", and 22 | add logging when adding and discarding groups to/from interfaces 23 | * Use (S, G) format for all logging 24 | * Silence bogus 'Failed MRT_DEL_MFC' warnings for routes never added to 25 | the MRIB due to missing reverse path 26 | * Drop lsb-base dependency for mrouted package. To use init script on 27 | non-systemd setups, install sysvinit-utils 28 | 29 | -- Joachim Wiberg Sun, 10 Nov 2024 09:01:00 +0100 30 | 31 | mrouted (4.5) stable; urgency=low 32 | 33 | * Ignore IGMP proxy querys (src ip: 0.0.0.0), they must never win 34 | a querier election. 35 | * Add support for configurable IGMP query response interval 36 | * Add support for configurable IGMP querier timeout 37 | * ADd support for explicit group memberships, using a new 38 | phyint keyword 'join-group '. Forces an IGMPv2 join 39 | on the given interface. Never expires 40 | * On startup and reconf, log why we skip disabled interfaces 41 | * Change to always log when assuming the IGMP querier role 42 | * Fix compat read location and new location for `mrouted.genid` 43 | * Fix "non-decreasing" generation id, must increment on each restart 44 | 45 | -- Joachim Wiberg Sun, 04 Jun 2023 17:05:48 +0200 46 | 47 | mrouted (4.4) stable; urgency=low 48 | 49 | * Issue #52: fix IPIP tunnels, both configuration and an off-by-one 50 | problem in unicast route distribution. 51 | * Fix 10 year old regression causing off-by-one (loss of one) in unicast 52 | route distribution (built-in RIP) -- root cause for issue #52 53 | * Warn if installing tunnel vifs fail, probably missing ipip.ko 54 | * Logging to stdout now always prefix messages with daemon identity 55 | * Renamed tunnel vifs to match kernel names -> dvmrpN 56 | * Dropped RSRR feature (never enabled in Debian packages) 57 | 58 | -- Joachim Wiberg Wed, 03 Nov 2021 11:54:42 +0100 59 | 60 | mrouted (4.3) stable; urgency=low 61 | * Add support for -i,--ident=NAME` to change identity of an instance 62 | * Add support for -p,--pidfile=FILE to override default PID file 63 | * Touch PID file at SIGHUP to acknowledge done reloading .conf file 64 | * Add support for -t,--table-id=ID, multicast routing tables 65 | * Add support for -u,--ipc=FILE to override /var/run/mrouted.sock file 66 | * Fix segfault when parsing phyint lines in .conf file interface 67 | cannot be found, e.g., phyint eth1 static-group 225.1.2.5 68 | * Prevent cascading warnings when phyint interface names cannot be found 69 | 70 | -- Joachim Wiberg Sun, 19 Sep 2021 01:06:37 +0200 71 | 72 | mrouted (4.2) stable; urgency=medium 73 | 74 | * Support for controlling IGMP Last Member Query Count using the 75 | igmp-robustness setting in mrouted.conf, default 2 76 | * Support for tuning the IGMP Last Member Query Interval using a 77 | new setting igmp-query-last-member-interval <1-1024> 78 | * Support for static multicast routing, similar to SMCRoute, using a new 79 | phyint keyword 'static-group GROUP'. Works as if an IGMPv2 join was 80 | received on the given interface. Never expires 81 | * IGMPv3 membership reports were parsed incorrectly. The problem affects 82 | users that use source specific multicast join, i.e., (S,G) join/leave 83 | using IGMPv3. Support for IGMPv3 was introduced in mrouted v4.0 84 | * Proper tracking of lower-version IGMP hosts. When a lower-version host 85 | joins a group no higer-version IGMP is allowed, e.g., IGMPv2 LEAVE is 86 | ignored if a group is in IGMPv1 compat mode 87 | * Allow IGMP reports from source address 0.0.0.0, for compliance with 88 | RFC3376. Should improve interop with IGMP snooping switches and any 89 | DHCP client that has not yet received a lease 90 | * Issue #46: Malformed group-specific IGMP query. The IGMP header no 91 | longer had the group field set, despite the query being addressed to a 92 | specific group. Regression introduced in v4.0 93 | * Issue #47: parser did not allow the (optional) phyint keyword 'igmpv3' 94 | * Improved support for running mroutectl under watch(1). No more 95 | artifacts due to unknown ANSI escape sequences to probe width 96 | * Delayed PID file creation until after initial startup delay, there 97 | is nobody home until after that delay, so no point in announcing 98 | availability until after that 99 | * Fix buffer overrun in descriptor `poll()` handling 100 | * Fix double-close on SIGHUP, Linux systems only 101 | * Various non-critical memory leak fixes, critical for no-MMU systems 102 | 103 | -- Joachim Wiberg Thu, 07 Jan 2021 04:57:48 +0100 104 | 105 | mrouted (4.1) stable; urgency=medium 106 | 107 | * Update maintainer last name 108 | * Refactor interface probing to fix `no phyint` on systems with 109 | many interfaces. Now possible to use only a select few phyints 110 | * Support for automatically adding secondary IP addresses as altnet 111 | * Improve error message, and document in mrouted(8), common startup 112 | problems, e.g., running out of IGMP groups on Linux 113 | * Improve error message when receiving multicast on unknown vifs 114 | * Massive update of mrouted.conf(5), lots of options missing: 115 | * prune-lifetime 116 | * rexmit-prunes 117 | * phyint and tunnel interface flags: 118 | * advert-metric 119 | * allow-nonpruners 120 | * blaster 121 | * force-leaf 122 | * noflood 123 | * passive 124 | * prune-lifetime 125 | rexmit-prunes 126 | * The tunnel option beside off 127 | * Route filtering options with accept, deny, and notransit 128 | * Fixes to update of mrouted.genid file 129 | * Fix location of mrouted.genid, should be in /var/lib/misc 130 | * Fix annoying message "cCannot disable multicast routing" at startup 131 | * Fix double free in PID file code 132 | 133 | -- Joachim Wiberg Fri, 02 Oct 2020 05:19:06 +0200 134 | 135 | mrouted (4.0) unstable; urgency=medium 136 | 137 | * New upstream release with support for IGMP v3 and a new mroutectl tool. 138 | For more information, see the upstream release notes at GitHub. 139 | https://github.com/troglobit/mrouted/releases/tag/4.0 140 | * Note: both command line options and .conf file settings have changed 141 | significantly from the mroute-3 series. 142 | 143 | -- Joachim Nilsson Tue, 09 Jun 2020 22:06:47 +0200 144 | 145 | mrouted (3.9.8) unstable; urgency=low 146 | 147 | * New upstream release. For details see the GitHub release page at 148 | https://github.com/troglobit/mrouted/releases/tag/3.9.8 149 | 150 | -- Joachim Nilsson Sun, 1 Jan 2017 20:23:00 +0100 151 | 152 | mrouted (3.9.7) unstable; urgency=low 153 | 154 | * New upstream release. For details see the GitHub release page at 155 | https://github.com/troglobit/mrouted/releases/tag/3.9.7 156 | 157 | -- Joachim Nilsson Sun, 28 Dec 2014 16:15:14 +0100 158 | 159 | mrouted (3.9.6) unstable; urgency=low 160 | 161 | * New upstream release. 162 | * Fix: Breakage caused by link list refactor. 163 | 164 | -- Joachim Nilsson Sun, 9 Jun 2013 22:45:00 +0100 165 | 166 | mrouted (3.9.5) unstable; urgency=low 167 | 168 | * New upstream release. 169 | * Fix: Insecure file creation in /var/tmp, files now in /var/run/mrouted 170 | 171 | -- Joachim Nilsson Sun, 5 Mar 2011 21:30:00 +0100 172 | 173 | mrouted (3.9.4) unstable; urgency=low 174 | 175 | * New upstream release. 176 | * Fix: mrouted exits with error when trying to remove interface gone down. 177 | 178 | -- Joachim Nilsson Sun, 3 Oct 2010 01:42:00 +0100 179 | 180 | mrouted (3.9.3) unstable; urgency=low 181 | 182 | * New upstream release. 183 | * Removes restriction on interfaces not having a 255.255.255.255 netmask. 184 | Fixes issues for users with OpenVPN, PPTP, L2TP tunnels or PPP links. 185 | See http://openvpn.net/archive/openvpn-users/2004-04/msg00003.html 186 | * Fixes segfaults at start with interfaces having no address. 187 | 188 | -- Joachim Nilsson Sun, 3 Oct 2010 01:42:00 +0100 189 | 190 | mrouted (3.9.2) unstable; urgency=low 191 | 192 | * New upstream (bugfix) release. 193 | * New maintainer and new upstream. 194 | * Move package back to main, the OpenBSD team has freed it! 195 | * Conflicts with pimd, for obvious reasons. 196 | * Conflicts with smcroute, due to it also having a daemon using the same 197 | interfaces in the kernel. 198 | * Added lintian-overrides for empty-debian-diff as debian dir is maintained 199 | along the upstream sources 200 | * Changed to use debhelper to manage debian/rules file. 201 | 202 | -- Joachim Nilsson Tue, 17 Aug 2010 08:32:02 +0100 203 | 204 | mrouted (3.9-beta3-3) unstable; urgency=low 205 | 206 | * New maintainer (close: #121397) 207 | * Added mrouted.conf installation 208 | * Added man pages 209 | 210 | -- Jean-Francois Dive Wed, 20 Feb 2002 18:39:57 +1100 211 | 212 | mrouted (3.9-beta3-2) unstable; urgency=low 213 | 214 | * add support for RSRR (closes: #94509) 215 | * add builddepends for yacc (closes: #102782) 216 | * try to load module ipip for tunneling (closes: #39668) 217 | * include NMU fixes (Closes: Bug#91018, Bug#91597, Bug#93844) 218 | 219 | -- Christoph Martin Sat, 10 Nov 2001 17:29:52 +0100 220 | 221 | mrouted (3.9-beta3-1.1) unstable; urgency=low 222 | 223 | * Non-Maintainer upload 224 | * Rebuilt with latest debmake (Closes: Bug#91018, Bug#91597) 225 | * Added missing #include (Closes: Bug#93844) 226 | * Bumped standards-version, and added build-deps 227 | 228 | -- Gergely Nagy <8@free.bsd.hu> Fri, 13 Apr 2001 16:17:17 +0200 229 | 230 | mrouted (3.9-beta3-1) unstable; urgency=low 231 | 232 | * Initial Release. 233 | * Move package to nonfree 234 | 235 | -- Christoph Martin Mon, 1 Mar 1999 21:36:23 +0100 236 | 237 | 238 | -------------------------------------------------------------------------------- /man/mrouted.8: -------------------------------------------------------------------------------- 1 | .\" $OpenBSD: mrouted.8,v 1.25 2014/09/08 01:27:55 schwarze Exp $ 2 | .\" The mrouted program is covered by the license in the accompanying file 3 | .\" named "LICENSE". Use of the mrouted program represents acceptance of 4 | .\" the terms and conditions listed in that file. 5 | .\" 6 | .\" The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 7 | .\" Leland Stanford Junior University. 8 | .Dd Jan 7, 2021 9 | .Dt MROUTED 8 SMM 10 | .Os 11 | .Sh NAME 12 | .Nm mrouted 13 | .Nd IP multicast routing daemon 14 | .Sh SYNOPSIS 15 | .Nm mrouted 16 | .Op Fl hnsv 17 | .Op Fl d Ar SYS[,SYS,... 18 | .Op Fl f Ar FILE 19 | .Op Fl i Ar NAME 20 | .Op Fl l Ar LEVEL 21 | .Op Fl p Ar FILE 22 | .Op Fl t Ar ID 23 | .Op Fl u Ar FILE 24 | .Op Fl w Ar SEC 25 | .Sh DESCRIPTION 26 | .Nm 27 | is the original implementation of the Distance-Vector Multicast Routing 28 | Protocol (DVMRP), RFC 1075. A dynamic (automatic) multicast routing 29 | daemon, that also supports static routing. See 30 | .Xr mrouted.conf 5 31 | for information on the 32 | .Cm static-group 33 | configuration directive. 34 | .Pp 35 | .Nm 36 | is 37 | .Em simple 38 | to use. DVMRP is derived from RIP, RFC 1058, which means 39 | .Nm 40 | works stand-alone without any extra network setup required. You can get 41 | up and running in a matter of minutes. 42 | .Pp 43 | .Nm 44 | maintains topological knowledge via DVMRP, upon which it implements a 45 | multicast datagram forwarding algorithm called Reverse Path 46 | Multicasting. 47 | .Pp 48 | .Nm 49 | forwards multicast datagrams along the shortest (reverse) path tree 50 | rooted at the subnet on which the datagram originates. The multicast 51 | delivery tree may be thought of as a broadcast delivery tree that has 52 | been pruned back so that it does not extend beyond those subnetworks 53 | that have members of the destination group. Hence, datagrams are not 54 | forwarded along those branches which have no listeners of the multicast 55 | group. The IP time-to-live of a multicast datagram can be used to limit 56 | the range of multicast datagrams. 57 | .Pp 58 | In order to support multicasting among subnets that are separated by 59 | (unicast) routers that do not support IP multicasting, you can set up 60 | GRE tunnels. However, 61 | .Nm 62 | includes (built-in) support for IP-in-IP tunnels, which are virtual 63 | point-to-point links between pairs of DVMRP capable routers located 64 | anywhere in an internet. IP multicast packets are encapsulated for 65 | transmission through tunnels, so that they look like normal unicast 66 | datagrams to intervening routers and subnets. The encapsulation is 67 | added on entry to a tunnel, and stripped off on exit from a tunnel. 68 | .Pp 69 | The tunneling mechanism allows 70 | .Nm 71 | to establish a virtual internet, for the purpose of multicasting only, 72 | which is independent of the physical internet, and which may span 73 | multiple Autonomous Systems. This capability is intended for 74 | experimental support of internet multicasting only, pending widespread 75 | support for multicast routing by the regular (unicast) routers. 76 | .Nm 77 | suffers from the well-known scaling problems of any distance-vector 78 | routing protocol, and does not support hierarchical multicast routing. 79 | .Pp 80 | A more common practice today is to set up GRE tunnels between multicast 81 | capable routers and limit 82 | .Nm 83 | to run on a select number of interfaces listed in the configuration. 84 | .Pp 85 | .Nm 86 | handles multicast routing only; there may or may not be unicast routing 87 | software running on the same machine as 88 | .Nm mrouted . 89 | With the use of tunnels, it is not necessary for 90 | .Nm 91 | to have access to more than one physical subnet in order to perform 92 | multicast forwarding. 93 | .Pp 94 | .Sh OPTIONS 95 | This program follows the usual UNIX command line syntax, with long 96 | options starting with two dashes (`--'). The options are as follows: 97 | .Bl -tag -width Ds 98 | .It Fl d, -debug Ar SYS[,SYS,..] 99 | This option enables subsystem debug messages and causes 100 | .Nm 101 | to run in the foreground of the starting terminal, regardless of the 102 | .Fl l 103 | flag controls the (syslog) log level of each subsystem. Use '?' for a 104 | complete list of supported subsystems. 105 | .Pp 106 | Available subystems: 107 | .Pp 108 | .Bl -tag -width route-detail -compact -offset indent 109 | .It Cm packet 110 | Display the type, source and destination of all packets sent or received 111 | .It Cm pruning 112 | Display more information about prunes sent or received 113 | .It Cm routing 114 | Display more information about routing update packets sent or received 115 | .It Cm route-detail 116 | Display routing updates in excruciating detail. This is generally way too much information 117 | .It Cm neighbors 118 | Display information about neighbor discovery 119 | .It Cm cache 120 | Display insertions, deletions and refreshes of entries in the kernel forwarding cache 121 | .It Cm timer 122 | Debug timeouts and periodic processes 123 | .It Cm interface 124 | Display information about interfaces and their configuration 125 | .It Cm membership 126 | Display information about group memberships on physical interfaces 127 | .It Cm traceroute 128 | Display information about multicast traceroute requests passing through this router 129 | .It Cm igmp 130 | Display IGMP operation including group membership and querier election 131 | .It Cm icmp 132 | Monitor ICMP handling 133 | .It Cm all 134 | Enable all debug messages (except noisy timer) 135 | .El 136 | .It Fl f, -config Ar FILE 137 | Specify an alternative configuration file, default 138 | .Pa /etc/mrouted.conf 139 | .It Fl h, -help 140 | Print a help message and exit. 141 | .It Fl i, -ident Ar NAME 142 | Specify program identity (name) to be used for configuration file, PID 143 | file, generation ID file, UNIX IPC socket, and syslog messages. Useful 144 | with multiple instances of 145 | .Nm , 146 | or to adapt to site specific practices, e.g. "DVMRP", without renaming 147 | the binary. 148 | .Pp 149 | Note, this option only changes the base name of the files, not the 150 | location, which is system specific. On most systems this is 151 | .Pa /var/run/mrouted.pid , 152 | or 153 | .Pa /run/mrouted.pid , 154 | .Pa /run/mrouted.genid , 155 | .Pa /run/mrouted.sock , 156 | and 157 | .Pa /etc/mrouted.conf . 158 | .It Fl l, -loglevel Ar LEVEL 159 | Set log level for syslog messages: none, err, notice (default), info, 160 | debug. Use '?' for a complete list of supported log levels. 161 | .Pp 162 | .Bl -tag -width WARNING -compact -offset indent 163 | .It Cm none 164 | Disable all logging 165 | .It Cm error 166 | Error conditions 167 | .It Cm warning 168 | Warning conditions 169 | .It Cm notice 170 | Normal but significant condition (default) 171 | .It Cm info 172 | Informational 173 | .It Cm debug 174 | Debug-level messages 175 | .El 176 | .It Fl n, -foreground 177 | Run in foreground, do not detach from controlling terminal. This option 178 | is usually required when running under process supervisors like systemd 179 | and Finit, but is also useful when running from the terminal, when 180 | debugging a config or at initial set up. Remember to also give the 181 | .Fl s 182 | option if you still want to redirect log messages to the syslog. 183 | .It Fl p, -pidfile Ar FILE 184 | Set PID file name and location, defaults to 185 | .Pa /var/run/mrouted.pid . 186 | .It Fl s, -syslog 187 | Use 188 | .Xr syslog 3 189 | for log messages, warnings and error conditions. This is the default 190 | when running in the background. When running in the foreground, see 191 | .Fl n , 192 | log messages are printed to stdout. 193 | .It Fl t, -table-id Ar ID 194 | Set multicast routing table ID. Remember to also create routing rules 195 | directing packets to the table. This example uses routing table ID 123: 196 | .Bd -unfilled -offset left 197 | ip mrule add iif eth0 lookup 123 198 | ip mrule add oif eth0 lookup 123 199 | .Ed 200 | .Pp 201 | .Nm Note: 202 | Only available on Linux. 203 | .It Fl u, -ipc Ar FILE 204 | Override UNIX domain socket filename, the default on most systems is 205 | .Pa /var/run/mrouted.sock . 206 | .It Fl w, -startup-delay Ar SEC 207 | Wait for 208 | .Ar SEC 209 | seconds before applying routes. This delay allows exchange of routes 210 | before starting to forward multicast packets. In certain setups this 211 | can prevent transient problems at startup, at the cost of a momentary 212 | black hole. 213 | .El 214 | .Pp 215 | .Sh SIGNALS 216 | .Nm 217 | responds to the following signals: 218 | .Pp 219 | .Bl -tag -width TERM -compact 220 | .It HUP 221 | Restart 222 | .Nm mrouted 223 | and reload the configuration file. 224 | .It INT 225 | Terminate execution gracefully, i.e., by sending good-bye messages to 226 | all neighboring routers. 227 | .It TERM 228 | Same as INT. 229 | .El 230 | .Pp 231 | For convenience, 232 | .Nm 233 | writes its process ID to 234 | .Pa /var/run/mrouted.pid 235 | when it has completed its start up and is ready to receive signals. 236 | .Sh FILES 237 | .Bl -tag -width /var/lib/misc/mrouted.genid -compact 238 | .It Pa /etc/mrouted.conf 239 | Main configuration file. 240 | .It Pa /var/lib/misc/mrouted.genid 241 | DVMRP generation ID. Used by neighboring DVRMP routers to detect when a 242 | router is restarted. On BSD 243 | .Pa /var/db/mrouted.genid 244 | is used. 245 | .It Pa /var/run/mrouted.pid 246 | Pidfile (re)created by 247 | .Nm 248 | daemon when it has started up and is ready to receive commands. 249 | .It Pa /var/run/mrouted.sock 250 | .Ux 251 | domain socket used for communication with 252 | .Xr mroutectl 8 253 | .It Pa /proc/net/ip_mr_cache 254 | Holds active IPv4 multicast routes (Linux). 255 | .It Pa /proc/net/ip_mr_vif 256 | Holds the IPv4 virtual interfaces used by the active multicast routing 257 | daemon (Linux). 258 | .El 259 | .Sh COMPATIBILITY 260 | Dynamic multicast routing has never been use-case 1a for UNIX systems. 261 | Most systems are by default tuned to act as workstations, end devices. 262 | When something does not work, or only sort of works, run 263 | .Ql Nm Fl l Ar debug Fl d Ar all , 264 | optionally also with 265 | .Fl n , 266 | to get full logs of its interaction with the system. 267 | .Pp 268 | Particular problems include, but are not limited to: 269 | .Pp 270 | .Bl -tag -compact 271 | .It Cm ENOPROTOOPT 272 | Or similar, with an error message like this: 273 | .Bd -literal -offset indent 274 | Cannot enable multicast routing in kernel 275 | .Ed 276 | .Pp 277 | This comes from missing multicast routing support in the kernel. On 278 | Linux you need at least: 279 | .Bd -literal -offset indent 280 | CONFIG_IP_MROUTE=y 281 | .Ed 282 | .Pp 283 | On *BSD: 284 | .Bd -literal -offset indent 285 | options MROUTING # Multicast routing 286 | .Ed 287 | .It Cm ENOBUFS 288 | On Linux systems a common problem is that of many interfaces. The error 289 | message used to be something like this: 290 | .Bd -literal -offset indent 291 | Cannot join group 224.0.0.4: No buffer space available 292 | .Ed 293 | .Pp 294 | Today that cryptic message has been replaced with a request to 295 | adjust 296 | .Pa /proc/sys/net/ipv4/igmp_max_memberships 297 | to a value at least 3x the number of vifs to run on, e.g., by setting it 298 | in 299 | .Pa /etc/sysctl.conf 300 | or similar, depending on the system. 301 | .El 302 | .Sh SEE ALSO 303 | .Xr mrouted.conf 5 , 304 | .Xr mroutectl 8 , 305 | .Xr map-mbone 8 , 306 | .Xr mrinfo 8 , 307 | .Xr mtrace 8 , 308 | .Xr pimd 8 , 309 | .Xr smcroute 8 310 | .Rs 311 | .%A S. Deering 312 | .%O Proceedings of the ACM SIGCOMM '88 Conference 313 | .%T Multicast Routing in Internetworks and Extended LANs 314 | .Re 315 | .Pp 316 | The 317 | .Nm mrouted 318 | home page is 319 | .Aq https://github.com/troglobit/mrouted 320 | .Sh AUTHORS 321 | The following are the principal authors of 322 | .Nm , 323 | listed in no particular order: 324 | .Pp 325 | .An David Waitzman , 326 | .An Craig Partridge , 327 | .An Steve Deering , 328 | .An Ajit Thyagarajan , 329 | .An Bill Fenner , 330 | .An David Thaler , and 331 | .An Daniel Zappala . 332 | .Pp 333 | With contributions by many others. 334 | --------------------------------------------------------------------------------