mirror of
https://github.com/samhocevar/rinetd.git
synced 2024-12-28 05:40:31 +08:00
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:
commit
a359399bb2
28
CHANGES
Normal file
28
CHANGES
Normal 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
9
Makefile
Normal 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
15
README
Normal 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
110
index.html
Normal 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
78
rinetd.8
Normal 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
822
rinetd.c
Normal 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 */
|
||||
}
|
Loading…
Reference in New Issue
Block a user