Import old rinetd 0.41.

Taken from the Debian archive:
  http://archive.debian.org/debian/dists/Debian-2.0/main/source/net/
This commit is contained in:
Sam Hocevar 2016-01-10 20:43:31 +01:00
commit a359399bb2
6 changed files with 1062 additions and 0 deletions

28
CHANGES Normal file
View File

@ -0,0 +1,28 @@
Version 0.1: original version.
Version 0.2: fixed bug when several reads are necessary
on one end or the other before a write flushes them.
Fixed bug which threw away data not yet sent to the
other side on close, when running under Linux. Fixed
associated bugs that probably affected other operating
systems as well. Fixed bug causing long, perhaps
indefinite pauses when a possible connection to a
server socket went away before the accept() call,
resulting in a blocking call.
Version 0.3: fixed additional bugs relating to
the code previously used only by non-Linux OSes.
This should fix problems such as connections not
going away when they should or connections being
mysteriously closed. Most of that code is now used by
Linux also, so it is likely that rinetd is much closer
to bug-free on non-Linux platforms. Of course, I don't
actually have any to play with it on.
Version 0.4: added support for kill -1 (SIGHUP)
and specification of service names instead of
port numbers. Removed calls to realloc(), replacing
them with code that should fail gracefully without
crashing the program or breaking existing connections
when another application is hogging memory.

9
Makefile Normal file
View File

@ -0,0 +1,9 @@
CFLAGS=-DLINUX -g
rinetd: rinetd.o
gcc rinetd.o -o rinetd
install: rinetd
install -m 700 rinetd /usr/sbin
install -m 644 rinetd.8 /usr/man/man8

15
README Normal file
View File

@ -0,0 +1,15 @@
rinetd version 0.41, by Thomas Boutell. Released under
the terms of the GNU Public License, version 2 or later.
This program is used to efficiently redirect connections
from one IP address/port combination to another. It is
useful when operating virtual servers, firewalls
and the like.
To build, check the Makefile for platform-specific
details and then type make. To install, type
"make install" as root.
For documentation run "make install", then type
"man rinetd" for details.

110
index.html Normal file
View File

@ -0,0 +1,110 @@
<html>
<head>
<title>RINETD(8)</title>
</head>
<body bgcolor="#FFFFF0">
<!--
Copyright (c) 1997, 1998, Thomas Boutell and Boutell.Com, Inc.
This software is released for free use under the terms of
the GNU Public License, version 2 or higher.
-->
<table>
<tr>
<th width=33% align=left>RINETD(8)
<th width=33% align=right>Unix System Manager's Manual
<th width=33% align=right>RINETD(8)
</tr>
</table>
<p>
<font color="#FF8888" size="4">NAME</font>
<p>
rinetd -- internet ``redirection server''
<p>
<font color="#FF8888" size="4">SYNOPSIS</font>
<p>
<code>/usr/sbin/rinetd</code>
<p>
<font color="#FF8888" size="4">VERSION</font>
<p>
Version 0.41, 2/11/1998.
<p>
<font color="#FF8888" size="4">WHERE TO GET</font>
<p>
<a href="ftp://ftp.boutell.com/pub/boutell/rinetd/rinetd.tar.gz">By
anonymous FTP from ftp.boutell.com</a> in the subdirectory
<code>boutell/rinetd</code> as the file <code>rinetd.tar.gz</code>.
<p>
<font color="#FF8888" size="4">DESCRIPTION</font>
<p>
Redirects TCP connections from one IP address and port to another. rinetd
is a single-process server which handles any number of connections to
the address/port pairs specified in the file <code>/etc/rinetd.conf</code>.
Since rinetd runs as a single process using nonblocking I/O, it is
able to redirect a large number of connections without a severe
impact on the machine. This makes it practical to run TCP services
on machines inside an IP masquerading firewall.
<p>
rinetd should be launched at boot time, using the following syntax:
<p>
<code>/usr/sbin/rinetd</code>
<p>
The format of <code>/etc/rinetd.conf</code> is as follows:
<p>
<code>bindaddress bindport connectaddress connectport</code>
<p>
For example:
<p>
<code>206.125.69.81 80 10.1.1.2 80</code>
<p>
Would redirect all connections to port 80 of the "real" IP address
206.125.69.81, which could be a virtual interface, through
rinetd to port 80 of the address 10.1.1.2, which would typically
be a machine on the inside of a firewall which has no
direct routing to the outside world.
<p>
Service names can be specified instead of port numbers. On most systems,
service names are defined in the file /etc/services.
<p>
Both IP addresses and hostnames are accepted for
bindaddress and connectaddress.
<p>
rinetd redirects TCP connections only. There is
no support for UDP.
<p>
The kill -1 signal (SIGHUP) can be used to cause rinetd
to reload its configuration file <strong>without</strong> interrupting existing
connections (this was added in version 0.4). Under Linux\(tm the process id
is saved in the file \fI/var/run/rinetd.pid\fR
to facilitate the kill -HUP (added in version 0.41).
<p>
<font color="#FF8888" size="4">BUGS</font>
<p>
rinetd does not currently produce any log information. The
server redirected to is not able to identify the host the
client really came from. Sockets would theoretically lose
data when closed with <code>SO_LINGER</code> turned off, but in Linux
this is not the case (kernel source comments support this
belief on my part). On non-Linux platforms, alternate code
which uses a different trick to work around blocking close()
is provided, but this code is untested. The manpage
is sketchy.
<p>
<font color="#FF8888" size="4">LICENSE</font>
<p>
Copyright (c) 1997, 1998,
<a href="http://www.boutell.com/boutell">Thomas Boutell</a> and
<a href="http://www.boutell.com/">Boutell.Com, Inc.</a>
This software is released for free use under the terms of
the GNU Public License, version 2 or higher.
<p>
<font color="#FF8888" size="4">CONTACT INFORMATION</font>
<p>
See <a href="http://www.boutell.com/rinetd">the rinetd web page</a>
for the latest release.
Thomas Boutell can be reached by email:
<a href="mailto:boutell@boutell.com">boutell@boutell.com</a>
<p>
<font color="#FF8888" size="4">THANKS</font>
<p>
Thanks are due to Bill Davidsen.

78
rinetd.8 Normal file
View File

@ -0,0 +1,78 @@
.\" Copyright (c) 1997, 1998, Thomas Boutell and Boutell.Com, Inc.
.\" This software is released for free use under the terms of
.\" the GNU Public License, version 2 or higher.
.\"
.Dd February 11, 1998
.Dt RINETD 8
.Os LINUX
.Sh NAME
.Nm rinetd
.Nd internet
.Dq redirection server
.Sh SYNOPSIS
.Nm /usr/sbin/rinetd
.Sh VERSION
Version 0.41, 3/1/1998.
.Sh DESCRIPTION
.Nm rinetd
redirects TCP connections from one IP address and port to another. rinetd
is a single-process server which handles any number of connections to
the address/port pairs specified in the file /etc/rinetd.conf.
Since rinetd runs as a single process using nonblocking I/O, it is
able to redirect a large number of connections without a severe
impact on the machine. This makes it practical to run TCP services
on machines inside an IP masquerading firewall.
.Pp
rinetd should be launched at boot time, using the following syntax:
.Pp
/usr/sbin/rinetd
.Pp
The format of /etc/rinetd.conf is as follows:
.Pp
bindaddress bindport connectaddress connectport
.Pp
For example:
.Pp
206.125.69.81 80 10.1.1.2 80
.Pp
Would redirect all connections to port 80 of the "real" IP address
206.125.69.81, which could be a virtual interface, through
rinetd to port 80 of the address 10.1.1.2, which would typically
be a machine on the inside of a firewall which has no
direct routing to the outside world.
.Pp
Service names can be specified instead of port numbers. On most systems,
service names are defined in the file /etc/services.
.Pp
Both IP addresses and hostnames are accepted for
bindaddress and connectaddress.
.Pp
rinetd redirects TCP connections only. There is
no support for UDP.
.Pp
The kill -1 signal (SIGHUP) can be used to cause rinetd
to reload its configuration file without interrupting existing
connections (this was added in version 0.4).
Under Linux\(tm the process id is saved in the file \fI/var/run/rinetd.pid\fR
to facilitate the kill -HUP (added in version 0.41).
.Pp
.Sh BUGS
rinetd does not currently produce any log information. The
server redirected to is not able to identify the host the
client really came from. Sockets would theoretically lose
data when closed with SO_LINGER turned off, but in Linux
this is not the case (kernel source comments support this
belief on my part). On non-Linux platforms, alternate code
which uses a different trick to work around blocking close()
is provided, but this code is untested. The manpage
is sketchy.
.Sh LICENSE
Copyright (c) 1997, 1998, Thomas Boutell and Boutell.Com, Inc.
This software is released for free use under the terms of
the GNU Public License, version 2 or higher.
.Sh CONTACT INFORMATION
See http://www.boutell.com/rinetd/ for the latest release.
Thomas Boutell can be reached by email: boutell@boutell.com
.Sh THANKS
Thanks are due to Bill Davidsen.

822
rinetd.c Normal file
View File

@ -0,0 +1,822 @@
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#ifdef DEBUG
#define PERROR perror
#else
#define PERROR(x)
#endif /* DEBUG */
int *seFds;
struct in_addr *seLocalAddrs;
unsigned short *seLocalPorts;
int *reFds;
int *loFds;
int *coInputRPos;
int *coInputWPos;
int *coOutputRPos;
int *coOutputWPos;
int *coClosed;
int *coClosing;
int *reClosed;
int *loClosed;
char **coInput;
char **coOutput;
int seTotal;
int coTotal;
int maxfd = 0;
/* If 'newsize' bytes can be allocated, *data is set to point
to them, the previous data is copied, and 1 is returned.
If 'size' bytes cannot be allocated, *data is UNCHANGED,
and 0 is returned. */
#define SAFE_REALLOC(x, y, z) safeRealloc((void **) (x), (y), (z))
int safeRealloc(void **data, int oldsize, int newsize);
/*
se: (se)rver sockets
re: (re)mote sockets
lo: (lo)cal sockets (being redirected to)
co: connections
*/
#define bufferSpace 1024
void createServerSockets();
/* Signal handlers */
void plumber(int s);
void hup(int s);
void initArrays();
void RegisterPID();
void selectLoop();
int main(int argc, char *argv[])
{
#ifndef DEBUG
if (!fork()) {
if (!fork()) {
#endif /* DEBUG */
signal(SIGPIPE, plumber);
signal(SIGHUP, hup);
initArrays();
RegisterPID();
createServerSockets();
selectLoop();
#ifndef DEBUG
} else {
exit(0);
}
} else {
exit(0);
}
#endif /* DEBUG */
return 0;
}
int getConfLine(FILE *in, char *line, int space, int *lnum);
void createServerSockets()
{
FILE *in;
char line[16384];
int lnum = 0;
int i;
if (seTotal) {
/* Close existing server sockets. */
for (i = 0; (i < seTotal); i++) {
close(seFds[i]);
}
/* Free memory associated with previous set. */
free(seFds);
free(seLocalAddrs);
free(seLocalPorts);
}
seTotal = 0;
/* 1. Count the non-comment lines and make room
for that many server sockets. */
in = fopen("/etc/rinetd.conf", "r");
if (!in) {
fprintf(stderr, "Can't open rinetd.conf\n");
exit(1);
}
while (1) {
if (!getConfLine(in, line, sizeof(line), &lnum)) {
break;
}
seTotal++;
}
fclose(in);
seFds = (int *) malloc(sizeof(int) * seTotal);
if (!seFds) {
fprintf(stderr, "Not enough memory to start rinetd.\n");
exit(1);
}
seLocalAddrs = (struct in_addr *) malloc(sizeof(struct in_addr) *
seTotal);
if (!seLocalAddrs) {
fprintf(stderr, "Not enough memory to start rinetd.\n");
exit(1);
}
seLocalPorts = (unsigned short *)
malloc(sizeof(unsigned short) * seTotal);
if (!seLocalPorts) {
fprintf(stderr, "Not enough memory to start rinetd.\n");
exit(1);
}
/* 2. Make a second pass to configure them. */
i = 0;
lnum = 0;
in = fopen("/etc/rinetd.conf", "r");
if (!in) {
fprintf(stderr, "Can't open rinetd.conf\n");
exit(1);
}
while (1) {
char *bindAddress;
unsigned short bindPort;
char *connectAddress;
char *tempS;
unsigned short connectPort;
struct in_addr iaddr;
struct sockaddr_in saddr;
struct servent *service;
int j;
if (!getConfLine(in, line, sizeof(line), &lnum)) {
break;
}
bindAddress = strtok(line, " \t\r\n");
if (!bindAddress) {
fprintf(stderr, "No bind address specified "
"on line %d.\n", lnum);
exit(1);
}
tempS = strtok(0, " \t\r\n");
if (!tempS) {
fprintf(stderr, "No bind port specified "
"on line %d.\n", lnum);
exit(1);
}
service = getservbyname(tempS, "tcp");
if (service) {
bindPort = ntohs(service->s_port);
} else {
bindPort = atoi(tempS);
}
if ((bindPort == 0) || (bindPort >= 65536)) {
fprintf(stderr, "Bind port missing or out "
"of range on line %d.\n", lnum);
exit(1);
}
connectAddress = strtok(0, " \t\r\n");
if (!connectAddress) {
fprintf(stderr, "No connect address specified "
"on line %d.\n", lnum);
exit(1);
}
tempS = strtok(0, " \t\r\n");
if (!tempS) {
fprintf(stderr, "No connect port specified "
"on line %d.\n", lnum);
exit(1);
}
service = getservbyname(tempS, "tcp");
if (service) {
connectPort = ntohs(service->s_port);
} else {
connectPort = atoi(tempS);
}
if ((connectPort == 0) || (connectPort >= 65536)) {
fprintf(stderr, "Bind port missing or out "
"of range on line %d.\n", lnum);
exit(1);
}
/* Turn all of this stuff into reasonable addresses */
if (!getAddress(bindAddress, &iaddr)) {
fprintf(stderr, "Host %s could not be resolved "
"on line %d.\n", bindAddress, lnum);
exit(1);
}
/* Make a server socket */
seFds[i] = socket(PF_INET, SOCK_STREAM, 0);
if (seFds[i] < 0) {
fprintf(stderr, "Couldn't create server socket!\n");
exit(1);
}
if (seFds[i] > maxfd) {
maxfd = seFds[i];
}
saddr.sin_family = AF_INET;
memcpy(&saddr.sin_addr, &iaddr, sizeof(iaddr));
saddr.sin_port = htons(bindPort);
j = 1;
setsockopt(seFds[i], SOL_SOCKET, SO_REUSEADDR,
&j, sizeof(j));
if (bind(seFds[i], (struct sockaddr *)
&saddr, sizeof(saddr)) < 0)
{
fprintf(stderr, "Couldn't bind to address %s port %d\n",
bindAddress, bindPort);
exit(1);
}
if (listen(seFds[i], 5) < 0) {
fprintf(stderr, "Couldn't listen to address %s "
"port %d\n",
bindAddress, bindPort);
exit(1);
}
fcntl(seFds[i], F_SETFL, O_NONBLOCK);
if (!getAddress(connectAddress, &iaddr)) {
fprintf(stderr, "Host %s could not be resolved "
"on line %d.\n", bindAddress, lnum);
exit(1);
}
seLocalAddrs[i] = iaddr;
seLocalPorts[i] = htons(connectPort);
i++;
}
}
int getConfLine(FILE *in, char *line, int space, int *lnum)
{
char *p;
while (1) {
if (!fgets(line, space, in)) {
return 0;
}
p = line;
while (isspace(*p)) {
p++;
}
if (!(*p)) {
/* Blank lines are OK */
continue;
}
if (*p == '#') {
/* Comment lines are also OK */
continue;
}
(*lnum)++;
return 1;
}
}
void initArrays()
{
int j;
coTotal = 64;
reFds = (int *) malloc(sizeof(int) * coTotal);
loFds = (int *) malloc(sizeof(int) * coTotal);
coInputRPos = (int *) malloc(sizeof(int) * coTotal);
coInputWPos = (int *) malloc(sizeof(int) * coTotal);
coOutputRPos = (int *) malloc(sizeof(int) * coTotal);
coOutputWPos = (int *) malloc(sizeof(int) * coTotal);
coClosed = (int *) malloc(sizeof(int) * coTotal);
coClosing = (int *) malloc(sizeof(int) * coTotal);
reClosed = (int *) malloc(sizeof(int) * coTotal);
loClosed = (int *) malloc(sizeof(int) * coTotal);
coInput = (char **) malloc(sizeof(char *) * coTotal);
coOutput = (char **) malloc(sizeof(char *) * coTotal);
if ((!reFds) || (!loFds) || (!coInputRPos) || (!coInputWPos) ||
(!coOutputRPos) || (!coOutputWPos) ||
(!coClosed) || (!coClosing) ||
(!reClosed) || (!loClosed) ||
(!coInput) || (!coOutput))
{
fprintf(stderr, "Not enough memory to start rinetd.\n");
exit(1);
}
for (j = 0; (j < coTotal); j++) {
coClosed[j] = 1;
coInput[j] = (char *) malloc(sizeof(char) * bufferSpace);
coOutput[j] = (char *) malloc(sizeof(char) * bufferSpace);
if ((!coInput[j]) || (!coOutput[j])) {
fprintf(stderr, "Not enough memory to start rinetd.\n");
exit(1);
}
}
}
void selectPass();
void selectLoop() {
while (1) {
selectPass();
}
}
void handleRemoteWrite(int i);
void handleRemoteRead(int i);
void handleLocalWrite(int i);
void handleLocalRead(int i);
void handleCloseFromLocal(int i);
void handleCloseFromRemote(int i);
void handleAccept(int i);
void openLocalFd(int se, int i);
int getAddress(char *host, struct in_addr *iaddr);
void selectPass() {
int i;
fd_set readfds, writefds;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
/* Server sockets */
for (i = 0; (i < seTotal); i++) {
FD_SET(seFds[i], &readfds);
}
/* Connection sockets */
for (i = 0; (i < coTotal); i++) {
if (coClosed[i]) {
continue;
}
if (coClosing[i]) {
if (!reClosed[i]) {
FD_SET(reFds[i], &writefds);
}
if (!loClosed[i]) {
FD_SET(loFds[i], &writefds);
}
}
/* Get more input if we have room for it */
if ((!reClosed[i]) && (coInputRPos[i] < bufferSpace)) {
FD_SET(reFds[i], &readfds);
}
/* Send more output if we have any */
if ((!reClosed[i]) && (coOutputWPos[i] < coOutputRPos[i])) {
FD_SET(reFds[i], &writefds);
}
/* Accept more output from the local
server if there's room */
if ((!loClosed[i]) && (coOutputRPos[i] < bufferSpace)) {
FD_SET(loFds[i], &readfds);
}
/* Send more input to the local server
if we have any */
if ((!loClosed[i]) && (coInputWPos[i] < coInputRPos[i])) {
FD_SET(loFds[i], &writefds);
}
}
select(maxfd + 1, &readfds, &writefds, 0, 0);
for (i = 0; (i < seTotal); i++) {
if (FD_ISSET(seFds[i], &readfds)) {
handleAccept(i);
}
}
for (i = 0; (i < coTotal); i++) {
if (coClosed[i]) {
continue;
}
if (!reClosed[i]) {
if (FD_ISSET(reFds[i], &readfds)) {
handleRemoteRead(i);
}
}
if (!reClosed[i]) {
if (FD_ISSET(reFds[i], &writefds)) {
handleRemoteWrite(i);
}
}
if (!loClosed[i]) {
if (FD_ISSET(loFds[i], &readfds)) {
handleLocalRead(i);
}
}
if (!loClosed[i]) {
if (FD_ISSET(loFds[i], &writefds)) {
handleLocalWrite(i);
}
}
if (loClosed[i] && reClosed[i]) {
coClosed[i] = 1;
}
}
}
void handleRemoteRead(int i)
{
int got;
if (bufferSpace == coInputRPos[i]) {
return;
}
got = recv(reFds[i], coInput[i] + coInputRPos[i],
bufferSpace - coInputRPos[i], 0);
if (got == 0) {
/* Prepare for closing */
handleCloseFromRemote(i);
return;
}
if (got < 0) {
if (errno == EWOULDBLOCK) {
return;
}
if (errno == EINPROGRESS) {
return;
}
handleCloseFromRemote(i);
return;
}
coInputRPos[i] += got;
}
void handleRemoteWrite(int i)
{
int got;
if (coClosing[i] && (coOutputWPos[i] == coOutputRPos[i])) {
reClosed[i] = 1;
coClosed[i] = 1;
PERROR("local closed and no more output");
close(reFds[i]);
return;
}
got = send(reFds[i], coOutput[i] + coOutputWPos[i],
coOutputRPos[i] - coOutputWPos[i], 0);
if (got < 0) {
if (errno == EWOULDBLOCK) {
return;
}
if (errno == EINPROGRESS) {
return;
}
handleCloseFromRemote(i);
return;
}
coOutputWPos[i] += got;
if (coOutputWPos[i] == coOutputRPos[i]) {
coOutputWPos[i] = 0;
coOutputRPos[i] = 0;
}
}
void handleLocalRead(int i)
{
int got;
if (bufferSpace == coOutputRPos[i]) {
return;
}
got = recv(loFds[i], coOutput[i] + coOutputRPos[i],
bufferSpace - coOutputRPos[i], 0);
if (got == 0) {
handleCloseFromLocal(i);
return;
}
if (got < 0) {
if (errno == EWOULDBLOCK) {
return;
}
if (errno == EINPROGRESS) {
return;
}
handleCloseFromLocal(i);
return;
}
coOutputRPos[i] += got;
}
void handleLocalWrite(int i)
{
int got;
if (coClosing[i] && (coInputWPos[i] == coInputRPos[i])) {
loClosed[i] = 1;
coClosed[i] = 1;
PERROR("remote closed and no more input");
close(loFds[i]);
return;
}
got = send(loFds[i], coInput[i] + coInputWPos[i],
coInputRPos[i] - coInputWPos[i], 0);
if (got < 0) {
if (errno == EWOULDBLOCK) {
return;
}
if (errno == EINPROGRESS) {
return;
}
handleCloseFromLocal(i);
return;
}
coInputWPos[i] += got;
if (coInputWPos[i] == coInputRPos[i]) {
coInputWPos[i] = 0;
coInputRPos[i] = 0;
}
}
void handleCloseFromLocal(int i)
{
int arg;
coClosing[i] = 1;
/* The local end fizzled out, so make sure
we're all done with that */
PERROR("close from local");
close(loFds[i]);
loClosed[i] = 1;
if (!reClosed[i]) {
#ifndef LINUX
/* Now set up the remote end for a polite closing */
/* Request a low-water mark equal to the entire
output buffer, so the next write notification
tells us for sure that we can close the socket. */
arg = 1024;
setsockopt(reFds[i], SOL_SOCKET, SO_SNDLOWAT,
&arg, sizeof(arg));
#endif /* LINUX */
}
}
void handleCloseFromRemote(int i)
{
int arg;
coClosing[i] = 1;
/* The remote end fizzled out, so make sure
we're all done with that */
PERROR("close from remote");
close(reFds[i]);
reClosed[i] = 1;
if (!loClosed[i]) {
#ifndef LINUX
/* Now set up the local end for a polite closing */
/* Request a low-water mark equal to the entire
output buffer, so the next write notification
tells us for sure that we can close the socket. */
arg = 1024;
setsockopt(loFds[i], SOL_SOCKET, SO_SNDLOWAT,
&arg, sizeof(arg));
#endif /* LINUX */
loClosed[i] = 0;
}
}
void handleAccept(int i)
{
struct sockaddr addr;
int j;
int addrlen;
int index = -1;
int o;
int nfd = accept(seFds[i], &addr, &addrlen);
if (nfd < 0) {
return;
}
if (nfd > maxfd) {
maxfd = nfd;
}
j = 1;
fcntl(nfd, F_SETFL, O_NONBLOCK);
j = 0;
setsockopt(nfd, SOL_SOCKET, SO_LINGER, &j, sizeof(j));
for (j = 0; (j < coTotal); j++) {
if (coClosed[j]) {
index = j;
break;
}
}
if (index == -1) {
o = coTotal;
coTotal *= 2;
if (!SAFE_REALLOC(&reFds, sizeof(int) * o,
sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&loFds, sizeof(int) * o,
sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&coInputRPos,
sizeof(int) * o, sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&coInputWPos,
sizeof(int) * o, sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&coOutputRPos,
sizeof(int) * o, sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&coOutputWPos, sizeof(int) * o,
sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&coClosed, sizeof(int) * o,
sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&reClosed, sizeof(int) * o,
sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&loClosed, sizeof(int) * o,
sizeof(int) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&coInput, sizeof(char *) * o,
sizeof(char *) * coTotal))
{
goto shortage;
}
if (!SAFE_REALLOC(&coOutput, sizeof(char *) * o,
sizeof(char *) * coTotal))
{
goto shortage;
}
for (j = o; (j < coTotal); j++) {
coClosed[j] = 1;
coInput[j] = (char *)
malloc(sizeof(char) * bufferSpace);
if (!coInput[j]) {
int k;
for (k = o; (k < j); k++) {
free(coInput[k]);
free(coOutput[k]);
}
goto shortage;
}
coOutput[j] = (char *)
malloc(sizeof(char) * bufferSpace);
if (!coOutput[j]) {
int k;
free(coInput[j]);
for (k = o; (k < j); k++) {
free(coInput[k]);
free(coOutput[k]);
}
goto shortage;
}
}
index = coTotal;
}
coInputRPos[index] = 0;
coInputWPos[index] = 0;
coOutputRPos[index] = 0;
coOutputWPos[index] = 0;
coClosed[index] = 0;
coClosing[index] = 0;
reClosed[index] = 0;
loClosed[index] = 0;
reFds[index] = nfd;
/* Now open a connection to the local server.
This, too, is nonblocking. Why wait
for anything when you don't have to? */
openLocalFd(i, index);
return;
shortage:
fprintf(stderr, "rinetd: not enough memory to "
"add slots. Currently %d slots.\n", o);
/* Go back to the previous total number of slots */
coTotal = o;
}
void openLocalFd(int se, int i)
{
int j;
struct sockaddr_in saddr;
loFds[i] = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (loFds[i] < 0) {
close(reFds[i]);
reClosed[i] = 1;
loClosed[i] = 1;
coClosed[i] = 1;
return;
}
if (loFds[i] > maxfd) {
maxfd = loFds[i];
}
/* Bind the local socket */
saddr.sin_family = AF_INET;
saddr.sin_port = INADDR_ANY;
saddr.sin_addr.s_addr = 0;
if (bind(loFds[i], (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
close(loFds[i]);
close(reFds[i]);
reClosed[i] = 1;
loClosed[i] = 1;
coClosed[i] = 1;
return;
}
memset(&saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
memcpy(&saddr.sin_addr, &seLocalAddrs[se], sizeof(struct in_addr));
saddr.sin_port = seLocalPorts[se];
#ifdef LINUX
j = 0;
setsockopt(loFds[i], SOL_SOCKET, SO_LINGER, &j, sizeof(j));
#else
j = 1024;
setsockopt(loFds[i], SOL_SOCKET, SO_SNDBUF, &j, sizeof(j));
#endif /* LINUX */
j = 1;
fcntl(loFds[i], F_SETFL, O_NONBLOCK);
if (connect(loFds[i], (struct sockaddr *)&saddr,
sizeof(struct sockaddr_in)) < 0)
{
if (errno != EINPROGRESS) {
PERROR("connect");
close(loFds[i]);
close(reFds[i]);
reClosed[i] = 1;
loClosed[i] = 1;
coClosed[i] = 1;
return;
}
}
}
int getAddress(char *host, struct in_addr *iaddr)
{
char *p = host;
int ishost = 0;
while (*p) {
if (!(isdigit(*p) || ((*p) == '.'))) {
ishost = 1;
break;
}
p++;
}
if (ishost) {
struct hostent *h;
h = gethostbyname(host);
if (!h) {
return 0;
}
memcpy(
(void *) &iaddr->s_addr,
(void *) h->h_addr,
4);
return 1;
} else {
iaddr->s_addr = inet_addr(host);
return 1;
}
}
void plumber(int s)
{
/* Just reinstall */
signal(SIGPIPE, plumber);
}
void hup(int s)
{
/* Recreate server sockets */
createServerSockets();
/* And reinstall */
signal(SIGHUP, hup);
}
int safeRealloc(void **data, int oldsize, int newsize)
{
void *newData = malloc(newsize + 1);
if (!newData) {
return 0;
}
if (newsize < oldsize) {
memcpy(newData, *data, newsize);
} else {
memcpy(newData, *data, oldsize);
}
*data = newData;
return 1;
}
void
RegisterPID()
{
FILE *pid_file;
/* add other systems with wherever they register processes */
#if defined(LINUX)
pid_file = fopen("/var/run/rinetd.pid", "w");
if (pid_file == NULL) {
/* non-fatal, non-Linux may lack /var/run... */
fprintf(stderr, "PID unregistered\n");
} else {
/* error checking deliberately omitted */
fprintf(pid_file, "%d\n", getpid());
fclose(pid_file);
}
#endif /* LINUX */
}