mirror of
https://github.com/samhocevar/rinetd.git
synced 2025-03-24 08:40:09 +08:00
183 lines
4.5 KiB
Plaintext
183 lines
4.5 KiB
Plaintext
%{
|
|
#define YY_CTX_LOCAL 1
|
|
#define YY_CTX_MEMBERS \
|
|
FILE *fp; \
|
|
int currentLine; \
|
|
int isAuthAllow; \
|
|
unsigned int port, bindPort, connectPort; \
|
|
char *bindAddress, *connectAddress;
|
|
#define YY_INPUT(yyctx, buf, result, max_size) \
|
|
{ \
|
|
int yyc = fgetc(yyctx->fp); \
|
|
result = (EOF == yyc) ? 0 : (*(buf) = yyc, 1); \
|
|
}
|
|
#define PARSE_ERROR exit(1);
|
|
%}
|
|
|
|
file = (sol (line eol | invalid_syntax))*
|
|
line = -? (rule | auth | logfile | pidlogfile | logcommon )? -? comment?
|
|
|
|
comment = "#" (!eol .)*
|
|
|
|
rule = bind_address - bind_port - connect_address - connect_port {
|
|
/* Turn all of this stuff into reasonable addresses */
|
|
struct in_addr iaddr;
|
|
if (getAddress(yy->bindAddress, &iaddr) < 0) {
|
|
fprintf(stderr, "rinetd: host %s could not be resolved.\n",
|
|
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;
|
|
}
|
|
|
|
bind_address = < ipv4 > { yy->bindAddress = strdup(yytext); }
|
|
connect_address = < ipv4 > { yy->connectAddress = strdup(yytext); }
|
|
bind_port = port { yy->bindPort = yy->port; }
|
|
connect_port = port { yy->connectPort = yy->port; }
|
|
|
|
port = < (number | service) > {
|
|
struct servent *bindService = getservbyname(yytext, "tcp");
|
|
yy->port = bindService ? ntohs(bindService->s_port) : atoi(yytext);
|
|
if (yy->port == 0 || yy->port >= 65536) {
|
|
syslog(LOG_ERR, "bind port missing or out of range\n");
|
|
PARSE_ERROR;
|
|
}
|
|
}
|
|
|
|
auth = auth_key - < pattern > {
|
|
allRules = (Rule *)
|
|
realloc(allRules, sizeof(Rule) * (allRulesCount + 1));
|
|
if (!allRules) {
|
|
PARSE_ERROR;
|
|
}
|
|
allRules[allRulesCount].pattern = strdup(yytext);
|
|
if (!allRules[allRulesCount].pattern) {
|
|
PARSE_ERROR;
|
|
}
|
|
allRules[allRulesCount].type = yy->isAuthAllow ? allowRule : denyRule;
|
|
if (seTotal > 0) {
|
|
if (seInfo[seTotal - 1].rulesStart == 0) {
|
|
seInfo[seTotal - 1].rulesStart = allRulesCount;
|
|
}
|
|
++seInfo[seTotal - 1].rulesCount;
|
|
} else {
|
|
++globalRulesCount;
|
|
}
|
|
++allRulesCount;
|
|
}
|
|
|
|
auth_key = < ("allow" | "deny") > { yy->isAuthAllow = (yytext[0] == 'a'); }
|
|
|
|
logfile = "logfile" - < filename > {
|
|
logFileName = strdup(yytext);
|
|
if (!logFileName) {
|
|
PARSE_ERROR;
|
|
}
|
|
}
|
|
|
|
pidlogfile = "pidlogfile" - < filename > {
|
|
pidLogFileName = strdup(yytext);
|
|
if (!pidLogFileName) {
|
|
PARSE_ERROR;
|
|
}
|
|
}
|
|
|
|
logcommon = "logcommon" {
|
|
logFormatCommon = 1;
|
|
}
|
|
|
|
invalid_syntax = < (!eol .)+ > eol {
|
|
fprintf(stderr, "rinetd: invalid syntax at line %d: %s\n",
|
|
yy->currentLine, yytext);
|
|
PARSE_ERROR; /* FIXME */
|
|
}
|
|
|
|
service = name
|
|
ipv4 = number [.] number [.] number [.] number | '0'
|
|
pattern = [0-9*?]+ ('.' [0-9*?]+ ('.' [0-9*?]+ ('.' [0-9*?]+)?)?)?
|
|
number = digit+
|
|
|
|
name = [a-zA-Z][a-zA-Z0-9_]*
|
|
filename = '"' [^"]+ '"'
|
|
| [^ \t\r\n]+
|
|
|
|
- = [ \t]+
|
|
digit = [0-9]
|
|
sol = { ++yy->currentLine; }
|
|
eol = '\r'? '\n' | eof
|
|
eof = '\0'
|
|
|