/************************************************************************
* IRC - Internet Relay Chat, iauth/mod_lhex.c
* Copyright (C) 1998-1999 Christophe Kalt and Andrew Snare
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef lint
static char rcsid[] = "@(#)$Id mod_lhex.c,v 1.12 1999/02/06 21:43:52 kalt Exp $";
#endif
#include "os.h"
#include "a_defines.h"
#define MOD_LHEX_C
#include "a_externs.h"
#undef MOD_LHEX_C
/****************************** PRIVATE *************************************/
#define LHEXPORT 9674
struct lhex_private
{
/* stats */
u_int ok, banned;
u_int tried, clean, timeout;
};
/******************************** PUBLIC ************************************/
/*
* lhex_init
*
* This procedure is called when a particular module is loaded.
* Returns NULL if everything went fine,
* an error message otherwise.
*/
char *
lhex_init(self)
AnInstance *self;
{
struct lhex_private *mydata;
#if defined(INET6)
return "IPv6 unsupported.";
#endif
if(self->opt == NULL)
return "Aie! no option(s): no LHEx server to connect to!";
if(!inetaton(self->opt,NULL))
return "Aie! Option wasn't a valid IP address!";
/* Allocate the module data */
mydata = (struct lhex_private *) malloc(sizeof(struct lhex_private));
bzero((char *) mydata, sizeof(struct lhex_private));
self->popt = mystrdup(self->opt);
self->data = mydata;
return NULL;
}
/*
* lhex_release
*
* This procedure is called when a particular module is unloaded.
*/
void
lhex_release(self)
AnInstance *self;
{
struct lhex_private *mydata = self->data;
free(mydata);
free(self->popt);
}
/*
* lhex_stats
*
* This procedure is called regularly to update statistics sent to ircd.
*/
void
lhex_stats(self)
AnInstance *self;
{
struct lhex_private *mydata = self->data;
sendto_ircd("S lhex ok %u banned %u", mydata->ok, mydata->banned);
sendto_ircd("S lhex tried %u aborted %u / %u",
mydata->tried, mydata->clean, mydata->timeout);
}
/*
* lhex_start
*
* This procedure is called to start the LHEx check procedure.
* Returns 0 if everything went fine,
* anything else otherwise (nothing to be done, or failure)
*
* It is responsible for sending error messages where appropriate.
* In case of failure, it's responsible for cleaning up (e.g. lhex_clean
* will NOT be called)
*/
int
lhex_start(cl)
u_int cl;
{
char *error;
int fd;
struct lhex_private *mydata = cldata[cl].instance->data;
if (cldata[cl].state & A_DENY)
{
/* no point of doing anything */
DebugLog((ALOG_DLHEX, 0,
"lhex_start(%d): A_DENY already set ", cl));
return -1;
}
DebugLog((ALOG_DLHEX, 0, "lhex_start(%d): Connecting to %s", cl,
cldata[cl].instance->opt));
mydata->tried += 1;
fd= tcp_connect(cldata[cl].ourip, cldata[cl].instance->opt,
LHEXPORT, &error);
if (fd < 0)
{
DebugLog((ALOG_DLHEX, 0,
"lhex_start(%d): tcp_connect() reported %s",
cl, error));
return -1;
}
cldata[cl].wfd = fd; /*so that lhex_work() is called when connected*/
return 0;
}
/*
* lhex_work
*
* This procedure is called whenever there's new data in the buffer.
* Returns 0 if everything went fine, and there is more work to be done,
* Returns -1 if the module has finished its work (and cleaned up).
*
* It is responsible for sending error messages where appropriate.
*/
int
lhex_work(cl)
u_int cl;
{
DebugLog((ALOG_DLHEX, 0, "lhex_work(%d): %d %d buflen=%d", cl,
cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen));
if (cldata[cl].wfd > 0)
{
/*
** We haven't sent the query yet, the connection was just
** established.
*/
char query[3+7+6+4+USERLEN+2*HOSTLEN+8+3];/*strlen(atoi(cl))<=8*/
char *ident = cldata[cl].authuser;
/* This is part of every request */
sprintf(query, "id:%u ip:%s", cl, cldata[cl].itsip);
/* These bits are optional, depending on what's known */
if (ident)
{
strcat(query, " ident:");
strcat(query, ident);
}
if (cldata[cl].state & A_GOTH)
{
strcat(query, " host:");
strcat(query, cldata[cl].host);
}
/* Terminate the request */
strcat(query, "\r\n");
DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): Sending query [%s]",
cl, query));
if (write(cldata[cl].wfd, query, strlen(query)) < 0)
{
/* most likely the connection failed */
DebugLog((ALOG_DLHEX, 0,
"lhex_work(%u): write() failed: %s",
cl, strerror(errno)));
close(cldata[cl].wfd);
cldata[cl].rfd = cldata[cl].wfd = 0;
return 1;
}
cldata[cl].rfd = cldata[cl].wfd;
cldata[cl].wfd = 0;
}
else
{
/* data's in from the other end */
char *ch, *nch;
u_int id;
int retval = 0;
cldata[cl].inbuffer[cldata[cl].buflen] = '\0';
nch = cldata[cl].inbuffer;
while((nch < (cldata[cl].inbuffer + cldata[cl].buflen)) &&
(ch = index(nch, '\r')) && !retval)
{
char *och = nch;
nch = ch+2; /* Skip the \r\n */
*ch = '\0';
DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): Got [%s]",
cl, och));
/* Have a go at parsing the return info */
if(sscanf(och, "%u", &id) != 1)
DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): "
"Malformed data!", cl));
else
{
struct lhex_private *d=cldata[cl].instance->data;
ch = index(och, ':');
while(isspace(*(++ch)));
if(!strcmp(ch,"OK"))
{
d->ok++;
DebugLog((ALOG_DLHEX, 0,
"lhex_work(%u): OK", id));
close(cldata[cl].rfd);
cldata[cl].rfd = 0;
retval = -1;
}
else if(!strcmp(ch,"Not OK"))
{
d->banned++;
DebugLog((ALOG_DLHEX, 0,
"lhex_work(%u): Not OK", id));
cldata[cl].state |= A_DENY;
/* I really wish we could send the
client a "reason" here :P */
sendto_ircd("K %d %s %u ", cl,
cldata[cl].itsip,
cldata[cl].itsport);
close(cldata[cl].rfd);
cldata[cl].rfd = 0;
retval = -1;
}
else
{
#if 0
/* Call this info for the client */
sendto_ircd("I %d %s %u NOTICE AUTH :%s",
cl, cldata[cl].itsip,
cldata[cl].itsport, ch);
#endif
retval = 0;
}
}
}
return retval;
}
return 0;
}
/*
* lhex_clean
*
* This procedure is called whenever the module should interrupt its work.
* It is responsible for cleaning up any allocated data, and in particular
* closing file descriptors.
*/
void
lhex_clean(cl)
u_int cl;
{
struct lhex_private *mydata = cldata[cl].instance->data;
mydata->clean += 1;
DebugLog((ALOG_DLHEX, 0, "lhex_clean(%d): cleaning up", cl));
/*
** only one of rfd and wfd may be set at the same time,
** in any case, they would be the same fd, so only close() once
*/
if (cldata[cl].rfd)
close(cldata[cl].rfd);
else if (cldata[cl].wfd)
close(cldata[cl].wfd);
cldata[cl].rfd = cldata[cl].wfd = 0;
}
/*
* lhex_timeout
*
* This procedure is called whenever the timeout set by the module is
* reached.
*
* Returns 0 if things are okay, -1 if check was aborted.
*/
int
lhex_timeout(cl)
u_int cl;
{
struct lhex_private *mydata = cldata[cl].instance->data;
mydata->timeout += 1;
DebugLog((ALOG_DLHEX, 0, "lhex_timeout(%d): calling lhex_clean ", cl));
lhex_clean(cl);
return -1;
}
aModule Module_lhex =
{ "lhex", lhex_init, lhex_release, lhex_stats,
lhex_start, lhex_work, lhex_timeout, lhex_clean };
syntax highlighted by Code2HTML, v. 0.9.1