summaryrefslogtreecommitdiffstats
path: root/ax25mond
diff options
context:
space:
mode:
authorCraig Small <csmall@enc.com.au>2001-04-10 01:57:46 +0000
committerCraig Small <csmall@enc.com.au>2001-04-10 01:57:46 +0000
commit628edceba5f1485ef7c4ef30fba93b4c0c0dd955 (patch)
treed3df0a0118e426470fce2bff0492b9d2ee06f4c7 /ax25mond
parent57cf4e9453c51359d0c9af334c3dc1156ea2527a (diff)
Initial revisionax25-apps-0.0.5p2
Diffstat (limited to 'ax25mond')
-rw-r--r--ax25mond/.cvsignore3
-rw-r--r--ax25mond/Makefile.am27
-rw-r--r--ax25mond/ax25mond.819
-rw-r--r--ax25mond/ax25mond.c377
-rw-r--r--ax25mond/ax25mond.conf3
-rw-r--r--ax25mond/ax25mond.conf.530
6 files changed, 459 insertions, 0 deletions
diff --git a/ax25mond/.cvsignore b/ax25mond/.cvsignore
new file mode 100644
index 0000000..2da6d7d
--- /dev/null
+++ b/ax25mond/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+ax25mond
diff --git a/ax25mond/Makefile.am b/ax25mond/Makefile.am
new file mode 100644
index 0000000..4ccbdc4
--- /dev/null
+++ b/ax25mond/Makefile.am
@@ -0,0 +1,27 @@
+
+sbin_PROGRAMS = ax25mond
+
+man_MANS = ax25mond.8 ax25mond.conf.5
+
+EXTRA_DIST = $(man_MANS) $(etcfiles)
+
+ax25mond_LDADD = $(AX25_LIB)
+
+ax25mond_SOURCES = \
+ ax25mond.c
+
+# Needed so that install is optional
+etcfiles = ax25mond.conf
+installconf:
+ $(mkinstalldirs) $(DESTDIR)$(AX25_SYSCONFDIR)
+ @list='$(etcfiles)'; for p in $$list; do \
+ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(AX25_SYSCONFDIR)/$$p"; \
+ $(INSTALL_DATA) $$p $(DESTDIR)$(AX25_SYSCONFDIR)/$$p; \
+ done
+
+AX25_SYSCONFDIR=$(sysconfdir)/ax25/
+AX25_LOCALSTATEDIR=$(localstatedir)/ax25/
+
+INCLUDES = -DAX25_SYSCONFDIR=\""$(AX25_SYSCONFDIR)"\" \
+ -DAX25_LOCALSTATEDIR=\""$(AX25_LOCALSTATEDIR)"\"
+
diff --git a/ax25mond/ax25mond.8 b/ax25mond/ax25mond.8
new file mode 100644
index 0000000..2ee9629
--- /dev/null
+++ b/ax25mond/ax25mond.8
@@ -0,0 +1,19 @@
+.TH AX25MOND 8 "30 January 1999" Linux "Linux System Managers Manual"
+.SH NAME
+ax25mond \- dump the AX.25 network traffic and and provide sockets
+where the received data will be retransmitted
+.SH SYNOPSIS
+.B ax25mond [-v|--version]
+.SH DESCRIPTION
+.LP
+.B Ax25mond
+will first read it's configuration file /etc/ax25/ax25mond.conf. It will
+then wait for connects on the sockets specified in this file. When
+connected, it will transmit all data which it has received on the AX.25
+monitor socket.
+.SH OPTIONS
+.TP 15
+.BI "\-v, \-\-version"
+Displays the version number and some copyright information.
+.SH AUTHOR
+Johann Hanne, DH3MB <jonny@baycom.org>
diff --git a/ax25mond/ax25mond.c b/ax25mond/ax25mond.c
new file mode 100644
index 0000000..58a932a
--- /dev/null
+++ b/ax25mond/ax25mond.c
@@ -0,0 +1,377 @@
+/*
+ * ax25mond.c - Wrapper for offering AX.25 traffic to non-root processes
+ *
+ * Copyright (C) 1998-1999 Johann Hanne, DH3MB. All rights reserved.
+ *
+ * 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.
+ */
+
+/*--------------------------------------------------------------------------*/
+
+#define VERSION "1.0"
+#define CONFFILE "/etc/ax25/ax25mond.conf"
+#define MAX_SOCKETS 5
+#define MAX_CONNECTS 50
+
+/*--------------------------------------------------------------------------*/
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+// For older kernels
+#ifndef PF_PACKET
+ #define PF_PACKET PF_INET
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+static union {
+ struct sockaddr sa;
+ struct sockaddr_in si;
+ struct sockaddr_un su;
+} addr;
+
+/*--------------------------------------------------------------------------*/
+
+int sock_list[MAX_SOCKETS];
+char sock_monmode[MAX_SOCKETS];
+char sock_filename[MAX_SOCKETS][100];
+int sock_num=0;
+int conn_list[MAX_CONNECTS];
+struct sockaddr conn_addr[MAX_CONNECTS];
+int conn_addrlen[MAX_CONNECTS];
+char conn_monmode[MAX_CONNECTS];
+int conn_num=0;
+int highest_sock_fd;
+int end=0;
+
+/*--------------------------------------------------------------------------*/
+
+/* from buildsaddr.c */
+struct sockaddr *build_sockaddr(const char *name, int *addrlen)
+{ char *host_name;
+ char *serv_name;
+ char buf[1024];
+
+ memset((char *) &addr, 0, sizeof(addr));
+ *addrlen=0;
+
+ host_name=strcpy(buf, name);
+ serv_name=strchr(buf, ':');
+ if(!serv_name)
+ return 0;
+ *serv_name++=0;
+ if(!*host_name || !*serv_name)
+ return 0;
+
+ if(!strcmp(host_name, "local") || !strcmp(host_name, "unix")) {
+ addr.su.sun_family=AF_UNIX;
+ *addr.su.sun_path=0;
+ strcat(addr.su.sun_path, serv_name);
+ *addrlen=sizeof(struct sockaddr_un);
+ return &addr.sa;
+ }
+
+ addr.si.sin_family=AF_INET;
+
+ if(!strcmp(host_name, "*")) {
+ addr.si.sin_addr.s_addr=INADDR_ANY;
+ } else if(!strcmp(host_name, "loopback")) {
+ addr.si.sin_addr.s_addr=inet_addr("127.0.0.1");
+ } else if((addr.si.sin_addr.s_addr=inet_addr(host_name))==-1L) {
+ struct hostent *hp=gethostbyname(host_name);
+ endhostent();
+ if(!hp)
+ return 0;
+ addr.si.sin_addr.s_addr=((struct in_addr *) (hp->h_addr))->s_addr;
+ }
+
+ if(isdigit(*serv_name & 0xff)) {
+ addr.si.sin_port=htons(atoi(serv_name));
+ } else {
+ struct servent *sp=getservbyname(serv_name, (char *) 0);
+ endservent();
+ if(!sp)
+ return 0;
+ addr.si.sin_port=sp->s_port;
+ }
+
+ *addrlen=sizeof(struct sockaddr_in);
+ return &addr.sa;
+}
+
+/*--------------------------------------------------------------------------*/
+
+void add_socket(char *sockname, char monmode) {
+ struct sockaddr *saddr;
+ int saddrlen;
+
+ if(sock_num==MAX_SOCKETS-1) {
+ fprintf(stderr, "WARNING: Too many sockets defined - only %d are "
+ "allowed\n", MAX_SOCKETS);
+ return;
+ }
+
+ if(!(saddr=build_sockaddr(sockname,&saddrlen))) {
+ fprintf(stderr, "WARNING: Invalid socket name: \"%s\"\n", sockname);
+ return;
+ }
+
+ if(saddr->sa_family==AF_UNIX)
+ strcpy(sock_filename[sock_num], strchr(sockname, ':')+1);
+ else
+ sock_filename[sock_num][0]=0;
+
+ if((sock_list[sock_num]=socket(saddr->sa_family,SOCK_STREAM,0))<0) {
+ fprintf(stderr, "WARNING: Error opening socket \"%s\": %s\n",
+ sockname, strerror(errno));
+ return;
+ }
+
+ if(bind(sock_list[sock_num],saddr,saddrlen)<0) {
+ fprintf(stderr, "WARNING: Error binding socket \"%s\": %s\n",
+ sockname, strerror(errno));
+ return;
+ }
+
+ if(listen(sock_list[sock_num], 5)<0) {
+ fprintf(stderr, "WARNING: Error listening on socket \"%s\": %s\n",
+ sockname, strerror(errno));
+ return;
+ }
+
+ fcntl(sock_list[sock_num],F_SETFL,O_NONBLOCK);
+
+ if(sock_list[sock_num] > highest_sock_fd)
+ highest_sock_fd=sock_list[sock_num];
+
+ sock_monmode[sock_num]=monmode;
+ sock_num++;
+}
+
+/*--------------------------------------------------------------------------*/
+
+void close_sockets() {
+ int i;
+
+ for(i=0;i<sock_num;i++) {
+ close(sock_list[i]);
+
+ if(sock_filename[i][0])
+ unlink(sock_filename[i]);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+void quit_handler(int dummy) {
+ end=1;
+}
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[]) {
+ fd_set monavail;
+ int monrx_fd, monrxtx_fd;
+ struct sockaddr monfrom;
+ int monfromlen;
+ fd_set conn_request;
+ struct timeval tv;
+ char buf[500];
+ int size;
+ int i;
+ struct ifreq ifr;
+ FILE *conffile;
+ char confline[100];
+ char *mode;
+ char *sockname;
+
+ if(argc>1) {
+ if(argc==2 &&
+ (strcmp(argv[1],"-v")==0 || strcmp(argv[1],"--version")==0)) {
+ printf("%s: Version " VERSION "\n\n", argv[0]);
+ printf("Copyright (C) 1998-1999 Johann Hanne, DH3MB. All rights reserved.\n"
+ "This program is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+ exit(1);
+ } else {
+ printf("Usage: %s [-v|--version]\n", argv[0]);
+ exit(0);
+ }
+ }
+
+ // At first, read the configuration file
+ if(!(conffile=fopen(CONFFILE, "r"))) {
+ fprintf(stderr, "Unable to open " CONFFILE ".\n");
+ exit(1);
+ }
+ while(fgets(confline, 100, conffile)) {
+ if(confline[0]=='#') // Comment
+ continue;
+
+ confline[strlen(confline)-1]=0; // Cut the LF
+
+ if(!(sockname=strchr(confline, ' '))) {
+ fprintf(stderr, "WARNING: The following configuration line includes "
+ "one or more errors:\n%s\n", confline);
+ continue;
+ }
+
+ *(sockname++)=0;
+ mode=confline;
+ if(strcasecmp(mode, "RX")==0)
+ add_socket(sockname, 0);
+ else if(strcasecmp(mode, "RXTX")==0)
+ add_socket(sockname, 1);
+ else
+ fprintf(stderr, "WARNING: Mode \"%s\" not supported\n", mode);
+
+ }
+ fclose(conffile);
+
+ if(sock_num==0) {
+ fprintf(stderr, "FATAL: No usable socket found\n");
+ exit(1);
+ }
+
+ // Fork into background
+ if(fork())
+ exit(0);
+
+ // Close stdout, stderr and stdin
+ fclose(stdout);
+ fclose(stderr);
+ fclose(stdin);
+
+ // Set some signal handlers
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTERM, quit_handler);
+
+ openlog("ax25mond", LOG_PID, LOG_DAEMON);
+
+ // Open AX.25 socket for monitoring RX traffic only
+ if((monrx_fd=socket(PF_PACKET,SOCK_PACKET,htons(ETH_P_AX25)))<0) {
+ syslog(LOG_ERR, "Error opening monitor socket: %s\n",strerror(errno));
+ exit(1);
+ }
+ fcntl(monrx_fd,F_SETFL,O_NONBLOCK);
+
+ // Open AX.25 socket for monitoring RX and TX traffic
+ if((monrxtx_fd=socket(PF_PACKET,SOCK_PACKET,htons(ETH_P_ALL)))<0) {
+ syslog(LOG_ERR, "Error opening monitor socket: %s\n",strerror(errno));
+ exit(1);
+ }
+ fcntl(monrxtx_fd,F_SETFL,O_NONBLOCK);
+
+ while(!end) {
+
+ // Look for incoming connects on all open sockets
+ FD_ZERO(&conn_request);
+ for(i=0;i<sock_num;i++)
+ FD_SET(sock_list[i], &conn_request);
+ tv.tv_sec=0;
+ tv.tv_usec=0;
+ select(highest_sock_fd+1, &conn_request, 0, 0, &tv);
+ for(i=0;i<sock_num;i++)
+ if(FD_ISSET(sock_list[i], &conn_request)) {
+ conn_list[conn_num]=accept(sock_list[i],
+ &conn_addr[conn_num],
+ &conn_addrlen[conn_num]);
+ conn_monmode[conn_num]=sock_monmode[i];
+ conn_num++;
+ }
+
+ // Check if there is new data on the RX-only monitor socket
+ FD_ZERO(&monavail);
+ FD_SET(monrx_fd,&monavail);
+ tv.tv_sec=0;
+ tv.tv_usec=10;
+ select(monrx_fd+1, &monavail, 0, 0, &tv);
+ if(FD_ISSET(monrx_fd,&monavail)) {
+ monfromlen=sizeof(monfrom);
+ size=recvfrom(monrx_fd,buf,sizeof(buf),0,&monfrom,&monfromlen);
+ // Send the packet to all connected sockets
+ for(i=0;i<conn_num;i++) {
+ if(conn_monmode[i]==0)
+ if(send(conn_list[i],buf,size,0)<0)
+ if(errno!=EAGAIN) {
+ syslog(LOG_ERR, "Error sending monitor data: %s\n",
+ strerror(errno));
+ close(conn_list[i]);
+ conn_list[i]=conn_list[conn_num-1];
+ conn_num--;
+ }
+ }
+ }
+
+ // Check if there is new data on the RX+TX monitor socket
+ FD_ZERO(&monavail);
+ FD_SET(monrxtx_fd,&monavail);
+ tv.tv_sec=0;
+ tv.tv_usec=10;
+ select(monrxtx_fd+1, &monavail, 0, 0, &tv);
+ if(FD_ISSET(monrxtx_fd,&monavail)) {
+ monfromlen=sizeof(monfrom);
+ size=recvfrom(monrxtx_fd,buf,sizeof(buf),0,&monfrom,&monfromlen);
+ // Check, if we have received a AX.25-packet
+ strcpy(ifr.ifr_name,monfrom.sa_data);
+ ioctl(monrxtx_fd,SIOCGIFHWADDR,&ifr);
+ if (ifr.ifr_hwaddr.sa_family==AF_AX25)
+ // Send the packet to all connected sockets
+ for(i=0;i<conn_num;i++) {
+ if(conn_monmode[i]==1)
+ if(send(conn_list[i],buf,size,0)<0)
+ if(errno!=EAGAIN) {
+ syslog(LOG_ERR, "Error sending monitor data: %s\n",
+ strerror(errno));
+ close(conn_list[i]);
+ conn_list[i]=conn_list[conn_num-1];
+ conn_num--;
+ }
+ }
+ }
+
+ }
+
+ for(i=0;i<conn_num;i++)
+ close(conn_list[i]);
+ close_sockets();
+ close(monrx_fd);
+ close(monrxtx_fd);
+ closelog();
+ return 0;
+}
diff --git a/ax25mond/ax25mond.conf b/ax25mond/ax25mond.conf
new file mode 100644
index 0000000..53b4d7a
--- /dev/null
+++ b/ax25mond/ax25mond.conf
@@ -0,0 +1,3 @@
+# Create an internet socket on port 1234 and transmit the whole
+# AX.25 traffic
+rxtx *:1234
diff --git a/ax25mond/ax25mond.conf.5 b/ax25mond/ax25mond.conf.5
new file mode 100644
index 0000000..66d343e
--- /dev/null
+++ b/ax25mond/ax25mond.conf.5
@@ -0,0 +1,30 @@
+.TH AX25MOND.CONF 5 "30 January 1999" Linux "Linux Programmer's Manual"
+.SH NAME
+ax25mond.conf \- Specify the sockets which ax25mond will provide.
+.SH DESCRIPTION
+.LP
+The
+.B ax25mond.conf
+file specifies the internet- and unix-sockets which ax25mond(8)
+will provide. Example:
+.LP
+# Create an internet socket on port 1234 where all the
+.br
+# AX.25 traffic will be transmitted
+.br
+rxtx *:1234
+.br
+# Create an unix socket where only the received AX.25
+.br
+# traffic will be transmitted
+.br
+rx unix:/var/spool/ax25/monitor
+.br
+.LP
+You may specify up to 5 sockets (definable in ax25mond.c) and ax25mond
+will accept up to 50 connects (also definable in ax25mond.c).
+.SH FILES
+.LP
+/etc/ax25/ax25mond.conf
+.SH "SEE ALSO"
+.BR ax25mond (8).