10 Commits
v0.71 ... main

Author SHA1 Message Date
Sam Hocevar
d4e0a60119 Fix a parsing bug in the rules that would ignore the very first rule. See #23. 2021-03-02 15:25:39 +01:00
Sam Hocevar
af88e6fd4f Release version 0.73. 2021-02-19 09:56:52 +01:00
Sam Hocevar
ff41723590 Improve error reporting. Fixes #15.
- Add an error message when the configuration file could not be found.
 - Log to stderr when running in the foreground.
2021-02-19 09:12:29 +01:00
Sam Hocevar
d3dd35327f Do not log to syslog when running in the foreground. Addresses #15. 2021-02-19 08:55:45 +01:00
Sam Hocevar
49bf544bad Fix another IPv6 parsing issue. Addresses #20. 2021-02-17 14:15:54 +01:00
Sam Hocevar
1060048fe8 Refactor getaddrinfo error reporting. 2021-02-17 08:21:58 +01:00
Sam Hocevar
e3b47d086a Fix some hostnames (e.g. 123.example.com) being wrongfully parsed as IPv6. 2021-02-17 08:17:03 +01:00
Sam Hocevar
f91e34c3af Release version 0.72. 2021-02-16 09:27:25 +01:00
Sam Hocevar
5e8be95d8a Fix a configuration parsing bug. 2021-02-16 09:22:25 +01:00
Sam Hocevar
7887c17096 Fix Mac OS X build. 2021-02-14 14:41:15 +01:00
11 changed files with 436 additions and 380 deletions

View File

@@ -1,20 +1,29 @@
## Version 0.71
## Version 0.73 (2021/02/19)
* improve error reporting
* fixed another configuration parsing bug
## Version 0.72 (2021/02/16)
* fixed a configuration parsing bug making 0.71 almost unusable
## Version 0.71 (2021/02/14)
* IPv6 support
* fix a display overflow in data usage statistics
* fixed a display overflow in data usage statistics
* made the configuration parser more tolerant with service names that contain
dashes (e.g. snmp-trap) or hostnames with underscores (e.g. \_http.example.com).
* create the log file if it does not exist
* new Visual Studio project file
## Version 0.70
## Version 0.70 (2017/09/09)
* UDP support
* source address binding support
* use a real grammar for the configuration file and get rid of the hand-made
parser
## Version 0.63
## Version 0.63 (2017/07/19)
* added a `-f` flag to run in the foreground
* quit cleanly when `SIGINT` is received

View File

@@ -1,6 +1,6 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.52)
AC_INIT(rinetd, 0.71, sam@hocevar.net)
AC_INIT(rinetd, 0.73, sam@hocevar.net)
AC_CONFIG_AUX_DIR(.auto)
AC_CONFIG_SRCDIR([src/rinetd.c])
AC_CONFIG_HEADER([src/config.h])

View File

@@ -1,4 +1,4 @@
.TH rinetd 8 "2021-02-14" "rinetd 0.71"
.TH rinetd 8 "2021-02-19" "rinetd 0.73"
.SH NAME
rinetd \- internet redirection server

View File

@@ -78,7 +78,7 @@
<SDLCheck>true</SDLCheck>
<CompileAs>CompileAsC</CompileAs>
<ConformanceMode>true</ConformanceMode>
<PreprocessorDefinitions>_CONSOLE;PACKAGE_VERSION="0.71";_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CONSOLE;PACKAGE_VERSION="0.73";_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@@ -15,9 +15,10 @@ parse.c: parse.peg
if which leg >/dev/null 2>&1; then leg -o $@ $^; else touch $@; fi
# _POSIX_C_SOURCE is for SA_RESTART and others
# _DARWIN_C_SOURCE is for NI_MAXHOST on OS X
# _XOPEN_SOURCE is for struct sigaction
# _GNU_SOURCE is for h_errno and gethostbyname-related macros
___rinetd_CFLAGS = -std=c99 \
-D_XOPEN_SOURCE -D_GNU_SOURCE -D_POSIX_C_SOURCE=200809L \
___rinetd_CFLAGS = -std=c99 -D_POSIX_C_SOURCE=200809L \
-D_XOPEN_SOURCE -D_GNU_SOURCE -D_DARWIN_C_SOURCE \
-Wall -Wextra -Wwrite-strings

View File

@@ -10,6 +10,7 @@
# include <config.h>
#endif
#include <stdio.h>
#include "net.h"
void setSocketDefaults(SOCKET fd) {
@@ -32,13 +33,23 @@ void setSocketDefaults(SOCKET fd) {
#endif
}
struct addrinfo getAddrInfoHint(int protocol) {
return (struct addrinfo) {
int getAddrInfoWithProto(char *address, char *port, int protocol, struct addrinfo **ai)
{
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_protocol = protocol,
.ai_socktype = protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM,
.ai_flags = AI_PASSIVE,
};
int ret = getaddrinfo(address, port, &hints, ai);
if (ret != 0) {
fprintf(stderr, "rinetd: cannot resolve host \"%s\" port %s "
"(getaddrinfo() error: %s)\n",
address, port ? port : "<null>", gai_strerror(ret));
}
return ret;
}
int sameSocketAddress(struct sockaddr_storage *a, struct sockaddr_storage *b) {

View File

@@ -85,6 +85,6 @@ static inline int GetLastError(void) {
#endif /* _WIN32 */
void setSocketDefaults(SOCKET fd);
struct addrinfo getAddrInfoHint(int protocol);
int sameSocketAddress(struct sockaddr_storage *a, struct sockaddr_storage *b);
int getAddrInfoWithProto(char *address, char *port, int protocol, struct addrinfo **ai);
uint16_t getPort(struct addrinfo* ai);

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,10 @@
result = (EOF == yyc) ? 0 : (*(buf) = yyc, 1); \
}
#define PARSE_ERROR exit(1);
#define MEMORY_ERROR { \
logError("could not allocate memory when parsing configuration.\n"); \
exit(1); \
}
#if defined __clang__
#pragma clang diagnostic ignored "-Wunused-parameter"
@@ -53,7 +57,13 @@ server-rule = bind-address - bind-port - connect-address - connect-port (-? se
yy->connectAddress, yy->connectPort, yy->connectProto,
yy->serverTimeout > 0 ? yy->serverTimeout : RINETD_DEFAULT_UDP_TIMEOUT,
yy->sourceAddress);
free(yy->bindAddress);
free(yy->connectAddress);
free(yy->sourceAddress);
yy->bindAddress = yy->connectAddress = yy->sourceAddress = NULL;
free(yy->bindPort);
free(yy->connectPort);
yy->bindPort = yy->connectPort = NULL;
yy->serverTimeout = 0;
}
@@ -66,13 +76,11 @@ server-options = "[" -? option-list -? "]"
option-list = option (-? ',' -? option-list)?
option = (option-timeout | option-source)
option-timeout = "timeout" -? "=" -? < number > { yy->serverTimeout = atoi(yytext); }
option-source = "src" -? "=" -? < address > { free(yy->sourceAddress);
yy->sourceAddress = strdup(yytext); }
option-source = "src" -? "=" -? < address > { yy->sourceAddress = strdup(yytext); }
full-port = port proto
port = < (number | service) > { free(yy->tmpPort);
yy->tmpPort = strdup(yytext); }
port = < (number | service) > { yy->tmpPort = strdup(yytext); }
proto = '/tcp' { yy->tmpProto = IPPROTO_TCP; }
| '/udp' { yy->tmpProto = IPPROTO_UDP; }
| '' { yy->tmpProto = IPPROTO_TCP; }
@@ -82,15 +90,15 @@ auth-rule = auth-key - < pattern >
allRules = (Rule *)
realloc(allRules, sizeof(Rule) * (allRulesCount + 1));
if (!allRules) {
PARSE_ERROR;
MEMORY_ERROR;
}
allRules[allRulesCount].pattern = strdup(yytext);
if (!allRules[allRulesCount].pattern) {
PARSE_ERROR;
MEMORY_ERROR;
}
allRules[allRulesCount].type = yy->isAuthAllow ? allowRule : denyRule;
if (seTotal > 0) {
if (seInfo[seTotal - 1].rulesStart == 0) {
if (seInfo[seTotal - 1].rulesStart == 0 && seInfo[seTotal - 1].rulesCount == 0) {
seInfo[seTotal - 1].rulesStart = allRulesCount;
}
++seInfo[seTotal - 1].rulesCount;
@@ -106,7 +114,7 @@ logfile = "logfile" - < filename >
{
logFileName = strdup(yytext);
if (!logFileName) {
PARSE_ERROR;
MEMORY_ERROR;
}
}
@@ -114,7 +122,7 @@ pidlogfile = "pidlogfile" - < filename >
{
pidLogFileName = strdup(yytext);
if (!pidLogFileName) {
PARSE_ERROR;
MEMORY_ERROR;
}
}
@@ -125,7 +133,7 @@ logcommon = "logcommon"
invalid_syntax = < (!eol .)+ > eol
{
fprintf(stderr, "rinetd: invalid syntax at line %d: %s\n",
logError("invalid syntax at line %d: %s\n",
yy->currentLine, yytext);
PARSE_ERROR; /* FIXME */
}
@@ -135,9 +143,10 @@ address = ipv4 | ipv6 | hostname
pattern = (hexdigit | '[' | ']' | ':' | '.' | [*?] )+
number = digit+
ipv4 = number '.' number '.' number '.' number | '0'
ipv6 = (hexdigit | ':')+ | '[' (hexdigit | ':')+ ']'
hostname = (label '.')* name '.'?
ipv4 = number '.' number '.' number '.' number | '0'
ipv6 = '[' bare_ipv6 ']' | bare_ipv6
bare_ipv6 = hexdigit* ':' (hexdigit | ':')* # Must have at least one ':'
hostname = (label '.')* name '.'?
name = id ('-' | id | digit)*
@@ -159,19 +168,17 @@ void parseConfiguration(char const *file)
{
FILE *in = fopen(file, "r");
if (!in) {
PARSE_ERROR;
logError("could not open configuration file %s.\n", file);
exit(1);
}
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);
logError("invalid syntax in file %s, line %d.\n", file, -1);
exit(1);
}
free(ctx.sourceAddress);
free(ctx.tmpPort);
yyrelease(&ctx);
fclose(in);

View File

@@ -28,9 +28,11 @@
# elif HAVE_SYS_TIME_H
# include <sys/time.h>
# endif
# include <syslog.h>
#endif /* _WIN32 */
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
@@ -106,11 +108,13 @@ enum {
logDenied,
};
RinetdOptions options = {
static RinetdOptions options = {
RINETD_CONFIG_FILE,
0,
};
static int forked = 0;
static void selectPass(void);
static void handleWrite(ConnectionInfo *cnx, Socket *socket, Socket *other_socket);
static void handleRead(ConnectionInfo *cnx, Socket *socket, Socket *other_socket);
@@ -158,15 +162,19 @@ int main(int argc, char *argv[])
readArgs(argc, argv, &options);
if (!options.foreground) {
#if HAVE_DAEMON && !DEBUG
if (!options.foreground && daemon(0, 0) != 0) {
exit(0);
}
if (daemon(0, 0) != 0) {
exit(0);
}
forked = 1;
#elif HAVE_FORK && !DEBUG
if (!options.foreground && fork() != 0) {
exit(0);
}
if (fork() != 0) {
exit(0);
}
forked = 1;
#endif
}
#if HAVE_SIGACTION
struct sigaction act;
@@ -188,7 +196,7 @@ int main(int argc, char *argv[])
registerPID(pidLogFileName ? pidLogFileName : RINETD_PID_FILE);
}
syslog(LOG_INFO, "Starting redirections...\n");
logInfo("starting redirections...\n");
while (1) {
selectPass();
}
@@ -196,6 +204,38 @@ int main(int argc, char *argv[])
return 0;
}
void logError(char const *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
#if !_WIN32
if (forked)
vsyslog(LOG_ERR, fmt, ap);
else
#endif
{
fprintf(stderr, "rinetd error: ");
vfprintf(stderr, fmt, ap);
}
va_end(ap);
}
void logInfo(char const *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
#if !_WIN32
if (forked)
vsyslog(LOG_INFO, fmt, ap);
else
#endif
{
fprintf(stderr, "rinetd: ");
vfprintf(stderr, fmt, ap);
}
va_end(ap);
}
static void clearConfiguration(void) {
/* Remove references to server information */
for (int i = 0; i < coTotal; ++i) {
@@ -250,7 +290,7 @@ static void readConfiguration(char const *file) {
if (logFile) {
setvbuf(logFile, NULL, _IONBF, 0);
} else {
syslog(LOG_ERR, "could not open %s to append (%m).\n",
logError("could not open %s to append (%m).\n",
logFileName);
}
}
@@ -261,22 +301,21 @@ void addServer(char *bindAddress, char *bindPort, int bindProtocol,
int serverTimeout, char *sourceAddress)
{
ServerInfo si = {
.fromHost = bindAddress,
.toHost = connectAddress,
.fromHost = strdup(bindAddress),
.toHost = strdup(connectAddress),
.serverTimeout = serverTimeout,
};
/* Make a server socket */
struct addrinfo hints = getAddrInfoHint(bindProtocol), *ai;
int ret = getaddrinfo(bindAddress, bindPort, &hints, &ai);
struct addrinfo *ai;
int ret = getAddrInfoWithProto(bindAddress, bindPort, bindProtocol, &ai);
if (ret != 0) {
fprintf(stderr, "rinetd: getaddrinfo error: %s\n", gai_strerror(ret));
exit(1);
}
si.fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (si.fd == INVALID_SOCKET) {
syslog(LOG_ERR, "couldn't create server socket! (%m)\n");
logError("couldn't create server socket! (%m)\n");
freeaddrinfo(ai);
exit(1);
}
@@ -285,7 +324,7 @@ void addServer(char *bindAddress, char *bindPort, int bindProtocol,
setsockopt(si.fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&tmp, sizeof(tmp));
if (bind(si.fd, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR) {
syslog(LOG_ERR, "couldn't bind to address %s port %s (%m)\n",
logError("couldn't bind to address %s port %s (%m)\n",
bindAddress, bindPort);
closesocket(si.fd);
freeaddrinfo(ai);
@@ -295,7 +334,7 @@ void addServer(char *bindAddress, char *bindPort, int bindProtocol,
if (bindProtocol == IPPROTO_TCP) {
if (listen(si.fd, RINETD_LISTEN_BACKLOG) == SOCKET_ERROR) {
/* Warn -- don't exit. */
syslog(LOG_ERR, "couldn't listen to address %s port %s (%m)\n",
logError("couldn't listen to address %s port %s (%m)\n",
bindAddress, bindPort);
/* XXX: check whether this is correct */
closesocket(si.fd);
@@ -308,10 +347,8 @@ void addServer(char *bindAddress, char *bindPort, int bindProtocol,
si.fromAddrInfo = ai;
/* Resolve destination address. */
hints = getAddrInfoHint(connectProtocol);
ret = getaddrinfo(connectAddress, connectPort, &hints, &ai);
ret = getAddrInfoWithProto(connectAddress, connectPort, connectProtocol, &ai);
if (ret != 0) {
fprintf(stderr, "rinetd: getaddrinfo error: %s\n", gai_strerror(ret));
freeaddrinfo(si.fromAddrInfo);
closesocket(si.fd);
exit(1);
@@ -320,10 +357,8 @@ void addServer(char *bindAddress, char *bindPort, int bindProtocol,
/* Resolve source address if applicable. */
if (sourceAddress) {
hints = getAddrInfoHint(connectProtocol);
ret = getaddrinfo(sourceAddress, NULL, &hints, &ai);
ret = getAddrInfoWithProto(sourceAddress, NULL, connectProtocol, &ai);
if (ret != 0) {
fprintf(stderr, "rinetd: getaddrinfo error: %s\n", gai_strerror(ret));
freeaddrinfo(si.fromAddrInfo);
freeaddrinfo(si.toAddrInfo);
exit(1);
@@ -413,7 +448,7 @@ static ConnectionInfo *findAvailableConnection(void)
int oldTotal = coTotal;
setConnectionCount(coTotal * 4 / 3 + 8);
if (coTotal == oldTotal) {
syslog(LOG_ERR, "not enough memory to add slots. "
logError("not enough memory to add slots. "
"Currently %d slots.\n", coTotal);
/* Go back to the previous total number of slots */
return NULL;
@@ -650,7 +685,7 @@ static void handleAccept(ServerInfo const *srv)
/* In TCP mode, get remote address using accept(). */
nfd = accept(srv->fd, (struct sockaddr *)&addr, &addrlen);
if (nfd == INVALID_SOCKET) {
syslog(LOG_ERR, "accept(%llu): %m\n", (long long unsigned int)srv->fd);
logError("accept(%llu): %m\n", (long long unsigned int)srv->fd);
logEvent(NULL, srv, logAcceptFailed);
return;
}
@@ -671,7 +706,7 @@ static void handleAccept(ServerInfo const *srv)
if (GetLastError() == WSAEINPROGRESS) {
return;
}
syslog(LOG_ERR, "recvfrom(%llu): %m\n", (long long unsigned int)srv->fd);
logError("recvfrom(%llu): %m\n", (long long unsigned int)srv->fd);
logEvent(NULL, srv, logAcceptFailed);
return;
}
@@ -730,7 +765,7 @@ static void handleAccept(ServerInfo const *srv)
struct addrinfo* to = srv->toAddrInfo;
cnx->local.fd = socket(to->ai_family, to->ai_socktype, to->ai_protocol);
if (cnx->local.fd == INVALID_SOCKET) {
syslog(LOG_ERR, "socket(): %m\n");
logError("socket(): %m\n");
if (cnx->remote.protocol == IPPROTO_TCP)
closesocket(cnx->remote.fd);
cnx->remote.fd = INVALID_SOCKET;
@@ -746,7 +781,7 @@ static void handleAccept(ServerInfo const *srv)
if (srv->sourceAddrInfo) {
if (bind(cnx->local.fd, srv->sourceAddrInfo->ai_addr,
srv->sourceAddrInfo->ai_addrlen) == SOCKET_ERROR) {
syslog(LOG_ERR, "bind(): %m\n");
logError("bind(): %m\n");
}
}
@@ -866,7 +901,7 @@ RETSIGTYPE plumber(int s)
RETSIGTYPE hup(int s)
{
(void)s;
syslog(LOG_INFO, "Received SIGHUP, reloading configuration...\n");
logInfo("received SIGHUP, reloading configuration...\n");
/* Learn the new rules */
clearConfiguration();
readConfiguration(options.conf_file);
@@ -896,8 +931,6 @@ void registerPID(char const *pid_file_name)
FILE *pid_file = fopen(pid_file_name, "w");
if (pid_file == NULL) {
/* non-fatal, non-Linux may lack /var/run... */
fprintf(stderr, "rinetd: Couldn't write to "
"%s. PID was not logged.\n", pid_file_name);
goto error;
} else {
fprintf(pid_file, "%d\n", getpid());
@@ -907,8 +940,8 @@ void registerPID(char const *pid_file_name)
}
return;
error:
syslog(LOG_ERR, "Couldn't write to "
"%s. PID was not logged (%m).\n", pid_file_name);
logError("couldn't write to %s. PID was not logged (%m).\n",
pid_file_name);
#else
/* add other systems with wherever they register processes */
(void)pid_file_name;
@@ -947,7 +980,7 @@ static void logEvent(ConnectionInfo const *cnx, ServerInfo const *srv, int resul
}
if (result==logNotAllowed || result==logDenied)
syslog(LOG_INFO, "%s %s\n"
logInfo("%s %s\n"
, addressText
, logMessages[result]);
if (logFile) {
@@ -1014,7 +1047,7 @@ static int readArgs (int argc, char **argv, RinetdOptions *options)
case 'c':
options->conf_file = optarg;
if (!options->conf_file) {
syslog(LOG_ERR, "Not enough memory to "
fprintf(stderr, "Not enough memory to "
"launch rinetd.\n");
exit(1);
}

View File

@@ -8,17 +8,6 @@
#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 */
#include <stdint.h>
/* Constants */
@@ -46,6 +35,8 @@ extern FILE *logFile;
/* Functions */
void logError(char const *fmt, ...);
void logInfo(char const *fmt, ...);
void addServer(char *bindAddress, char *bindPort, int bindProtocol,
char *connectAddress, char *connectPort, int connectProtocol,
int serverTimeout, char *sourceAddress);