New plugin API and porting of the plugins (+ several changes in the DNS plugin)

Initial
Stephane Bortzmeyer 20 years ago
parent 85adcec177
commit ace6dee486

@ -1,22 +1,42 @@
If you want to write your own plugins, they will have to provide three
functions:
If you want to write your own plugins, you will first have to decide
wether your plugin uses a "cooked" hostname or a "raw" one.
char * init (const int argc, const char **argv)
Accepts remaining arguments (you have to use popt to parse them, or
do it by hand, getopt does not allow you to resume the parsing) and
returns a string identifying the port name. If it makes no sense, you
can safely return NULL.
In the first case, the cooked hostname, your plugin will receive from
echoping a struct addrinfo. All the DNS stuff, including IDN, is
performed by echoping. You can immediately start using the struct
addrinfo.
But some libraries (typically, the one used by the DBMS) do not work
on struct addrinfo but on strings such as "dbname=test
hostname=foo.bar". Plugins using these libraries will have to use the
raw interface.
You indicate to echoping wether you use the raw interface or the
cooked one by returning a port name or NULL from the init() function.
You will have to provide three functions:
char * init (const int argc, const char **argv) Accepts remaining
arguments (you have to use popt to parse them, or do it by hand,
getopt does not allow you to resume the parsing) and returns a
string identifying the port name (cooked interface) or NULL (raw
interface).
For the cooked interface:
void start (struct addrinfo *res)
Typically just stores the res structure for later use.
TODO: two start() routines, one which takes a struct addrinfo and one
which does not (PostgreSQL or MySQL does not use struct addrinfo but a
string)?
For the raw interface:
void start_raw ()
Typically connects to the server.
int execute ()
Connects and do whatever the protocol requires. It is called once
per iteration. It returns >=0 if it succeeds and -1 if it failed.
per iteration. It returns >=0 if it succeeds, -1 if it failed
temporarily (so echoping will continue its loop) and -2 if it failes
permanently (so echoping will stop the iteration).
void terminate ()
Cleans everything. It is called after all iterations.
@ -24,11 +44,12 @@ void terminate ()
Start your plugin source code with:
#define IN_PLUGIN
#include "../echoping.h"
#include "/wherever/echoping/is/installed/echoping.h"
You can look at random.c, the simplest plugin, and whois.c, the
simplest which still does something useful.
TODO: documentation of the plugin. A man page echoping_PLUGINNAME?
The documentation of the plugin should be in a manual page named
echoping_PLUGINNAME. See the above plugins for examples.
$Id$

1
SRC/configure vendored

@ -18940,6 +18940,7 @@ _ACEOF
fi
fi;
# Check whether --with-popt or --without-popt was given.
if test "${with_popt+set}" = set; then
withval="$with_popt"

@ -98,8 +98,15 @@ AC_ARG_WITH(gnutls,
CPPFLAGS="${CPPFLAGS} -I$GNUTLSROOT/include"
fi
fi],
dnl Default: disable it
)
dnl Default: disable it
)
dnl TODO: test if the getopt variable optreset exists and, if it
dnl does, we can use getopt (Free BSDs and MacOS X). This implies to
dnl maintain the two versions, popt and getopt, while echoping has
dnl many options. It probably means a high-level language to describe
dnl the options and to produce the two versions. gengetopt is an obvious
dnl candidate.
AC_ARG_WITH(popt,
[ --with-popt[=DIR] popt command-line parsing library],dnl
[if test "$withval" != "no"; then

@ -87,6 +87,7 @@ main (argc, argv)
char *plugin_name, *complete_plugin_name = NULL;
char *ext;
void *plugin;
int plugin_result;
char *dl_result;
void to_alarm (); /* our alarm() signal handler */
@ -100,6 +101,7 @@ main (argc, argv)
#endif
char *plugin_port_name, *port_name;
unsigned short plugin_raw;
unsigned short port_to_use = USE_ECHO;
unsigned short http = 0;
unsigned short smtp = 0;
@ -143,6 +145,7 @@ main (argc, argv)
/* popt variables */
const struct poptOption options[] = {
{"verbose", 'v', POPT_ARG_NONE, &verbose, 'v'},
{"help", '?', POPT_ARG_NONE, NULL, '?'},
{"size", 's', POPT_ARG_INT, &size, 's'},
{"number", 'n', POPT_ARG_INT, &number, 'n'},
#ifdef HAVE_USLEEP
@ -167,7 +170,7 @@ main (argc, argv)
{"ipv4", '4', POPT_ARG_NONE, NULL, '4'},
{"ipv6", '6', POPT_ARG_NONE, NULL, '6'},
{"module", 'm', POPT_ARG_STRING, &plugin_name, 'm'},
{NULL, 0, 0, NULL, 0, NULL, NULL}
POPT_TABLEEND
};
poptContext poptcon;
@ -192,20 +195,25 @@ main (argc, argv)
}
progname = (char *) argv[0];
poptcon = poptGetContext (NULL, argc, argv, options, 0);
poptcon =
poptGetContext (NULL, argc, argv, options, POPT_CONTEXT_POSIXMEHARDER);
while ((!module_find) && (result = poptGetNextOpt (poptcon)) != -1)
while ((result = poptGetNextOpt (poptcon)) != -1)
{
if (result < -1)
{
printf ("%s: %s",
poptBadOption (poptcon, POPT_BADOPTION_NOALIAS),
poptStrerror (result));
usage ();
fprintf (stderr, "%s: %s\n",
poptBadOption (poptcon, POPT_BADOPTION_NOALIAS),
poptStrerror (result));
usage (poptcon);
}
remaining--;
switch ((char) result)
{
case '?':
poptPrintHelp (poptcon, stdout, 0);
fprintf (stdout, " hostname [plugin-options...]\n");
exit (0);
case 'v':
break;
case 'r':
@ -324,7 +332,7 @@ main (argc, argv)
break;
default:
printf ("Unknown character option %d (%c)", result, (char) result);
usage ();
usage (poptcon);
}
}
if (udp && ((port_to_use == USE_CHARGEN) ||
@ -445,29 +453,43 @@ main (argc, argv)
plugin_name, PLUGINS_DIR, dlerror ());
}
plugin_init = dlsym (plugin, "init");
if (! plugin_init)
if (!plugin_init)
{
err_sys ("Cannot find init in %s: %s", plugin_name, dlerror());
err_sys ("Cannot find init in %s: %s", plugin_name, dlerror ());
}
plugin_port_name = plugin_init (remaining, (const char **) leftover);
if (plugin_port_name != NULL)
strcpy (port_name, plugin_port_name);
{
strcpy (port_name, plugin_port_name);
plugin_raw = FALSE;
plugin_start = dlsym (plugin, "start");
if (!plugin_start)
{
err_sys ("Cannot find start in %s: %s", plugin_name,
dlerror ());
}
}
else
port_name = 0;
plugin_start = dlsym (plugin, "start");
if (! plugin_start)
{
err_sys ("Cannot find start in %s: %s", plugin_name, dlerror());
port_name = 0;
plugin_raw = TRUE;
plugin_raw_start = dlsym (plugin, "start_raw");
if (!plugin_raw_start)
{
err_sys ("Cannot find start_raw in %s: %s", plugin_name,
dlerror ());
}
}
plugin_execute = dlsym (plugin, "execute");
if (!plugin_execute)
{
err_sys ("Cannot find execute in %s: %s", plugin_name, dlerror());
err_sys ("Cannot find execute in %s: %s", plugin_name, dlerror ());
}
plugin_terminate = dlsym (plugin, "terminate");
if (! plugin_terminate)
if (!plugin_terminate)
{
err_sys ("Cannot find terminate in %s: %s", plugin_name, dlerror());
err_sys ("Cannot find terminate in %s: %s", plugin_name,
dlerror ());
}
}
if (!udp && !ttcp)
@ -475,11 +497,11 @@ main (argc, argv)
tcp = 1;
}
if (remaining == 0)
usage ();
usage (poptcon);
if (!module_find && remaining != 1)
{
printf ("%d args remaning, should be 1\n", remaining);
usage ();
printf ("%d args remaining, should be 1\n", remaining);
usage (poptcon);
}
if (verbose)
{
@ -613,18 +635,21 @@ main (argc, argv)
}
} /* Else it is an address, do not IDNize it */
#endif
error = getaddrinfo (server, port_name, &hints, &res);
if (error)
if (!plugin || !plugin_raw)
{
err_quit ("getaddrinfo error for host: %s %s",
server, gai_strerror (error));
}
error = getaddrinfo (server, port_name, &hints, &res);
if (error)
{
err_quit ("getaddrinfo error for host: %s %s",
server, gai_strerror (error));
}
if (getnameinfo (res->ai_addr, res->ai_addrlen, hbuf, sizeof (hbuf),
pbuf, sizeof (pbuf), niflags) != 0)
{
strcpy (hbuf, "?");
strcpy (pbuf, "?");
if (getnameinfo (res->ai_addr, res->ai_addrlen, hbuf, sizeof (hbuf),
pbuf, sizeof (pbuf), niflags) != 0)
{
strcpy (hbuf, "?");
strcpy (pbuf, "?");
}
}
if (plugin)
{
@ -632,7 +657,10 @@ main (argc, argv)
{
printf ("Running start() for the plugin %s...\n", plugin_name);
}
plugin_start (res);
if (plugin_raw)
plugin_raw_start ();
else
plugin_start (res);
}
#ifdef HTTP
if (http)
@ -823,9 +851,12 @@ main (argc, argv)
}
else
{
printf
("Trying to call plugin %s for internet address %s %s...\n",
plugin_name, hbuf, pbuf);
if (plugin_raw)
printf ("Trying to call plugin %s...\n", plugin_name);
else
printf
("Trying to call plugin %s for internet address %s %s...\n",
plugin_name, hbuf, pbuf);
}
}
#ifdef FLUSH_OUTPUT
@ -856,8 +887,9 @@ main (argc, argv)
(void) gettimeofday (&oldtv, (struct timezone *) NULL);
if (plugin)
{
plugin_execute ();
/* TODO: do something with the return code */
plugin_result = plugin_execute ();
if (plugin_result == -2)
err_quit("");
}
else
{

@ -127,6 +127,8 @@ typedef char * (*init_f) (const int argc, const char **argv);
init_f plugin_init;
typedef void (*start_f) (struct addrinfo *);
start_f plugin_start;
typedef void (*start_raw_f) ();
start_raw_f plugin_raw_start;
typedef int (*execute_f) ();
execute_f plugin_execute;
typedef void (*terminate_f) ();

@ -85,11 +85,10 @@ err_sys (char *str, ...)
}
void
usage ()
usage (poptContext context)
{
fprintf (stderr,
"Usage: %s [-4] [-6] [-v] [-r] [-f fill] [-t timeout] [-c] [-d] [-u] [-s size] [-n number] [-w delay] [-h url] [-i url] [-p priority] [-P tos] [-C] [-S] [-m plugin] hostname[:port]\n",
progname);
poptPrintUsage (context, stderr, 0);
fprintf (stderr, " hostname [plugin-options...]\n");
exit (1);
}
@ -110,11 +109,11 @@ sys_err_str ()
if (errno != 0)
{
sprintf (msgstr, "(%s)", strerror(errno));
sprintf (msgstr, "(%s)", strerror (errno));
}
else
{
msgstr[0] = '\0';
}
}
return (msgstr);
}

@ -1,7 +1,5 @@
/*
* DNS plugin.
* TODO: return errors to echoping (name server not existing, for instance)
* TODO: allow options like TCP
* $Id$
*/
@ -16,6 +14,8 @@ struct addrinfo name_server;
poptContext dns_poptcon;
char *request;
int type;
short use_tcp = FALSE;
short no_recurse = FALSE;
/* nsError stolen from Liu & Albitz check_soa (in their book "DNS and BIND") */
@ -78,6 +78,12 @@ init (const int argc, const char **argv)
{"type", 't', POPT_ARG_STRING, &type_name, 0,
"Type of resources queried (A, MX, SOA, etc)",
"type"},
{"tcp", NULL, POPT_ARG_NONE, &use_tcp, 0,
"Use TCP for the request (virtual circuit)",
"tcp"},
{"no-recurse", NULL, POPT_ARG_NONE, &no_recurse, 0,
"Do not ask recursion",
"no-recurse"},
POPT_AUTOHELP POPT_TABLEEND
};
dns_poptcon = poptGetContext (NULL, argc,
@ -100,14 +106,18 @@ init (const int argc, const char **argv)
{ /* TODO: a better algorithm. Use dns_rdatatype_fromtext in BIND ? */
if (!strcmp (type_name, "A"))
type = T_A;
else if (!strcmp (type_name, "AAAA"))
type = T_AAAA;
else if (!strcmp (type_name, "NS"))
type = T_NS;
else if (!strcmp (type_name, "SOA"))
type = T_SOA;
else if (!strcmp (type_name, "MX"))
type = T_MX;
else if (!strcmp (type_name, "AAAA"))
type = T_AAAA;
else if (!strcmp (type_name, "SRV"))
type = T_SRV;
else if (!strcmp (type_name, "TXT"))
type = T_TXT;
else
dns_usage ("Unknown type");
}
@ -129,6 +139,14 @@ start (struct addrinfo *res)
_res.nsaddr_list[0] = name_server_sockaddr_in; /* TODO: and IPv6? Detect _resext with autoconf (*BSD) and use it */
_res.nscount = 1;
_res.options &= ~(RES_DNSRCH | RES_DEFNAMES | RES_NOALIASES);
if (use_tcp)
{
_res.options &= RES_USEVC;
}
if (no_recurse)
{
_res.options &= ~RES_RECURSE;
}
}
int
@ -142,13 +160,15 @@ execute ()
int response_length; /* buffer length */
if ((response_length = res_query (request, /* the domain we care about */
C_IN, /* Internet class records */
type,
(u_char *) & response, /*response buffer */
type, (u_char *) & response, /*response buffer */
sizeof (response))) /*buffer size */
< 0)
{ /*If negative */
nsError (h_errno, request); /* report the error */
return -1; /* and quit */
if (h_errno == TRY_AGAIN)
return -1; /* More luck next time? */
else
return -2; /* Give in */
}
/* TODO: better analysis of the replies. For instance, replies can be in the authority section (delegation info) */
return 0;

@ -58,7 +58,7 @@ init (const int argc, const char **argv)
postgresql_usage (msg);
}
}
if (request == NULL) /* TODO: a default like SELECT now()? */
if (request == NULL) /* TODO: a default like SELECT now()? */
postgresql_usage ("Mandatory request missing");
if (conninfo == NULL)
postgresql_usage ("Mandatory connection information missing");
@ -66,18 +66,16 @@ init (const int argc, const char **argv)
}
void
start (struct addrinfo *res)
start_raw ()
{
conn = PQconnectdb (conninfo);
if (conn == NULL)
{
printf ("Cannot create connection\n");
exit (1);
err_quit ("Cannot create connection\n");
}
if (PQstatus (conn) == CONNECTION_BAD)
{
printf ("Connection failed: %s\n", PQerrorMessage (conn));
exit (1);
err_quit ("Connection failed: %s\n", PQerrorMessage (conn));
}
}

Loading…
Cancel
Save