mirror of
https://github.com/samhocevar/rinetd.git
synced 2025-03-22 15:50:08 +08:00
Merge branch 'feature-udp-support'. Closes #8.
This commit is contained in:
commit
f64f42ba81
@ -8,12 +8,12 @@ man_MANS = rinetd.8
|
|||||||
sysconf_DATA = rinetd.conf
|
sysconf_DATA = rinetd.conf
|
||||||
|
|
||||||
sbin_PROGRAMS = rinetd
|
sbin_PROGRAMS = rinetd
|
||||||
rinetd_SOURCES = rinetd.c rinetd.h parse.h match.c match.h
|
rinetd_SOURCES = rinetd.c rinetd.h parse.c parse.h match.c match.h net.c net.h
|
||||||
|
|
||||||
BUILT_SOURCES = parse.h
|
BUILT_SOURCES = parse.c
|
||||||
|
|
||||||
# If peg/leg is available, regenerate parse.h
|
# If peg/leg is available, regenerate parse.h
|
||||||
parse.h: parse.peg
|
parse.c: parse.peg
|
||||||
if which leg >/dev/null 2>&1; then leg -o $@ $^; else touch $@; fi
|
if which leg >/dev/null 2>&1; then leg -o $@ $^; else touch $@; fi
|
||||||
|
|
||||||
# _POSIX_C_SOURCE is for SA_RESTART and others
|
# _POSIX_C_SOURCE is for SA_RESTART and others
|
||||||
|
10
match.c
10
match.c
@ -1,5 +1,13 @@
|
|||||||
|
/* Copyright © 1997—1999 Thomas Boutell <boutell@boutell.com>
|
||||||
|
and Boutell.Com, Inc.
|
||||||
|
© 2003—2017 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
This software is released for free use under the terms of
|
||||||
|
the GNU Public License, version 2 or higher. NO WARRANTY
|
||||||
|
IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK. */
|
||||||
|
|
||||||
#if HAVE_CONFIG_H
|
#if HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
13
match.h
13
match.h
@ -1,9 +1,14 @@
|
|||||||
#ifndef MATCH_H
|
/* Copyright © 1997—1999 Thomas Boutell <boutell@boutell.com>
|
||||||
#define MATCH_H 1
|
and Boutell.Com, Inc.
|
||||||
|
© 2003—2017 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
This software is released for free use under the terms of
|
||||||
|
the GNU Public License, version 2 or higher. NO WARRANTY
|
||||||
|
IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
extern int match(char const *s, char const *p);
|
extern int match(char const *s, char const *p);
|
||||||
extern int matchNoCase(char const *s, char const *p);
|
extern int matchNoCase(char const *s, char const *p);
|
||||||
extern int matchBody(char const *s, char const *p, int nocase);
|
extern int matchBody(char const *s, char const *p, int nocase);
|
||||||
|
|
||||||
#endif /* MATCH_H */
|
|
||||||
|
|
||||||
|
35
net.c
Normal file
35
net.c
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/* Copyright © 1997—1999 Thomas Boutell <boutell@boutell.com>
|
||||||
|
and Boutell.Com, Inc.
|
||||||
|
© 2003—2017 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
This software is released for free use under the terms of
|
||||||
|
the GNU Public License, version 2 or higher. NO WARRANTY
|
||||||
|
IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK. */
|
||||||
|
|
||||||
|
#if HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
void setSocketDefaults(SOCKET fd)
|
||||||
|
{
|
||||||
|
/* Make socket non-blocking (FIXME: this uses legacy API) */
|
||||||
|
FIONBIO_ARG_T ioctltmp = 1;
|
||||||
|
#if _WIN32
|
||||||
|
ioctlsocket(fd, FIONBIO, &ioctltmp);
|
||||||
|
#else
|
||||||
|
ioctl(fd, FIONBIO, &ioctltmp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined __linux__
|
||||||
|
int tmp = 0;
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_LINGER, &tmp, sizeof(tmp));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined __linux__ && !defined _WIN32
|
||||||
|
int tmp = 1024;
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
74
net.h
Normal file
74
net.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* Copyright © 1997—1999 Thomas Boutell <boutell@boutell.com>
|
||||||
|
and Boutell.Com, Inc.
|
||||||
|
© 2003—2017 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
This software is released for free use under the terms of
|
||||||
|
the GNU Public License, version 2 or higher. NO WARRANTY
|
||||||
|
IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
/* Define this to a reasonably large value */
|
||||||
|
# define FD_SETSIZE 4096
|
||||||
|
# include <winsock2.h>
|
||||||
|
# include <windows.h>
|
||||||
|
#else
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <sys/ioctl.h>
|
||||||
|
# include <netdb.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined HAVE_ERRNO_H
|
||||||
|
# include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We've got to get FIONBIO from somewhere. Try the Solaris location
|
||||||
|
if it isn't defined yet by the above includes. */
|
||||||
|
#ifndef FIONBIO
|
||||||
|
# include <sys/filio.h>
|
||||||
|
#endif /* FIONBIO */
|
||||||
|
|
||||||
|
#if HAVE_SOCKLEN_T
|
||||||
|
# define SOCKLEN_T socklen_t
|
||||||
|
#else
|
||||||
|
# define SOCKLEN_T int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
# define FIONBIO_ARG_T u_long
|
||||||
|
#else
|
||||||
|
# define FIONBIO_ARG_T int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
/* _WIN32 doesn't really have WSAEAGAIN */
|
||||||
|
# ifndef WSAEAGAIN
|
||||||
|
# define WSAEAGAIN WSAEWOULDBLOCK
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
/* Windows sockets compatibility defines */
|
||||||
|
# define INVALID_SOCKET (-1)
|
||||||
|
# define SOCKET_ERROR (-1)
|
||||||
|
static inline int closesocket(int s) {
|
||||||
|
return close(s);
|
||||||
|
}
|
||||||
|
# define WSAEWOULDBLOCK EWOULDBLOCK
|
||||||
|
# define WSAEAGAIN EAGAIN
|
||||||
|
# define WSAEINPROGRESS EINPROGRESS
|
||||||
|
# define WSAEINTR EINTR
|
||||||
|
# define SOCKET int
|
||||||
|
static inline int GetLastError(void) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
void setSocketDefaults(SOCKET fd);
|
||||||
|
|
203
parse.peg
203
parse.peg
@ -1,123 +1,86 @@
|
|||||||
|
# Copyright © 1997—1999 Thomas Boutell <boutell@boutell.com>
|
||||||
|
# and Boutell.Com, Inc.
|
||||||
|
# © 2003—2017 Sam Hocevar <sam@hocevar.net>
|
||||||
|
#
|
||||||
|
# This software is released for free use under the terms of
|
||||||
|
# the GNU Public License, version 2 or higher. NO WARRANTY
|
||||||
|
# IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK. */
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
#if HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "net.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "rinetd.h"
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
#define YY_CTX_LOCAL 1
|
#define YY_CTX_LOCAL 1
|
||||||
#define YY_CTX_MEMBERS \
|
#define YY_CTX_MEMBERS \
|
||||||
FILE *fp; \
|
FILE *fp; \
|
||||||
int currentLine; \
|
int currentLine; \
|
||||||
int isAuthAllow; \
|
int isAuthAllow; \
|
||||||
unsigned int port, bindPort, connectPort; \
|
char *tmpPort; \
|
||||||
char *bindAddress, *connectAddress;
|
int tmpPortNum, tmpProto; \
|
||||||
|
int bindPortNum, bindProto, connectPortNum, connectProto; \
|
||||||
|
int serverTimeout; \
|
||||||
|
char *bindAddress, *connectAddress;
|
||||||
#define YY_INPUT(yyctx, buf, result, max_size) \
|
#define YY_INPUT(yyctx, buf, result, max_size) \
|
||||||
{ \
|
{ \
|
||||||
int yyc = fgetc(yyctx->fp); \
|
int yyc = fgetc(yyctx->fp); \
|
||||||
result = (EOF == yyc) ? 0 : (*(buf) = yyc, 1); \
|
result = (EOF == yyc) ? 0 : (*(buf) = yyc, 1); \
|
||||||
}
|
}
|
||||||
#define PARSE_ERROR exit(1);
|
#define PARSE_ERROR exit(1);
|
||||||
|
|
||||||
|
#if defined __clang__
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-label"
|
||||||
|
#elif defined __GNUC__
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-label"
|
||||||
|
#endif
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
file = (sol (line eol | invalid_syntax))*
|
file = (sol (line eol | invalid-syntax))*
|
||||||
line = -? (rule | auth | logfile | pidlogfile | logcommon )? -? comment?
|
line = -? (command -?)? comment?
|
||||||
|
command = (server-rule | auth-rule | logfile | pidlogfile | logcommon)
|
||||||
comment = "#" (!eol .)*
|
comment = "#" (!eol .)*
|
||||||
|
|
||||||
rule = bind_address - bind_port - connect_address - connect_port {
|
server-rule = bind-address - bind-port - connect-address - connect-port (-? "[" -? server-options -? "]")?
|
||||||
/* Turn all of this stuff into reasonable addresses */
|
{
|
||||||
struct in_addr iaddr;
|
addServer(yy->bindAddress, yy->bindPortNum, yy->bindProto,
|
||||||
if (getAddress(yy->bindAddress, &iaddr) < 0) {
|
yy->connectAddress, yy->connectPortNum, yy->connectProto,
|
||||||
fprintf(stderr, "rinetd: host %s could not be resolved.\n",
|
yy->serverTimeout > 0 ? yy->serverTimeout : RINETD_DEFAULT_UDP_TIMEOUT);
|
||||||
yy->bindAddress);
|
|
||||||
PARSE_ERROR;
|
|
||||||
}
|
|
||||||
/* Make a server socket */
|
|
||||||
SOCKET fd = socket(PF_INET, SOCK_STREAM, 0);
|
|
||||||
if (fd == INVALID_SOCKET) {
|
|
||||||
syslog(LOG_ERR, "couldn't create "
|
|
||||||
"server socket! (%m)\n");
|
|
||||||
PARSE_ERROR;
|
|
||||||
}
|
|
||||||
struct sockaddr_in saddr;
|
|
||||||
saddr.sin_family = AF_INET;
|
|
||||||
memcpy(&saddr.sin_addr, &iaddr, sizeof(iaddr));
|
|
||||||
saddr.sin_port = htons(yy->bindPort);
|
|
||||||
int tmp = 1;
|
|
||||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
|
||||||
(const char *) &tmp, sizeof(tmp));
|
|
||||||
if (bind(fd, (struct sockaddr *)
|
|
||||||
&saddr, sizeof(saddr)) == SOCKET_ERROR)
|
|
||||||
{
|
|
||||||
/* Warn -- don't exit. */
|
|
||||||
syslog(LOG_ERR, "couldn't bind to "
|
|
||||||
"address %s port %d (%m)\n",
|
|
||||||
yy->bindAddress, yy->bindPort);
|
|
||||||
closesocket(fd);
|
|
||||||
PARSE_ERROR;
|
|
||||||
}
|
|
||||||
if (listen(fd, RINETD_LISTEN_BACKLOG) == SOCKET_ERROR) {
|
|
||||||
/* Warn -- don't exit. */
|
|
||||||
syslog(LOG_ERR, "couldn't listen to "
|
|
||||||
"address %s port %d (%m)\n",
|
|
||||||
yy->bindAddress, yy->bindPort);
|
|
||||||
closesocket(fd);
|
|
||||||
PARSE_ERROR;
|
|
||||||
}
|
|
||||||
#if _WIN32
|
|
||||||
u_long ioctltmp;
|
|
||||||
#else
|
|
||||||
int ioctltmp;
|
|
||||||
#endif
|
|
||||||
ioctlsocket(fd, FIONBIO, &ioctltmp);
|
|
||||||
if (getAddress(yy->connectAddress, &iaddr) < 0) {
|
|
||||||
/* Warn -- don't exit. */
|
|
||||||
syslog(LOG_ERR, "host %s could not be resolved.\n",
|
|
||||||
yy->bindAddress);
|
|
||||||
closesocket(fd);
|
|
||||||
PARSE_ERROR;
|
|
||||||
}
|
|
||||||
/* Allocate server info */
|
|
||||||
seInfo = (ServerInfo *)
|
|
||||||
realloc(seInfo, sizeof(ServerInfo) * (seTotal + 1));
|
|
||||||
if (!seInfo) {
|
|
||||||
PARSE_ERROR;
|
|
||||||
}
|
|
||||||
ServerInfo *srv = &seInfo[seTotal];
|
|
||||||
memset(srv, 0, sizeof(*srv));
|
|
||||||
srv->fd = fd;
|
|
||||||
srv->localAddr = iaddr;
|
|
||||||
srv->localPort = htons(yy->connectPort);
|
|
||||||
srv->fromHost = yy->bindAddress;
|
|
||||||
if (!srv->fromHost) {
|
|
||||||
PARSE_ERROR;
|
|
||||||
}
|
|
||||||
srv->fromPort = yy->bindPort;
|
|
||||||
srv->toHost = yy->connectAddress;
|
|
||||||
if (!srv->toHost) {
|
|
||||||
PARSE_ERROR;
|
|
||||||
}
|
|
||||||
srv->toPort = yy->connectPort;
|
|
||||||
#ifndef _WIN32
|
|
||||||
if (fd > maxfd) {
|
|
||||||
maxfd = fd;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
++seTotal;
|
|
||||||
|
|
||||||
yy->bindAddress = yy->connectAddress = NULL;
|
yy->bindAddress = yy->connectAddress = NULL;
|
||||||
|
yy->serverTimeout = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bind_address = < ipv4 > { yy->bindAddress = strdup(yytext); }
|
bind-address = < ipv4 > { yy->bindAddress = strdup(yytext); }
|
||||||
connect_address = < ipv4 > { yy->connectAddress = strdup(yytext); }
|
connect-address = < ipv4 > { yy->connectAddress = strdup(yytext); }
|
||||||
bind_port = port { yy->bindPort = yy->port; }
|
bind-port = full-port { yy->bindPortNum = yy->tmpPortNum; yy->bindProto = yy->tmpProto; }
|
||||||
connect_port = port { yy->connectPort = yy->port; }
|
connect-port = full-port { yy->connectPortNum = yy->tmpPortNum; yy->connectProto = yy->tmpProto; }
|
||||||
|
server-options = ("timeout" -? "=" -? < number >) { yy->serverTimeout = atoi(yytext); }
|
||||||
|
|
||||||
port = < (number | service) > {
|
full-port = port proto
|
||||||
struct servent *bindService = getservbyname(yytext, "tcp");
|
{
|
||||||
yy->port = bindService ? ntohs(bindService->s_port) : atoi(yytext);
|
char const *proto = yy->tmpProto == protoTcp ? "tcp" : "udp";
|
||||||
if (yy->port == 0 || yy->port >= 65536) {
|
struct servent *service = getservbyname(yy->tmpPort, proto);
|
||||||
syslog(LOG_ERR, "bind port missing or out of range\n");
|
yy->tmpPortNum = service ? ntohs(service->s_port) : atoi(yy->tmpPort);
|
||||||
|
if (yy->tmpPortNum == 0 || yy->tmpPortNum >= 65536) {
|
||||||
|
syslog(LOG_ERR, "port %s/%s missing or out of range\n", yy->tmpPort, proto);
|
||||||
PARSE_ERROR;
|
PARSE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auth = auth_key - < pattern > {
|
port = < (number | service) > { yy->tmpPort = strdup(yytext); }
|
||||||
|
proto = '/tcp' { yy->tmpProto = protoTcp; }
|
||||||
|
| '/udp' { yy->tmpProto = protoUdp; }
|
||||||
|
| '' { yy->tmpProto = protoTcp; }
|
||||||
|
|
||||||
|
auth-rule = auth-key - < pattern >
|
||||||
|
{
|
||||||
allRules = (Rule *)
|
allRules = (Rule *)
|
||||||
realloc(allRules, sizeof(Rule) * (allRulesCount + 1));
|
realloc(allRules, sizeof(Rule) * (allRulesCount + 1));
|
||||||
if (!allRules) {
|
if (!allRules) {
|
||||||
@ -139,27 +102,31 @@ auth = auth_key - < pattern > {
|
|||||||
++allRulesCount;
|
++allRulesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
auth_key = < ("allow" | "deny") > { yy->isAuthAllow = (yytext[0] == 'a'); }
|
auth-key = < ("allow" | "deny") > { yy->isAuthAllow = (yytext[0] == 'a'); }
|
||||||
|
|
||||||
logfile = "logfile" - < filename > {
|
logfile = "logfile" - < filename >
|
||||||
|
{
|
||||||
logFileName = strdup(yytext);
|
logFileName = strdup(yytext);
|
||||||
if (!logFileName) {
|
if (!logFileName) {
|
||||||
PARSE_ERROR;
|
PARSE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pidlogfile = "pidlogfile" - < filename > {
|
pidlogfile = "pidlogfile" - < filename >
|
||||||
|
{
|
||||||
pidLogFileName = strdup(yytext);
|
pidLogFileName = strdup(yytext);
|
||||||
if (!pidLogFileName) {
|
if (!pidLogFileName) {
|
||||||
PARSE_ERROR;
|
PARSE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logcommon = "logcommon" {
|
logcommon = "logcommon"
|
||||||
|
{
|
||||||
logFormatCommon = 1;
|
logFormatCommon = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
invalid_syntax = < (!eol .)+ > eol {
|
invalid_syntax = < (!eol .)+ > eol
|
||||||
|
{
|
||||||
fprintf(stderr, "rinetd: invalid syntax at line %d: %s\n",
|
fprintf(stderr, "rinetd: invalid syntax at line %d: %s\n",
|
||||||
yy->currentLine, yytext);
|
yy->currentLine, yytext);
|
||||||
PARSE_ERROR; /* FIXME */
|
PARSE_ERROR; /* FIXME */
|
||||||
@ -180,3 +147,27 @@ sol = { ++yy->currentLine; }
|
|||||||
eol = '\r'? '\n' | eof
|
eol = '\r'? '\n' | eof
|
||||||
eof = '\0'
|
eof = '\0'
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
void parseConfiguration(char const *file)
|
||||||
|
{
|
||||||
|
FILE *in = fopen(file, "r");
|
||||||
|
if (!in) {
|
||||||
|
PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
yycontext ctx;
|
||||||
|
memset(&ctx, 0, sizeof(yycontext));
|
||||||
|
ctx.fp = in;
|
||||||
|
if (!yyparse(&ctx)) {
|
||||||
|
syslog(LOG_ERR, "invalid syntax "
|
||||||
|
"on file %s, line %d.\n", file, -1);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(in);
|
||||||
|
|
||||||
|
/* Avopid warnings for these unused functions */
|
||||||
|
(void)yySet; (void)yyPush; (void)yyPop; (void)yyAccept;
|
||||||
|
}
|
||||||
|
|
||||||
|
501
rinetd.c
501
rinetd.c
@ -1,3 +1,11 @@
|
|||||||
|
/* Copyright © 1997—1999 Thomas Boutell <boutell@boutell.com>
|
||||||
|
and Boutell.Com, Inc.
|
||||||
|
© 2003—2017 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
This software is released for free use under the terms of
|
||||||
|
the GNU Public License, version 2 or higher. NO WARRANTY
|
||||||
|
IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK. */
|
||||||
|
|
||||||
#if HAVE_CONFIG_H
|
#if HAVE_CONFIG_H
|
||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif
|
#endif
|
||||||
@ -7,27 +15,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
/* Define this to a reasonably large value */
|
|
||||||
# define FD_SETSIZE 4096
|
|
||||||
# include <winsock2.h>
|
|
||||||
# include <windows.h>
|
|
||||||
# include "getopt.h"
|
# include "getopt.h"
|
||||||
# define syslog fprintf
|
|
||||||
# define LOG_ERR stderr
|
|
||||||
# define LOG_INFO stdout
|
|
||||||
#else
|
#else
|
||||||
# include <sys/types.h>
|
|
||||||
# include <sys/socket.h>
|
|
||||||
# include <sys/ioctl.h>
|
|
||||||
# include <unistd.h>
|
|
||||||
# include <netdb.h>
|
|
||||||
# include <netinet/in.h>
|
|
||||||
# include <arpa/inet.h>
|
|
||||||
# include <getopt.h>
|
# include <getopt.h>
|
||||||
# include <errno.h>
|
|
||||||
# include <syslog.h>
|
|
||||||
# define INVALID_SOCKET (-1)
|
|
||||||
# define SOCKET_ERROR (-1)
|
|
||||||
# if TIME_WITH_SYS_TIME
|
# if TIME_WITH_SYS_TIME
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
@ -46,43 +36,17 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
/* _WIN32 doesn't really have WSAEAGAIN */
|
|
||||||
# ifndef WSAEAGAIN
|
|
||||||
# define WSAEAGAIN WSAEWOULDBLOCK
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
/* Windows sockets compatibility defines */
|
|
||||||
# define INVALID_SOCKET (-1)
|
|
||||||
# define SOCKET_ERROR (-1)
|
|
||||||
static inline int closesocket(int s) {
|
|
||||||
return close(s);
|
|
||||||
}
|
|
||||||
# define ioctlsocket ioctl
|
|
||||||
# define WSAEWOULDBLOCK EWOULDBLOCK
|
|
||||||
# define WSAEAGAIN EAGAIN
|
|
||||||
# define WSAEINPROGRESS EINPROGRESS
|
|
||||||
# define WSAEINTR EINTR
|
|
||||||
# define SOCKET int
|
|
||||||
static inline int GetLastError(void) {
|
|
||||||
return errno;
|
|
||||||
}
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define PERROR perror
|
# define PERROR perror
|
||||||
#else
|
#else
|
||||||
# define PERROR(x)
|
# define PERROR(x)
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
/* We've got to get FIONBIO from somewhere. Try the Solaris location
|
|
||||||
if it isn't defined yet by the above includes. */
|
|
||||||
#ifndef FIONBIO
|
|
||||||
# include <sys/filio.h>
|
|
||||||
#endif /* FIONBIO */
|
|
||||||
|
|
||||||
#include "match.h"
|
#include "match.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "types.h"
|
||||||
#include "rinetd.h"
|
#include "rinetd.h"
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
Rule *allRules = NULL;
|
Rule *allRules = NULL;
|
||||||
int allRulesCount = 0;
|
int allRulesCount = 0;
|
||||||
@ -121,8 +85,7 @@ char const *logMessages[] = {
|
|||||||
"denied",
|
"denied",
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
logUnknownError = 0,
|
logUnknownError = 0,
|
||||||
logLocalClosedFirst,
|
logLocalClosedFirst,
|
||||||
logRemoteClosedFirst,
|
logRemoteClosedFirst,
|
||||||
@ -131,6 +94,7 @@ enum
|
|||||||
logLocalBindFailed,
|
logLocalBindFailed,
|
||||||
logLocalConnectFailed,
|
logLocalConnectFailed,
|
||||||
logOpened,
|
logOpened,
|
||||||
|
logAllowed,
|
||||||
logNotAllowed,
|
logNotAllowed,
|
||||||
logDenied,
|
logDenied,
|
||||||
};
|
};
|
||||||
@ -148,10 +112,9 @@ static void handleAccept(ServerInfo const *srv);
|
|||||||
static ConnectionInfo *findAvailableConnection(void);
|
static ConnectionInfo *findAvailableConnection(void);
|
||||||
static void setConnectionCount(int newCount);
|
static void setConnectionCount(int newCount);
|
||||||
static int getAddress(char const *host, struct in_addr *iaddr);
|
static int getAddress(char const *host, struct in_addr *iaddr);
|
||||||
static void refuse(ConnectionInfo *cnx, int logCode);
|
static int checkConnectionAllowed(ConnectionInfo const *cnx);
|
||||||
|
|
||||||
static int readArgs (int argc, char **argv, RinetdOptions *options);
|
static int readArgs (int argc, char **argv, RinetdOptions *options);
|
||||||
static int getConfLine(FILE *in, char *line, int space, int *lnum);
|
|
||||||
static void clearConfiguration(void);
|
static void clearConfiguration(void);
|
||||||
static void readConfiguration(char const *file);
|
static void readConfiguration(char const *file);
|
||||||
|
|
||||||
@ -159,8 +122,6 @@ static void registerPID(char const *pid_file_name);
|
|||||||
static void logEvent(ConnectionInfo const *cnx, ServerInfo const *srv, int result);
|
static void logEvent(ConnectionInfo const *cnx, ServerInfo const *srv, int result);
|
||||||
static struct tm *get_gmtoff(int *tz);
|
static struct tm *get_gmtoff(int *tz);
|
||||||
|
|
||||||
#include "parse.h"
|
|
||||||
|
|
||||||
/* Signal handlers */
|
/* Signal handlers */
|
||||||
#if !HAVE_SIGACTION && !_WIN32
|
#if !HAVE_SIGACTION && !_WIN32
|
||||||
static RETSIGTYPE plumber(int s);
|
static RETSIGTYPE plumber(int s);
|
||||||
@ -220,7 +181,7 @@ int main(int argc, char *argv[])
|
|||||||
registerPID(pidLogFileName ? pidLogFileName : RINETD_PID_FILE);
|
registerPID(pidLogFileName ? pidLogFileName : RINETD_PID_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
syslog(LOG_INFO, "Starting redirections...");
|
syslog(LOG_INFO, "Starting redirections...\n");
|
||||||
while (1) {
|
while (1) {
|
||||||
selectPass();
|
selectPass();
|
||||||
}
|
}
|
||||||
@ -265,19 +226,7 @@ static void clearConfiguration(void) {
|
|||||||
static void readConfiguration(char const *file) {
|
static void readConfiguration(char const *file) {
|
||||||
|
|
||||||
/* Parse the configuration file. */
|
/* Parse the configuration file. */
|
||||||
FILE *in = fopen(file, "r");
|
parseConfiguration(file);
|
||||||
if (!in) {
|
|
||||||
goto lowMemory;
|
|
||||||
}
|
|
||||||
yycontext ctx;
|
|
||||||
memset(&ctx, 0, sizeof(yycontext));
|
|
||||||
ctx.fp = in;
|
|
||||||
if (!yyparse(&ctx)) {
|
|
||||||
syslog(LOG_ERR, "invalid syntax "
|
|
||||||
"on file %s, line %d.\n", file, -1);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
fclose(in);
|
|
||||||
|
|
||||||
/* Open the log file */
|
/* Open the log file */
|
||||||
if (logFile) {
|
if (logFile) {
|
||||||
@ -293,33 +242,94 @@ static void readConfiguration(char const *file) {
|
|||||||
logFileName);
|
logFileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
lowMemory:
|
|
||||||
syslog(LOG_ERR, "not enough memory to start rinetd.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getConfLine(FILE *in, char *line, int space, int *lnum)
|
void addServer(char *bindAddress, int bindPort, int bindProto,
|
||||||
{
|
char *connectAddress, int connectPort, int connectProto,
|
||||||
while (1) {
|
int serverTimeout) {
|
||||||
(*lnum)++;
|
/* Turn all of this stuff into reasonable addresses */
|
||||||
if (!fgets(line, space, in)) {
|
struct in_addr iaddr;
|
||||||
return 0;
|
if (getAddress(bindAddress, &iaddr) < 0) {
|
||||||
}
|
fprintf(stderr, "rinetd: host %s could not be resolved.\n",
|
||||||
char const *p = line;
|
bindAddress);
|
||||||
while (isspace(*p)) {
|
exit(1);
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (!(*p)) {
|
|
||||||
/* Blank lines are OK */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (*p == '#') {
|
|
||||||
/* Comment lines are also OK */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
/* Make a server socket */
|
||||||
|
SOCKET fd = socket(PF_INET,
|
||||||
|
bindProto == protoTcp ? SOCK_STREAM : SOCK_DGRAM,
|
||||||
|
bindProto == protoTcp ? IPPROTO_TCP : IPPROTO_UDP);
|
||||||
|
if (fd == INVALID_SOCKET) {
|
||||||
|
syslog(LOG_ERR, "couldn't create "
|
||||||
|
"server socket! (%m)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
saddr.sin_family = AF_INET;
|
||||||
|
memcpy(&saddr.sin_addr, &iaddr, sizeof(iaddr));
|
||||||
|
saddr.sin_port = htons(bindPort);
|
||||||
|
int tmp = 1;
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
||||||
|
(const char *) &tmp, sizeof(tmp));
|
||||||
|
if (bind(fd, (struct sockaddr *)
|
||||||
|
&saddr, sizeof(saddr)) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
/* Warn -- don't exit. */
|
||||||
|
syslog(LOG_ERR, "couldn't bind to "
|
||||||
|
"address %s port %d (%m)\n",
|
||||||
|
bindAddress, bindPort);
|
||||||
|
closesocket(fd);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bindProto == protoTcp) {
|
||||||
|
if (listen(fd, RINETD_LISTEN_BACKLOG) == SOCKET_ERROR) {
|
||||||
|
/* Warn -- don't exit. */
|
||||||
|
syslog(LOG_ERR, "couldn't listen to "
|
||||||
|
"address %s port %d (%m)\n",
|
||||||
|
bindAddress, bindPort);
|
||||||
|
closesocket(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSocketDefaults(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getAddress(connectAddress, &iaddr) < 0) {
|
||||||
|
/* Warn -- don't exit. */
|
||||||
|
syslog(LOG_ERR, "host %s could not be resolved.\n",
|
||||||
|
bindAddress);
|
||||||
|
closesocket(fd);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* Allocate server info */
|
||||||
|
seInfo = (ServerInfo *)
|
||||||
|
realloc(seInfo, sizeof(ServerInfo) * (seTotal + 1));
|
||||||
|
if (!seInfo) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ServerInfo *srv = &seInfo[seTotal];
|
||||||
|
memset(srv, 0, sizeof(*srv));
|
||||||
|
srv->fd = fd;
|
||||||
|
srv->localAddr = iaddr;
|
||||||
|
srv->localPort = htons(connectPort);
|
||||||
|
srv->fromHost = bindAddress;
|
||||||
|
if (!srv->fromHost) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
srv->fromPort = bindPort;
|
||||||
|
srv->fromProto = bindProto;
|
||||||
|
srv->toHost = connectAddress;
|
||||||
|
if (!srv->toHost) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
srv->toPort = connectPort;
|
||||||
|
srv->toProto = connectProto;
|
||||||
|
srv->serverTimeout = serverTimeout;
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (fd > maxfd) {
|
||||||
|
maxfd = fd;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
++seTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setConnectionCount(int newCount)
|
static void setConnectionCount(int newCount)
|
||||||
@ -333,7 +343,8 @@ static void setConnectionCount(int newCount)
|
|||||||
closesocket(coInfo[i].local.fd);
|
closesocket(coInfo[i].local.fd);
|
||||||
}
|
}
|
||||||
if (coInfo[i].remote.fd != INVALID_SOCKET) {
|
if (coInfo[i].remote.fd != INVALID_SOCKET) {
|
||||||
closesocket(coInfo[i].remote.fd);
|
if (coInfo[i].remote.proto == protoTcp)
|
||||||
|
closesocket(coInfo[i].remote.fd);
|
||||||
}
|
}
|
||||||
free(coInfo[i].local.buffer);
|
free(coInfo[i].local.buffer);
|
||||||
}
|
}
|
||||||
@ -396,8 +407,8 @@ static ConnectionInfo *findAvailableConnection(void)
|
|||||||
return &coInfo[oldTotal];
|
return &coInfo[oldTotal];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void selectPass(void) {
|
static void selectPass(void)
|
||||||
|
{
|
||||||
int const fdSetCount = maxfd / FD_SETSIZE + 1;
|
int const fdSetCount = maxfd / FD_SETSIZE + 1;
|
||||||
# define FD_ZERO_EXT(ar) for (int i = 0; i < fdSetCount; ++i) { FD_ZERO(&(ar)[i]); }
|
# define FD_ZERO_EXT(ar) for (int i = 0; i < fdSetCount; ++i) { FD_ZERO(&(ar)[i]); }
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -409,6 +420,11 @@ static void selectPass(void) {
|
|||||||
# define FD_ISSET_EXT(fd, ar) FD_ISSET((fd) % FD_SETSIZE, &(ar)[(fd) / FD_SETSIZE])
|
# define FD_ISSET_EXT(fd, ar) FD_ISSET((fd) % FD_SETSIZE, &(ar)[(fd) / FD_SETSIZE])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Timeout value -- infinite by default */
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = timeout.tv_usec = 0;
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
fd_set readfds[fdSetCount], writefds[fdSetCount];
|
fd_set readfds[fdSetCount], writefds[fdSetCount];
|
||||||
FD_ZERO_EXT(readfds);
|
FD_ZERO_EXT(readfds);
|
||||||
FD_ZERO_EXT(writefds);
|
FD_ZERO_EXT(writefds);
|
||||||
@ -437,6 +453,13 @@ static void selectPass(void) {
|
|||||||
/* Get more input if we have room for it */
|
/* Get more input if we have room for it */
|
||||||
if (cnx->remote.recvPos < RINETD_BUFFER_SIZE) {
|
if (cnx->remote.recvPos < RINETD_BUFFER_SIZE) {
|
||||||
FD_SET_EXT(cnx->remote.fd, readfds);
|
FD_SET_EXT(cnx->remote.fd, readfds);
|
||||||
|
/* For UDP connections, we need to handle timeouts */
|
||||||
|
if (cnx->remote.proto == protoUdp) {
|
||||||
|
long delay = (long)(cnx->remoteTimeout - now);
|
||||||
|
timeout.tv_sec = delay <= 1 ? 1
|
||||||
|
: (delay < timeout.tv_sec || timeout.tv_sec == 0) ? delay
|
||||||
|
: timeout.tv_sec;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Send more output if we have any, or if we’re closing */
|
/* Send more output if we have any, or if we’re closing */
|
||||||
if (cnx->remote.sentPos < cnx->local.recvPos || cnx->coClosing) {
|
if (cnx->remote.sentPos < cnx->local.recvPos || cnx->coClosing) {
|
||||||
@ -444,12 +467,21 @@ static void selectPass(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
select(maxfd + 1, readfds, writefds, 0, 0);
|
|
||||||
|
select(maxfd + 1, readfds, writefds, 0, timeout.tv_sec ? &timeout : NULL);
|
||||||
for (int i = 0; i < coTotal; ++i) {
|
for (int i = 0; i < coTotal; ++i) {
|
||||||
ConnectionInfo *cnx = &coInfo[i];
|
ConnectionInfo *cnx = &coInfo[i];
|
||||||
if (cnx->remote.fd != INVALID_SOCKET) {
|
if (cnx->remote.fd != INVALID_SOCKET) {
|
||||||
if (FD_ISSET_EXT(cnx->remote.fd, readfds)) {
|
/* Do not read on remote UDP sockets, the server does it,
|
||||||
handleRead(cnx, &cnx->remote, &cnx->local);
|
but handle timeouts instead. */
|
||||||
|
if (cnx->remote.proto == protoTcp) {
|
||||||
|
if (FD_ISSET_EXT(cnx->remote.fd, readfds)) {
|
||||||
|
handleRead(cnx, &cnx->remote, &cnx->local);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (now > cnx->remoteTimeout) {
|
||||||
|
handleClose(cnx, &cnx->remote, &cnx->local);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cnx->remote.fd != INVALID_SOCKET) {
|
if (cnx->remote.fd != INVALID_SOCKET) {
|
||||||
@ -508,12 +540,22 @@ static void handleWrite(ConnectionInfo *cnx, Socket *socket, Socket *other_socke
|
|||||||
if (cnx->coClosing && (socket->sentPos == other_socket->recvPos)) {
|
if (cnx->coClosing && (socket->sentPos == other_socket->recvPos)) {
|
||||||
PERROR("rinetd: local closed and no more output");
|
PERROR("rinetd: local closed and no more output");
|
||||||
logEvent(cnx, cnx->server, cnx->coLog);
|
logEvent(cnx, cnx->server, cnx->coLog);
|
||||||
closesocket(socket->fd);
|
if (socket->proto == protoTcp)
|
||||||
|
closesocket(socket->fd);
|
||||||
socket->fd = INVALID_SOCKET;
|
socket->fd = INVALID_SOCKET;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int got = send(socket->fd, other_socket->buffer + socket->sentPos,
|
|
||||||
other_socket->recvPos - socket->sentPos, 0);
|
struct sockaddr const *addr = NULL;
|
||||||
|
SOCKLEN_T addrlen = 0;
|
||||||
|
if (socket->proto == protoUdp && socket == &cnx->remote) {
|
||||||
|
addr = (struct sockaddr const*)&cnx->remoteAddress;
|
||||||
|
addrlen = (SOCKLEN_T)sizeof(cnx->remoteAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
int got = sendto(socket->fd, other_socket->buffer + socket->sentPos,
|
||||||
|
other_socket->recvPos - socket->sentPos, 0,
|
||||||
|
addr, addrlen);
|
||||||
if (got < 0) {
|
if (got < 0) {
|
||||||
if (GetLastError() == WSAEWOULDBLOCK) {
|
if (GetLastError() == WSAEWOULDBLOCK) {
|
||||||
return;
|
return;
|
||||||
@ -534,12 +576,15 @@ static void handleWrite(ConnectionInfo *cnx, Socket *socket, Socket *other_socke
|
|||||||
static void handleClose(ConnectionInfo *cnx, Socket *socket, Socket *other_socket)
|
static void handleClose(ConnectionInfo *cnx, Socket *socket, Socket *other_socket)
|
||||||
{
|
{
|
||||||
cnx->coClosing = 1;
|
cnx->coClosing = 1;
|
||||||
/* One end fizzled out, so make sure we're all done with that */
|
if (socket->proto == protoTcp) {
|
||||||
closesocket(socket->fd);
|
/* One end fizzled out, so make sure we're all done with that */
|
||||||
|
closesocket(socket->fd);
|
||||||
|
} else /* if (socket->proto == protoUdp) */ {
|
||||||
|
/* Nothing to do in UDP mode */
|
||||||
|
}
|
||||||
socket->fd = INVALID_SOCKET;
|
socket->fd = INVALID_SOCKET;
|
||||||
if (other_socket->fd != INVALID_SOCKET) {
|
if (other_socket->fd != INVALID_SOCKET) {
|
||||||
#ifndef __linux__
|
#if !defined __linux__ && !defined _WIN32
|
||||||
#ifndef _WIN32
|
|
||||||
/* Now set up the other end for a polite closing */
|
/* Now set up the other end for a polite closing */
|
||||||
|
|
||||||
/* Request a low-water mark equal to the entire
|
/* Request a low-water mark equal to the entire
|
||||||
@ -548,8 +593,7 @@ static void handleClose(ConnectionInfo *cnx, Socket *socket, Socket *other_socke
|
|||||||
int arg = 1024;
|
int arg = 1024;
|
||||||
setsockopt(other_socket->fd, SOL_SOCKET, SO_SNDLOWAT,
|
setsockopt(other_socket->fd, SOL_SOCKET, SO_SNDLOWAT,
|
||||||
&arg, sizeof(arg));
|
&arg, sizeof(arg));
|
||||||
#endif /* _WIN32 */
|
#endif
|
||||||
#endif /* __linux__ */
|
|
||||||
cnx->coLog = socket == &cnx->local ?
|
cnx->coLog = socket == &cnx->local ?
|
||||||
logLocalClosedFirst : logRemoteClosedFirst;
|
logLocalClosedFirst : logRemoteClosedFirst;
|
||||||
}
|
}
|
||||||
@ -557,112 +601,96 @@ static void handleClose(ConnectionInfo *cnx, Socket *socket, Socket *other_socke
|
|||||||
|
|
||||||
static void handleAccept(ServerInfo const *srv)
|
static void handleAccept(ServerInfo const *srv)
|
||||||
{
|
{
|
||||||
|
struct sockaddr addr;
|
||||||
|
SOCKLEN_T addrlen = sizeof(addr);
|
||||||
|
|
||||||
|
SOCKET nfd;
|
||||||
|
if (srv->fromProto == protoTcp) {
|
||||||
|
/* In TCP mode, get remote address using accept(). */
|
||||||
|
nfd = accept(srv->fd, &addr, &addrlen);
|
||||||
|
if (nfd == INVALID_SOCKET) {
|
||||||
|
syslog(LOG_ERR, "accept(%d): %m\n", srv->fd);
|
||||||
|
logEvent(NULL, srv, logAcceptFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSocketDefaults(nfd);
|
||||||
|
} else /* if (srv->fromProto == protoUdp) */ {
|
||||||
|
/* In UDP mode, get remote address using recvfrom() and check
|
||||||
|
for an existing connection from this client. */
|
||||||
|
nfd = srv->fd;
|
||||||
|
ssize_t ret = recvfrom(srv->fd, NULL, 0, MSG_PEEK,
|
||||||
|
&addr, &addrlen);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (GetLastError() == WSAEWOULDBLOCK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (GetLastError() == WSAEINPROGRESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
syslog(LOG_ERR, "recvfrom(%d): %m\n", srv->fd);
|
||||||
|
logEvent(NULL, srv, logAcceptFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < coTotal; ++i) {
|
||||||
|
ConnectionInfo *cnx = &coInfo[i];
|
||||||
|
struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
|
||||||
|
if (cnx->remote.fd == nfd
|
||||||
|
&& cnx->remoteAddress.sin_family == addr_in->sin_family
|
||||||
|
&& cnx->remoteAddress.sin_port == addr_in->sin_port
|
||||||
|
&& cnx->remoteAddress.sin_addr.s_addr == addr_in->sin_addr.s_addr) {
|
||||||
|
cnx->remoteTimeout = time(NULL) + srv->serverTimeout;
|
||||||
|
handleRead(cnx, &cnx->remote, &cnx->local);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConnectionInfo *cnx = findAvailableConnection();
|
ConnectionInfo *cnx = findAvailableConnection();
|
||||||
if (!cnx) {
|
if (!cnx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr addr;
|
|
||||||
struct in_addr address;
|
|
||||||
#if HAVE_SOCKLEN_T
|
|
||||||
socklen_t addrlen;
|
|
||||||
#else
|
|
||||||
int addrlen;
|
|
||||||
#endif
|
|
||||||
addrlen = sizeof(addr);
|
|
||||||
SOCKET nfd = accept(srv->fd, &addr, &addrlen);
|
|
||||||
if (nfd == INVALID_SOCKET) {
|
|
||||||
syslog(LOG_ERR, "accept(%d): %m", srv->fd);
|
|
||||||
logEvent(NULL, srv, logAcceptFailed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
u_long ioctltmp;
|
|
||||||
#else
|
|
||||||
int ioctltmp;
|
|
||||||
#endif
|
|
||||||
ioctlsocket(nfd, FIONBIO, &ioctltmp);
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
int tmp = 0;
|
|
||||||
setsockopt(nfd, SOL_SOCKET, SO_LINGER, &tmp, sizeof(tmp));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cnx->local.fd = INVALID_SOCKET;
|
cnx->local.fd = INVALID_SOCKET;
|
||||||
|
cnx->local.proto = srv->toProto;
|
||||||
cnx->local.recvPos = cnx->local.sentPos = 0;
|
cnx->local.recvPos = cnx->local.sentPos = 0;
|
||||||
cnx->local.recvBytes = cnx->local.sentBytes = 0;
|
cnx->local.recvBytes = cnx->local.sentBytes = 0;
|
||||||
|
|
||||||
cnx->remote.fd = nfd;
|
cnx->remote.fd = nfd;
|
||||||
|
cnx->remote.proto = srv->fromProto;
|
||||||
cnx->remote.recvPos = cnx->remote.sentPos = 0;
|
cnx->remote.recvPos = cnx->remote.sentPos = 0;
|
||||||
cnx->remote.recvBytes = cnx->remote.sentBytes = 0;
|
cnx->remote.recvBytes = cnx->remote.sentBytes = 0;
|
||||||
|
cnx->remoteAddress = *(struct sockaddr_in *)&addr;
|
||||||
|
if (srv->fromProto == protoUdp)
|
||||||
|
cnx->remoteTimeout = time(NULL) + srv->serverTimeout;
|
||||||
|
|
||||||
cnx->coClosing = 0;
|
cnx->coClosing = 0;
|
||||||
cnx->coLog = logUnknownError;
|
cnx->coLog = logUnknownError;
|
||||||
cnx->server = srv;
|
cnx->server = srv;
|
||||||
|
|
||||||
struct sockaddr_in *sin = (struct sockaddr_in *) &addr;
|
int logCode = checkConnectionAllowed(cnx);
|
||||||
cnx->reAddresses.s_addr = address.s_addr = sin->sin_addr.s_addr;
|
if (logCode != logAllowed) {
|
||||||
char const *addressText = inet_ntoa(address);
|
/* Local fd is not open yet, so only
|
||||||
|
close the remote socket. */
|
||||||
|
if (cnx->remote.proto == protoTcp)
|
||||||
|
closesocket(cnx->remote.fd);
|
||||||
|
cnx->remote.fd = INVALID_SOCKET;
|
||||||
|
logEvent(cnx, cnx->server, logCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* 1. Check global allow rules. If there are no
|
|
||||||
global allow rules, it's presumed OK at
|
|
||||||
this step. If there are any, and it doesn't
|
|
||||||
match at least one, kick it out. */
|
|
||||||
int good = 1;
|
|
||||||
for (int j = 0; j < globalRulesCount; ++j) {
|
|
||||||
if (allRules[j].type == allowRule) {
|
|
||||||
good = 0;
|
|
||||||
if (match(addressText, allRules[j].pattern)) {
|
|
||||||
good = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!good) {
|
|
||||||
refuse(cnx, logNotAllowed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* 2. Check global deny rules. If it matches
|
|
||||||
any of the global deny rules, kick it out. */
|
|
||||||
for (int j = 0; j < globalRulesCount; ++j) {
|
|
||||||
if (allRules[j].type == denyRule
|
|
||||||
&& match(addressText, allRules[j].pattern)) {
|
|
||||||
refuse(cnx, logDenied);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 3. Check allow rules specific to this forwarding rule.
|
|
||||||
If there are none, it's OK. If there are any,
|
|
||||||
it must match at least one. */
|
|
||||||
good = 1;
|
|
||||||
for (int j = 0; j < srv->rulesCount; ++j) {
|
|
||||||
if (allRules[srv->rulesStart + j].type == allowRule) {
|
|
||||||
good = 0;
|
|
||||||
if (match(addressText,
|
|
||||||
allRules[srv->rulesStart + j].pattern)) {
|
|
||||||
good = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!good) {
|
|
||||||
refuse(cnx, logNotAllowed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* 4. Check deny rules specific to this forwarding rule. If
|
|
||||||
it matches any of the deny rules, kick it out. */
|
|
||||||
for (int j = 0; j < srv->rulesCount; ++j) {
|
|
||||||
if (allRules[srv->rulesStart + j].type == denyRule
|
|
||||||
&& match(addressText, allRules[srv->rulesStart + j].pattern)) {
|
|
||||||
refuse(cnx, logDenied);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Now open a connection to the local server.
|
/* Now open a connection to the local server.
|
||||||
This, too, is nonblocking. Why wait
|
This, too, is nonblocking. Why wait
|
||||||
for anything when you don't have to? */
|
for anything when you don't have to? */
|
||||||
struct sockaddr_in saddr;
|
struct sockaddr_in saddr;
|
||||||
cnx->local.fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
cnx->local.fd = srv->toProto == protoTcp
|
||||||
|
? socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
|
||||||
|
: socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if (cnx->local.fd == INVALID_SOCKET) {
|
if (cnx->local.fd == INVALID_SOCKET) {
|
||||||
syslog(LOG_ERR, "socket(): %m");
|
syslog(LOG_ERR, "socket(): %m\n");
|
||||||
closesocket(cnx->remote.fd);
|
if (cnx->remote.proto == protoTcp)
|
||||||
|
closesocket(cnx->remote.fd);
|
||||||
cnx->remote.fd = INVALID_SOCKET;
|
cnx->remote.fd = INVALID_SOCKET;
|
||||||
logEvent(cnx, srv, logLocalSocketFailed);
|
logEvent(cnx, srv, logLocalSocketFailed);
|
||||||
return;
|
return;
|
||||||
@ -675,7 +703,8 @@ static void handleAccept(ServerInfo const *srv)
|
|||||||
saddr.sin_addr.s_addr = 0;
|
saddr.sin_addr.s_addr = 0;
|
||||||
if (bind(cnx->local.fd, (struct sockaddr *) &saddr, sizeof(saddr)) == SOCKET_ERROR) {
|
if (bind(cnx->local.fd, (struct sockaddr *) &saddr, sizeof(saddr)) == SOCKET_ERROR) {
|
||||||
closesocket(cnx->local.fd);
|
closesocket(cnx->local.fd);
|
||||||
closesocket(cnx->remote.fd);
|
if (cnx->remote.proto == protoTcp)
|
||||||
|
closesocket(cnx->remote.fd);
|
||||||
cnx->remote.fd = INVALID_SOCKET;
|
cnx->remote.fd = INVALID_SOCKET;
|
||||||
cnx->local.fd = INVALID_SOCKET;
|
cnx->local.fd = INVALID_SOCKET;
|
||||||
logEvent(cnx, srv, logLocalBindFailed);
|
logEvent(cnx, srv, logLocalBindFailed);
|
||||||
@ -688,18 +717,8 @@ static void handleAccept(ServerInfo const *srv)
|
|||||||
memcpy(&saddr.sin_addr, &srv->localAddr, sizeof(struct in_addr));
|
memcpy(&saddr.sin_addr, &srv->localAddr, sizeof(struct in_addr));
|
||||||
saddr.sin_port = srv->localPort;
|
saddr.sin_port = srv->localPort;
|
||||||
|
|
||||||
#ifndef _WIN32
|
if (srv->toProto == protoTcp)
|
||||||
#ifdef __linux__
|
setSocketDefaults(cnx->local.fd);
|
||||||
tmp = 0;
|
|
||||||
setsockopt(cnx->local.fd, SOL_SOCKET, SO_LINGER, &tmp, sizeof(tmp));
|
|
||||||
#else
|
|
||||||
tmp = 1024;
|
|
||||||
setsockopt(cnx->local.fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp));
|
|
||||||
#endif /* __linux__ */
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
ioctltmp = 1;
|
|
||||||
ioctlsocket(cnx->local.fd, FIONBIO, &ioctltmp);
|
|
||||||
|
|
||||||
if (connect(cnx->local.fd, (struct sockaddr *)&saddr,
|
if (connect(cnx->local.fd, (struct sockaddr *)&saddr,
|
||||||
sizeof(struct sockaddr_in)) == SOCKET_ERROR)
|
sizeof(struct sockaddr_in)) == SOCKET_ERROR)
|
||||||
@ -709,7 +728,8 @@ static void handleAccept(ServerInfo const *srv)
|
|||||||
{
|
{
|
||||||
PERROR("rinetd: connect");
|
PERROR("rinetd: connect");
|
||||||
closesocket(cnx->local.fd);
|
closesocket(cnx->local.fd);
|
||||||
closesocket(cnx->remote.fd);
|
if (cnx->remote.proto == protoTcp)
|
||||||
|
closesocket(cnx->remote.fd);
|
||||||
cnx->remote.fd = INVALID_SOCKET;
|
cnx->remote.fd = INVALID_SOCKET;
|
||||||
cnx->local.fd = INVALID_SOCKET;
|
cnx->local.fd = INVALID_SOCKET;
|
||||||
logEvent(cnx, srv, logLocalConnectFailed);
|
logEvent(cnx, srv, logLocalConnectFailed);
|
||||||
@ -729,13 +749,63 @@ static void handleAccept(ServerInfo const *srv)
|
|||||||
logEvent(cnx, srv, logOpened);
|
logEvent(cnx, srv, logOpened);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refuse(ConnectionInfo *cnx, int logCode)
|
static int checkConnectionAllowed(ConnectionInfo const *cnx)
|
||||||
{
|
{
|
||||||
/* Local fd is not open yet when we refuse(), so only
|
ServerInfo const *srv = cnx->server;
|
||||||
close the remote socket. */
|
char const *addressText = inet_ntoa(cnx->remoteAddress.sin_addr);
|
||||||
closesocket(cnx->remote.fd);
|
|
||||||
cnx->remote.fd = INVALID_SOCKET;
|
/* 1. Check global allow rules. If there are no
|
||||||
logEvent(cnx, cnx->server, logCode);
|
global allow rules, it's presumed OK at
|
||||||
|
this step. If there are any, and it doesn't
|
||||||
|
match at least one, kick it out. */
|
||||||
|
int good = 1;
|
||||||
|
for (int j = 0; j < globalRulesCount; ++j) {
|
||||||
|
if (allRules[j].type == allowRule) {
|
||||||
|
good = 0;
|
||||||
|
if (match(addressText, allRules[j].pattern)) {
|
||||||
|
good = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!good) {
|
||||||
|
return logNotAllowed;
|
||||||
|
}
|
||||||
|
/* 2. Check global deny rules. If it matches
|
||||||
|
any of the global deny rules, kick it out. */
|
||||||
|
for (int j = 0; j < globalRulesCount; ++j) {
|
||||||
|
if (allRules[j].type == denyRule
|
||||||
|
&& match(addressText, allRules[j].pattern)) {
|
||||||
|
return logDenied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 3. Check allow rules specific to this forwarding rule.
|
||||||
|
If there are none, it's OK. If there are any,
|
||||||
|
it must match at least one. */
|
||||||
|
good = 1;
|
||||||
|
for (int j = 0; j < srv->rulesCount; ++j) {
|
||||||
|
if (allRules[srv->rulesStart + j].type == allowRule) {
|
||||||
|
good = 0;
|
||||||
|
if (match(addressText,
|
||||||
|
allRules[srv->rulesStart + j].pattern)) {
|
||||||
|
good = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!good) {
|
||||||
|
return logNotAllowed;
|
||||||
|
}
|
||||||
|
/* 4. Check deny rules specific to this forwarding rule. If
|
||||||
|
it matches any of the deny rules, kick it out. */
|
||||||
|
for (int j = 0; j < srv->rulesCount; ++j) {
|
||||||
|
if (allRules[srv->rulesStart + j].type == denyRule
|
||||||
|
&& match(addressText, allRules[srv->rulesStart + j].pattern)) {
|
||||||
|
return logDenied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getAddress(char const *host, struct in_addr *iaddr)
|
static int getAddress(char const *host, struct in_addr *iaddr)
|
||||||
@ -784,7 +854,7 @@ static int getAddress(char const *host, struct in_addr *iaddr)
|
|||||||
msg = "A temporary error occurred on an authoritative name server. Try again later.";
|
msg = "A temporary error occurred on an authoritative name server. Try again later.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
syslog(LOG_ERR, "While resolving `%s' got: %s", host, msg);
|
syslog(LOG_ERR, "While resolving `%s' got: %s\n", host, msg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,7 +870,7 @@ RETSIGTYPE plumber(int s)
|
|||||||
RETSIGTYPE hup(int s)
|
RETSIGTYPE hup(int s)
|
||||||
{
|
{
|
||||||
(void)s;
|
(void)s;
|
||||||
syslog(LOG_INFO, "Received SIGHUP, reloading configuration...");
|
syslog(LOG_INFO, "Received SIGHUP, reloading configuration...\n");
|
||||||
/* Learn the new rules */
|
/* Learn the new rules */
|
||||||
clearConfiguration();
|
clearConfiguration();
|
||||||
readConfiguration(options.conf_file);
|
readConfiguration(options.conf_file);
|
||||||
@ -866,8 +936,7 @@ static void logEvent(ConnectionInfo const *cnx, ServerInfo const *srv, int resul
|
|||||||
int bytesOutput = 0;
|
int bytesOutput = 0;
|
||||||
int bytesInput = 0;
|
int bytesInput = 0;
|
||||||
if (cnx != NULL) {
|
if (cnx != NULL) {
|
||||||
struct in_addr const *reAddress = &cnx->reAddresses;
|
addressText = inet_ntoa(cnx->remoteAddress.sin_addr);
|
||||||
addressText = inet_ntoa(*reAddress);
|
|
||||||
bytesOutput = cnx->remote.sentBytes;
|
bytesOutput = cnx->remote.sentBytes;
|
||||||
bytesInput = cnx->remote.recvBytes;
|
bytesInput = cnx->remote.recvBytes;
|
||||||
}
|
}
|
||||||
@ -884,7 +953,7 @@ static void logEvent(ConnectionInfo const *cnx, ServerInfo const *srv, int resul
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result==logNotAllowed || result==logDenied)
|
if (result==logNotAllowed || result==logDenied)
|
||||||
syslog(LOG_INFO, "%s %s"
|
syslog(LOG_INFO, "%s %s\n"
|
||||||
, addressText
|
, addressText
|
||||||
, logMessages[result]);
|
, logMessages[result]);
|
||||||
if (logFile) {
|
if (logFile) {
|
||||||
|
@ -16,8 +16,10 @@
|
|||||||
# to apply to only that forwarding rule
|
# to apply to only that forwarding rule
|
||||||
#
|
#
|
||||||
# bindadress bindport connectaddress connectport
|
# bindadress bindport connectaddress connectport
|
||||||
127.0.0.1 4000 127.0.0.1 22
|
#127.0.0.1 4000 127.0.0.1 3000
|
||||||
#127.0.0.1 4000/udp 127.0.0.1 22
|
#127.0.0.1 4000/udp 127.0.0.1 22
|
||||||
|
127.0.0.1 4000 127.0.0.1 3000/udp
|
||||||
|
127.0.0.1 3000/udp 127.0.0.1 22
|
||||||
|
|
||||||
# logging information
|
# logging information
|
||||||
logfile /var/log/rinetd.log
|
logfile /var/log/rinetd.log
|
||||||
|
91
rinetd.h
91
rinetd.h
@ -1,69 +1,50 @@
|
|||||||
|
/* Copyright © 1997—1999 Thomas Boutell <boutell@boutell.com>
|
||||||
|
and Boutell.Com, Inc.
|
||||||
|
© 2003—2017 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
This software is released for free use under the terms of
|
||||||
|
the GNU Public License, version 2 or higher. NO WARRANTY
|
||||||
|
IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* Syslog feature */
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
# include <stdio.h>
|
||||||
|
# define syslog fprintf
|
||||||
|
# define LOG_ERR stderr
|
||||||
|
# define LOG_INFO stdout
|
||||||
|
#else
|
||||||
|
# include <syslog.h>
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
|
|
||||||
static int const RINETD_BUFFER_SIZE = 16384;
|
static int const RINETD_BUFFER_SIZE = 16384;
|
||||||
static int const RINETD_LISTEN_BACKLOG = 128;
|
static int const RINETD_LISTEN_BACKLOG = 128;
|
||||||
|
static int const RINETD_DEFAULT_UDP_TIMEOUT = 72;
|
||||||
|
|
||||||
#define RINETD_CONFIG_FILE "/etc/rinetd.conf"
|
#define RINETD_CONFIG_FILE "/etc/rinetd.conf"
|
||||||
#define RINETD_PID_FILE "/var/run/rinetd.pid"
|
#define RINETD_PID_FILE "/var/run/rinetd.pid"
|
||||||
|
|
||||||
/* Program state */
|
/* Global configuration */
|
||||||
|
|
||||||
enum ruleType {
|
extern Rule *allRules;
|
||||||
allowRule,
|
extern int allRulesCount;
|
||||||
denyRule,
|
extern int globalRulesCount;
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _rule Rule;
|
extern ServerInfo *seInfo;
|
||||||
struct _rule
|
extern int seTotal;
|
||||||
{
|
|
||||||
char *pattern;
|
|
||||||
int type;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _server_info ServerInfo;
|
extern char *logFileName;
|
||||||
struct _server_info {
|
extern char *pidLogFileName;
|
||||||
SOCKET fd;
|
extern int logFormatCommon;
|
||||||
|
extern FILE *logFile;
|
||||||
|
|
||||||
/* In network order, for network purposes */
|
/* Functions */
|
||||||
struct in_addr localAddr;
|
|
||||||
unsigned short localPort;
|
|
||||||
|
|
||||||
/* In ASCII and local byte order, for logging purposes */
|
void addServer(char *bindAddress, int bindPort, int bindProto,
|
||||||
char *fromHost, *toHost;
|
char *connectAddress, int connectPort, int connectProto,
|
||||||
int fromPort, toPort;
|
int serverTimeout);
|
||||||
|
|
||||||
/* Offset and count into list of allow and deny rules. Any rules
|
|
||||||
prior to globalAllowRules and globalDenyRules are global rules. */
|
|
||||||
int rulesStart, rulesCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _socket Socket;
|
|
||||||
struct _socket
|
|
||||||
{
|
|
||||||
SOCKET fd;
|
|
||||||
/* recv: received on this socket
|
|
||||||
sent: sent to this socket from the other buffer */
|
|
||||||
int recvPos, sentPos;
|
|
||||||
int recvBytes, sentBytes;
|
|
||||||
char *buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _connection_info ConnectionInfo;
|
|
||||||
struct _connection_info
|
|
||||||
{
|
|
||||||
Socket remote, local;
|
|
||||||
struct in_addr reAddresses;
|
|
||||||
int coClosing;
|
|
||||||
int coLog;
|
|
||||||
ServerInfo const *server; // only useful for logEvent
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Option parsing */
|
|
||||||
|
|
||||||
typedef struct _rinetd_options RinetdOptions;
|
|
||||||
struct _rinetd_options
|
|
||||||
{
|
|
||||||
char const *conf_file;
|
|
||||||
int foreground;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
81
types.h
Normal file
81
types.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/* Copyright © 1997—1999 Thomas Boutell <boutell@boutell.com>
|
||||||
|
and Boutell.Com, Inc.
|
||||||
|
© 2003—2017 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
This software is released for free use under the terms of
|
||||||
|
the GNU Public License, version 2 or higher. NO WARRANTY
|
||||||
|
IS EXPRESSED OR IMPLIED. USE THIS SOFTWARE AT YOUR OWN RISK. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
enum ruleType {
|
||||||
|
allowRule,
|
||||||
|
denyRule,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum protocolType {
|
||||||
|
protoTcp = 1,
|
||||||
|
protoUdp = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _rule Rule;
|
||||||
|
struct _rule
|
||||||
|
{
|
||||||
|
char *pattern;
|
||||||
|
int type;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _server_info ServerInfo;
|
||||||
|
struct _server_info {
|
||||||
|
SOCKET fd;
|
||||||
|
|
||||||
|
/* In network order, for network purposes */
|
||||||
|
struct in_addr localAddr;
|
||||||
|
unsigned short localPort;
|
||||||
|
|
||||||
|
/* In ASCII and local byte order, for logging purposes */
|
||||||
|
char *fromHost, *toHost;
|
||||||
|
int fromPort, fromProto, toPort, toProto;
|
||||||
|
|
||||||
|
/* Offset and count into list of allow and deny rules. Any rules
|
||||||
|
prior to globalAllowRules and globalDenyRules are global rules. */
|
||||||
|
int rulesStart, rulesCount;
|
||||||
|
/* Timeout for UDP traffic before we consider the connection
|
||||||
|
was dropped by the remote host. */
|
||||||
|
int serverTimeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _socket Socket;
|
||||||
|
struct _socket
|
||||||
|
{
|
||||||
|
SOCKET fd;
|
||||||
|
int proto;
|
||||||
|
/* recv: received on this socket
|
||||||
|
sent: sent to this socket from the other buffer */
|
||||||
|
int recvPos, sentPos;
|
||||||
|
int recvBytes, sentBytes;
|
||||||
|
char *buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _connection_info ConnectionInfo;
|
||||||
|
struct _connection_info
|
||||||
|
{
|
||||||
|
Socket remote, local;
|
||||||
|
struct sockaddr_in remoteAddress;
|
||||||
|
time_t remoteTimeout;
|
||||||
|
int coClosing;
|
||||||
|
int coLog;
|
||||||
|
ServerInfo const *server; // only useful for logEvent
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Option parsing */
|
||||||
|
|
||||||
|
typedef struct _rinetd_options RinetdOptions;
|
||||||
|
struct _rinetd_options
|
||||||
|
{
|
||||||
|
char const *conf_file;
|
||||||
|
int foreground;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user