275 lines
7.4 KiB
C
275 lines
7.4 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* Purpose ...............: Fidonet mailer
|
||
|
*
|
||
|
*****************************************************************************
|
||
|
* Copyright (C) 1997-2011
|
||
|
*
|
||
|
* Michiel Broek FIDO: 2:280/2802
|
||
|
* Beekmansbos 10
|
||
|
* 1971 BV IJmuiden
|
||
|
* the Netherlands
|
||
|
*
|
||
|
* This file is part of MBSE BBS.
|
||
|
*
|
||
|
* This BBS 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, or (at your option) any
|
||
|
* later version.
|
||
|
*
|
||
|
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
|
||
|
* Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include "../config.h"
|
||
|
#include "../lib/mbselib.h"
|
||
|
#include "../lib/nodelist.h"
|
||
|
#include "../lib/users.h"
|
||
|
#include "../lib/mbsedb.h"
|
||
|
#include "session.h"
|
||
|
#include "ttyio.h"
|
||
|
#include "openport.h"
|
||
|
#include "opentcp.h"
|
||
|
|
||
|
|
||
|
#define BINKPORT 24554
|
||
|
#define TELNPORT 23
|
||
|
#define FIDOPORT 60179 /* Eugene G. Crossers birthday */
|
||
|
|
||
|
|
||
|
static int fd=-1;
|
||
|
extern int f_flags;
|
||
|
extern int tcp_mode;
|
||
|
extern time_t c_start;
|
||
|
extern time_t c_end;
|
||
|
extern int online;
|
||
|
extern int master;
|
||
|
extern int carrier;
|
||
|
extern int sentbytes;
|
||
|
extern int rcvdbytes;
|
||
|
extern int Loaded;
|
||
|
static int tcp_is_open = FALSE;
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Parameter may be:
|
||
|
* host.example.com
|
||
|
* host.example.com:portnumber
|
||
|
* host.example.com:portname
|
||
|
*/
|
||
|
int opentcp(char *servname)
|
||
|
{
|
||
|
struct servent *se;
|
||
|
struct sockaddr_in server;
|
||
|
int rc, GotPort = FALSE;
|
||
|
char *tservname, *portname, *ipver = NULL, servport[20], ipstr[INET6_ADDRSTRLEN];
|
||
|
u_int16_t portnum;
|
||
|
struct addrinfo hints, *res=NULL, *p;
|
||
|
|
||
|
memset(&hints, 0, sizeof(hints));
|
||
|
hints.ai_family = AF_UNSPEC;
|
||
|
hints.ai_socktype = SOCK_STREAM;
|
||
|
|
||
|
Syslog('+', "Open TCP connection to \"%s\"", MBSE_SS(servname));
|
||
|
tcp_is_open = FALSE;
|
||
|
|
||
|
if ((tservname = strchr(servname,'['))) {
|
||
|
|
||
|
/*
|
||
|
* Literal IPv6 address; check for port after ending bracket.
|
||
|
*/
|
||
|
|
||
|
tservname++; /* Strip left bracket. */
|
||
|
portname = strchr(tservname,']'); /* Find end of IPv6 address. */
|
||
|
*portname++='\0'; /* Strip right bracket. */
|
||
|
if ((portname = strchr(portname,':'))) {
|
||
|
*portname++='\0';
|
||
|
if ((portnum = atoi(portname))) {
|
||
|
server.sin_port = htons(portnum);
|
||
|
GotPort = TRUE;
|
||
|
} else if ((se = getservbyname(portname, "tcp"))) {
|
||
|
server.sin_port= se->s_port;
|
||
|
GotPort = TRUE;
|
||
|
}
|
||
|
servname = tservname;
|
||
|
}
|
||
|
} else if ((portname = strchr(servname,':'))) {
|
||
|
/*
|
||
|
* Hostname or IPv4 address.
|
||
|
* Get port number from name argument if there is a : part
|
||
|
*/
|
||
|
*portname++='\0';
|
||
|
if ((portnum = atoi(portname))) {
|
||
|
server.sin_port = htons(portnum);
|
||
|
GotPort = TRUE;
|
||
|
} else if ((se = getservbyname(portname, "tcp"))) {
|
||
|
server.sin_port = se->s_port;
|
||
|
GotPort = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If not a forced port number, get the defaults.
|
||
|
*/
|
||
|
if (! GotPort) {
|
||
|
switch (tcp_mode) {
|
||
|
case TCPMODE_IFC: if ((se = getservbyname("fido", "tcp")))
|
||
|
server.sin_port = se->s_port;
|
||
|
else
|
||
|
server.sin_port = htons(FIDOPORT);
|
||
|
break;
|
||
|
case TCPMODE_ITN: if ((se = getservbyname("telnet", "tcp")))
|
||
|
server.sin_port = se->s_port;
|
||
|
else
|
||
|
server.sin_port = htons(TELNPORT);
|
||
|
break;
|
||
|
case TCPMODE_IBN: if ((se = getservbyname("binkd", "tcp")))
|
||
|
server.sin_port = se->s_port;
|
||
|
else
|
||
|
server.sin_port = htons(BINKPORT);
|
||
|
break;
|
||
|
default: server.sin_port = htons(FIDOPORT);
|
||
|
}
|
||
|
}
|
||
|
snprintf(servport, 19, "%d", ntohs(server.sin_port));
|
||
|
|
||
|
/*
|
||
|
* Lookup hostname and return list of IPv4 and or IPv6 addresses.
|
||
|
*/
|
||
|
if ((rc = getaddrinfo(servname, servport, &hints, &res))) {
|
||
|
if (rc == EAI_SYSTEM)
|
||
|
WriteError("opentcp: getaddrinfo() failed");
|
||
|
else
|
||
|
Syslog('+', "Host not found --> %s\n", gai_strerror(rc));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
signal(SIGPIPE, sigpipe);
|
||
|
signal(SIGHUP, linedrop);
|
||
|
|
||
|
fflush(stdin);
|
||
|
fflush(stdout);
|
||
|
setbuf(stdin,NULL);
|
||
|
setbuf(stdout,NULL);
|
||
|
close(0);
|
||
|
close(1);
|
||
|
|
||
|
/*
|
||
|
* In case a node has a A and AAAA dns entry, we now have a list of
|
||
|
* possible connections to make, we try them until we succeed.
|
||
|
* Most likely, the first one is ok.
|
||
|
* Nice that this also works for clustered hosts, not that we will
|
||
|
* find any in fidonet, but .....
|
||
|
*/
|
||
|
for (p = res; p != NULL; p = p->ai_next) {
|
||
|
void *addr;
|
||
|
|
||
|
rc = 0;
|
||
|
if (p->ai_family == AF_INET) {
|
||
|
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||
|
addr = &(ipv4->sin_addr);
|
||
|
ipver = (char *)"IPv4";
|
||
|
} else {
|
||
|
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||
|
addr = &(ipv6->sin6_addr);
|
||
|
ipver = (char *)"IPv6";
|
||
|
}
|
||
|
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||
|
Syslog('+', "Trying %s %s port %s", ipver, ipstr, servport);
|
||
|
|
||
|
if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) != 0) {
|
||
|
if (fd > 0)
|
||
|
WriteError("Cannot create socket (got %d, expected 0)", fd);
|
||
|
else
|
||
|
WriteError("$Cannot create socket");
|
||
|
rc = -1;
|
||
|
} else {
|
||
|
if (dup(fd) != 1) {
|
||
|
WriteError("$Cannot dup socket");
|
||
|
rc = -1;
|
||
|
} else {
|
||
|
clearerr(stdin);
|
||
|
clearerr(stdout);
|
||
|
if (connect(fd, p->ai_addr, p->ai_addrlen) == -1) {
|
||
|
Syslog('+', "$Cannot connect %s port %s", ipstr, servport);
|
||
|
close(fd+1); /* close duped socket */
|
||
|
close(fd); /* close this socket */
|
||
|
rc = -1;
|
||
|
} else {
|
||
|
/*
|
||
|
* Connected, leave this loop
|
||
|
*/
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (rc == -1) {
|
||
|
open("/dev/null", O_RDONLY);
|
||
|
open("/dev/null", O_WRONLY);
|
||
|
freeaddrinfo(res);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
f_flags=0;
|
||
|
Syslog('+', "Established %s/TCP %s connection with %s, port %s",
|
||
|
(tcp_mode == TCPMODE_IFC) ? "IFC":(tcp_mode == TCPMODE_ITN) ?"ITN":(tcp_mode == TCPMODE_IBN) ? "IBN":"Unknown",
|
||
|
ipver, ipstr, servport);
|
||
|
freeaddrinfo(res);
|
||
|
c_start = time(NULL);
|
||
|
carrier = TRUE;
|
||
|
tcp_is_open = TRUE;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void closetcp(void)
|
||
|
{
|
||
|
FILE *fph;
|
||
|
char *tmp;
|
||
|
|
||
|
if (!tcp_is_open)
|
||
|
return;
|
||
|
|
||
|
shutdown(fd, SHUT_RDWR);
|
||
|
signal(SIGHUP, SIG_IGN);
|
||
|
signal(SIGPIPE, SIG_IGN);
|
||
|
|
||
|
if (carrier) {
|
||
|
c_end = time(NULL);
|
||
|
online += (c_end - c_start);
|
||
|
Syslog('+', "Closing TCP connection, connected %s", t_elapsed(c_start, c_end));
|
||
|
carrier = FALSE;
|
||
|
history.offline = (int)c_end;
|
||
|
history.online = (int)c_start;
|
||
|
history.sent_bytes = sentbytes;
|
||
|
history.rcvd_bytes = rcvdbytes;
|
||
|
history.inbound = ~master;
|
||
|
tmp = calloc(PATH_MAX, sizeof(char));
|
||
|
snprintf(tmp, PATH_MAX -1, "%s/var/mailer.hist", getenv("MBSE_ROOT"));
|
||
|
if ((fph = fopen(tmp, "a")) == NULL)
|
||
|
WriteError("$Can't open %s", tmp);
|
||
|
else {
|
||
|
fwrite(&history, sizeof(history), 1, fph);
|
||
|
fclose(fph);
|
||
|
}
|
||
|
free(tmp);
|
||
|
memset(&history, 0, sizeof(history));
|
||
|
if (Loaded) {
|
||
|
nodes.LastDate = time(NULL);
|
||
|
UpdateNode();
|
||
|
}
|
||
|
}
|
||
|
tcp_is_open = FALSE;
|
||
|
}
|
||
|
|
||
|
|