/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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;i1) { 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