From 17287576555a5c46fa23549e2e5f073660dccb70 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 21 Apr 1999 09:51:03 +0200 Subject: Import ax25-tools 0.0.1 from tarball --- tcpip/Makefile.am | 23 ++ tcpip/Makefile.in | 386 +++++++++++++++++++++++++++ tcpip/rip98.conf | 1 + tcpip/rip98.conf.5 | 19 ++ tcpip/rip98d.8 | 59 +++++ tcpip/rip98d.c | 360 +++++++++++++++++++++++++ tcpip/rip98d.h | 58 ++++ tcpip/rip98r.c | 255 ++++++++++++++++++ tcpip/rip98t.c | 76 ++++++ tcpip/ttylinkd.8 | 53 ++++ tcpip/ttylinkd.c | 719 ++++++++++++++++++++++++++++++++++++++++++++++++++ tcpip/ttylinkd.conf | 10 + tcpip/ttylinkd.conf.5 | 22 ++ 13 files changed, 2041 insertions(+) create mode 100644 tcpip/Makefile.am create mode 100644 tcpip/Makefile.in create mode 100644 tcpip/rip98.conf create mode 100644 tcpip/rip98.conf.5 create mode 100644 tcpip/rip98d.8 create mode 100644 tcpip/rip98d.c create mode 100644 tcpip/rip98d.h create mode 100644 tcpip/rip98r.c create mode 100644 tcpip/rip98t.c create mode 100644 tcpip/ttylinkd.8 create mode 100644 tcpip/ttylinkd.c create mode 100644 tcpip/ttylinkd.conf create mode 100644 tcpip/ttylinkd.conf.5 (limited to 'tcpip') diff --git a/tcpip/Makefile.am b/tcpip/Makefile.am new file mode 100644 index 0000000..d047ac5 --- /dev/null +++ b/tcpip/Makefile.am @@ -0,0 +1,23 @@ + +etcfiles = rip98.conf ttylinkd.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 = rip98d ttylinkd + +man_MANS = rip98.conf.5 rip98d.8 ttylinkd.conf.5 ttylinkd.8 + +EXTRA_DIST = $(man_MANS) $(etcfiles) + +rip98d_SOURCES = \ + rip98d.c \ + rip98r.c \ + rip98t.c \ + rip98d.h + diff --git a/tcpip/Makefile.in b/tcpip/Makefile.in new file mode 100644 index 0000000..90da959 --- /dev/null +++ b/tcpip/Makefile.in @@ -0,0 +1,386 @@ +# 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 = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +etcfiles = rip98.conf ttylinkd.conf +etcdir = $(sysconfdir)/ax25 + +sbin_PROGRAMS = rip98d ttylinkd + +man_MANS = rip98.conf.5 rip98d.8 ttylinkd.conf.5 ttylinkd.8 + +EXTRA_DIST = $(man_MANS) $(etcfiles) + +rip98d_SOURCES = rip98d.c rip98r.c rip98t.c rip98d.h + +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@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +rip98d_OBJECTS = rip98d.o rip98r.o rip98t.o +rip98d_LDADD = $(LDADD) +rip98d_DEPENDENCIES = +rip98d_LDFLAGS = +ttylinkd_SOURCES = ttylinkd.c +ttylinkd_OBJECTS = ttylinkd.o +ttylinkd_LDADD = $(LDADD) +ttylinkd_DEPENDENCIES = +ttylinkd_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man5dir = $(mandir)/man5 +man8dir = $(mandir)/man8 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(rip98d_SOURCES) ttylinkd.c +OBJECTS = $(rip98d_OBJECTS) ttylinkd.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps tcpip/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 " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(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: + +rip98d: $(rip98d_OBJECTS) $(rip98d_DEPENDENCIES) + @rm -f rip98d + $(LINK) $(rip98d_LDFLAGS) $(rip98d_OBJECTS) $(rip98d_LDADD) $(LIBS) + +ttylinkd: $(ttylinkd_OBJECTS) $(ttylinkd_DEPENDENCIES) + @rm -f ttylinkd + $(LINK) $(ttylinkd_LDFLAGS) $(ttylinkd_OBJECTS) $(ttylinkd_LDADD) $(LIBS) + +install-man5: + $(mkinstalldirs) $(DESTDIR)$(man5dir) + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \ + done + +uninstall-man5: + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \ + rm -f $(DESTDIR)$(man5dir)/$$inst; \ + done + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man5 install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man5 uninstall-man8 + +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 = tcpip + +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 +rip98d.o: rip98d.c ../config.h ../pathnames.h rip98d.h +rip98r.o: rip98r.c rip98d.h +rip98t.o: rip98t.c rip98d.h +ttylinkd.o: ttylinkd.c ../pathnames.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-man +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-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man5 \ + $(DESTDIR)$(mandir)/man8 + + +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-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile 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 install-man5 uninstall-man5 \ +install-man8 uninstall-man8 install-man uninstall-man 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/tcpip/rip98.conf b/tcpip/rip98.conf new file mode 100644 index 0000000..3574d56 --- /dev/null +++ b/tcpip/rip98.conf @@ -0,0 +1 @@ +44.131.4.7 diff --git a/tcpip/rip98.conf.5 b/tcpip/rip98.conf.5 new file mode 100644 index 0000000..7e2d3a4 --- /dev/null +++ b/tcpip/rip98.conf.5 @@ -0,0 +1,19 @@ +.TH RIP98.CONF 5 "2 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +rip98.conf \- control RIP98 routing messages. +.SH DESCRIPTION +.LP +.B Rip98.conf +controls the transmission of RIP98 routing messages. RIP98 is not a +broadcast protocol but instead is transmitted individually to each other +known RIP98 capable system. The list of these systems is kept in the RIP98 +configuration file as a list of host names or IP numbers that are to be +transmitted to, and messages received from. +.SH FILES +.LP +/etc/ax25/rip98.conf +.SH "SEE ALSO" +.BR arp (8), +.BR ifconfig (8), +.BR rip98d (8), +.BR route (8). diff --git a/tcpip/rip98d.8 b/tcpip/rip98d.8 new file mode 100644 index 0000000..0ee12dc --- /dev/null +++ b/tcpip/rip98d.8 @@ -0,0 +1,59 @@ +.TH RIP98D 8 "20 August 1996" Linux "Linux System Managers Manual" +.SH NAME +rip98d \- Send and receive RIP98 routing messages +.SH SYNOPSIS +.B rip98d [-d] [-l] [-r] [-t interval] [-v] +.SH DESCRIPTION +.LP +The RIP98 routing protocol was devised by John Wiseman G8BPQ as an +alternative to both traditional RIP and RSPF for use in an RF environment. +Its main advantage is that each routing element only takes six bytes and is +therefore much more efficient in terms of bandwidth than other routing +protocols. +.LP +In operation +.B rip98d +that each neighbour that also uses RIP98 must be listed. RIP98 is not a +broadcast protocol and each neighbour is individually contacted. Any +incoming RIP98 message is also validated against this list. The list of +neighbours is held in /etc/ax25/rip98.conf, and each line is +either the name or the dotted decimal IP address of the neighbour. +.LP +The time interval between RIP98 transmissions is set to one hour by default +but other intervals can be set with the \-t option. The routes advertised +and received can be restricted by the \-r option which only allows +processing of ampr.org addresses. At present +.B rip98d +is under development and any feedback on its operation would be welcome. +.SH OPTIONS +.TP 16 +.BI \-d +Set debugging on. Information is only output if the logging option is also +enabled. +.TP 16 +.BI \-l +Enable logging to the system log, the default is off. +.TP 16 +.BI \-r +Restricts the transmitting and receiving of routes to ampr.org (44.x.x.x) +addresses only. +.TP 16 +.BI "\-t interval" +The time interval between routing broadcasts, in minutes. The default is 60 +minutes. +.TP 16 +.BI \-v +Display the version. +.SH FILES +.nf +/proc/net/route +.br +/etc/ax25/rip98.conf +.fi +.SH "SEE ALSO" +.BR rip98.conf (5), +.BR arp (8), +.BR ifconfig (8), +.BR route (8). +.SH AUTHOR +Jonathan Naylor G4KLX diff --git a/tcpip/rip98d.c b/tcpip/rip98d.c new file mode 100644 index 0000000..78851cd --- /dev/null +++ b/tcpip/rip98d.c @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "../pathnames.h" +#include "rip98d.h" + +struct dest_struct dest_list[50]; + +int dest_count = 0; + +int debug = FALSE; +int restrict = FALSE; +int logging = FALSE; + +struct route_struct *first_route = NULL; + +static struct mask_struct { + unsigned long int mask; + unsigned int bits; +} mask_table[] = { + {0xFFFFFFFF, 32}, + {0xFFFFFFFE, 31}, + {0xFFFFFFFC, 30}, + {0xFFFFFFF8, 29}, + {0xFFFFFFF0, 28}, + {0xFFFFFFE0, 27}, + {0xFFFFFFC0, 26}, + {0xFFFFFF80, 25}, + {0xFFFFFF00, 24}, + {0xFFFFFE00, 23}, + {0xFFFFFC00, 22}, + {0xFFFFF800, 21}, + {0xFFFFF000, 20}, + {0xFFFFE000, 19}, + {0xFFFFC000, 18}, + {0xFFFF8000, 17}, + {0xFFFF0000, 16}, + {0xFFFE0000, 15}, + {0xFFFC0000, 14}, + {0xFFF80000, 13}, + {0xFFF00000, 12}, + {0xFFE00000, 11}, + {0xFFC00000, 10}, + {0xFF800000, 9}, + {0xFF000000, 8}, + {0xFE000000, 7}, + {0xFC000000, 6}, + {0xF8000000, 5}, + {0xF0000000, 4}, + {0xE0000000, 3}, + {0xC0000000, 2}, + {0x80000000, 1}, + {0x00000000, 0}, +}; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +unsigned int mask2bits(unsigned long int mask) +{ + struct mask_struct *t; + + for (t = mask_table; t->mask != 0; t++) + if (mask == t->mask) + return t->bits; + + return 0; +} + +unsigned long int bits2mask(unsigned int bits) +{ + struct mask_struct *t; + + for (t = mask_table; t->mask != 0; t++) + if (bits == t->bits) + return htonl(t->mask); + + return 0; +} + +static unsigned long int hex2intrev(char *buffer) +{ + unsigned long int result = 0L; + + if (buffer[0] >= 'A') + result += (buffer[0] - 'A' + 10) * 16; + else + result += (buffer[0] - '0') * 16; + + if (buffer[1] >= 'A') + result += buffer[1] - 'A' + 10; + else + result += buffer[1] - '0'; + + if (buffer[2] >= 'A') + result += (buffer[2] - 'A' + 10) * 16 * 16 * 16; + else + result += (buffer[2] - '0') * 16 * 16 * 16; + + if (buffer[3] >= 'A') + result += (buffer[3] - 'A' + 10) * 16 * 16; + else + result += (buffer[3] - '0') * 16 * 16; + + if (buffer[4] >= 'A') + result += (buffer[4] - 'A' + 10) * 16 * 16 * 16 * 16 * 16; + else + result += (buffer[4] - '0') * 16 * 16 * 16 * 16 * 16; + + if (buffer[5] >= 'A') + result += (buffer[5] - 'A' + 10) * 16 * 16 * 16 * 16; + else + result += (buffer[5] - '0') * 16 * 16 * 16 * 16; + + if (buffer[6] >= 'A') + result += (buffer[6] - 'A' + 10) * 16 * 16 * 16 * 16 * 16 * 16 * 16; + else + result += (buffer[6] - '0') * 16 * 16 * 16 * 16 * 16 * 16 * 16; + + if (buffer[7] >= 'A') + result += (buffer[7] - 'A' + 10) * 16 * 16 * 16 * 16 * 16 * 16; + else + result += (buffer[7] - '0') * 16 * 16 * 16 * 16 * 16 * 16; + + return result; +} + +static int read_routes(void) +{ + struct route_struct *route, *temp; + char buffer[1023], iface[16], net_addr[64], gate_addr[64], mask_addr[64]; + int n, iflags, refcnt, use, metric, mss, window; + struct in_addr address; + unsigned long int netmask; + unsigned long int network; + FILE *fp; + + if (first_route != NULL) { + route = first_route; + + while (route != NULL) { + temp = route->next; + free(route); + route = temp; + } + + first_route = NULL; + } + + if ((fp = fopen(PROC_IP_ROUTE_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "error cannot open %s\n", PROC_IP_ROUTE_FILE); + return FALSE; + } + + while (fgets(buffer, 1023, fp) != NULL) { + n = sscanf(buffer, "%s %s %s %X %d %d %d %s %d %d\n", + iface, net_addr, gate_addr, &iflags, &refcnt, &use, + &metric, mask_addr, &mss, &window); + + if (n != 10) + continue; + + address.s_addr = htonl(hex2intrev(net_addr)); + netmask = mask2bits(hex2intrev(mask_addr)); + + network = inet_netof(address); + + if (network == 0 || network == 127) { + if (debug && logging) + syslog(LOG_DEBUG, "rejecting route to %s/%ld - should not be propogated\n", inet_ntoa(address), netmask); + continue; + } + + if (restrict) { + if (inet_netof(address) != 44) { + if (debug && logging) + syslog(LOG_DEBUG, "rejecting route to %s/%ld - not ampr.org\n", inet_ntoa(address), netmask); + continue; + } + } + + if ((route = malloc(sizeof(struct route_struct))) == NULL) { + if (logging) + syslog(LOG_ERR, "out of memory !\n"); + return FALSE; + } + + route->addr = address; + route->bits = netmask; + route->metric = metric; + route->action = (iflags & RTF_DYNAMIC) ? ORIG_ROUTE : FIXED_ROUTE; + + route->next = first_route; + first_route = route; + } + + fclose(fp); + + return TRUE; +} + +static int load_dests(void) +{ + struct hostent *host; + char buffer[255], *s; + FILE *fp; + + if ((fp = fopen(CONF_RIP98D_FILE, "r")) == NULL) { + fprintf(stderr, "rip98d: cannot open config file\n"); + return FALSE; + } + + while (fgets(buffer, 255, fp) != NULL) { + if ((s = strchr(buffer, '\n')) != NULL) *s = '\0'; + + if ((host = gethostbyname(buffer)) == NULL) { + fprintf(stderr, "rip98d: cannot resolve name %s\n", buffer); + fclose(fp); + return FALSE; + } + + bcopy(host->h_addr, (char *)&dest_list[dest_count].dest_addr, host->h_length); + dest_count++; + } + + fclose(fp); + + if (dest_count == 0) + return FALSE; + + return TRUE; +} + +int main(int argc, char **argv) +{ + int s, i; + struct sockaddr_in loc_addr; + struct timeval timeout; + time_t timenow, timelast = 0; + int interval = 3600; + fd_set fdset; + + if (!load_dests()) { + fprintf(stderr, "rip98d: no destination routers defined\n"); + return 1; + } + + while ((i = getopt(argc, argv, "dlrt:v")) != -1) { + switch (i) { + case 'd': + debug = TRUE; + break; + case 'l': + logging = TRUE; + break; + case 'r': + restrict = TRUE; + break; + case 't': + interval = atoi(optarg) * 60; + if (interval < 60 || interval > 7200) { + fprintf(stderr, "rip98d: invalid time interval\n"); + return 1; + } + break; + case 'v': + printf("rip98d: %s\n", VERSION); + return 0; + case ':': + fprintf(stderr, "rip98d: invalid time interval\n"); + return 1; + case '?': + fprintf(stderr, "usage: rip98d [-d] [-l] [-r] [-t interval] [-v]\n"); + return 1; + } + } + + signal(SIGTERM, terminate); + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("rip98d: socket"); + return 1; + } + + bzero((char *)&loc_addr, sizeof(loc_addr)); + loc_addr.sin_family = AF_INET; + loc_addr.sin_addr.s_addr = htonl(INADDR_ANY); + loc_addr.sin_port = htons(RIP_PORT); + + if (bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) { + perror("rip98d: bind"); + close(s); + return 1; + } + + if (!daemon_start(FALSE)) { + fprintf(stderr, "rip98d: cannot become a daemon\n"); + close(s); + return 1; + } + + if (logging) { + openlog("rip98d", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + for (;;) { + FD_ZERO(&fdset); + FD_SET(s, &fdset); + + timeout.tv_sec = 60; + timeout.tv_usec = 0; + + select(s + 1, &fdset, NULL, NULL, &timeout); + + if (!read_routes()) { + if (logging) + closelog(); + return 1; + } + + if (FD_ISSET(s, &fdset)) + receive_routes(s); + + time(&timenow); + + if ((timenow - timelast) > interval) { + timelast = timenow; + if (first_route != NULL) + transmit_routes(s); + } + } +} diff --git a/tcpip/rip98d.h b/tcpip/rip98d.h new file mode 100644 index 0000000..fb00a7d --- /dev/null +++ b/tcpip/rip98d.h @@ -0,0 +1,58 @@ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define RIP_PORT 520 + +#define RIPCMD_REQUEST 1 +#define RIPCMD_RESPONSE 2 + +#define RIP98_INFINITY 16 + +#define RIP_VERSION_98 98 + +#define RIP_AF_INET 2 + +#define RIP98_HEADER 4 +#define RIP98_ENTRY 6 + +#define RIP98_MAX_FRAME 30 + +struct route_struct { + struct route_struct *next; + struct in_addr addr; + int bits; + int metric; +#define ORIG_ROUTE 0 +#define FIXED_ROUTE 1 +#define NEW_ROUTE 2 +#define DEL_ROUTE 3 + int action; +}; + +extern struct route_struct *first_route; + +struct dest_struct { + struct in_addr dest_addr; +}; + +extern struct dest_struct dest_list[]; + +extern int dest_count; + +extern int debug; +extern int restrict; +extern int logging; + +/* In rip98d.c */ +extern unsigned int mask2bits(unsigned long int); +extern unsigned long int bits2mask(unsigned int); + +/* In rip98t.c */ +extern void transmit_routes(int); + +/* In rip98r.c */ +extern void receive_routes(int); diff --git a/tcpip/rip98r.c b/tcpip/rip98r.c new file mode 100644 index 0000000..765e786 --- /dev/null +++ b/tcpip/rip98r.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + + +#include "rip98d.h" + +#define UNMATCH_ROUTE 0 +#define NO_ROUTE 1 +#define REPLACE_ROUTE 2 +#define ADDITIONAL_ROUTE 3 + +static int cmp_route(struct route_struct *route, struct in_addr addr, int bits, int metric) +{ + unsigned long int old_mask, new_mask; + unsigned long int old_addr, new_addr; + + old_mask = ntohl(bits2mask(route->bits)); + new_mask = ntohl(bits2mask(bits)); + + old_addr = route->addr.s_addr; + new_addr = addr.s_addr; + + if (bits < route->bits) { + new_addr = ntohl(new_addr) & new_mask; + old_addr = ntohl(old_addr) & new_mask; + } else { + new_addr = ntohl(new_addr) & old_mask; + old_addr = ntohl(old_addr) & old_mask; + } + + if (route->action == DEL_ROUTE || route->action == NEW_ROUTE) + return UNMATCH_ROUTE; + + if (old_addr != new_addr) + return UNMATCH_ROUTE; + + if (route->metric <= metric) + return NO_ROUTE; + + if (debug && logging) { + syslog(LOG_DEBUG, "comparing old: %s/%d to\n", inet_ntoa(route->addr), route->bits); + syslog(LOG_DEBUG, " new: %s/%d\n", inet_ntoa(addr), bits); + } + + if (route->bits <= bits) { + if (route->action == ORIG_ROUTE) { + if (debug && logging) + syslog(LOG_DEBUG, " better route, replacing existing route\n"); + return REPLACE_ROUTE; + } else { + if (debug && logging) + syslog(LOG_DEBUG, " better route, adding additional route\n"); + return ADDITIONAL_ROUTE; + } + } else { + if (debug && logging) + syslog(LOG_DEBUG, " better route, adding additional route\n"); + return ADDITIONAL_ROUTE; + } +} + +void receive_routes(int s) +{ + unsigned char message[500], *p; + struct sockaddr_in rem_addr; + struct in_addr addr; + struct route_struct *route, *new; + struct sockaddr_in trg; + struct rtentry rt; + unsigned long int netmask; + unsigned long int network; + int bits, metric; + int size, found, matched; + int mess_len; + int i; + + size = sizeof(struct sockaddr_in); + + mess_len = recvfrom(s, message, 500, 0, (struct sockaddr *)&rem_addr, &size); + + if (message[0] != RIPCMD_RESPONSE || message[1] != RIP_VERSION_98) { + if (debug && logging) { + syslog(LOG_DEBUG, "invalid RIP98 header received\n"); + syslog(LOG_DEBUG, " cmd: %d vers: %d\n", message[0], message[1]); + } + return; + } + + for (found = FALSE, i = 0; i < dest_count; i++) { + if (rem_addr.sin_addr.s_addr == dest_list[i].dest_addr.s_addr) { + found = TRUE; + break; + } + } + + if (!found) { + if (debug && logging) + syslog(LOG_DEBUG, "RIP98 message from unknown address %s\n", inet_ntoa(rem_addr.sin_addr)); + return; + } + + if (debug && logging) + syslog(LOG_DEBUG, "RIP98 message received from %s\n", inet_ntoa(rem_addr.sin_addr)); + + for (p = message + RIP98_HEADER; p < message + mess_len; p += RIP98_ENTRY) { + bcopy((char *)p, (char *)&addr, sizeof(addr)); + bits = p[4]; + metric = p[5]; + + network = inet_netof(addr); + + if (network == 0 || network == 127) { + if (debug && logging) + syslog(LOG_DEBUG, " route to %s/%d metric %d - rejected\n", inet_ntoa(addr), bits, metric); + continue; + } + + if (restrict) { + if (network != 44) { + if (debug && logging) + syslog(LOG_DEBUG, " route to %s/%d metric %d - rejected\n", inet_ntoa(addr), bits, metric); + continue; + } + } + + if (debug && logging) + syslog(LOG_DEBUG, " route to %s/%d metric %d\n", inet_ntoa(addr), bits, metric); + + metric++; + + if (metric > RIP98_INFINITY) + metric = RIP98_INFINITY; + + found = FALSE; + matched = FALSE; + + for (route = first_route; route != NULL; route = route->next) { + + switch (cmp_route(route, addr, bits, metric)) { + + case NO_ROUTE: + matched = TRUE; + break; + + case REPLACE_ROUTE: + route->action = DEL_ROUTE; + + case ADDITIONAL_ROUTE: + if (!found) { + if ((new = malloc(sizeof(struct route_struct))) == NULL) { + if (logging) + syslog(LOG_ERR, "out of memory\n"); + return; + } + + new->addr = addr; + new->bits = bits; + new->metric = metric; + new->action = NEW_ROUTE; + + new->next = first_route; + first_route = new; + + found = TRUE; + } + + matched = TRUE; + break; + + default: + break; + } + } + + if (!matched) { + if ((new = malloc(sizeof(struct route_struct))) == NULL) { + if (logging) + syslog(LOG_ERR, "out of memory\n"); + return; + } + + new->addr = addr; + new->bits = bits; + new->metric = metric; + new->action = NEW_ROUTE; + + new->next = first_route; + first_route = new; + } + } + + for (route = first_route; route != NULL; route = route->next) { + if (route->action == DEL_ROUTE) { + bzero((char *)&rt, sizeof(rt)); + + trg.sin_family = AF_INET; + trg.sin_addr = route->addr; + trg.sin_port = 0; + bcopy((char *)&trg, (char *)&rt.rt_dst, sizeof(struct sockaddr)); + + if (ioctl(s, SIOCDELRT, &rt) < 0) { + if (logging) + syslog(LOG_ERR, "SIOCDELRT: %m"); + } + } + } + + for (route = first_route; route != NULL; route = route->next) { + if (route->action == NEW_ROUTE) { + bzero((char *)&rt, sizeof(rt)); + + trg.sin_family = AF_INET; + trg.sin_addr = route->addr; + trg.sin_port = 0; + bcopy((char *)&trg, (char *)&rt.rt_dst, sizeof(struct sockaddr)); + + rt.rt_flags = RTF_UP | RTF_GATEWAY | RTF_DYNAMIC; + + if (route->bits == 32) { + rt.rt_flags |= RTF_HOST; + } else { + netmask = bits2mask(route->bits); + + trg.sin_family = AF_INET; + bcopy((char *)&netmask, (char *)&trg.sin_addr, sizeof(struct in_addr)); + trg.sin_port = 0; + bcopy((char *)&trg, (char *)&rt.rt_genmask, sizeof(struct sockaddr)); + } + + rt.rt_metric = route->metric; + + trg.sin_family = AF_INET; + trg.sin_addr = rem_addr.sin_addr; + trg.sin_port = 0; + bcopy((char *)&trg, (char *)&rt.rt_gateway, sizeof(struct sockaddr)); + + if (ioctl(s, SIOCADDRT, &rt) < 0) { + if (logging) + syslog(LOG_ERR, "SIOCADDRT: %m"); + } + } + } +} diff --git a/tcpip/rip98t.c b/tcpip/rip98t.c new file mode 100644 index 0000000..c227fc4 --- /dev/null +++ b/tcpip/rip98t.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "rip98d.h" + +static int build_header(unsigned char *message) +{ + message[0] = RIPCMD_RESPONSE; + message[1] = RIP_VERSION_98; + + message[2] = 0; + message[3] = 0; + + return RIP98_HEADER; +} + + +void transmit_routes(int s) +{ + unsigned char message[500]; + struct route_struct *route; + struct sockaddr_in rem_addr; + int mess_len; + int size; + int i; + + size = sizeof(struct sockaddr_in); + + for (i = 0; i < dest_count; i++) { + + if (debug && logging) + syslog(LOG_DEBUG, "transmit_routes: sending routing message to %s\n", inet_ntoa(dest_list[i].dest_addr)); + + bzero((char *)&rem_addr, sizeof(rem_addr)); + rem_addr.sin_family = AF_INET; + rem_addr.sin_addr = dest_list[i].dest_addr; + rem_addr.sin_port = htons(RIP_PORT); + + route = first_route; + + while (route != NULL) { + + mess_len = build_header(message); + + while (mess_len < 184 && route != NULL) { + if (route->action != DEL_ROUTE) { + bcopy((char *)&route->addr, message + mess_len + 0, sizeof(struct in_addr)); + message[mess_len + 4] = route->bits; + message[mess_len + 5] = route->metric; + + mess_len += RIP98_ENTRY; + } + + route = route->next; + } + + if (mess_len > RIP98_HEADER) { + if (sendto(s, message, mess_len, 0, (struct sockaddr *)&rem_addr, size) < 0) { + if (logging) + syslog(LOG_ERR, "sendto: %m"); + } + } + } + } +} diff --git a/tcpip/ttylinkd.8 b/tcpip/ttylinkd.8 new file mode 100644 index 0000000..7b2379f --- /dev/null +++ b/tcpip/ttylinkd.8 @@ -0,0 +1,53 @@ +.TH TTYLINKD 8 "5 March 1997" Linux "Linux System Managers Manual" +.SH NAME +ttylinkd \- TTYlink daemon for AX.25, NET/ROM, ROSE and IP. +.SH SYNOPSIS +.B ttylinkd [-hv] [-c callsign] [-f file] +.SH DESCRIPTION +.LP +.B ttylinkd +is a simple daemon that allows incoming ttylink calls to be routed through +to Linux's normal talkd(8) +system and provides a pipe between the two. +.LP +.B ttylinkd +is usually setup to be spawned from ax25d(8) or inetd(8) +but can, since version 0.03, be used on the command line, although +talk(1) is a much better idea for interactive users. +.LP +Use splitscreen(1) +for outgoing ttylink sessions. +.SH OPTIONS +.TP 10 +.BI \-v +Display the version. +.TP 10 +.BI \-h +Display some help and information on it. +.TP 10 +.BI "\-c callsign" +Disable callsign checking and use the given callsign for a name for this +end of the link. +.TP 10 +.BI "\-f file" +Use for the configuration file, instead of the default +/etc/ax25/ttylinkd.conf +.SH FILES +.LP +/etc/ax25/ttylinkd.conf the configuration file for ttylinkd +.SH "SEE ALSO" +.BR talk (1), +.BR splitscreen (1), +.BR ttylinkd.conf (5), +.BR ax25d (8), +.BR inetd (8), +.BR talkd (8). +.SH BUGS +.LP +There is still some need for some checking of who is still logged on. +.LP +The daemon may hang if you disconnect from it strangely. +.LP +There is no real way of working out what is going on with talkd. +.SH AUTHOR +Craig Small VK2XLZ diff --git a/tcpip/ttylinkd.c b/tcpip/ttylinkd.c new file mode 100644 index 0000000..e185c7e --- /dev/null +++ b/tcpip/ttylinkd.c @@ -0,0 +1,719 @@ +/* + * ttylinkd: A ttylink daemon using the ntalkd protocol. + * Copyright (C) 1996,1197 Craig Small (csmall@gonzo.triode.net.au) + * + * 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 recieved 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. + */ + /* + * Versions: + * 13/01/96 cs Original Version + * 29/01/96 cs Added AX.25 proper support, thanks Tomi OH2BNS!! + * 27/01/97 cs Added support for stdin/stdout. + * 04/03/97 cs Added config file, no more defines. + * 09/03/97 tjd Enhanced to allow specifying user@hostname.wherever. + * rather than be confined to localhost. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define osockaddr sockaddr +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../pathnames.h" + + +static char version[] = "ttylink daemon (Version 0.05, 9 March 1997) ready.\n"; + +#define SYSOP_USER "root" + +/* TTY control characters from the sysop's talk screen */ +char erasec; +char killc; +char werasec; + +/* Users address family */ +int userfamily; + +#define ADDR_SIZE 256 +char sysop_addr[ADDR_SIZE]; +char *sysop_user=NULL, *sysop_host=NULL; +char config_file[128]; + +int send_control(int skt, struct in_addr addr, CTL_MSG msg, CTL_RESPONSE *resp); +void alarm_handle(int i); +void do_talk(int skt); +void read_config_file(int dummy); + +/*static char *Commands[] = { + "leaving invitation", + "look-up", + "delete", + "announce" }; +*/ +static char *Responses[] = { + "success", + "sysop not logged on", + "failed for unknown reason", + "sysop's machine unknown", + "permission denied", + "unknown request", + "bad version", + "bad address", + "bad control address" }; + + +int main(int argc, char *argv[]) +{ + struct sockaddr_in sin, ctl_sin; + struct in_addr my_addr, rem_addr; + int ctl_skt, skt, new_skt; + int length; + CTL_RESPONSE resp; + CTL_MSG msg; + struct protoent *ppe; + struct hostent *phe, *rhe=NULL; + char hostname[256]; + int local_id, remote_id; + char buf[256]; + char user[NAME_SIZE]; + struct sockaddr sa; + int sa_len, i; + struct sockaddr_in *peer_sin=NULL; + struct sockaddr_ax25 *peer_sax; + struct sockaddr_rose *peer_srose; + + /* Open up the system logger */ + openlog(argv[0], LOG_PID, LOG_DAEMON); + + write(STDOUT_FILENO, version, strlen(version)); + + /* Work out who is calling us */ + userfamily = AF_UNSPEC; + bzero(user, NAME_SIZE); + strcpy(sysop_addr, SYSOP_USER); + strcpy(config_file, CONF_TTYLINKD_FILE); + for(i=1 ; i < argc ; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'v': + return 0; + break; + case 'h': + printf("ttylinkd comes with ABSOLUTELY NO WARRANY, see the file COPYING\n"); + printf("This is free software, and you are welcome to redistribute it\n"); + printf("under the terms of the GNU General Public License.\n\n"); + printf("Usage: %s [-hv] [-c ] [-f ]\n", argv[0]); + return 0; + break; + case 'f': + if (i+2 > argc) + { + printf("The -f flag needs a parameter.\n"); + return 0; + break; + } + strncpy(config_file, argv[++i], 127); + break; + case 'c': + if ( i+2 > argc) + { + printf("The -c flag need a parameter.\n"); + return 0; + break; + } + strncpy(user, argv[++i], NAME_SIZE); + break; + default: + fprintf(stderr, "%s: Unknown flag, type %s -h for help\n", argv[0], argv[0]); + return -1; + break; + } /*switch */ + } /* - */ + } /* for */ + if (user[0] == '\0') + { + sa_len = sizeof(sa); + if (getpeername(STDOUT_FILENO, &sa, &sa_len) < 0) + { + fprintf(stderr, "%s: getpeername() failed, you must specify a callsign in stdin mode.\n", argv[0]); + syslog(LOG_CRIT | LOG_DAEMON, "main(): getpeername() failed."); + return 0; + } else { + userfamily = sa.sa_family; + switch(sa.sa_family) { + case AF_INET: + peer_sin = (struct sockaddr_in*)&sa; + write(STDOUT_FILENO, buf, strlen(buf)); + sprintf(buf, "Please enter your callsign: "); + write(STDOUT_FILENO, buf, strlen(buf)); + fflush(stdout); + if (fgets(user, NAME_SIZE-1, stdin) == NULL) + return 0; + for (i = 0; user[i] != '\0' && user[i] != '\n' && user[i] != '\r'; i++) + ; + user[i] = '\0'; + if (strlen(user) < 1) + return 0; + userfamily = AF_INET; + break; + case AF_AX25: + case AF_NETROM: + peer_sax = (struct sockaddr_ax25*)&sa; + for(i=0 ; i < 6 ; i++) + { + user[i] = tolower(((peer_sax->sax25_call.ax25_call[i]) >>1)&0x7f); + if (user[i] == ' ') + break; + } + user[i] = '\0'; + break; + case AF_ROSE: + peer_srose = (struct sockaddr_rose*)&sa; + for(i=0 ; i < 6 ; i++) + { + user[i] = tolower(((peer_srose->srose_call.ax25_call[i]) >>1)&0x7f); + if (user[i] == ' ') + break; + } + user[i] = '\0'; + break; + default: + syslog(LOG_DAEMON | LOG_CRIT, "Unsupported address family."); + exit(1); + } + + } + } /* argc */ + + /* Read the configuration file to find the System Operator. */ + read_config_file(0); + /* ... and parse it into user@host */ + sysop_user=strtok(sysop_addr,"@"); + sysop_host=strtok(NULL,"@"); + + if ((ppe = getprotobyname("udp")) == 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "Cannot find udp protocol entry."); + exit(1); + } + + /* Obtain our local hostname */ + gethostname(hostname,256); + + /* Get the remote address, or use ours if remote isn't specified */ + if (sysop_host) + { + if ((rhe = gethostbyname(sysop_host)) == NULL) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): gethostbyname failed."); + exit(1); + } + } + else + { + if ((rhe = gethostbyname(hostname)) == NULL) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): gethostbyname failed."); + exit(1); + } + } + bcopy(rhe->h_addr, (char*)&rem_addr, rhe->h_length); + + /* Get our local address */ + if ((phe = gethostbyname(hostname)) == NULL) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): gethostbyname failed."); + exit(1); + } + bcopy(phe->h_addr, (char*)&my_addr, phe->h_length); + + /* Create local data socket */ + bzero((char*)&sin, sizeof(sin)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(0); + bcopy(phe->h_addr, (char*)&sin.sin_addr, phe->h_length); + + if ((skt = socket(PF_INET, SOCK_STREAM, 0)) < 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): socket() failed."); + exit(1); + } + + if (bind( skt, (struct sockaddr*)&sin, sizeof(sin)) != 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): bind() failed."); + exit(1); + } + + length = sizeof(sin); + if (getsockname(skt, (struct sockaddr*)&sin, &length) < 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): getsockname() failed."); + exit(1); + } + + /* Create local control socket */ + bzero((char*)&ctl_sin, sizeof(ctl_sin)); + + ctl_sin.sin_family = AF_INET; + bcopy(phe->h_addr, (char*)&ctl_sin.sin_addr, phe->h_length); + ctl_sin.sin_port = htons(0); + + if ((ctl_skt = socket(PF_INET, SOCK_DGRAM, 0)) < 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): socket() while attempting to create control socket."); + close(skt); + exit(1); + } + + if (bind(ctl_skt, (struct sockaddr*)&ctl_sin, sizeof(ctl_sin)) != 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): Error when trying to bind() control socket."); + close(skt); + exit(1); + } + + length = sizeof(ctl_sin); + if (getsockname(ctl_skt, (struct sockaddr*)&ctl_sin, &length) < 0) + { + syslog(LOG_DAEMON | LOG_CRIT,"main(): Error when trying to getsockname() for control socket."); + close(skt); + close(ctl_skt); + exit(1); + } + + /* Start talking to the talk daemon */ + bzero((char*)&msg, sizeof(msg)); + msg.vers = TALK_VERSION; + msg.id_num = htonl(0); + msg.addr.sa_family = ntohs(AF_INET); + msg.ctl_addr = *(struct sockaddr*)&ctl_sin; + msg.ctl_addr = *(struct sockaddr*)&ctl_sin; + msg.ctl_addr.sa_family = ntohs(AF_INET); + msg.pid = htonl(getpid()); + strncpy(msg.l_name, user, NAME_SIZE-1); + strncpy(msg.r_name, sysop_user, NAME_SIZE-1); + + + /* Now look for an invite */ + msg.type = LOOK_UP; + (void) send_control(ctl_skt, rem_addr, msg, &resp); + + /* The person not there? Send an announce and wake him up */ + msg.type = ANNOUNCE; + msg.addr = *(struct sockaddr*)&sin; + msg.addr.sa_family = htons(AF_INET); + msg.id_num = -1; + i = send_control(ctl_skt, rem_addr, msg, &resp); + if ( i != SUCCESS) + { + if (i > BADCTLADDR) + printf("Cannot talk to sysop errno=%d.\n",i); + else + printf("Cannot talk to sysop, reason: %s.\n",Responses[i]); + + close(skt); + close(ctl_skt); + return 0; + } + /* Update the ID number so that we both know what we're talking about. */ + remote_id = resp.id_num; + + /* Get the TCP port ready for a connection */ + if (listen(skt, 5) != 0) + { + syslog(LOG_DAEMON | LOG_CRIT, "main(): Error when trying to listen() on socket."); + exit(1); + } + + /* Now we have to make an invitation for the other user */ + msg.type = LEAVE_INVITE; + if (send_control(ctl_skt, my_addr, msg, &resp) != SUCCESS) + { + printf("Problem with leaving an invitation\n"); + syslog(LOG_DAEMON | LOG_CRIT, "main(): Cannot leave invititation."); + close(skt); + close(ctl_skt); + return 0; + } + local_id = resp.id_num; + + sprintf(buf, "Paging sysop.\n"); + write(STDOUT_FILENO, buf, strlen(buf)); + + /* Wait for the sysop to connect to us */ + signal(SIGALRM, alarm_handle); + alarm(30); + + if ((new_skt = accept(skt, 0, 0)) < 0) + { + if (errno == EINTR) + { + /* Delete invitations from both daemons */ + msg.type = DELETE; + msg.id_num = htonl(local_id); + send_control(ctl_skt, my_addr, msg, &resp); + msg.id_num = htonl(remote_id); + send_control(ctl_skt, rem_addr, msg, &resp); + + close(skt); + close(ctl_skt); + return 0; + } + syslog(LOG_DAEMON | LOG_WARNING, "main(): accept() failed. (%m)"); + } + alarm(0); + signal(SIGALRM, SIG_DFL); + + close(skt); + skt = new_skt; + + /* Delete invitations from both daemons */ + msg.type = DELETE; + msg.id_num = htonl(local_id); + send_control(ctl_skt, my_addr, msg, &resp); + msg.id_num = htonl(remote_id); + send_control(ctl_skt, rem_addr, msg, &resp); + + sprintf(buf, "Sysop has responded.\n"); + write(STDOUT_FILENO, buf, strlen(buf)); + + /* + * A little thing that they don't mention anywhere is the fact that the + * first three characters on a connection are used to work out to erase, + * kill and word erase characters. Nice to know eh? + */ + /* We send ours first, but then again we get data in cooked form, so + * we don't use this. */ + buf[0] = '\0'; + buf[1] = '\0'; + buf[2] = '\0'; + if (write(skt, buf, 3) != 3) + { + printf("Connnection lost\n"); + close(skt); + close(ctl_skt); + return 0; + } + /* Get their character stuff */ + if (read(skt, buf, 3) != 3) + { + printf("Connection lost\n"); + close(skt); + close(ctl_skt); + return 0; + } + erasec = buf[0]; + killc = buf[1]; + werasec = buf[2]; + + /* Tell the sysop who this person is */ + if (sa.sa_family == AF_AX25) + { + sprintf(buf, "Incoming ttylink from %s.\n", user); + write(skt, buf, strlen(buf)); + } + if (sa.sa_family == AF_INET) + { + sprintf(buf, "Incoming ttylink from %s@%s.\n", user, inet_ntoa(peer_sin->sin_addr)); + write(skt, buf, strlen(buf)); + } + + + do_talk(skt); + + close(skt); + close(ctl_skt); + return 0; +} + +/* + * Used to send control messages to our friendly local talk daemon + */ +int send_control(int skt, struct in_addr addr, CTL_MSG msg, CTL_RESPONSE *resp) +{ + fd_set fdvar; + struct timeval timeout; + struct sockaddr_in sin; + static int talk_port = 0; + struct servent *pse; + + /* Look up talk port once only */ + if (talk_port == 0) + { + if ((pse = getservbyname("ntalk", "udp")) == NULL) + { + perror("getservbyname, assuming 518"); + talk_port = 518; + } else { + talk_port = pse->s_port; + } + } + + /* Create the socket address */ + bzero((char*)&sin, sizeof(sin)); + sin.sin_addr = addr; + sin.sin_family = AF_INET; + sin.sin_port = talk_port; + + if (sendto(skt, (char*)&msg, sizeof(msg), 0, (struct sockaddr*)&sin, sizeof(sin)) != sizeof(msg)) + { + syslog(LOG_DAEMON | LOG_ERR, "send_control(): sendto failed (%m)."); + return -1; + } + + /* Wait for reply */ + FD_ZERO(&fdvar); + FD_SET(skt, &fdvar); + timeout.tv_sec = RING_WAIT; + timeout.tv_usec = 0; + + if (select(32, &fdvar, NULL, NULL, &timeout) < 0) + syslog(LOG_DAEMON | LOG_ERR, "send_control(): select failed. (%m)"); + + /* + * The server is ignoring us, see ya later + */ + if (!(FD_ISSET(skt, &fdvar))) + { + printf("Talk server not responding after %d seconds, aborting.\n", RING_WAIT); + return -1; + } + + /* Get the message */ + if(recv(skt, resp, sizeof(resp),0) ==0) + syslog(LOG_DAEMON | LOG_ERR, "send_control(): recv failed. (%m)"); + + return resp->answer; +} + +/* Used to process the data from the sysop */ +int send_sysop_data(char *buf, int len) +{ + static char outbuf[82]; + static char *bptr = outbuf; + int i; + + for(i = 0; i < len; i++) + { + /* Check for erase character */ + if (buf[i] == erasec) + { + if (bptr > outbuf) + bptr--; + continue; + } + + /* Check for kill character */ + if (buf[i] == killc) + { + bptr = outbuf; + continue; + } + + /* Check for word-erase character */ + if (buf[i] == werasec) + { + while( (bptr > outbuf) && (*bptr != ' ') ) + bptr--; + continue; + } + + /* Check for newline character */ + if (buf[i] == '\n') + { + if ( (userfamily == AF_AX25) || (userfamily == AF_NETROM) || (userfamily == AF_ROSE) ) + { + *bptr = '\r'; + bptr++; + } else { + *bptr = '\r'; + bptr++; + *bptr = '\n'; + bptr++; + } + } else { + *bptr = buf[i]; + bptr++; + } + + /* Check for carriage return, which means send it */ + /* We also send if we have more than 80 characters */ + if (buf[i] == '\n' || (bptr - outbuf) > 80 ) + { + if (write(STDOUT_FILENO, outbuf, (bptr - outbuf) ) != (bptr - outbuf) ) + { + return -1; + } + bptr = outbuf; + } + } /* for */ + return 0; +} + +/* Used to process the data from the user - len must not exceed 256 */ +int send_user_data(int skt, char *buf, int len) +{ + char outbuf[256]; + char *bptr = outbuf; + int i; + + for(i = 0; i < len; i++) + { + if (buf[i] == '\r') + { + if (userfamily == AF_INET) + { + *bptr = '\n'; + bptr++; + /* + * check if this is a or a + * and skip the or . + */ + if (buf[i + 1] == '\n' || buf[i + 1] == '\0') + { + i++; + } + } else + { + *bptr = '\n'; + bptr++; + } + continue; + } + *bptr = buf[i]; + bptr++; + } /* for */ + + if (write(skt, outbuf, bptr - outbuf) != bptr - outbuf) + { + return -1; + } + return 0; +} + + +/* The main talking loop */ +void do_talk(int skt) +{ + fd_set fdvar; + char inbuf[256], outbuf[256]; + struct timeval timeout; + int i; + + + while(1) + { + FD_ZERO(&fdvar); + FD_SET(skt, &fdvar); + FD_SET(STDIN_FILENO, &fdvar); + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + if (select(32, &fdvar, NULL, NULL, &timeout) == 0) + { + if (ioctl(STDIN_FILENO, FIONREAD, (struct sgttyb *)&i) < 0) + return; + if (ioctl(skt, FIONREAD, (struct sgttyb*)&i) < 0) + return; + } + + if (FD_ISSET(skt, &fdvar)) + { + if ((i = read(skt, inbuf, 256)) <= 0) + { + strcpy(inbuf,"Sysop closed connection.\n"); + write(STDOUT_FILENO, inbuf, strlen(inbuf)); + return; + } + if (send_sysop_data(inbuf, i) < 0) + { + strcpy(outbuf, "User closed connection.\n"); + (void) write(skt, outbuf, strlen(outbuf)); + return; + } + } + if (FD_ISSET(STDIN_FILENO, &fdvar)) + { + if ((i = read(STDIN_FILENO, outbuf, 256)) <= 0) + { + strcpy(outbuf, "User closed connection.\n"); + (void) write(skt, outbuf, strlen(outbuf)); + return; + } + if (send_user_data(skt, outbuf, i) < 0) + { + strcpy(inbuf,"Sysop closed connection.\n"); + write(STDOUT_FILENO, inbuf, strlen(inbuf)); + return; + } + } + } +} + +void alarm_handle(int i) +{ + char buf[256]; + + strcpy(buf, "Sysop not responding.\n"); + write(STDOUT_FILENO, buf, strlen(buf)); +} + +void read_config_file(int dummy) +{ + char buf[128]; + char param[20], value[108]; + FILE *fp; + + if ( (fp = fopen(config_file, "r")) == NULL) { + syslog(LOG_DAEMON | LOG_ERR, "Cannot find configuration file: %s (%m)\n",config_file); + return; + } + /* Reset any variables here */ + + while ( fgets(buf, 128, fp) != NULL) { + if ( buf[0] == '#') + continue; + if (sscanf(buf, "%[^=]%*c%[^\n]", param, value) == 2) { + /* A big wierdo switch */ + if (strcasecmp(param, "sysop") == 0) { + strncpy(sysop_addr, value, ADDR_SIZE); + } + } + } /* while */ + fclose(fp); + signal(SIGHUP, read_config_file); +} diff --git a/tcpip/ttylinkd.conf b/tcpip/ttylinkd.conf new file mode 100644 index 0000000..ae65749 --- /dev/null +++ b/tcpip/ttylinkd.conf @@ -0,0 +1,10 @@ +# /etc/ax25/ttylinkd.conf : config file for ttylinkd(8) +# +# We just have one line, who gets the incoming ttylink calls. +# +# sysop=user@hostname.domain.name +# or: +# sysop=user +# +sysop=root + diff --git a/tcpip/ttylinkd.conf.5 b/tcpip/ttylinkd.conf.5 new file mode 100644 index 0000000..ecba3a1 --- /dev/null +++ b/tcpip/ttylinkd.conf.5 @@ -0,0 +1,22 @@ +.TH TTYLINKD.CONF 5 "9 March 1997" Linux "Linux Programmer's Manual" +.SH NAME +ttylinkd.conf \- ttylinkd configuration file. +.SH DESCRIPTION +.LP +.B ttylinkd.conf +allows the super user to determine certain parameters with ttylinkd(8). +Current there is only one field, with the view of not extending this further +(ttylinkd is about a resourceful as it is going to get). +.SH PARAMETERS +.TP 10 +.B # +Any line beginning with the hash (#) symbol is a comment and wille be ignored. +.TP 10 +.B "sysop=[@hostname.domain.name]" +The login will be attempted to be contacted with ttylinkd(8) is +launched. If you do not supply a hostname then the local host will be assumed. +.SH SEE ALSO +.BR ttylinkd (8). +.SH AUTHOR +Craig Small VK2XLZ + -- cgit v1.2.3