diff options
Diffstat (limited to 'ax25rtd')
-rw-r--r-- | ax25rtd/Makefile.am | 25 | ||||
-rw-r--r-- | ax25rtd/Makefile.in | 342 | ||||
-rw-r--r-- | ax25rtd/README | 268 | ||||
-rw-r--r-- | ax25rtd/TODO | 10 | ||||
-rw-r--r-- | ax25rtd/ax25rtctl.c | 437 | ||||
-rw-r--r-- | ax25rtd/ax25rtd.c | 233 | ||||
-rw-r--r-- | ax25rtd/ax25rtd.conf | 82 | ||||
-rw-r--r-- | ax25rtd/ax25rtd.h | 163 | ||||
-rw-r--r-- | ax25rtd/cache_ctl.c | 330 | ||||
-rw-r--r-- | ax25rtd/cache_dump.c | 141 | ||||
-rw-r--r-- | ax25rtd/config.c | 736 | ||||
-rw-r--r-- | ax25rtd/listener.c | 579 |
12 files changed, 3346 insertions, 0 deletions
diff --git a/ax25rtd/Makefile.am b/ax25rtd/Makefile.am new file mode 100644 index 0000000..b804faa --- /dev/null +++ b/ax25rtd/Makefile.am @@ -0,0 +1,25 @@ + +etcfiles = ax25rtd.conf +etcdir = $(sysconfdir)/ax25 + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + +sbin_PROGRAMS = ax25rtd ax25rtctl + +LDADD = $(AX25_LIB) + +EXTRA_DIST = $(etcfiles) + +ax25rtd_SOURCES = \ + ax25rtd.c \ + ax25rtd.h \ + cache_ctl.c \ + cache_dump.c \ + config.c \ + listener.c + diff --git a/ax25rtd/Makefile.in b/ax25rtd/Makefile.in new file mode 100644 index 0000000..8925278 --- /dev/null +++ b/ax25rtd/Makefile.in @@ -0,0 +1,342 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AS = @AS@ +AWK = @AWK@ +AX25_LIB = @AX25_LIB@ +CC = @CC@ +DLLTOOL = @DLLTOOL@ +LD = @LD@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +NM = @NM@ +OBJDUMP = @OBJDUMP@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ + +etcfiles = ax25rtd.conf +etcdir = $(sysconfdir)/ax25 + +sbin_PROGRAMS = ax25rtd ax25rtctl + +LDADD = $(AX25_LIB) + +EXTRA_DIST = $(etcfiles) + +ax25rtd_SOURCES = ax25rtd.c ax25rtd.h cache_ctl.c cache_dump.c config.c listener.c + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +ax25rtd_OBJECTS = ax25rtd.o cache_ctl.o cache_dump.o config.o \ +listener.o +ax25rtd_LDADD = $(LDADD) +ax25rtd_DEPENDENCIES = +ax25rtd_LDFLAGS = +ax25rtctl_SOURCES = ax25rtctl.c +ax25rtctl_OBJECTS = ax25rtctl.o +ax25rtctl_LDADD = $(LDADD) +ax25rtctl_DEPENDENCIES = +ax25rtctl_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = README Makefile.am Makefile.in TODO + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(ax25rtd_SOURCES) ax25rtctl.c +OBJECTS = $(ax25rtd_OBJECTS) ax25rtctl.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ax25rtd/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.c.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +ax25rtd: $(ax25rtd_OBJECTS) $(ax25rtd_DEPENDENCIES) + @rm -f ax25rtd + $(LINK) $(ax25rtd_LDFLAGS) $(ax25rtd_OBJECTS) $(ax25rtd_LDADD) $(LIBS) + +ax25rtctl: $(ax25rtctl_OBJECTS) $(ax25rtctl_DEPENDENCIES) + @rm -f ax25rtctl + $(LINK) $(ax25rtctl_LDFLAGS) $(ax25rtctl_OBJECTS) $(ax25rtctl_LDADD) $(LIBS) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = ax25rtd + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +ax25rtctl.o: ax25rtctl.c ../config.h ../pathnames.h +ax25rtd.o: ax25rtd.c ../pathnames.h ax25rtd.h +cache_ctl.o: cache_ctl.c ax25rtd.h +cache_dump.o: cache_dump.c ax25rtd.h +config.o: config.c ../pathnames.h ax25rtd.h +listener.o: listener.c ../pathnames.h ax25rtd.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-sbinPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-sbinPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-libtool clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile \ + distclean-libtool distclean-tags distclean-generic \ + clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ +clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile mostlyclean-libtool \ +distclean-libtool clean-libtool maintainer-clean-libtool tags \ +mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \ +distdir info-am info dvi-am dvi check check-am installcheck-am \ +installcheck install-exec-am install-exec install-data-am install-data \ +install-am install uninstall-am uninstall all-redirect all-am all \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + @list='$(etcfiles)'; for p in $$list; do \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \ + done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ax25rtd/README b/ax25rtd/README new file mode 100644 index 0000000..a7bf2c4 --- /dev/null +++ b/ax25rtd/README @@ -0,0 +1,268 @@ +***************************************************************** +* Please send all comments and suggestions regarding ax25rtd to * +* Klaus Kudielka (oe1kib@oe1xtu.ampr.org). * +***************************************************************** + +Just a quick small README... +This will hopefully go into the man pages ASAP. + +Ax25routed +---------- + +/usr/sbin/ax25rtd + +This is a daemon that: + +- emulates the ceased "autorouter" of Linux Kernel AX.25 +- sets up ARP entries automagically +- may adjust IP routes and encapsulation mode + (although I really do not recomment to use this feature...) + +The "autorouter" is not really an autorouter. It just listens to the AX.25 +traffic on your ports and uses this information to setup AX.25 routes. This +can be turned on or off by altering the configuration file +/etc/ax25/ax25rtd.conf. + +Ax25routed provides a socket /var/ax25/ax25rtd/control which is used for +runtime maintainance through ax25rtctl or to set up new routes by other +daemons (a Flexnet router, perhaps?) + +On startup ax25rtd reads the configuration file and afterwards preloads +the caches from the files /var/ax25/ax25rtd/ax25_routes and +/var/ax25/ax25rtd/ip_routes. On SIGTERM or ax25rtctl --save it saves the +caches to those files. + +ax25rtd.conf +--------------- + +The file /etc/ax25/ax25rtd.conf is the configuration file for ax25rtd. +The parameters of the options shown here are the default values except the +ones marked with (example) + +ax25-maxroutes 256 +ip-maxroutes 256 + + The maximum size of the three lists / caches. On overflow, + ax25rtd will substitute the oldest entry with the new one. +[1k2] + This marks the beginning of per-port definitions. Note that + you have to use port names as defined in axports(5) here, + anywhere else you may use the port or the device name. + +ax25-learn-routes no + + Set this to "yes", ax25rtd will add the routing information + for every heard frame (with complete digipeater path) to the + kernel AX.25 routing table. Note that ax25rtd's internal cache + will be updated anyway, regardless of this option. + +ax25-learn-only-mine no + + If you set it to "yes", only frames that are sent to (1) the + interface callsign, (2) any of the listeners on this device, or + (3) the callsigns specified by ax25-more-mycalls will be used + to update the internal cache and (depending on + ax25-learn-routes) the kernel routing table. + +ax25-add-path db0ach (example) + + This is useful on DAMA digipeaters. In this case, the DAMA + master has to be used for _every_ AX.25 connection, thus + ax25rtd will add this digipeater(s) to every target we learn + that has no digipeater path (yet). "db0ach" is just an + example here. + +ax25-more-mycalls dl1bke dl1bke-8 (example) + + You can specify more calls as calls here that belong to + this interface... "dl1bke" and "dl1bke-8" are examples. + +ip-learn-routes no + + If set to "yes", ax25rtd will modify the IP routing table if it + receives an IP frame (directed to us). This is dangerous! + + It should not screw up your routing table, though. Ax25rtd + recognizes the netmask of the device and will adjust the route + only if it fits the netmask and the old route points to + one of the devices ax25rtd knows about (hence an AX.25 device). + + The problems begin if you have more than one port and a user + is able to hear your outgoing traffic on at least two of them. + Due to technical reasons ax25rtd adjusts the route _after_ the + kernel has sent the reply to the received TCP frame already. + This has technical reasons. + + If the remote does the same both are switching between the two + ports. + + Don't use this feature unless you know what you are doing. + + It _should_ be safe do enable this on one-port machines, although + I strongly recommend to set a network route instead, i.e.: + + route add -net 44.0.0.0 scc3 + + Note that ax25rtd's internal cache will be updated anyway, + regardless of this option. + +irtt <irtt> + + If ip-learn-routes is enabled this will assign newly added + routes an initial round trip time (IRTT) for TCP. <irtt> + is measured in msec, hence + + irtt 10000 + + sets the irtt to 10 seconds. A value of 0 disables this + feature (default). + +ip-adjust-mode no + + If you set this option to "yes" ax25rtd will change the IP + encapsulation mode according to the last received IP frame. + + The problem with this option is that the kernel AX.25 sends + a received IP frame to the IP layer regardless if it was + sent in UI frame encapsulation "mode datagram (dg)" or + in I frame encaps, hence in an AX.25 connection, "mode virtual + connect (vc)". The Linux kernel will respond to this frame + before ax25rtd can adjust the mode. If the remote does the + same... You get the picture. + + Don't use this feature unless you know what you are doing. + +arp-add no + + This option, if set to "yes", changes the ARP table to the + source callsign of the received frame. It should be harmless, + just has the the effect that if it is a new entry, the Linux + ARP code will send one ARP request before ax25rtd has adjust + the ARP table. If there was already an existing ARP entry + for this IP route, one IP datagram will be sent to the old + address. Not really a problem, I hope. + + +Ax25rtctl +--------- + +/usr/sbin/ax25rtctl <option> + +This is a program to control ax25rtd. There are several options: + +ax25rtctl --add ax25 <callsign> <dev> <time> [digipeater] +ax25rtctl -a ax25 <callsign> <dev> <time> [digipeater] + + Add an entry to the AX.25 routing table. If time is "0" + this entry will be marked permanent, hence: the daemon will not + overwrite this route. + +ax25rtctl --del ax25 <callsign> <dev> +ax25rtctl -d ax25 <callsign> <dev> + + Remove an entry from the AX.25 routing table. + +ax25rtctl --add ip <ip> <dev> <time> <call> <ipmode> +ax25rtctl -a ip <ip> <dev> <time> <call> <ipmode> + + Add an entry to the IP routing table. If time is "0" the + entry will be marked permanent. + +ax25rtctl --del ip <ip> +ax25rtctl -d ip <ip> + + Remove an entry from the IP routing table. + +ax25rtctl --list ax25 +ax25rtctl -l ax25 + + Lists the content of the cache for the AX.25 routing table. + +ax25rtctl --list ip +ax25rtctl -l ip + + Lists the content of the cache for the IP routing table. + +ax25rtctl --expire <minutes> +ax25rtctl -e <minutes> + + Removes the entries older than <minutes> from the caches and + the kernel routing tables. + +ax25rtctl --save +ax25rtctl -s + + Saves the AX.25 and IP cache to /var/ax25/ax25rtd/ax25_routes and + /var/ax25/ax25rtd/ip_routes (or the files specified in + /etc/ax25/ax25rtd.conf). + +ax25rtctl --reload +ax25rtctl -r + + Reloads the config file /etc/ax25/ax25rtd.conf. This will + *not* affect the caches or the heard list. + +ax25rtctl --shutdown +ax25rtctl -q + + Same as 'killall -TERM ax25rtd' ;-) + + +ax25rtctl --version +ax25rtctl -V + + Guess what... + + +Note that you can specify either the port name (as defined in +/etc/ax25/axports) or the interface name (shown by ifconfig). If names +conflict (i.e. port scc0 is in fact interface scc3, and vica versa), the +interface name has precedence over the port name. Example: + + ax25rtctl --add ax25 dl0tha scc3 0 db0pra + +is equivalent to + + ax25rtctl --add ax25 dl0tha 9k6 0 dbpra + +All commands return port names in their output, though. +With one exception: ax25_routes and ip_routes use interface names. + + +/var/ax25/ax25rtd/control +---------------------------- + +The commands recognized on this socket are: + +add ax25 <callsign> <dev> <time> [<digipeater>] + Add an AX.25 route +add ip <ip> <dev> <time> <call> <mode> + Add an IP route & mode + +del ax25 <callsign> <dev> + Remove an AX.25 route from cache an kernel routing table +del ip <ip> + Remove an IP route from cache and kernel routing table + +list [ax25|ip] + List cache entries. + +reload + Reload config + +save + Save cache + +expire <min> + Expire cache entries older than <min> minutes + +shutdown + Save caches and exit + +version + Prints the version of the ax25rtd + + +Note that every command has to end with a '\n', and every line of the +response ends with an '\n' as well. The last line of a cache list +is just a period alone on a line (".\n"). diff --git a/ax25rtd/TODO b/ax25rtd/TODO new file mode 100644 index 0000000..19e6627 --- /dev/null +++ b/ax25rtd/TODO @@ -0,0 +1,10 @@ + +What to do next? + +- convert the content of README to manual pages +- Use partly digipeated frames for the AX.25 routing table if we are the + next digipeater +- A solution for IP encapsulation mode changes +- Support for Flexnet routing information +- Support PE1CHL's autorouter (Rob, you promised to send me the specs...) +- A similar program for NET/ROM diff --git a/ax25rtd/ax25rtctl.c b/ax25rtd/ax25rtctl.c new file mode 100644 index 0000000..6f40423 --- /dev/null +++ b/ax25rtd/ax25rtctl.c @@ -0,0 +1,437 @@ +/* $Id: ax25rtctl.c,v 1.7 1997/06/05 18:52:55 oe1kib Exp oe1kib $ + * + * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <time.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/un.h> + +#include <config.h> +#include "../pathnames.h" + +static const struct option lopts[] = { + {"add", 1, 0, 'a'}, + {"del", 1, 0, 'd'}, + {"list", 1, 0, 'l'}, + {"expire", 1, 0, 'e'}, + {"save", 0, 0, 's'}, + {"reload", 0, 0, 'r'}, + {"shutdown", 0, 0, 'q'}, + {"Version", 0, 0, 'V'}, + {"help", 0, 0, 'h'}, + {"debug", 0, 0, 'x'}, + {"version", 0, 0, 'v'}, + {NULL, 0, 0, 0 } +}; + +static const char *sopts = "a:d:l:e:srqvVh"; + +static void usage(void) +{ + fprintf(stderr,"usage:\n"); + fprintf(stderr,"ax25rtctl -a|--add ax25 <callsign> <dev> <time> [digipeater]\n"); + fprintf(stderr," -a|--add ip <ip> <dev> <time> <call> <ipmode>\n"); + fprintf(stderr," -d|--del ax25 <callsign> <dev>\n"); + fprintf(stderr," -d|--del ip <ip>\n"); + fprintf(stderr," -l|--list ax25|ip\n"); + fprintf(stderr," -e|--expire <minutes>\n"); + fprintf(stderr," -s|--save\n"); + fprintf(stderr," -r|--reload\n"); + fprintf(stderr," -q|--shutdown\n"); + fprintf(stderr," -V|--Version\n"); + fprintf(stderr," -h|--help\n"); + fprintf(stderr," -v|--version\n"); + exit(1); +} + +static int open_socket(void) +{ + int sock, addrlen; + struct sockaddr_un addr; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + perror("ax25rtctl socket"); + exit(1); + } + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, DATA_AX25ROUTED_CTL_SOCK); + addrlen = strlen(DATA_AX25ROUTED_CTL_SOCK) + sizeof(addr.sun_family); + + if (connect(sock, (struct sockaddr *) &addr, addrlen) < 0) + { + perror("ax25rtctl connect"); + exit(1); + } + + return sock; +} + +static int wsock(int sock, char *s) +{ + return write(sock, s, strlen(s)); +} + +static char *get_next_arg(char **p) +{ + char *p2; + + if (p == NULL || *p == NULL) + return NULL; + + p2 = *p; + for (; *p2 && *p2 == ' '; p2++) ; + if (!*p2) + return NULL; + + *p = strchr(p2, ' '); + if (*p != NULL) + { + **p = '\0'; + (*p)++; + } + + return p2; +} + +static void list_ax25(void) +{ + int sock, len, offs; + char buf[512], *b, *s, *digi, *call, *dev, *ct; + time_t t; + + sock = open_socket(); + + wsock(sock, "list ax25\n"); + + offs = 0; + + printf("Callsign Port Last update Path\n"); + +/* + DB0PRA-15 scc3 Tue Aug 6 16:35:38 1996 +*/ + + while(1) + { + len = read(sock, buf+offs, sizeof(buf)-offs-1); + if (len <= 0) + { + close(sock); + return; + } + + buf[len+offs] = '\0'; + s = buf; + for (s = buf; (b = strchr(s, '\n')) != NULL; s = b+1) + { + *b = '\0'; + + if (s[0] == '.') + { + close(sock); + return; + } + + call = get_next_arg(&s); + dev = get_next_arg(&s); + t = strtol(get_next_arg(&s), NULL, 16); + + if (t == 0) + { + ct = "(permanent)"; + ct = strdup(ct); + } else { + ct = strdup(ctime(&t)); + ct[strlen(ct)-6] = '\0'; + } + + printf("%-9s %-6s %s", call, dev, ct); + + free(ct); + + while ( (digi = get_next_arg(&s)) != NULL) + printf(" %s", digi); + + printf("\n"); + } + + if (b == NULL && s != NULL) + { + offs = strlen(s); + if (offs) + memcpy(buf, s, offs); + } + } + + close(sock); +} + +static void list_ip(void) +{ + int sock, len, offs; + char buf[512], *b, *s, *ip, *call, *dev, *ct, *mode; + time_t t; + + sock = open_socket(); + + wsock(sock, "list ip\n"); + + offs = 0; + printf("IP Address Port Callsign Mode Last update\n"); + +/* + 255.255.255.255 scc3 DB0PRA-15 v Thu Jan 7 06:54:19 1971 + */ + while(1) + { + len = read(sock, buf+offs, sizeof(buf)-offs-1); + if (len <= 0) + { + close(sock); + return; + } + + buf[len+offs] = '\0'; + s = buf; + for (s = buf; (b = strchr(s, '\n')) != NULL; s = b+1) + { + *b = '\0'; + + if (s[0] == '.') + { + close(sock); + return; + } + + ip = get_next_arg(&s); + dev = get_next_arg(&s); + t = strtol(get_next_arg(&s), NULL, 16); + call = get_next_arg(&s); + mode = get_next_arg(&s); + + if (t == 0) + { + ct = "(permanent)"; + } else { + ct = ctime(&t); + ct[strlen(ct)-6] = '\0'; + } + + printf("%-15s %-6s %-9s %-4s %s\n", ip, dev, call, mode, ct); + } + + if (b == NULL && s != NULL) + { + offs = strlen(s); + if (offs) + memcpy(buf, s, offs); + } + } + + close(sock); +} + +static void Version(void) +{ + int sock; + char buf[256]; + + printf("ax25rtctl $Revision: 1.7 $\n"); + sock = open_socket(); + wsock(sock, "version\n"); + read(sock, buf, sizeof(buf)); + printf("%s", buf); + close(sock); +} + +static void debug(void) +{ + int sock, n, k; + unsigned char buf[256]; + fd_set fd_set, fd_set2; + struct timeval tv; + + + sock = open_socket(); + + while (1) + { + FD_ZERO(&fd_set); + FD_SET(0, &fd_set); + FD_SET(sock, &fd_set); + + FD_ZERO(&fd_set2); + FD_SET(sock, &fd_set2); + + tv.tv_sec = 0; + tv.tv_usec = 0; + if (select(sock+1, &fd_set, NULL, &fd_set2, &tv) < 0) + { + perror("socket gone"); + exit(1); + } + + if (FD_ISSET(sock, &fd_set2)) + exit(0); + + if (FD_ISSET(0, &fd_set)) + { + n = read(0, buf, sizeof(buf)); + if (n) + { + k = write(sock, buf, n); + if (k <= 0) + exit(0); + } + } + + if (FD_ISSET(sock, &fd_set)) + { + n = read(sock, buf, sizeof(buf)); + if (n) + write(0, buf, n); + } + } +} + +int main(int argc, char **argv) +{ + int sock, cmd, k, len; + unsigned char buf[256]; + int opt_ind = 0; + long when; + + cmd = getopt_long(argc, argv, sopts, lopts, &opt_ind); + switch (cmd) + { + case 'a': + if (!strcmp(optarg, "ax25")) + { + if (argc < optind+3) + usage(); + + len = sprintf(buf, "add ax25"); + for (k = optind; k < argc; k++) + len += sprintf(buf+len, " %s", argv[k]); + sprintf(buf+len, "\n"); + + sock = open_socket(); + wsock(sock, buf); + close(sock); + } else + if (!strcmp(optarg, "ip")) + { + if (argc < optind+5) + usage(); + + len = sprintf(buf, "add ip"); + for (k = optind; k < argc; k++) + len += sprintf(buf+len, " %s", argv[k]); + sprintf(buf+len, "\n"); + + sock = open_socket(); + wsock(sock, buf); + close(sock); + } else + usage(); + return 0; + case 'd': + if (!strcmp(optarg, "ax25")) + { + if (argc < optind+2) + usage(); + + sprintf(buf, "del ax25 %s %s\n", argv[optind], argv[optind+1]); + + sock = open_socket(); + wsock(sock, buf); + close(sock); + } else + if (!strcmp(optarg, "ip")) + { + if (argc < optind+1) + usage(); + + sprintf(buf, "del ip %s\n", argv[optind]); + + sock = open_socket(); + wsock(sock, buf); + close(sock); + } else + usage(); + return 0; + case 'l': + if (!strcmp(optarg, "ax25")) + list_ax25(); + else if (!strcmp(optarg, "ip")) + list_ip(); + else + usage(); + return 0; + case 'e': + when = atoi(optarg); + if (when <= 0) + usage(); + sock = open_socket(); + sprintf(buf, "expire %ld\n", when); + wsock(sock, buf); + close(sock); + return 0; + case 's': + sock = open_socket(); + wsock(sock, "save\n"); + close(sock); + return 0; + case 'r': + sock = open_socket(); + wsock(sock, "reload\n"); + close(sock); + return 0; + case 'q': + sock = open_socket(); + wsock(sock, "shutdown\n"); + close(sock); + return 0; + case 'V': + Version(); + return 0; + case 'v': + printf("ax25rtctl: %s\n", VERSION); + return 0; + case 'x': + debug(); + case ':': + case 'h': + case '?': + default: + usage(); + } + usage(); + return 1; +} diff --git a/ax25rtd/ax25rtd.c b/ax25rtd/ax25rtd.c new file mode 100644 index 0000000..0fdbb39 --- /dev/null +++ b/ax25rtd/ax25rtd.c @@ -0,0 +1,233 @@ +/* $Id: ax25rtd.c,v 1.6 1996/10/23 18:27:43 jreuter Exp jreuter $ + * + * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * This daemon tries to learn AX.25, ARP, IP route entries by listening + * to the AX.25 traffic. It caches up to 256 entries (in "FIFO" mode) + * and saves the cache on demand or at shutdown in /var/ax25/ax25rtd/ip_routes + * and /var/ax25/ax25rtd/ax25_routes. The configuration file is + * /etc/ax25/ax25rtd.conf, you can almost everything configure + * there. See ax25rtcl.c for runtime maintainance. + * + */ + +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <net/ethernet.h> +#include <netax25/ax25.h> +#include <netax25/axconfig.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> + +#include "../pathnames.h" +#include "ax25rtd.h" + +const char *Version = "ax25rtd $Revision: 1.6 $"; +config *Config = NULL; + +int reload = 0; + +ip_rt_entry * ip_routes = NULL; +int ip_routes_cnt = 0; +int ip_maxroutes = IP_MAXROUTES; + +ax25_rt_entry * ax25_routes = NULL; +int ax25_routes_cnt = 0; +int ax25_maxroutes = AX25_MAXROUTES; + + +config *dev_get_config(char *dev) +{ + config *config; + + for (config = Config; config; config = config->next) + if (!strcmp(config->dev, dev)) + return config; + + return port_get_config(dev); +} + +config *port_get_config(char *port) +{ + config *config; + + for (config = Config; config; config = config->next) + if (!strcmp(config->port, port)) + return config; + return NULL; +} + +void sig_reload(int d) +{ + reload = 1; + signal(SIGHUP, sig_reload); +} + +void sig_debug(int d) +{ + fprintf(stderr, "config:\n"); + dump_config(2); + fprintf(stderr, "ip-routes:\n"); + dump_ip_routes(2, 0); + fprintf(stderr, "ax25-routes:\n"); + dump_ax25_routes(2, 0); + signal(SIGUSR1, sig_debug); +} + +void sig_term(int d) +{ + save_cache(); + daemon_shutdown(0); +} + +void daemon_shutdown(int reason) +{ + unlink(DATA_AX25ROUTED_CTL_SOCK); + exit(reason); +} + +#define FD_MAX(fd) {fd_max = (fd > fd_max? fd : fd_max); FD_SET(fd, &fd_set);} + +int main(int argc, char **argv) +{ + unsigned char buf[256]; + int size, s; + int cntrl_s, cntrl_fd, cntrl_len; + struct sockaddr_un cntrl_addr; + fd_set fd_set, fd_set2; + int fd_max; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "ax25rtd: no AX.25 port configured\n"); + return 1; + } + + load_config(); + load_cache(); + + if (fork()) + return 0; + + if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_AX25))) == -1) + { + perror("AX.25 socket"); + return 1; + } + + if ((cntrl_s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + perror("Control socket"); + return 1; + } + + unlink(DATA_AX25ROUTED_CTL_SOCK); + + cntrl_addr.sun_family = AF_UNIX; + strcpy(cntrl_addr.sun_path, DATA_AX25ROUTED_CTL_SOCK); + cntrl_len = sizeof(cntrl_addr.sun_family) + strlen(DATA_AX25ROUTED_CTL_SOCK); + + if (bind(cntrl_s, (struct sockaddr *)&cntrl_addr, cntrl_len) < 0) + { + perror("bind Control socket"); + daemon_shutdown(1); + } + + chmod(DATA_AX25ROUTED_CTL_SOCK, 0600); + listen(cntrl_s, 1); + + signal(SIGUSR1, sig_debug); + signal(SIGHUP, sig_reload); + signal(SIGTERM, sig_term); + + cntrl_fd = -1; + + for (;;) + { + fd_max = 0; + FD_ZERO(&fd_set); + FD_ZERO(&fd_set2); + FD_MAX(s); + if (cntrl_fd > 0) + { + FD_MAX(cntrl_fd); + FD_SET(cntrl_fd, &fd_set2); + } else { + FD_MAX(cntrl_s); + } + + if (select(fd_max+1, &fd_set, NULL, &fd_set2, NULL) < 0) + { + if (errno == EINTR) /* woops! */ + continue; + + if (!FD_ISSET(cntrl_fd, &fd_set2)) + { + perror("select"); + save_cache(); + daemon_shutdown(1); + } else { + close(cntrl_fd); + cntrl_fd = -1; + continue; + } + } + + if (cntrl_fd > 0) + { + if (FD_ISSET(cntrl_fd, &fd_set)) + { + size = read(cntrl_fd, buf, sizeof(buf)); + if (size > 0) + { + buf[size] = '\0'; + interpret_command(cntrl_fd, buf); + } else { + close(cntrl_fd); + cntrl_fd = -1; + } + } + } else + if (FD_ISSET(cntrl_s, &fd_set)) + { + if ((cntrl_fd=accept(cntrl_s, (struct sockaddr *) &cntrl_addr, &cntrl_len)) < 0) + { + perror("accept Control"); + save_cache(); + daemon_shutdown(1); + } + } + + if (reload) + reload_config(); + + if (FD_ISSET(s, &fd_set)) + ax25_receive(s); + } + + return 0; /* what ?! */ +} diff --git a/ax25rtd/ax25rtd.conf b/ax25rtd/ax25rtd.conf new file mode 100644 index 0000000..47111a9 --- /dev/null +++ b/ax25rtd/ax25rtd.conf @@ -0,0 +1,82 @@ +# Example configuration for ax25rtd. I'm assuming that you have a central +# node with two interfaces serving the same subnet (this is my personal +# setup). +# +# For a general discussion of each parameter see ax25rtd/README. +# +# General setup +# ============= +# +# The size of the caches. When the cache is full, the oldest entry +# gets removed. +# +ax25-maxroutes 256 +ip-maxroutes 256 +# +# Port config +# =========== +# +# Note that you *must* specify the symbolic port +# name as defined in axports, not the device names. Personally, I like +# them to be identical. +# +# This is my 56kbps port (pi0a). It is the default interface and has a +# static network route pointing to it. All users access this interface +# directly and *not* via digipeaters. +# +[pi0a] +# +# Since all users access this interface directly, I don't need any +# AX.25 routes here. +# +ax25-learn-routes no +# +# The internal cache should only learn from frames directed to me. +# +ax25-learn-only-mine yes +# +# Here you could specify a digipeater path added to every learned route +# that has no digipeaters. +# +# ax25-add-path oe1xxx +# +# Since ax25rtd will learn only frames directed to the interface +# callsign or one of our listeners we can specify additional mycalls. +# +# ax25-more-mycalls oe1xxx +# +# We already have a static network route to this interface and don't need +# to learn any host route. +# +ip-learn-routes no +# +# I really don't like to change the mode. +# +ip-adjust-mode no +# +# ARP is correctly handled by the kernel on this interface (no digipeaters). +# +arp-add no +# +# Here is my second port (ax0). It is the "optional" interface. Any user +# accessing my system on this interface causes the following entries to +# be added: +# +# - IP host route +# - ARP entry +# - AX.25 route +# +# The nice feature is that the host route overrides the network route to +# the default interface, allowing this setup to work. Note also that users +# may access this interface via digipeaters. +# If a user switches back to the default interface, the IP host route is +# automatically deleted. The other entries remain, but this is not a +# problem. +# +[ax0] +# +ax25-learn-routes yes +ax24-learn-only-mine yes +ip-learn-routes yes +ip-adjust-mode no +arp-add yes diff --git a/ax25rtd/ax25rtd.h b/ax25rtd/ax25rtd.h new file mode 100644 index 0000000..b45771f --- /dev/null +++ b/ax25rtd/ax25rtd.h @@ -0,0 +1,163 @@ +/* $Id: ax25rtd.h,v 1.5 1997/06/05 18:54:57 oe1kib Exp oe1kib $ + * + * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Defines for defaults */ + +#define IP_MAXROUTES 256 +#define AX25_MAXROUTES 256 +#define AX25_MAXCALLS 32 + +/* Some AX.25 stuff */ + +#define NEW_ARP 1 +#define NEW_ROUTE 2 +#define NEW_IPMODE 4 + +#define SEG_FIRST 0x80 +#define SEG_REM 0x7F + +#define PID_SEGMENT 0x08 +#define PID_ARP 0xCD +#define PID_IP 0xCC +#define PID_NETROM 0xCF + +#define HDLCAEB 0x01 +#define SSSID_SPARE 0x40 +#define AX25_REPEATED 0x80 + +#define LAPB_I 0x00 +#define LAPB_S 0x01 +#define LAPB_UI 0x03 +#define LAPB_PF 0x10 + +#define ALEN 6 +#define AXLEN 7 +#define IPLEN 20 + + +/* structs for the caches */ + +typedef struct ip_rt_entry_ { + struct ip_rt_entry_ *next, *prev; + unsigned long ip; + unsigned char iface[14]; + ax25_address call; + char ipmode; + time_t timestamp; + char invalid; +} ip_rt_entry; + +typedef struct ax25_rt_entry_ { + struct ax25_rt_entry_ *next, *prev; + unsigned char iface[14]; + ax25_address call; + ax25_address digipeater[AX25_MAX_DIGIS]; + int ndigi; + long cnt; + time_t timestamp; +} ax25_rt_entry; + +/* struct for the channel configuration */ + +typedef struct config_ { + struct config_ *next; + char port[128]; + char dev[14]; + + char ax25_add_route; + char ax25_for_me; + char ax25_add_default; + + char ip_add_route; + char ip_add_arp; + char ip_adjust_mode; + char ip_arp_use_netlink; + + unsigned int dg_mtu; + unsigned int vc_mtu; + unsigned long tcp_irtt; + + unsigned long netmask; + unsigned long ip; + + int nmycalls; + ax25_address mycalls[AX25_MAXCALLS]; + + struct full_sockaddr_ax25 ax25_default_path; +} config; + +/* global variables */ + +extern const char * Version; + +extern int reload; + +extern config *Config; + +extern ip_rt_entry * ip_routes; +extern int ip_routes_cnt; +extern int ip_maxroutes; + +extern ax25_rt_entry * ax25_routes; +extern int ax25_routes_cnt; +extern int ax25_maxroutes; + + +/* config.c */ + +void load_config(void); +void reload_config(void); +void load_cache(void); +void save_cache(void); +void interpret_command(int fd, unsigned char *buf); + +/* listener.c */ + +int call_is_mycall(config *config, ax25_address *call); +int set_arp(config *config, long ip, ax25_address *call); +int set_route(config *config, long ip); +int set_ax25_route(config *config, ax25_rt_entry *rt); +int set_ipmode(config *config, ax25_address *call, int ipmode); +int del_kernel_ip_route(char *dev, long ip); +int del_kernel_ax25_route(char *dev, ax25_address *call); +void ax25_receive(int sock); + +/* ax25rtd.c */ + +void daemon_shutdown(int reason); +int set_ipmode(config *config, ax25_address *call, int ipmode); +config * dev_get_config(char *dev); +config * port_get_config(char *port); + +/* cache_dump.c */ + +void dump_ip_routes(int fd, int cmd); +void dump_ax25_routes(int fd, int cmd); +void dump_config(int fd); + +/* cache_ctl.c */ + +int update_ip_route(config *config, unsigned long ip, int ipmode, ax25_address *call, time_t timestamp); +ax25_rt_entry * update_ax25_route(config *config, ax25_address *call, int ndigi, ax25_address *digi, time_t timestamp); +int del_ip_route(unsigned long ip); +int invalidate_ip_route(unsigned long ip); +int del_ax25_route(config * config, ax25_address *call); +void expire_ax25_route(time_t when); +void expire_ip_route(time_t when); diff --git a/ax25rtd/cache_ctl.c b/ax25rtd/cache_ctl.c new file mode 100644 index 0000000..0d892ad --- /dev/null +++ b/ax25rtd/cache_ctl.c @@ -0,0 +1,330 @@ +/* $Id: cache_ctl.c,v 1.4 1996/10/23 18:27:43 jreuter Exp jreuter $ + * + * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/socket.h> +#include <netax25/ax25.h> + +#include "ax25rtd.h" + +/* Hmm, we really should implement this in C++ */ +/* But I HATE it. */ + +/* (later: haven't I seen this statement elsewere? hmm...) */ + +int update_ip_route(config *config, unsigned long ip, int ipmode, ax25_address *call, time_t timestamp) +{ + ip_rt_entry *bp = ip_routes; + ip_rt_entry *bp_prev = ip_routes; + char *iface = config->dev; + int action = 0; + + if (((ip ^ config->ip) & config->netmask) != 0) + return 0; + + iface = config->dev; + + while (bp) + { + if (bp->ip == ip) + { + if (bp->timestamp == 0 && timestamp != 0) + return 0; + + if (strcmp(bp->iface, iface)) + { + action |= NEW_ROUTE; + strcpy(bp->iface, iface); + } + + if (memcmp(&bp->call, call, AXLEN)) + { + action |= NEW_ARP; + memcpy(&bp->call, call, AXLEN); + } + + if (ipmode && ipmode != bp->ipmode) + { + action |= NEW_IPMODE; + bp->ipmode = ipmode; + } + + bp->timestamp = timestamp; + + if (bp != ip_routes) + { + if (bp->next) + bp->next->prev = bp->prev; + if (bp->prev) + bp->prev->next = bp->next; + + bp->next = ip_routes; + bp->prev = NULL; + ip_routes->prev = bp; + ip_routes = bp; + } + + return action; + } + + bp_prev = bp; + bp = bp->next; + } + + if (ip_routes_cnt >= ip_maxroutes) + { + if (bp_prev == NULL) /* error */ + return 0; + + bp_prev->prev->next = NULL; + free(bp_prev); + ip_routes_cnt--; + } + + bp = (ip_rt_entry *) malloc(sizeof(ip_rt_entry)); + if (bp == NULL) + return 0; + + ip_routes_cnt++; + action = NEW_ROUTE | NEW_ARP | NEW_IPMODE; + bp->ipmode = ipmode; + bp->ip = ip; + bp->invalid = 0; + + bp->timestamp = timestamp; + strcpy(bp->iface, iface); + memcpy(&bp->call, call, AXLEN); + + if (ip_routes == NULL) + { + ip_routes = bp; + bp->next = bp->prev = NULL; + return action; + } + + bp->next = ip_routes; + bp->prev = NULL; + ip_routes->prev = bp; + ip_routes = bp; + + return action; +} + + +ax25_rt_entry *update_ax25_route(config *config, ax25_address *call, int ndigi, ax25_address *digi, time_t timestamp) +{ + ax25_rt_entry *bp = ax25_routes; + ax25_rt_entry *bp_prev = ax25_routes; + unsigned char *iface = config->dev; + int action = 0; + + while (bp) + { + if (!memcmp(call, &bp->call, AXLEN) && !strcmp(bp->iface, iface)) + { + if (bp->timestamp == 0 && timestamp != 0) + return NULL; + + if (ndigi != bp->ndigi || memcmp(bp->digipeater, digi, bp->ndigi*AXLEN)) + { + action |= NEW_ROUTE; + memcpy(bp->digipeater, digi, ndigi*AXLEN); + bp->ndigi = ndigi; + } + + bp->timestamp = timestamp; + + if (bp != ax25_routes) + { + if (bp->next) + bp->next->prev = bp->prev; + if (bp->prev) + bp->prev->next = bp->next; + + bp->next = ax25_routes; + bp->prev = NULL; + ax25_routes->prev = bp; + ax25_routes = bp; + } + + if (action) + return bp; + else + return NULL; + } + + bp_prev = bp; + bp = bp->next; + } + + if (ax25_routes_cnt >= ax25_maxroutes) + { + if (bp_prev == NULL) /* error */ + return NULL; + + bp_prev->prev->next = NULL; + free(bp_prev); + ax25_routes_cnt--; + } + + bp = (ax25_rt_entry *) malloc(sizeof(ax25_rt_entry)); + if (bp == NULL) + return NULL; + + ax25_routes_cnt++; + + bp->timestamp = timestamp; + strcpy(bp->iface, iface); + bp->call = *call; + + if (ndigi) + memcpy(bp->digipeater, digi, ndigi*AXLEN); + + bp->ndigi = ndigi; + + if (ax25_routes == NULL) + { + ax25_routes = bp; + bp->next = bp->prev = NULL; + return bp; + } + + bp->next = ax25_routes; + bp->prev = NULL; + ax25_routes->prev = bp; + ax25_routes = bp; + + return bp; +} + +ip_rt_entry * remove_ip_route(ip_rt_entry *bp) +{ + ip_rt_entry *bp2; + + bp2 = bp->next; + if (bp2) + bp2->prev = bp->prev; + if (bp->prev) + bp->prev->next = bp2; + if (bp == ip_routes) + ip_routes = bp2; + + del_kernel_ip_route(bp->iface, bp->ip); + + free(bp); + ip_routes_cnt--; + return bp2; +} + +ax25_rt_entry * remove_ax25_route(ax25_rt_entry *bp) +{ + ax25_rt_entry *bp2; + ip_rt_entry *iprt; + + bp2 = bp->next; + if (bp2) + bp2->prev = bp->prev; + if (bp->prev) + bp->prev->next = bp2; + if (bp == ax25_routes) + ax25_routes = bp2; + + for (iprt = ip_routes; iprt; iprt = iprt->next) + if (!memcmp(&iprt->call, &bp->call, AXLEN)) + remove_ip_route(iprt); + + del_kernel_ax25_route(bp->iface, &bp->call); + + free(bp); + ax25_routes_cnt--; + return bp2; +} + +int del_ip_route(unsigned long ip) +{ + ip_rt_entry *bp; + + if (ip == 0) + return 1; + + for (bp=ip_routes; bp; bp = bp->next) + if (bp->ip == ip) + { + remove_ip_route(bp); + return 0; + } + + return 1; +} + +int invalidate_ip_route(unsigned long ip) +{ + ip_rt_entry *bp; + + for (bp=ip_routes; bp; bp = bp->next) + if (bp->ip == ip) + { + bp->invalid = 1; + return 1; + } + + return 0; +} + +int del_ax25_route(config * config, ax25_address *call) +{ + ax25_rt_entry *bp; + + for (bp=ax25_routes; bp; bp = bp->next) + if (!memcmp(call, &bp->call, AXLEN) && !strcmp(config->dev, bp->iface)) + { + remove_ax25_route(bp); + return 0; + } + + return 1; +} + + +void expire_ax25_route(time_t when) +{ + ax25_rt_entry *bp; + time_t now = time(NULL); + + for (bp = ax25_routes; bp; ) + if (bp->timestamp != 0 && bp->timestamp+when <= now) + bp = remove_ax25_route(bp); + else + bp = bp->next; +} + +void expire_ip_route(time_t when) +{ + ip_rt_entry *bp; + time_t now = time(NULL); + + for (bp = ip_routes; bp; ) + if (bp->timestamp != 0 && bp->timestamp+when <= now) + bp = remove_ip_route(bp); + else + bp = bp->next; +} diff --git a/ax25rtd/cache_dump.c b/ax25rtd/cache_dump.c new file mode 100644 index 0000000..93b211e --- /dev/null +++ b/ax25rtd/cache_dump.c @@ -0,0 +1,141 @@ +/* $Id: cache_dump.c,v 1.5 1996/10/23 18:27:43 jreuter Exp jreuter $ + * + * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> + +#include "ax25rtd.h" + +void dump_ip_routes(int fd, int cmd) +{ + ip_rt_entry *bp; + config *config; + char buf[256], *dev; + unsigned long ip; + int len; + + for (bp = ip_routes; bp; bp = bp->next) + { + ip = htonl(bp->ip); + + if (cmd) + { + len = sprintf(buf, "add ip "); + dev = bp->iface; + } else { + len = 0; + config = dev_get_config(bp->iface); + if (config != NULL) + dev = config->port; + else + dev = bp->iface; + } + + len += sprintf(buf+len, "%d.%d.%d.%d", + (int) ((ip & 0xFF000000) >> 24), + (int) ((ip & 0x00FF0000) >> 16), + (int) ((ip & 0x0000FF00) >> 8), + (int) (ip & 0x000000FF)); + + len += sprintf(buf+len, " %-4s %8.8lx %-9s ", dev, bp->timestamp, ax25_ntoa(&bp->call)); + if (bp->invalid) + len += sprintf(buf+len, "X\n"); + else + len += sprintf(buf+len, "%c\n", bp->ipmode? 'v':'d'); + + write(fd, buf, len); + } + + if (!cmd) + write(fd, ".\n", 2); + +} + +void dump_ax25_routes(int fd, int cmd) +{ + ax25_rt_entry *bp; + config *config; + char buf[256], *dev; + int k, len; + + for (bp = ax25_routes; bp; bp = bp->next) + { + if (cmd) + { + len = sprintf(buf, "add ax25 "); + dev = bp->iface; + } else { + len = 0; + config = dev_get_config(bp->iface); + if (config != NULL) + dev = config->port; + else + dev = bp->iface; + } + + len += sprintf(buf+len, "%-9s %-4s %8.8lx", ax25_ntoa(&bp->call), dev, bp->timestamp); + + for (k = 0; k < bp->ndigi; k++) + len += sprintf(buf+len, " %s", ax25_ntoa(&bp->digipeater[k])); + len += sprintf(buf+len, "\n"); + write(fd, buf, len); + } + + if (!cmd) + write(fd, ".\n", 2); +} + +void dump_config(int fd) +{ + config *config; + int k; + + fprintf(stderr, "config:\n"); + for (config = Config; config; config = config->next) + { + fprintf(stderr, "Device = %s\n", config->dev); + fprintf(stderr, "Port = %s\n", config->port); + fprintf(stderr, "ax25_add_route = %d\n", config->ax25_add_route); + fprintf(stderr, "ax25_for_me = %d\n", config->ax25_for_me); + fprintf(stderr, "ax25_add_default = %d\n", config->ax25_add_default); + fprintf(stderr, "ip_add_route = %d\n", config->ip_add_route); + fprintf(stderr, "ip_add_arp = %d\n", config->ip_add_arp); + fprintf(stderr, "ip_adjust_mode = %d\n", config->ip_adjust_mode); + fprintf(stderr, "netmask = %8.8lx\n", config->netmask); + fprintf(stderr, "ip = %8.8lx\n", config->ip); + fprintf(stderr, "nmycalls = %d\n", config->nmycalls); + fprintf(stderr, "calls ="); + for (k = 0; k < config->nmycalls; k++) + fprintf(stderr, " %s", ax25_ntoa(&config->mycalls[k])); + fprintf(stderr, "\n"); + fprintf(stderr, "ax25_default_path="); + for (k = 0; k < config->ax25_default_path.fsa_ax25.sax25_ndigis; k++) + fprintf(stderr, " %s", ax25_ntoa(&config->ax25_default_path.fsa_digipeater[k])); + fprintf(stderr, "\n.\n"); + } +} diff --git a/ax25rtd/config.c b/ax25rtd/config.c new file mode 100644 index 0000000..1306d2a --- /dev/null +++ b/ax25rtd/config.c @@ -0,0 +1,736 @@ +/* $Id: config.c,v 1.7 1997/06/05 18:55:51 oe1kib Exp oe1kib $ + * + * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <time.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <net/if.h> +#include <net/ethernet.h> +#include <net/if_arp.h> +#include <netax25/ax25.h> +#include <netrose/rose.h> +#include <netax25/axlib.h> +#include <netax25/axconfig.h> + +#include "../pathnames.h" +#include "ax25rtd.h" + +ax25_address *asc2ax(char *call) +{ + static ax25_address callsign; + + ax25_aton_entry(call, (char *)&callsign); + + return &callsign; +} + +static long asc2ip(char *s) +{ + struct in_addr addr; + + if (!inet_aton(s, &addr)) + return 0; + + return addr.s_addr; +} + + +char * prepare_cmdline(char *buf) +{ + char *p; + for (p = buf; *p; p++) + { + if (*p == '\t') *p = ' '; + *p = tolower(*p); + + if (*p == '\n') + { + *p = '\0'; + break; + } + + if (*p == '#') + { + *p = '\0'; + break; + } + } + + return buf; +} + +char * get_next_arg(char **p) +{ + char *p2; + + if (p == NULL || *p == NULL) + return NULL; + + p2 = *p; + for (; *p2 && *p2 == ' '; p2++) ; + if (!*p2) + return NULL; + + *p = strchr(p2, ' '); + if (*p != NULL) + { + **p = '\0'; + (*p)++; + } + + return p2; +} + +static inline void invalid_arg(char *c, char *p) +{ + fprintf(stderr, "%s: invalid argument %s\n", c, p); +} + +static inline void missing_arg(char *c) +{ + fprintf(stderr, "%s: argument missing\n", c); +} + +static int yesno(char *arg) +{ + if (!arg) + return 0; + if (!strcmp(arg, "yes") || !strcmp(arg, "1")) + return 1; + if (!strcmp(arg, "no") || !strcmp(arg, "0")) + return 0; + return -1; +} + +static ax25_address *get_mycall(char *port) +{ + char *addr; + + if ((addr = ax25_config_get_addr(port)) == NULL) + return NULL; + + return asc2ax(addr); +} + + +void load_ports(void) +{ + config *config, *cfg, *ncfg; + char buf[1024]; + struct ifconf ifc; + struct ifreq ifr, *ifrp; + int k, fd; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + fprintf(stderr, "Unable to open socket\n"); + exit(1); + } + + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) + { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + + ifrp = ifc.ifc_req; + for (k = ifc.ifc_len / sizeof(struct ifreq); k > 0; k--, ifrp++) + { + strcpy(ifr.ifr_name, ifrp->ifr_name); + if (strcmp(ifr.ifr_name, "lo") == 0) continue; + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) + { + fprintf(stderr, "SIOCGIFFLAGS: %s\n", strerror(errno)); + exit(1); + } + + if (!(ifr.ifr_flags & IFF_UP)) continue; + + ioctl(fd, SIOCGIFHWADDR, &ifr); + + if (ifr.ifr_hwaddr.sa_family != ARPHRD_AX25) + continue; + + for (config = Config; config; config = config->next) + if (!memcmp(&config->mycalls[0], ifr.ifr_hwaddr.sa_data, AXLEN) && !*config->dev) + { + strcpy(config->dev, ifr.ifr_name); + ioctl(fd, SIOCGIFADDR, &ifr); + config->ip = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr; + strcpy(ifr.ifr_name, config->dev); + ioctl(fd, SIOCGIFNETMASK, &ifr); + config->netmask = ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr; + break; + } + } + close(fd); + + config = cfg = Config; + + while(config) + { + if (!*config->dev) + { + if (config == Config) + { + Config = config->next; + cfg = Config; + } else + cfg->next = config->next; + ncfg = config->next; + free(config); + config = ncfg; + } else { + cfg = config; + config = config->next; + } + } +} + +void load_listeners(void) +{ + config *config; + char buf[1024], device[14], call[10], dcall[10]; + int k; + FILE *fp; + ax25_address *axcall; + + + fp = fopen(PROC_AX25_FILE, "r"); + + if (fp == NULL) + { + fprintf(stderr, "No AX.25 in kernel. Tss, tss...\n"); + exit(1); + } + + while (fgets(buf, sizeof(buf)-1, fp) != NULL) + { + k = sscanf(buf, "%s %s %s", dcall, call, device); + if (k == 3 && !strcmp(dcall, "*")) + { + axcall = asc2ax(call); + if (!strcmp("???", device)) + { + for (config = Config; config; config = config->next) + { + if (call_is_mycall(config, axcall) || config->nmycalls > AX25_MAXCALLS) + continue; + memcpy(&config->mycalls[config->nmycalls++], axcall, AXLEN); + } + } else { + config = dev_get_config(device); + if (config == NULL || call_is_mycall(config, axcall) || config->nmycalls > AX25_MAXCALLS) + continue; + + memcpy(&config->mycalls[config->nmycalls++], axcall, AXLEN); + } + } + } + fclose(fp); +} + +void load_config() +{ + FILE *fp; + char buf[1024], *p, *cmd, *arg; + config *config, *cfg; + ax25_address *axcall; + + config = NULL; + + fp = fopen(CONF_AX25ROUTED_FILE, "r"); + + if (fp == NULL) + { + fprintf(stderr, "config file %s not found\n", CONF_AX25ROUTED_FILE); + exit(1); + } + + while(fgets(buf, sizeof(buf)-1, fp) != NULL) + { + p = prepare_cmdline(buf); + if (!*p) + continue; + + cmd = get_next_arg(&p); + if (cmd == NULL) + continue; + arg = get_next_arg(&p); + + if (*cmd == '[') + { + cmd++; + p = strrchr(cmd, ']'); + if (p == NULL) + { + fprintf(stderr, "syntax error: [%s\n", cmd); + continue; + } + *p = '\0'; + + axcall = get_mycall(cmd); + if (axcall == NULL) + continue; + + cfg = (struct config_ *) malloc(sizeof(struct config_)); + if (cfg == NULL) + { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(cfg, 0, sizeof(struct config_)); + + if (config) + config->next = cfg; + else + Config = cfg; + + cfg->next = NULL; + config = cfg; + strcpy(config->port, cmd); + memcpy(&config->mycalls[0], axcall, AXLEN); + config->nmycalls = 1; + } else + if (config && !strcmp(cmd, "ax25-learn-routes")) + { + /* ax25-learn-routes no|yes: learn digipeater path */ + if (arg) + { + int k = yesno(arg); + + if (k == -1) + { + invalid_arg(cmd, arg); + continue; + } else { + config->ax25_add_route = k; + } + } else + missing_arg(cmd); + } else + if (config && !strcmp(cmd, "ax25-learn-only-mine")) + { + /* ax25-learn-only-mine no|yes: learn only if addressed to me */ + if (arg) + { + int k = yesno(arg); + + if (k == -1) + { + invalid_arg(cmd, arg); + continue; + } else { + config->ax25_for_me = k; + } + } else + missing_arg(cmd); + } else + if (config && !strcmp(cmd, "ax25-add-path")) + { + /* ax25-add-path [no|<digis>]: add digis if digi-less frame rvd */ + int k = 0; + if (!arg || (arg && yesno(arg) == 0)) + continue; + + config->ax25_add_default = 1; + while (arg && k < AX25_MAX_DIGIS) + { + memcpy(&config->ax25_default_path.fsa_digipeater[k], asc2ax(arg), AXLEN); + arg = get_next_arg(&p); + k++; + } + config->ax25_default_path.fsa_ax25.sax25_ndigis = k; + } else + if (config && !strcmp(cmd, "ax25-more-mycalls")) + { + /* ax25-more-mycalls call1 call2: frames to this calls are for "me", too. */ + if (arg) + { + while(arg && config->nmycalls < AX25_MAXCALLS) + { + axcall = asc2ax(arg); + if (call_is_mycall(config, axcall)) + continue; + memcpy(&config->mycalls[config->nmycalls++], axcall, AXLEN); + arg = get_next_arg(&p); + } + } else + missing_arg(cmd); + } else + if (config && !strcmp(cmd, "ip-learn-routes")) + { + /* ip-learn-routes no|yes: learn ip routes */ + if (arg) + { + int k = yesno(arg); + + if (k == -1) + { + invalid_arg(cmd, arg); + continue; + } else { + config->ip_add_route = k; + } + } else + missing_arg(cmd); + } else + if (config && !strcmp(cmd, "irtt")) + { + /* irtt <irtt>: new routes will get this IRTT in msec */ + if (arg) + { + int k = atoi(arg); + + if (k == 0) + { + invalid_arg(cmd, arg); + continue; + } else { + config->tcp_irtt = k; + } + } else + missing_arg(cmd); + } else + if (config && !strcmp(cmd, "dg-mtu")) + { + /* dg-mtu <mtu>: MTU for datagram mode routes (unused) */ + if (arg) + { + int k = atoi(arg); + + if (k == 0) + { + invalid_arg(cmd, arg); + continue; + } else { + config->dg_mtu = k; + } + } else + missing_arg(cmd); + } else + if (config && !strcmp(cmd, "vc-mtu")) + { + /* vc-mtu <mtu>: MTU for virtual connect mode routes (unused) */ + if (arg) + { + int k = atoi(arg); + + if (k == 0) + { + invalid_arg(cmd, arg); + continue; + } else { + config->vc_mtu = k; + } + } else + missing_arg(cmd); + } else + if (config && !strcmp(cmd, "ip-adjust-mode")) + { + /* ip-adjust-mode no|yes: adjust ip-mode? (dg or vc) */ + if (arg) + { + int k = yesno(arg); + + if (k == -1) + { + invalid_arg(cmd, arg); + continue; + } else { + config->ip_adjust_mode = k; + } + } else + missing_arg(cmd); + } else + if (config && !strcmp(cmd, "arp-add")) + { + /* arp-add no|yes: adjust arp table? */ + if (arg) + { + int k = yesno(arg); + + if (k == -1) + { + invalid_arg(cmd, arg); + continue; + } else { + config->ip_add_arp = k; + } + } else + missing_arg(cmd); + } else + if (!strcmp(cmd, "ax25-maxroutes")) + { + if (arg) + ax25_maxroutes = atoi(arg); + else + missing_arg(cmd); + } else + if (!strcmp(cmd, "ip-maxroutes")) + { + if (arg) + ax25_maxroutes = atoi(arg); + else + missing_arg(cmd); + + } else + fprintf(stderr, "invalid command %s\n", cmd); + } + fclose(fp); + + load_ports(); + load_listeners(); + + reload = 0; +} + +void reload_config(void) +{ + config *cfg, *config = Config; + + while(config) + { + cfg = config->next; + free(config); + config = cfg; + } + Config = NULL; + + load_config(); +} + + +/* commands: + --------- + + add ax25 <callsign> <dev> <time> [<digipeater>] # Add an AX.25 route + add ip <ip> <dev> <time> <call> <mode> # Add an IP route & mode + del ax25 <callsign> <dev> # Remove an AX.25 route (from cache) + del ip <ip> # Remove an IP route (from cache) + list [ax25|ip] # List cache entries + reload # Reload config + save # Save cache + expire <minutes> # Expire cache entries + shutdown # Save cache and exit + + There's a difference between 'list heard' and 'heard': + + The 'list' commands will output the symbolic port names as defined in + /usr/local/etc/axports (i.e. 9k6 for scc3), while 'heard' shows the + 'real' network device name (i.e. scc3). All commands accept either the + port or the network device name. The expample + + add ax25 dl0tha scc3 0 db0pra + + is equivalent to + + add ax25 dl0tha 9k6 0 dbpra + + Note that in conflicting cases the network device name has precedence + over the port name. +*/ + + +void interpret_command(int fd, unsigned char *buf) +{ + char *p, *cmd, *arg, *arg2, *dev, *time; + ax25_address digipeater[AX25_MAX_DIGIS]; + ax25_rt_entry *ax25rt; + int ndigi, ipmode, action; + time_t stamp; + config *config; + long ip; + + p = prepare_cmdline(buf); + + if (!*p) return; + + cmd = get_next_arg(&p); + arg = get_next_arg(&p); + + if (!strcmp(cmd, "add")) + { + if (arg == NULL) + return; + if ((arg2 = get_next_arg(&p)) == NULL) + return; + if ( (dev = get_next_arg(&p)) == NULL) + return; + if ( (time = get_next_arg(&p)) == NULL) + return; + if ( (config = dev_get_config(dev)) == NULL) + return; + + sscanf(time, "%lx", &stamp); + + if (!strcmp(arg, "ax25")) + { + ndigi = 0; + arg = get_next_arg(&p); + + while (arg != NULL) + { + memcpy(&digipeater[ndigi++], asc2ax(arg), AXLEN); + if (ndigi == AX25_MAX_DIGIS) + break; + arg = get_next_arg(&p); + } + + ax25rt = update_ax25_route(config, asc2ax(arg2), ndigi, digipeater, stamp); + if (ax25rt != NULL) + set_ax25_route(config, ax25rt); + } else + if (!strcmp(arg, "ip")) + { + ip = asc2ip(arg2); + + if ((arg2 = get_next_arg(&p)) == NULL) + return; + + if ((arg = get_next_arg(&p)) == NULL) + return; + + if (*arg == 'x') + return; + + ipmode = (*arg == 'v'); + + action = update_ip_route(config, ip, ipmode, asc2ax(arg2), stamp); + + if (action & NEW_ROUTE) + if (set_route(config, ip)) + return; + + if (action & NEW_ARP) + if (set_arp(config, ip, asc2ax(arg2))) + return; + + if (action & NEW_IPMODE) + if (set_ipmode(config, asc2ax(arg2), ipmode)) + return; + } + } else if (!strcmp(cmd, "del")) + { + if (arg == NULL) + return; + arg2 = get_next_arg(&p); + if (arg2 == NULL) + return; + + if (!strcmp(arg, "ax25")) + { + arg = get_next_arg(&p); + if (arg == NULL || (config = dev_get_config(arg)) == NULL) + return; + del_ax25_route(config, asc2ax(arg2)); + } else + if (!strcmp(arg, "ip")) + { + del_ip_route(asc2ip(arg2)); + } + } else if (!strcmp(cmd, "expire")) + { + if (arg == NULL) + return; + sscanf(arg, "%ld", &stamp); + if (stamp != 0) + { + stamp*=60; + expire_ax25_route(stamp); + expire_ip_route(stamp); + } + } else if (!strcmp(cmd, "reload")) + { + reload_config(); + } else if (!strcmp(cmd, "list")) + { + if (arg == NULL) + return; + + if (!strcmp(arg, "ax25")) + dump_ax25_routes(fd, 0); + else + if (!strcmp(arg, "ip")) + dump_ip_routes(fd, 0); + } else if (!strcmp(cmd, "shutdown")) + { + save_cache(); + daemon_shutdown(0); + } else if (!strcmp(cmd, "save")) + { + save_cache(); + } else if (!strcmp(cmd, "version")) + { + char buf[256]; + sprintf(buf, "%s\n", Version); + write(fd, buf, strlen(buf)); + } else if (!strcmp(cmd, "quit")) + { + close(fd); + } +} + +void load_cache(void) +{ + FILE *fp; + char buf[512]; + + fp = fopen(DATA_AX25ROUTED_AXRT_FILE, "r"); + if (fp != NULL) + { + while(fgets(buf, sizeof(buf), fp) != NULL) + interpret_command(2, buf); + } + fclose(fp); + + fp = fopen(DATA_AX25ROUTED_IPRT_FILE, "r"); + if (fp != NULL) + { + while(fgets(buf, sizeof(buf), fp) != NULL) + interpret_command(2, buf); + } + fclose(fp); +} + +void save_cache(void) +{ + int fd; + + fd = creat(DATA_AX25ROUTED_AXRT_FILE, 0664); + dump_ax25_routes(fd, 1); + close(fd); + + fd = creat(DATA_AX25ROUTED_IPRT_FILE, 0664); + dump_ip_routes(fd, 1); + close(fd); + +} diff --git a/ax25rtd/listener.c b/ax25rtd/listener.c new file mode 100644 index 0000000..27b8622 --- /dev/null +++ b/ax25rtd/listener.c @@ -0,0 +1,579 @@ +/* $Id: listener.c,v 1.9 1997/06/05 18:56:08 oe1kib Exp oe1kib $ + * + * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + /* TODO: Should add partial path to ax25_route if we are one of the + * digipeaters. + */ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <net/route.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <netax25/ax25.h> + +#include "../pathnames.h" +#include "ax25rtd.h" + + +/* FIXME */ +static unsigned long get_from_arp(unsigned char *data, int size) +{ + if (size < 16) + return 0; + + return ntohl(0); +} + +static unsigned long get_from_ip(unsigned char *data, int size) +{ + unsigned long adr; + + if ((*data & 0xf)*4 < IPLEN) + return 0; + + adr = data[12] << 24; /* NETWORK byte order */ + adr += data[13] << 16; + adr += data[14] << 8; + adr += data[15]; + + return ntohl(adr); /* HOST byte order */ +} + +int call_is_mycall(config *config, ax25_address *call) +{ + int k; + + for (k = 0; k < config->nmycalls; k++) + if (!memcmp(call, &config->mycalls[k], AXLEN)) + return 1; + return 0; +} + +/* + * This catches *all* invalid callsigns, unlike ax25validate. + */ + +static int check_ax25_addr(unsigned char *buf) +{ + int k; + unsigned char c; + + /* must start with at least one capital letter or digit */ + for (k=0; k < 6; k++) { + c = buf[k] >> 1; + if (c == ' ') break; + if ((c < 'A' || c > 'Z') && (c < '0' || c > '9')) + return 1; + } + + /* NULL address is invalid */ + if (k == 0) + return 1; + + /* remaining fields must consist of spaces only */ + for (k++; k < 6; k++) + if (buf[k] >> 1 != ' ') + return 1; + + return 0; +} + +static inline void invert_digipeater_path(ax25_address *digipeater, int ndigi) +{ + int k, m; + ax25_address fdigi; + + if (ndigi == 0) + return; + + ndigi--; + + memcpy(&fdigi, &digipeater[0], AXLEN); + + for (m = 0,k = ndigi; k > 0; k--, m++) + memcpy(&digipeater[m], &digipeater[k], AXLEN); + + memcpy(&digipeater[ndigi], &fdigi, AXLEN); +} + +int set_arp(config *config, long ip, ax25_address *call) +{ + struct sockaddr_in *isa; + struct sockaddr_ax25 *asa; + struct arpreq arp; + int fds; + + if (!config->ip_add_arp) + return 0; + + fds = socket(AF_INET, SOCK_DGRAM, 0); + + memset((char *) &arp, 0, sizeof(arp)); + + isa = (struct sockaddr_in *) &arp.arp_pa; + asa = (struct sockaddr_ax25 *) &arp.arp_ha; + + isa->sin_family = AF_INET; + isa->sin_port = 0; + isa->sin_addr.s_addr = ip; + + asa->sax25_family = AF_AX25; + asa->sax25_ndigis = 0; + asa->sax25_call = *call; + + arp.arp_flags = ATF_PERM | ATF_COM; + strcpy(arp.arp_dev, config->dev); + + if (ioctl(fds, SIOCSARP, &arp) < 0) + { + invalidate_ip_route(ip); + perror("routspy: SIOCSARP"); + close(fds); + return 1; + } + close(fds); + return 0; +} + +int set_route(config *config, long ip) +{ + struct rtentry rt; + struct sockaddr_in *isa; + char origdev[16], buf[1024]; + long ipr; + int fds; + FILE *fp; + + fp = fopen(PROC_IP_ROUTE_FILE, "r"); + if (fp == NULL) + { + invalidate_ip_route(ip); + return 1; + } + + fgets(buf, sizeof(buf)-1, fp); /* discard header */ + while (fgets(buf, sizeof(buf)-1, fp) != NULL) + { + sscanf(buf, "%s %lx", origdev, &ipr); + if (ipr == ip) + { + if (dev_get_config(origdev) == NULL) + { + invalidate_ip_route(ip); + fclose(fp); + return 1; + } + else + { + del_kernel_ip_route(origdev, ip); + } + } + + } + fclose(fp); + + if (!config->ip_add_route) + return 0; + + fds = socket(AF_INET, SOCK_DGRAM, 0); + + memset((char *) &rt, 0, sizeof(rt)); + + isa = (struct sockaddr_in *) &rt.rt_dst; + + isa->sin_family = AF_INET; + isa->sin_port = 0; + isa->sin_addr.s_addr = ip; + + rt.rt_flags = RTF_UP | RTF_HOST; + rt.rt_dev = config->dev; + + if (config->tcp_irtt != 0) + { + rt.rt_irtt = config->tcp_irtt; + rt.rt_flags |= RTF_IRTT; + } + + isa = (struct sockaddr_in *) &rt.rt_genmask; + isa->sin_addr.s_addr = 0xffffffff; + + if (ioctl(fds, SIOCADDRT, &rt) < 0) + { + invalidate_ip_route(ip); + perror("ax25rtd: IP SIOCADDRT"); + close(fds); + return 1; + } + close(fds); + return 0; +} + +int del_kernel_ip_route(char *dev, long ip) +{ + int fds; + struct rtentry rt; + struct sockaddr_in *isa; + config *config; + + config = dev_get_config(dev); + if (config == NULL || !config->ip_add_route) + return 0; + + fds = socket(AF_INET, SOCK_DGRAM, 0); + + memset((char *) &rt, 0, sizeof(struct rtentry)); + + isa = (struct sockaddr_in *) &rt.rt_dst; + + isa->sin_family = AF_INET; + isa->sin_addr.s_addr = ip; + + rt.rt_flags = RTF_UP | RTF_HOST; + rt.rt_dev = dev; + + if (ioctl(fds, SIOCDELRT, &rt) < 0) + { + perror("ax25rtd: IP SIOCDELRT"); + close(fds); + return 1; + } + close(fds); + return 0; +} + +int set_ax25_route(config *config, ax25_rt_entry *rt) +{ + struct ax25_routes_struct ax25_route; + int fds, k; + + if (!config->ax25_add_route) + return 0; + + ax25_route.port_addr = config->mycalls[0]; + ax25_route.dest_addr = rt->call; + ax25_route.digi_count = rt->ndigi; + + for (k = 0; k < rt->ndigi; k++) + ax25_route.digi_addr[k] = rt->digipeater[k]; + + fds = socket(AF_AX25, SOCK_SEQPACKET, 0); + + if (ioctl(fds, SIOCADDRT, &ax25_route) < 0) + { + perror("ax25rtd: AX.25 SIOCADDRT"); + close(fds); + return 1; + } + + close(fds); + return 0; +} + +int del_kernel_ax25_route(char *dev, ax25_address *call) +{ + struct ax25_routes_struct ax25_route; + int fds; + config *config; + + config = dev_get_config(dev); + if (config == NULL || !config->ax25_add_route) + return 0; + + ax25_route.port_addr = config->mycalls[0]; + ax25_route.dest_addr = *call; + + fds = socket(AF_AX25, SOCK_SEQPACKET, 0); + + if (ioctl(fds, SIOCDELRT, &ax25_route) < 0) + { + perror("ax25rtd: AX.25 SIOCDELRT"); + close(fds); + return 1; + } + + close(fds); + return 0; +} + +int set_ipmode(config *config, ax25_address *call, int ipmode) +{ + struct ax25_route_opt_struct ax25_opt; + int fds; + + if (!config->ip_adjust_mode) + return 0; + + ax25_opt.port_addr = config->mycalls[0]; + ax25_opt.dest_addr = *call; + ax25_opt.cmd = AX25_SET_RT_IPMODE; + ax25_opt.arg = ipmode? 'V':'C'; + + fds = socket(AF_AX25, SOCK_SEQPACKET, 0); + + if (ioctl(fds, SIOCAX25OPTRT, &ax25_opt) < 0) + { + perror("ax25rtd: SIOCAX25OPTRT"); + close(fds); + return 1; + } + + close(fds); + return 0; + +} + +/* Yes, the code *IS* ugly... */ + +#define SKIP(o) {data+=(o); size-=(o);} +void ax25_receive(int sock) +{ + unsigned char buf[1500]; + unsigned char *data; + unsigned long ip; + struct sockaddr sa; + ax25_address srccall, destcall, digipeater[AX25_MAX_DIGIS]; + char extseq = 0; + int size, asize, action, ipmode, ctl, pid, ndigi, kdigi, mine; + time_t stamp; + config *config; + ax25_rt_entry * ax25rt; + + asize = sizeof(sa); + if ((size = recvfrom(sock, buf, sizeof(buf), 0, &sa, &asize)) < 0) + { + perror("recvfrom"); + save_cache(); + daemon_shutdown(1); + } + + stamp = time(NULL); + ip = 0; + pid = ctl = 0; + + config = dev_get_config(sa.sa_data); + + if (config == NULL) + return; + + data = buf; + + /* + * KISS data? + */ + + if (*data != 0) + return; + + SKIP(1); + + /* valid frame? */ + + if (size < (2*AXLEN+1)) + return; + + /* + * Get destination callsign + */ + + if (check_ax25_addr(data)) + return; + + memcpy(&destcall, data, AXLEN); + destcall.ax25_call[6] &= 0x1e; + SKIP(AXLEN); + + mine = call_is_mycall(config, &destcall); + + /* + * Get Source callsign + */ + + if (check_ax25_addr(data)) + return; + + memcpy(&srccall, data, AXLEN); + srccall.ax25_call[6] &= 0x1e; + SKIP(ALEN); + + /* + * How long is our control field? + */ + + extseq = ~(*data) & SSSID_SPARE; + + /* + * Extract digipeaters + */ + + ndigi = 0; + while (((*data) & HDLCAEB) != HDLCAEB) + { + SKIP(1); + if (size <= 0 || check_ax25_addr(data)) + return; + + if (ndigi < AX25_MAX_DIGIS) + memcpy(&digipeater[ndigi++], data, AXLEN); + else + return; + + + SKIP(ALEN); + } + + SKIP(1); + if (size <= 0) + return; + + /* + * Get type of frame + */ + + if ((*data & LAPB_S) == LAPB_I) + ctl = LAPB_I; + else + { + ctl = *data; + if (extseq == 0) + ctl &= ~LAPB_PF; + } + + /* + * Check if info frame and get PID + */ + + if (ctl == LAPB_I || ctl == LAPB_UI) + { + SKIP(extseq? 2:1); + if (size <= 0) + return; + + /* Get PID */ + + pid = *data; + + if (pid == PID_SEGMENT) + { + SKIP(1); + if (size <= 0) + return; + pid = 0; + + if (*data && SEG_FIRST) + { + pid = *data; + SKIP(1); + if (size <= 0) + return; + } + } + } + + /* + * See if it is fully digipeated (TODO: or if we are the next digipeater) + */ + + for (kdigi = 0; kdigi < ndigi; kdigi++) + { + if ((digipeater[kdigi].ax25_call[6] & AX25_REPEATED) != AX25_REPEATED) + return; + + digipeater[kdigi].ax25_call[6] &= 0x1e; + } + + invert_digipeater_path(digipeater, ndigi); + + /* + * Are we allowed to add it to our routing table? + */ + + if (mine || !config->ax25_for_me) + { + if (!mine && ndigi == 0 && config->ax25_add_default) + { + ndigi = config->ax25_default_path.fsa_ax25.sax25_ndigis; + for (kdigi = 0; kdigi < ndigi; kdigi++) + if (!memcmp(&srccall, &config->ax25_default_path.fsa_digipeater[kdigi], AXLEN)) + break; + + if (ndigi == kdigi) + memcpy(digipeater, config->ax25_default_path.fsa_digipeater, ndigi*AXLEN); + else + ndigi = 0; + } + + ax25rt = update_ax25_route(config, &srccall, ndigi, digipeater, stamp); + + if (ax25rt != NULL) + set_ax25_route(config, ax25rt); + } + + /* + * Now see if it carries IP traffic + */ + + switch(pid) + { + case PID_ARP: + SKIP(1); + if (size > 0) + ip = get_from_arp(data, size); + break; + case PID_IP: + if (!mine) + return; + + SKIP(1); + if (size > 0) + ip = get_from_ip(data, size); + break; + default: + return; + } + + /* + * And adjust routes/arp/ipmode if we are allowed to... + */ + + ipmode = (ctl == LAPB_I); + + if (ip != 0) + { + action = update_ip_route(config, ip, ipmode, &srccall, stamp); + + if (action & NEW_ROUTE) + if (set_route(config, ip)) + return; + + if (action & NEW_ARP) + if (set_arp(config, ip, &srccall)) + return; + + if (action & NEW_IPMODE) + if (set_ipmode(config, &srccall, ipmode)) + return; + } +} |