From 4f7366640bc21430e5c3210c8708226a3186bfaf Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 18 Jul 2016 11:10:19 +0200 Subject: [PATCH] Add optional support for RFC864, Character Generator Protocol Signed-off-by: Joachim Nilsson --- README.md | 34 +++++++++----- configure.ac | 1 + plugins/Makefile.am | 8 ++++ plugins/chargen.c | 110 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 plugins/chargen.c diff --git a/README.md b/README.md index 28d6f1af..4231887e 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ interface, reducing the need for a full blown firewall. Built-in optional inetd services: - echo RFC862 +- chargen RFC864 - discard RFC863 - time (rdate) RFC868 @@ -478,28 +479,30 @@ Compared to Finit v1.12 you must *explicitly deny* access from `eth0`! **Internal Services** -The original `inetd` had a few standard services built-in: +Like the original `inetd`, Finit has a few standard services built-in. +They are realized as plugins to provide a simple means of testing the +inetd functionality stand-alone. But this also provides both a useful +network testing/availability, as well as a rudimentary time server for +`rdate` clients. -- time - echo - chargen - discard +- time -Finit currently supports the `time`, `echo`, and `discard` services. -Both of which are realized as plugins to provide a simple means of -testing the inetd functionality stand-alone. But this also provides -both a useful network testing/availability and a rudimentary time server -for rdate clients. - -Internal inetd services are set up as follows: +For security reasons they are all disabled by default and have to be +enabled with both the `configure` script and a special `inetd` stanza in +the `finit.conf` or `finit.d/*.conf` like this: ```shell - inetd time/udp wait [2345] internal - inetd time/tcp nowait [2345] internal inetd echo/udp wait [2345] internal inetd echo/tcp nowait [2345] internal + inetd chargen/udp wait [2345] internal + inetd chargen/tcp nowait [2345] internal inetd discard/udp wait [2345] internal inetd discard/tcp nowait [2345] internal + inetd time/udp wait [2345] internal + inetd time/tcp nowait [2345] internal ``` Then call `rdate` from a remote machine (or use localhost): @@ -523,6 +526,13 @@ Or `echoping -d` to reach the discard service: echoping -duv ``` +Or `echoping -c` to reach the chargen service: + +```shell + echoping -cv + echoping -cuv +``` + If you use `time/udp` you must use the standard rdate implementation and then call it with `rdate -up` to connect using UDP. Without the `-p` argument rdate will try to set the system clock. Please note that rdate @@ -565,6 +575,8 @@ For your convenience a set of *optional* plugins are available: * *echo.so*: RFC 862 plugin. Start as inetd service, like time below. +* *chargen.so*: RFC 864 plugin. Start as inetd service, like time below. + * *discard.so*: RFC 863 plugin. Start as inetd service, like time below. * *hwclock.so*: Restore and save system clock from/to RTC on diff --git a/configure.ac b/configure.ac index 8146b80b..2e1f4081 100644 --- a/configure.ac +++ b/configure.ac @@ -56,6 +56,7 @@ enable_all_plugins=auto AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl]) AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus]) AC_PLUGIN([inetd-echo], [no], [Inetd plugin: echo server, RFC862]) +AC_PLUGIN([inetd-chargen], [no], [Inetd plugin: character generator, RFC864]) AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC862]) AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868]) AC_PLUGIN([lost], [no], [Example HOOK_SVC_LOST plugin, very noisy as-is!]) diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 528a9457..49d6a5c4 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -19,6 +19,10 @@ if BUILD_INETD_ECHO_PLUGIN libplug_la_SOURCES += echo.c endif +if BUILD_INETD_CHARGEN_PLUGIN +libplug_la_SOURCES += chargen.c +endif + if BUILD_INETD_DISCARD_PLUGIN libplug_la_SOURCES += discard.c endif @@ -54,6 +58,10 @@ if BUILD_INETD_ECHO_PLUGIN pkglib_LTLIBRARIES += echo.la endif +if BUILD_INETD_CHARGEN_PLUGIN +pkglib_LTLIBRARIES += chargen.la +endif + if BUILD_INETD_DISCARD_PLUGIN pkglib_LTLIBRARIES += discard.la endif diff --git a/plugins/chargen.c b/plugins/chargen.c new file mode 100644 index 00000000..30528b51 --- /dev/null +++ b/plugins/chargen.c @@ -0,0 +1,110 @@ +/* Optional inetd plugin for the Character Generator Protocol, RFC 864 + * + * Copyright (c) 2016 Joachim Nilsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include /* STDIN_FILENO */ +#include + +#include "../plugin.h" + +#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " + +static char *generator(char *buf, size_t len) +{ + size_t num; + static size_t pos = 0; + const char pattern[] = PATTERN; + + len = 72; + if (pos + len > sizeof(pattern)) { + num = sizeof(pattern) - pos; + len -= num; + } else { + num = 72; + len = 0; + } + + strncpy(&buf[0], &pattern[pos], num--); + if (len++) + strncpy(&buf[num], pattern, len); + strcat(buf, "\r\n"); + + if (++pos >= sizeof(pattern) - 1) + pos = 0; + + return buf; +} + +static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len) +{ + len = recvfrom(sd, buf, len, MSG_DONTWAIT, sa, sa_len); + if (-1 == len) + return -1; /* On error, close connection. */ + + return 0; +} + +static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len) +{ + char *pattern = generator(buf, len); + + return sendto(sd, pattern, strlen(pattern), MSG_DONTWAIT, sa, sa_len); +} + +static int cb(int type) +{ + int sd = STDIN_FILENO; + ssize_t len; + char buf[BUFSIZ]; + struct sockaddr_storage sa; + socklen_t sa_len = sizeof(sa); + + if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len)) + return -1; + + return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len); +} + +static plugin_t plugin = { + .name = "chargen", /* Must match the inetd /etc/services entry */ + .inetd = { + .cmd = cb + }, +}; + +PLUGIN_INIT(plugin_init) +{ + plugin_register(&plugin); +} + +PLUGIN_EXIT(plugin_exit) +{ + plugin_unregister(&plugin); +} + +/** + * Local Variables: + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */