- Add startup-config(5) manpage [FIXME].
authorBrendan O'Dea <bod@optus.net>
Wed, 17 Nov 2004 08:23:34 +0000 (08:23 +0000)
committerBrendan O'Dea <bod@optus.net>
Wed, 17 Nov 2004 08:23:34 +0000 (08:23 +0000)
- Revise nsctl to allow arbitrary strings/args to be passed to plugins.

17 files changed:
Changes
Docs/l2tpns.8 [new file with mode: 0644]
Docs/nsctl.8 [new file with mode: 0644]
Makefile
autosnoop.c
autothrottle.c
control.c
control.h
garden.c
l2tpns.8 [deleted file]
l2tpns.c
l2tpns.spec
nsctl.8 [deleted file]
nsctl.c
plugin.h
setrxspeed.c
stripdomain.c

diff --git a/Changes b/Changes
index e64d7af..dcc3e40 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,12 +1,12 @@
-* ?
-- Add manpages from Jonathan McDowell
-- Remove reference to old -a command line argument
-
-* Tue Nov 16 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.8
+* Wed Nov 17 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.8
 - Ignore gateway address in Framed-Route (from Jonathan McDowell).
 - Call sessionshutdown() when a tunnel is dropped rather than
   sessionkill() to ensure that RADIUS stop records are sent.
 - Cleanup: make a bunch of global functions/variables static.
+- Remove reference to old -a command line argument.
+- Add l2tpns(8) and nsctl(8) manpages from Jonathan McDowell.
+- Add startup-config(5) manpage [FIXME].
+- Revise nsctl to allow arbitrary strings/args to be passed to plugins.
 
 * Mon Nov 15 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.7
 - Fix socket creation in host_unreachable() (thanks to Bjørn Augestad)
diff --git a/Docs/l2tpns.8 b/Docs/l2tpns.8
new file mode 100644 (file)
index 0000000..537fa08
--- /dev/null
@@ -0,0 +1,64 @@
+.\" -*- nroff -*-
+.de Id
+.ds Dt \\$4 \\$5
+..
+.Id $Id: l2tpns.8,v 1.1 2004-11-17 08:23:35 bodea Exp $
+.TH L2TPNS 8 "\*(Dt" L2TPNS "System Management Commands"
+.SH NAME
+l2tpns \- L2TP LNS daemon
+.SH SYNOPSIS
+.B l2tpns
+.RB [ \-d ]
+.RB [ \-v ]
+.RB [ \-c
+.IR file ]
+.RB [ \-h
+.IR hostname ]
+.SH DESCRIPTION
+This manual page documents briefly the
+.B l2tpns
+command.
+.PP
+.B l2tpns
+is an L2TP LNS daemon that doesn't require kernel support for PPP or
+L2TP, nor any kernel patches.  For more information on L2TP see RFC
+2661.
+.PP
+Once running,
+.B l2tpns
+may be controlled by telnetting to port 23 on the machine running the
+daemon and with the
+.B nsctl
+utility.
+.SH OPTIONS
+.TP
+.B \-d
+Detach from terminal and fork into the background. By default l2tpns
+will stay in the foreground.
+.TP
+.B \-v
+Increase verbosity for debugging. Can be used multiple times.
+.TP
+.BI "\-c " file
+Specify configuration file.
+.TP
+.BI "\-h " hostname
+Force hostname to
+.IR hostname .
+.SH FILES
+.TP
+.I /etc/l2tpns/startup-config
+The default configuration file.
+.TP
+.I /etc/l2tpns/ip_pool
+IP address pool configuration.
+.TP
+.I /etc/l2tpns/users
+Username/password configuration for access to admin interface.
+.SH SEE ALSO
+.BR startup-config (5),
+and
+.BR nsctl (8)
+.SH AUTHOR
+This manual page was written by Jonathan McDowell <noodles@earth.li>,
+for the Debian GNU/Linux system (but may be used by others).
diff --git a/Docs/nsctl.8 b/Docs/nsctl.8
new file mode 100644 (file)
index 0000000..ec2d7df
--- /dev/null
@@ -0,0 +1,67 @@
+.\" -*- nroff -*-
+.de Id
+.ds Dt \\$4 \\$5
+..
+.Id $Id: nsctl.8,v 1.1 2004-11-17 08:23:35 bodea Exp $
+.TH NSCTL 8 "\*(Dt" L2TPNS "System Management Commands"
+.SH NAME
+nsctl \- Issue commands to l2tpns plugins
+.SH SYNOPSIS
+.B nsctl
+.RB [ \-d ]
+.RB [ \-h
+.IR host [: port ]]
+.RB [ \-t
+.IR timeout ]
+.I command
+.RI [ arg " ...]"
+.SH DESCRIPTION
+.B nsctl
+is part of the
+.B l2tpns
+package.  It allows the system administrator to send manage plugin
+features of a running l2tpns process.
+.SH OPTIONS
+.TP
+.B \-d
+Enable debugging output.
+.TP
+.B \-h \fIhost\fR[:\fIport\fR]
+The host running
+.B l2tpns
+that should receive the message.  By default the message is sent to
+UDP port 1702 on
+.BR localhost .
+.TP
+.B \-t \fItimeout\fR
+Timeout in seconds to wait for a response from the server.
+.SH COMMANDS
+The first argument specifies the command to send to
+.B l2tpns .
+The following commands are as defined:
+.TP
+.BI "load_plugin " plugin
+Load the named
+.IR plugin .
+.TP
+.BI "unload_plugin " plugin
+Unload the named
+.IR plugin .
+.TP
+.B help
+Each loaded plugin is queried for what commands it supports and the
+synopsis for each is output.
+.PP
+Any other value of
+.I command
+(and
+.I args
+if any)
+are sent to
+.B l2tpns
+as-is, to be passed to each plugin in turn (and possibly acted upon).
+.SH SEE ALSO
+.BR l2tpns (8)
+.SH AUTHOR
+This manual page was written by Jonathan McDowell <noodles@the.earth.li>,
+for the Debian GNU/Linux system (but may be used by others).
index cc3429c..3c203c1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,8 @@ DESTDIR =
 bindir = /usr/sbin
 etcdir = /etc/l2tpns
 libdir = /usr/lib/l2tpns
-mandir = /usr/share/man/man8
+man5dir = /usr/share/man/man5
+man8dir = /usr/share/man/man8
 statedir = /var/lib/l2tpns
 
 DEFINES =
@@ -84,9 +85,14 @@ bounce:      test/bounce.o
 
 install: all
        $(INSTALL) -m 0755 l2tpns $(DESTDIR)$(bindir)/l2tpns
-       $(INSTALL) -m 0644 l2tpns.8 $(DESTDIR)$(mandir)/l2tpns.8
        $(INSTALL) -m 0755 nsctl $(DESTDIR)$(bindir)/nsctl
-       $(INSTALL) -m 0644 nsctl.8 $(DESTDIR)$(mandir)/nsctl.8
+
+       $(INSTALL) -m 0644 Docs/startup-config.5 $(DESTDIR)$(man5dir)/startup-config.5
+       $(INSTALL) -m 0644 Docs/l2tpns.8 $(DESTDIR)$(man8dir)/l2tpns.8
+       $(INSTALL) -m 0644 Docs/nsctl.8 $(DESTDIR)$(man8dir)/nsctl.8
+
+       gzip $(DESTDIR)$(man5dir)/*.5 $(DESTDIR)$(man8dir)/*.8
+
        @if [ -f $(DESTDIR)$(etcdir)/startup-config ]; then \
                echo '***' Installing default config files in $(DESTDIR)$(etcdir) as .defaults; \
                suffix=.default; \
@@ -115,7 +121,7 @@ bgp.o: bgp.c l2tpns.h bgp.h util.h
 cli.o: cli.c l2tpns.h util.h cluster.h tbf.h ll.h bgp.h
 cluster.o: cluster.c l2tpns.h cluster.h util.h tbf.h bgp.h
 constants.o: constants.c constants.h
-control.o: control.c control.h
+control.o: control.c l2tpns.h control.h
 icmp.o: icmp.c l2tpns.h
 l2tpns.o: l2tpns.c md5.h l2tpns.h cluster.h plugin.h ll.h constants.h \
   control.h util.h tbf.h bgp.h
index 910a569..beb8f8d 100644 (file)
@@ -4,9 +4,9 @@
 
 /* set up intercept based on RADIUS reply */
 
-char const *cvs_id = "$Id: autosnoop.c,v 1.7 2004-11-09 08:05:02 bodea Exp $";
+char const *cvs_id = "$Id: autosnoop.c,v 1.8 2004-11-17 08:23:34 bodea Exp $";
 
-int __plugin_api_version = PLUGIN_API_VERSION;
+int plugin_api_version = PLUGIN_API_VERSION;
 struct pluginfuncs *p;
 
 int plugin_radius_response(struct param_radius_response *data)
index 9980011..9973a4f 100644 (file)
@@ -4,9 +4,9 @@
 
 /* set up throttling based on RADIUS reply */
 
-char const *cvs_id = "$Id: autothrottle.c,v 1.8 2004-11-09 08:05:02 bodea Exp $";
+char const *cvs_id = "$Id: autothrottle.c,v 1.9 2004-11-17 08:23:34 bodea Exp $";
 
-int __plugin_api_version = PLUGIN_API_VERSION;
+int plugin_api_version = PLUGIN_API_VERSION;
 struct pluginfuncs *p;
 
 #define THROTTLE_KEY "lcp:interface-config"
index db86e2d..45657d8 100644 (file)
--- a/control.c
+++ b/control.c
 // L2TPNS: control
 
-char const *cvs_id_control = "$Id: control.c,v 1.2 2004-06-28 02:43:13 fred_nerk Exp $";
-
-#include <stdio.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <malloc.h>
-#include <netdb.h>
+char const *cvs_id_control = "$Id: control.c,v 1.3 2004-11-17 08:23:34 bodea Exp $";
+
 #include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
+#include "l2tpns.h"
 #include "control.h"
 
-int new_packet(short type, char *packet)
+int pack_control(char *data, int len, u8 type, int argc, char *argv[])
 {
-       int id = (time(NULL) ^ (rand() * 1024*1024));
+    struct nsctl_packet pkt;
+    struct nsctl_args arg;
+    char *p = pkt.argv;
+    int sz = (p - (char *) &pkt);
+
+    if (len > sizeof(pkt))
+       len = sizeof(pkt);
+
+    if (argc > 0xff)
+       argc = 0xff; // paranoia
+
+    pkt.magic = ntohs(NSCTL_MAGIC);
+    pkt.type = type;
+    pkt.argc = argc;
+
+    while (argc-- > 0)
+    {
+       char *a = *argv++;
+       int s = strlen(a);
+
+       if (s > sizeof(arg.value))
+               s = sizeof(arg.value); // silently truncate
+
+       arg.len = s;
+       s += sizeof(arg.len);
+
+       if (sz + s > len)
+           return -1; // overflow
 
-       *(short *)(packet + 0) = ntohs(0x9012);
-       *(short *)(packet + 2) = ntohs(type);
-       *(int *)(packet + 6) = ntohl(id);
+       if (arg.len)
+           memcpy(arg.value, a, arg.len);
 
-       return 10;
+       memcpy(p, &arg, s);
+       sz += s;
+       p += s;
+    }
+
+    /*
+     * terminate:  this is both a sanity check and additionally
+     * ensures that there's a spare byte in the packet to null
+     * terminate the last argument when unpacking (see unpack_control)
+     */
+    if (sz + sizeof(arg.len) > len)
+       return -1; // overflow
+
+    arg.len = 0xff;
+    memcpy(p, &arg.len, sizeof(arg.len));
+
+    sz += sizeof(arg.len);
+    memcpy(data, &pkt, sz);
+
+    return sz;
 }
 
-int send_packet(int sockfd, int dest_ip, int dest_port, char *packet, int len)
+int unpack_control(struct nsctl *control, char *data, int len)
 {
-       struct sockaddr_in addr;
+    struct nsctl_packet pkt;
+    char *p = pkt.argv;
+    int sz = (p - (char *) &pkt);
+    int i;
+
+    if (len < sz)
+       return NSCTL_ERR_SHORT;
+
+    if (len > sizeof(pkt))
+       return NSCTL_ERR_LONG;
+
+    memcpy(&pkt, data, len);
+    if (ntohs(pkt.magic) != NSCTL_MAGIC)
+       return NSCTL_ERR_MAGIC;
+
+    switch (pkt.type)
+    {
+    case NSCTL_REQ_LOAD:
+    case NSCTL_REQ_UNLOAD:
+    case NSCTL_REQ_HELP:
+    case NSCTL_REQ_CONTROL:
+    case NSCTL_RES_OK:
+    case NSCTL_RES_ERR:
+       control->type = pkt.type;
+       break;
 
-       *(short *)(packet + 4) = ntohs(len);
+    default:
+       return NSCTL_ERR_TYPE;
+    }
 
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-       *(int*)&addr.sin_addr = htonl(dest_ip);
-       addr.sin_port = htons(dest_port);
-       if (sendto(sockfd, packet, len, 0, (void *) &addr, sizeof(addr)) < 0)
+    control->argc = pkt.argc;
+    for (i = 0; i <= control->argc; i++)
+    {
+       unsigned s;
+
+       if (len < sz + 1)
+           return NSCTL_ERR_SHORT;
+
+       s = (u8) *p;
+       *p++ = 0; // null terminate previous arg
+       sz++;
+
+       if (i < control->argc)
+       {
+           if (len < sz + s)
+               return NSCTL_ERR_SHORT;
+
+           control->argv[i] = p;
+           p += s;
+           sz += s;
+       }
+       else
        {
-               perror("sendto");
-               return 0;
+           /* check for terminator */
+           if (s != 0xff)
+               return NSCTL_ERR_SHORT;
        }
-       return 1;
-}
+    }
 
-int read_packet(int sockfd, char *packet)
-{
-       struct sockaddr_in addr;
-       int alen = sizeof(addr);
-       memset(&addr, 0, sizeof(addr));
-       return recvfrom(sockfd, packet, 1400, 0, (void *) &addr, &alen);
+    if (sz != len)
+       return NSCTL_ERR_LONG; // trailing cr*p
+
+    return control->type;
 }
 
-void dump_packet(char *packet, FILE *stream)
+void dump_control(struct nsctl *control, FILE *stream)
 {
-       if (htons(*(short *)(packet + 0)) != 0x9012)
-       {
-               fprintf(stream, "Invalid packet identifier %x\n", htons(*(short *)(packet + 0)));
-               return;
-       }
-       fprintf(stream, "Control packet:\n");
-       fprintf(stream, "       Type: %d\n", htons(*(short *)(packet + 2)));
-       fprintf(stream, "       Length: %d\n", htons(*(short *)(packet + 4)));
-       fprintf(stream, "       Identifier: %x\n", htonl(*(int *)(packet + 6)));
-       fprintf(stream, "\n");
-}
+    char *type = "*unknown*";
 
+    if (!stream)
+       stream = stdout;
 
+    switch (control->type)
+    {
+    case NSCTL_REQ_LOAD:       type = "NSCTL_REQ_LOAD";        break;
+    case NSCTL_REQ_UNLOAD:     type = "NSCTL_REQ_UNLOAD";      break;
+    case NSCTL_REQ_HELP:       type = "NSCTL_REQ_HELP";        break;
+    case NSCTL_REQ_CONTROL:    type = "NSCTL_REQ_CONTROL";     break;
+    case NSCTL_RES_OK:         type = "NSCTL_RES_OK";          break;
+    case NSCTL_RES_ERR:                type = "NSCTL_RES_ERR";         break;
+    }
+
+    fprintf(stream, "Control packet:\n");
+    fprintf(stream, "  Type: %d (%s)\n", (int) control->type, type);
+    fprintf(stream, "  Args: %d", (int) control->argc);
+    if (control->argc)
+    {
+       int i;
+       fprintf(stream, " (\"");
+       for (i = 0; i < control->argc; i++)
+           fprintf(stream, "%s%s", i ? "\", \"" : "", control->argv[i]);
+
+       fprintf(stream, "\")");
+    }
+
+    fprintf(stream, "\n\n");
+}
index 60e0d03..8dd159c 100644 (file)
--- a/control.h
+++ b/control.h
@@ -1,18 +1,54 @@
 #ifndef __CONTROL_H__
 #define __CONTROL_H__
 
-#define PKT_RESP_OK            1
-#define PKT_RESP_ERROR         2
+#define NSCTL_PORT             1702
+#define NSCTL_MAGIC            0x9013
 
-#define PKT_LOAD_PLUGIN                5
-#define PKT_UNLOAD_PLUGIN      6
+/* builtin commands */
+#define NSCTL_REQUEST          (1 << 4)
+#define NSCTL_REQ_LOAD         (NSCTL_REQUEST | 1)
+#define NSCTL_REQ_UNLOAD       (NSCTL_REQUEST | 2)
+#define NSCTL_REQ_HELP         (NSCTL_REQUEST | 3)
 
-#define PKT_GARDEN             1000
-#define PKT_UNGARDEN           1001
+/* general control message, passed to plugins */
+#define NSCTL_REQ_CONTROL      (NSCTL_REQUEST | 4)
 
-int new_packet(short type, char *packet);
-int send_packet(int sockfd, int dest_ip, int dest_port, char *packet, int len);
-void dump_packet(char *packet, FILE *stream);
-int read_packet(int sockfd, char *packet);
+/* response messages */
+#define NSCTL_RESPONSE         (1 << 5)
+#define NSCTL_RES_OK           (NSCTL_RESPONSE | 1)
+#define NSCTL_RES_ERR          (NSCTL_RESPONSE | 2)
+
+/* unpack errors */
+#define NSCTL_ERR_SHORT                -1      // short packet
+#define NSCTL_ERR_LONG         -2      // packet exceeds max, or trailing cr*p
+#define NSCTL_ERR_MAGIC                -3      // invalid magic number
+#define NSCTL_ERR_TYPE         -4      // unrecognised type
+
+#define NSCTL_MAX_PKT_SZ       4096
+
+struct nsctl_packet {
+    u16 magic;
+    u8 type;
+    u8 argc;
+    char argv[NSCTL_MAX_PKT_SZ - 4];
+} __attribute__ ((packed));
+
+#define NSCTL_MAX_ARG_SZ       512
+
+struct nsctl_args {
+    u8 len;
+    char value[NSCTL_MAX_ARG_SZ - 1];
+} __attribute__ ((packed));
+
+/* parsed packet */
+struct nsctl {
+    u8 type;
+    u8 argc;
+    char *argv[0xff];
+};
+
+int pack_control(char *data, int len, u8 type, int argc, char *argv[]);
+int unpack_control(struct nsctl *packet, char *data, int len);
+void dump_control(struct nsctl *control, FILE *stream);
 
 #endif /* __CONTROL_H__ */
index 92320a7..ba228cd 100644 (file)
--- a/garden.c
+++ b/garden.c
@@ -9,9 +9,9 @@
 
 /* walled garden */
 
-char const *cvs_id = "$Id: garden.c,v 1.12 2004-11-09 08:05:02 bodea Exp $";
+char const *cvs_id = "$Id: garden.c,v 1.13 2004-11-17 08:23:34 bodea Exp $";
 
-int __plugin_api_version = PLUGIN_API_VERSION;
+int plugin_api_version = PLUGIN_API_VERSION;
 static struct pluginfuncs *p = 0;
 
 static int iam_master = 0;     // We're all slaves! Slaves I tell you!
@@ -75,46 +75,62 @@ int plugin_kill_session(struct param_new_session *data)
        return PLUGIN_RET_OK;
 }
 
+char *plugin_control_help[] = {
+       "  garden USER|SID       Put user into the walled garden",
+       "  ungarden USER|SID     Release user",
+       0
+};
+
 int plugin_control(struct param_control *data)
 {
-       sessiont *s;
        sessionidt session;
+       sessiont *s = 0;
+       int flag;
+       char *end;
+
+       if (data->argc < 1 || (strcmp(data->argv[0], "garden") && strcmp(data->argv[0], "ungarden")))
+               return PLUGIN_RET_OK; // not for us
+
+       flag = data->argv[0][0] == 'g';
 
        if (!iam_master)        // All garden processing happens on the master.
-               return PLUGIN_RET_OK;
+       {
+               data->response = NSCTL_RES_ERR;
+               data->additional = "must be run on the cluster master";
+               return PLUGIN_RET_STOP;
+       }
 
-       if (data->type != PKT_GARDEN && data->type != PKT_UNGARDEN)
-               return PLUGIN_RET_OK;
+       if (data->argc != 2)
+       {
+               data->response = NSCTL_RES_ERR;
+               data->additional = "one argument required: username or session id";
+               return PLUGIN_RET_STOP;
+       }
 
-       if (!data->data && data->data_length)
-               return PLUGIN_RET_OK;
+       if (!(session = strtol(data->argv[0], &end, 10)) || *end)
+               session = p->get_session_by_username(data->argv[0]);
 
-       session = atoi((char*)(data->data));
-       if (!session)
-               return PLUGIN_RET_OK;
+       if (session)
+               s = p->get_session_by_id(session);
 
-       data->send_response = 1;
-       s = p->get_session_by_id(session);
        if (!s || !s->ip)
        {
-               char *errormsg = "Session not connected";
-               *(short *)(data->response + 2) = ntohs(PKT_RESP_ERROR);
-               sprintf((data->response + data->response_length), "%s", errormsg);
-               data->response_length += strlen(errormsg) + 1;
-
-               p->log(3, 0, 0, 0, "Unknown session %d\n", session);
+               data->response = NSCTL_RES_ERR;
+               data->additional = "session not found";
                return PLUGIN_RET_STOP;
        }
-       *(short *)(data->response + 2) = ntohs(PKT_RESP_OK);
 
-       if (!(garden_session(s, (data->type == PKT_GARDEN))))
+       if (s->walled_garden == flag)
        {
-               char *errormsg = "User not connected";
-               *(short *)(data->response + 2) = ntohs(PKT_RESP_ERROR);
-               sprintf((data->response + data->response_length), "%s", errormsg);
-               data->response_length += strlen(errormsg) + 1;
+               data->response = NSCTL_RES_ERR;
+               data->additional = flag ? "already in walled garden" : "not in walled garden";
+               return PLUGIN_RET_STOP;
        }
 
+       garden_session(s, flag);
+       data->response = NSCTL_RES_OK;
+       data->additional = 0;
+
        return PLUGIN_RET_STOP;
 }
 
@@ -136,7 +152,10 @@ int plugin_become_master(void)
 int plugin_new_session_master(sessiont * s)
 {      
        if (s->walled_garden)
+       {
+               s->walled_garden = 0;
                garden_session(s, 1);
+       }
 
        return PLUGIN_RET_OK;
 }
diff --git a/l2tpns.8 b/l2tpns.8
deleted file mode 100644 (file)
index 1f6c687..0000000
--- a/l2tpns.8
+++ /dev/null
@@ -1,68 +0,0 @@
-.\"                                      Hey, EMACS: -*- nroff -*-
-.\" First parameter, NAME, should be all caps
-.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
-.\" other parameters are allowed: see man(7), man(1)
-.TH L2TPNS 8 "November 16, 2004"
-.\" Please adjust this date whenever revising the manpage.
-.\"
-.\" Some roff macros, for reference:
-.\" .nh        disable hyphenation
-.\" .hy        enable hyphenation
-.\" .ad l      left justify
-.\" .ad b      justify to both left and right margins
-.\" .nf        disable filling
-.\" .fi        enable filling
-.\" .br        insert line break
-.\" .sp <n>    insert n+1 empty lines
-.\" for manpage-specific macros, see man(7)
-.SH NAME
-l2tpns \- L2TP LNS daemon
-.SH SYNOPSIS
-.B l2tpns
-[ \fB-d\fR ] [ \fB-c\fR \fI<file>\fR ] [ \fB-h\fR \fI<hostname>\fR ] [ \fB-a\fR \fI<address>\fR ] [ \fB-v\fR ]
-.br
-.SH DESCRIPTION
-This manual page documents briefly the
-.B l2tpns
-command.
-.PP
-.\" TeX users may be more comfortable with the \fB<whatever>\fP and
-.\" \fI<whatever>\fP escape sequences to invode bold face and italics, 
-.\" respectively.
-\fBl2tpns\fP is an L2TP LNS daemon that doesn't require kernel support
-for PPP or L2TP, nor any kernel patches. For more information on L2TP see
-RFC 2661.
-.PP
-Once running l2tpns can be controlled by telnetting to port 23 on the
-machine running the daemon.
-.SH OPTIONS
-.TP
-.B \-d
-Detach from terminal and fork into the background. By default l2tpns
-will stay in the foreground.
-.TP
-.B \-c <file>
-Specify config file.
-.TP
-.B \-h <hostname>
-Force hostname to <hostname>.
-.TP
-.B \-v
-Increase verbosity for debugging. Can be used multiple times.
-.br
-.SH FILES
-.TP
-\fB\fI/etc/l2tpns/startup-config\fR
-The default configuration file.
-.TP
-\fB\fI/etc/l2tpns/ip_pool\fR
-IP address pool configuration.
-.TP
-\fB\fI/etc/l2tpns/users\fR
-Username/password configuration for access to admin interface.
-.SH SEE ALSO
-\fInsctl\fR(8)
-.SH AUTHOR
-This manual page was written by Jonathan McDowell <noodles@earth.li>,
-for the Debian GNU/Linux system (but may be used by others).
-
index a6bff01..facecab 100644 (file)
--- a/l2tpns.c
+++ b/l2tpns.c
@@ -4,7 +4,7 @@
 // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
 // vim: sw=8 ts=8
 
-char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.50 2004-11-16 21:54:46 fred_nerk Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.51 2004-11-17 08:23:34 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <assert.h>
@@ -167,10 +167,10 @@ static void build_chap_response(char *challenge, u8 id, u16 challenge_length, ch
 static void update_config(void);
 static void read_config_file(void);
 static void initplugins(void);
-static void add_plugin(char *plugin_name);
-static void remove_plugin(char *plugin_name);
+static int add_plugin(char *plugin_name);
+static int remove_plugin(char *plugin_name);
 static void plugins_done(void);
-static void processcontrol(u8 * buf, int len, struct sockaddr_in *addr);
+static void processcontrol(u8 * buf, int len, struct sockaddr_in *addr, int alen);
 static tunnelidt new_tunnel(void);
 static int unhide_avp(u8 *avp, tunnelidt t, sessionidt s, u16 length);
 
@@ -434,8 +434,8 @@ static void initudp(void)
        // Control
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
-       addr.sin_port = htons(1702);
-       controlfd = socket(AF_INET, SOCK_DGRAM, 17);
+       addr.sin_port = htons(NSCTL_PORT);
+       controlfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        setsockopt(controlfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        if (bind(controlfd, (void *) &addr, sizeof(addr)) < 0)
        {
@@ -2324,7 +2324,7 @@ static void mainloop(void)
                        }
 
                        if (FD_ISSET(controlfd, &r))
-                               processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr);
+                               processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
 
                        if (FD_ISSET(clifd, &r))
                        {
@@ -2934,31 +2934,31 @@ int main(int argc, char *argv[])
        {
                switch (i)
                {
-                       case 'd':
-                               if (fork()) exit(0);
-                               setsid();
-                               freopen("/dev/null", "r", stdin);
-                               freopen("/dev/null", "w", stdout);
-                               freopen("/dev/null", "w", stderr);
-                               break;
-                       case 'v':
-                               optdebug++;
-                               break;
-                       case 'c':
-                               optconfig = optarg;
-                               break;
-                       case 'h':
-                               snprintf(hostname, sizeof(hostname), "%s", optarg);
-                               break;
-                       default:
-                               printf("Args are:\n"
-                                      "\t-d\t\tDetach from terminal\n"
-                                      "\t-c <file>\tConfig file\n"
-                                      "\t-h <hostname>\tForce hostname\n"
-                                      "\t-v\t\tDebug\n");
-
-                               return (0);
-                               break;
+               case 'd':
+                       if (fork()) exit(0);
+                       setsid();
+                       freopen("/dev/null", "r", stdin);
+                       freopen("/dev/null", "w", stdout);
+                       freopen("/dev/null", "w", stderr);
+                       break;
+               case 'v':
+                       optdebug++;
+                       break;
+               case 'c':
+                       optconfig = optarg;
+                       break;
+               case 'h':
+                       snprintf(hostname, sizeof(hostname), "%s", optarg);
+                       break;
+               default:
+                       printf("Args are:\n"
+                              "\t-d\t\tDetach from terminal\n"
+                              "\t-c <file>\tConfig file\n"
+                              "\t-h <hostname>\tForce hostname\n"
+                              "\t-v\t\tDebug\n");
+
+                       return (0);
+                       break;
                }
        }
 
@@ -3751,7 +3751,7 @@ static void *getconfig(char *key, enum config_typet type)
        return 0;
 }
 
-static void add_plugin(char *plugin_name)
+static int add_plugin(char *plugin_name)
 {
        static struct pluginfuncs funcs = {
                _log,
@@ -3773,22 +3773,22 @@ static void add_plugin(char *plugin_name)
        if (!p)
        {
                LOG(1, 0, 0, 0, "   Plugin load failed: %s\n", dlerror());
-               return;
+               return -1;
        }
 
        if (ll_contains(loaded_plugins, p))
        {
                dlclose(p);
-               return;
+               return 0; // already loaded
        }
 
        {
-               int *v = dlsym(p, "__plugin_api_version");
+               int *v = dlsym(p, "plugin_api_version");
                if (!v || *v != PLUGIN_API_VERSION)
                {
                        LOG(1, 0, 0, 0, "   Plugin load failed: API version mismatch: %s\n", dlerror());
                        dlclose(p);
-                       return;
+                       return -1;
                }
        }
 
@@ -3798,7 +3798,7 @@ static void add_plugin(char *plugin_name)
                {
                        LOG(1, 0, 0, 0, "   Plugin load failed: plugin_init() returned FALSE: %s\n", dlerror());
                        dlclose(p);
-                       return;
+                       return -1;
                }
        }
 
@@ -3815,6 +3815,7 @@ static void add_plugin(char *plugin_name)
        }
 
        LOG(2, 0, 0, 0, "   Loaded plugin %s\n", plugin_name);
+       return 1;
 }
 
 static void run_plugin_done(void *plugin)
@@ -3825,29 +3826,32 @@ static void run_plugin_done(void *plugin)
                donefunc();
 }
 
-static void remove_plugin(char *plugin_name)
+static int remove_plugin(char *plugin_name)
 {
        void *p = open_plugin(plugin_name, 0);
-       int i;
+       int loaded = 0;
 
        if (!p)
-               return;
-
-       for (i = 0; i < max_plugin_functions; i++)
-       {
-               void *x;
-               if (plugin_functions[i] && (x = dlsym(p, plugin_functions[i])))
-                       ll_delete(plugins[i], x);
-       }
+               return -1;
 
        if (ll_contains(loaded_plugins, p))
        {
+               int i;
+               for (i = 0; i < max_plugin_functions; i++)
+               {
+                       void *x;
+                       if (plugin_functions[i] && (x = dlsym(p, plugin_functions[i])))
+                               ll_delete(plugins[i], x);
+               }
+
                ll_delete(loaded_plugins, p);
                run_plugin_done(p);
+               loaded = 1;
        }
 
        dlclose(p);
        LOG(2, 0, 0, 0, "Removed plugin %s\n", plugin_name);
+       return loaded;
 }
 
 int run_plugins(int plugin_type, void *data)
@@ -3875,39 +3879,149 @@ static void plugins_done()
                run_plugin_done(p);
 }
 
-static void processcontrol(u8 * buf, int len, struct sockaddr_in *addr)
+static void processcontrol(u8 * buf, int len, struct sockaddr_in *addr, int alen)
 {
-       char *resp;
-       int l;
-       struct param_control param = { buf, len, ntohl(addr->sin_addr.s_addr), ntohs(addr->sin_port), NULL, 0, 0 };
-
+       struct nsctl request;
+       struct nsctl response;
+       int type = unpack_control(&request, buf, len);
+       int r;
+       void *p;
 
        if (log_stream && config->debug >= 4)
        {
-               LOG(4, ntohl(addr->sin_addr.s_addr), 0, 0, "Received ");
-               dump_packet(buf, log_stream);
+               if (type < 0)
+               {
+                       LOG(4, ntohl(addr->sin_addr.s_addr), 0, 0, "Bogus control message (%d)\n", type);
+               }
+               else
+               {
+                       LOG(4, ntohl(addr->sin_addr.s_addr), 0, 0, "Received ");
+                       dump_control(&request, log_stream);
+               }
        }
 
-       resp = calloc(1400, 1);
-       l = new_packet(PKT_RESP_ERROR, resp);
-       *(int *)(resp + 6) = *(int *)(buf + 6);
+       switch (type)
+       {
+       case NSCTL_REQ_LOAD:
+               if (request.argc != 1)
+               {
+                       response.type = NSCTL_RES_ERR;
+                       response.argc = 1;
+                       response.argv[0] = "name of plugin required";
+               }
+               else if ((r = add_plugin(request.argv[0])) < 1)
+               {
+                       response.type = NSCTL_RES_ERR;
+                       response.argc = 1;
+                       response.argv[0] = !r
+                               ? "plugin already loaded"
+                               : "error loading plugin";
+               }
+               else
+               {
+                       response.type = NSCTL_RES_OK;
+                       response.argc = 0;
+               }
+
+               break;
+
+       case NSCTL_REQ_UNLOAD:
+               if (request.argc != 1)
+               {
+                       response.type = NSCTL_RES_ERR;
+                       response.argc = 1;
+                       response.argv[0] = "name of plugin required";
+               }
+               else if ((r = remove_plugin(request.argv[0])) < 1)
+               {
+                       response.type = NSCTL_RES_ERR;
+                       response.argc = 1;
+                       response.argv[0] = !r
+                               ? "plugin not loaded"
+                               : "plugin not found";
+               }
+               else
+               {
+                       response.type = NSCTL_RES_OK;
+                       response.argc = 0;
+               }
+
+               break;
+
+       case NSCTL_REQ_HELP:
+               response.type = NSCTL_RES_OK;
+               response.argc = 0;
+
+               ll_reset(loaded_plugins);
+               while ((p = ll_next(loaded_plugins)))
+               {
+                       char **help = dlsym(p, "plugin_control_help");
+                       while (response.argc < 0xff && help && *help)
+                               response.argv[response.argc++] = *help++;
+               }
+
+               break;
+
+       case NSCTL_REQ_CONTROL:
+               {
+                       struct param_control param = { request.argc, request.argv, 0, NULL };
+                       if (!run_plugins(PLUGIN_CONTROL, &param))
+                       {
+                               response.type = NSCTL_RES_ERR;
+                               response.argc = 1;
+                               response.argv[0] = param.additional
+                                       ? param.additional
+                                       : "error returned by plugin";
+                       }
+                       else if (!(param.response & NSCTL_RESPONSE))
+                       {
+                               response.type = NSCTL_RES_ERR;
+                               response.argc = 1;
+                               response.argv[0] = param.response
+                                       ? "unrecognised response value from plugin"
+                                       : "unhandled action";
+                       }
+                       else
+                       {
+                               response.type = param.response;
+                               response.argc = 0;
+                               if (param.additional)
+                               {
+                                       response.argc = 1;
+                                       response.argv[0] = param.additional;
+                               }
+                       }
+               }
 
-       param.type = ntohs(*(short *)(buf + 2));
-       param.id = ntohl(*(int *)(buf + 6));
-       param.data_length = ntohs(*(short *)(buf + 4)) - 10;
-       param.data = (param.data_length > 0) ? (char *)(buf + 10) : NULL;
-       param.response = resp;
-       param.response_length = l;
+               break;
 
-       run_plugins(PLUGIN_CONTROL, &param);
+       default:
+               response.type = NSCTL_RES_ERR;
+               response.argc = 1;
+               response.argv[0] = "error unpacking control packet";
+       }
 
-       if (param.send_response)
+       buf = calloc(NSCTL_MAX_PKT_SZ, 1);
+       if (!buf)
        {
-               send_packet(controlfd, ntohl(addr->sin_addr.s_addr), ntohs(addr->sin_port), param.response, param.response_length);
-               LOG(4, ntohl(addr->sin_addr.s_addr), 0, 0, "Sent Control packet response\n");
+               LOG(2, ntohl(addr->sin_addr.s_addr), 0, 0, "Failed to allocate nsctl response\n");
+               return;
        }
 
-       free(resp);
+       r = pack_control(buf, NSCTL_MAX_PKT_SZ, response.type, response.argc, response.argv);
+       if (r > 0)
+       {
+               sendto(controlfd, buf, r, 0, (const struct sockaddr *) addr, alen);
+               if (log_stream && config->debug >= 4)
+               {
+                       LOG(4, ntohl(addr->sin_addr.s_addr), 0, 0, "Sent ");
+                       dump_control(&response, log_stream);
+               }
+       }
+       else
+               LOG(2, ntohl(addr->sin_addr.s_addr), 0, 0, "Failed to pack nsctl response (%d)\n", r);
+
+       free(buf);
 }
 
 static tunnelidt new_tunnel()
index 79bf046..d6c8f56 100644 (file)
@@ -39,7 +39,8 @@ rm -rf %{buildroot}
 %config(noreplace) /etc/l2tpns/ip_pool
 %attr(700,root,root) /usr/sbin/l2tpns
 %attr(755,root,root) /usr/lib/l2tpns
+%attr(644,root,root) /usr/share/man/man[58]/*
 
 %changelog
-* Mon Nov 15 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.8-1
+* Wed Nov 17 2004 Brendan O'Dea <bod@optusnet.com.au> 2.0.8-1
 - 2.0.8 release, see /usr/share/doc/l2tpns-2.0.8/Changes
diff --git a/nsctl.8 b/nsctl.8
deleted file mode 100644 (file)
index 9d79f56..0000000
--- a/nsctl.8
+++ /dev/null
@@ -1,41 +0,0 @@
-.\"                                      Hey, EMACS: -*- nroff -*-
-.\" First parameter, NAME, should be all caps
-.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
-.\" other parameters are allowed: see man(7), man(1)
-.TH NSCTL 8 "November 16, 2004"
-.\" Please adjust this date whenever revising the manpage.
-.\"
-.\" Some roff macros, for reference:
-.\" .nh        disable hyphenation
-.\" .hy        enable hyphenation
-.\" .ad l      left justify
-.\" .ad b      justify to both left and right margins
-.\" .nf        disable filling
-.\" .fi        enable filling
-.\" .br        insert line break
-.\" .sp <n>    insert n+1 empty lines
-.\" for manpage-specific macros, see man(7)
-.SH NAME
-nsctl \- Issue commands to l2tpns plugins
-.SH SYNOPSIS
-.B nsctl \fI<host>\fP \fI<command>\fP [ \fIargs...\fP ]
-.SH DESCRIPTION
-nsctl is part of the l2tpns package. It allows the system administrator
-to allow messages to be passed to l2tpns plugins.
-.SH OPTIONS
-.TP
-.B <host>
-The host running l2tpns that should receive the message.
-.TP
-.B <command>
-The command to send. Currently one of \fIload_plugin\fP,
-\fIunload_plugin\fP, \fIgarden\fP or \fIungarden\fP.
-\fIgarden\fP/\fIungarden\fP enable or disable the walled garden plugin
-for a particular user; they take a single argument which is the session
-id to affect.
-.SH SEE ALSO
-.BR l2tpns(8)
-.SH AUTHOR
-This manual page was written by Jonathan McDowell <noodles@the.earth.li>,
-for the Debian GNU/Linux system (but may be used by others).
-
diff --git a/nsctl.c b/nsctl.c
index aa6a300..2ad6a7a 100644 (file)
--- a/nsctl.c
+++ b/nsctl.c
+/* l2tpns plugin control */
+
 #include <stdio.h>
-#include <arpa/inet.h>
+#include <stdlib.h>
+#include <unistd.h>
 #include <errno.h>
-#include <fcntl.h>
-#include <malloc.h>
-#include <netdb.h>
 #include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
+#include <netdb.h>
 #include <signal.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
+
+#include "l2tpns.h"
 #include "control.h"
 
-struct { char *command; int pkt_type; int params; } commands[] = {
-       { "load_plugin", PKT_LOAD_PLUGIN, 1 },
-       { "unload_plugin", PKT_UNLOAD_PLUGIN, 1 },
-       { "garden", PKT_GARDEN, 1 },
-       { "ungarden", PKT_UNGARDEN, 1 },
+struct {
+    char *command;
+    char *usage;
+    int action;
+} builtins[] = {
+    { "load_plugin", " PLUGIN    Load named plugin",           NSCTL_REQ_LOAD },
+    { "unload_plugin", " PLUGIN  Unload named plugin",         NSCTL_REQ_UNLOAD },
+    { "help", "                  List available commands",     NSCTL_REQ_HELP },
+    { 0 }
 };
 
-char *dest_host = NULL;
-unsigned int dest_port = 1702;
-int udpfd;
+
+static int debug = 0;
+static int timeout = 2; // 2 seconds
+static char *me;
+
+#define USAGE() fprintf(stderr, "Usage: %s [-d] [-h HOST[:PORT]] [-t TIMEOUT] COMMAND [ARG ...]\n", me)
+
+static struct nsctl *request(char *host, int port, int type, int argc, char *argv[]);
 
 int main(int argc, char *argv[])
 {
-       int len = 0;
-       int dest_ip = 0;
-       int pkt_type = 0;
-       char *packet = NULL;
-       int i;
+    int req_type = 0;
+    char *host = 0;
+    int port;
+    int i;
+    char *p;
+    struct nsctl *res;
+
+    if ((p = strrchr((me = argv[0]), '/')))
+       me = p + 1;
+
+    opterr = 0;
+    while ((i = getopt(argc, argv, "dh:t:")) != -1)
+       switch (i)
+       {
+       case 'd':
+           debug++;
+           break;
 
-       setbuf(stdout, NULL);
+       case 'h':
+           host = optarg;
+           break;
 
-       if (argc < 3)
-       {
-               printf("Usage: %s <host> <command> [args...]\n", argv[0]);
-               return 1;
+       case 't':
+           timeout = atoi(optarg);
+           break;
+
+       default:
+           USAGE();
+           return EXIT_FAILURE;
        }
 
-       dest_host = strdup(argv[1]);
+    argc -= optind;
+    argv += optind;
 
-       {
-               // Init socket
-               int on = 1;
-               struct sockaddr_in addr;
-
-               memset(&addr, 0, sizeof(addr));
-               addr.sin_family = AF_INET;
-               addr.sin_port = htons(1703);
-               udpfd = socket(AF_INET, SOCK_DGRAM, 17);
-               setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-               if (bind(udpfd, (void *) &addr, sizeof(addr)) < 0)
-               {
-                       perror("bind");
-                       return(1);
-               }
-       }
+    if (argc < 1 || !argv[0][0])
+    {
+       USAGE();
+       return EXIT_FAILURE;
+    }
+
+    if (!host)
+       host = "127.0.0.1";
 
+    if ((p = strchr(host, ':')))
+    {
+       port = atoi(p + 1);
+       if (!port)
        {
-               struct hostent *h = gethostbyname(dest_host);
-               if (h) dest_ip = ntohl(*(unsigned int *)h->h_addr);
-               if (!dest_ip) dest_ip = ntohl(inet_addr(dest_host));
-               if (!dest_ip)
-               {
-                       printf("Can't resolve \"%s\"\n", dest_host);
-                       return 0;
-               }
+           fprintf(stderr, "%s: invalid port `%s'\n", me, p + 1);
+           return EXIT_FAILURE;
        }
 
-       if (!(packet = calloc(1400, 1)))
+       *p = 0;
+    }
+    else
+    {
+       port = NSCTL_PORT;
+    }
+
+    for (i = 0; !req_type && builtins[i].command; i++)
+       if (!strcmp(argv[0], builtins[i].command))
+           req_type = builtins[i].action;
+
+    if (req_type == NSCTL_REQ_HELP)
+    {
+       printf("Available commands:\n");
+       for (i = 0; builtins[i].command; i++)
+           printf("  %s%s\n", builtins[i].command, builtins[i].usage);
+    }
+
+    if (req_type)
+    {
+       argc--;
+       argv++;
+    }
+    else
+    {
+       req_type = NSCTL_REQ_CONTROL;
+    }
+
+    if ((res = request(host, port, req_type, argc, argv)))
+    {
+       FILE *stream = stderr;
+       int status = EXIT_FAILURE;
+
+       if (res->type == NSCTL_RES_OK)
        {
-               perror("calloc");
-               return(1);
+           stream = stdout;
+           status = EXIT_SUCCESS;
        }
 
-       srand(time(NULL));
+       for (i = 0; i < res->argc; i++)
+           fprintf(stream, "%s\n", res->argv[i]);
 
-       // Deal with command & params
-       for (i = 0; i < (sizeof(commands) / sizeof(commands[0])); i++)
-       {
-               if (strcasecmp(commands[i].command, argv[2]) == 0)
-               {
-                       int p;
-                       pkt_type = commands[i].pkt_type;
-                       len = new_packet(pkt_type, packet);
-                       if (argc < (commands[i].params + 3))
-                       {
-                               printf("Not enough parameters for %s\n", argv[2]);
-                               return 1;
-                       }
-                       for (p = 0; p < commands[i].params; p++)
-                       {
-                               strncpy((packet + len), argv[p + 3], 1400 - len - 1);
-                               len += strlen(argv[p + 3]) + 1;
-                       }
-                       break;
-               }
-       }
-       if (!pkt_type)
-       {
-               printf("Unknown command\n");
-               return 1;
-       }
+       return status;
+    }
+
+    return EXIT_FAILURE;
+}
 
-       send_packet(udpfd, dest_ip, dest_port, packet, len);
+static void sigalrm_handler(int sig) { }
 
+static struct nsctl *request(char *host, int port, int type, int argc, char *argv[])
+{
+    static struct nsctl res;
+    struct sockaddr_in peer;
+    socklen_t len = sizeof(peer);
+    struct hostent *h = gethostbyname(host);
+    int fd;
+    char buf[NSCTL_MAX_PKT_SZ];
+    int sz;
+    char *err;
+
+    if (!h || h->h_addrtype != AF_INET)
+    {
+       fprintf(stderr, "%s: invalid host `%s'\n", me, host);
+       return 0;
+    }
+
+    if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+    {
+       fprintf(stderr, "%s: can't create udp socket (%s)\n", me, strerror(errno));
+       return 0;
+    }
+
+    memset(&peer, 0, len);
+    peer.sin_family = AF_INET;
+    peer.sin_port = htons(port);
+    memcpy(&peer.sin_addr.s_addr, h->h_addr, sizeof(peer.sin_addr.s_addr));
+
+    if (connect(fd, (struct sockaddr *) &peer, sizeof(peer)) < 0)
+    {
+       fprintf(stderr, "%s: udp connect failed (%s)\n", me, strerror(errno));
+       return 0;
+    }
+
+    if ((sz = pack_control(buf, sizeof(buf), type, argc, argv)) < 0)
+    {
+       fprintf(stderr, "%s: error packing request\n", me);
+       return 0;
+    }
+
+    if (debug)
+    {
+       struct nsctl req;
+       if (unpack_control(&req, buf, sz) == type)
        {
-               int n;
-               fd_set r;
-               struct timeval timeout;
-
-               FD_ZERO(&r);
-               FD_SET(udpfd, &r);
-               timeout.tv_sec = 1;
-               timeout.tv_usec = 0;
-
-               n = select(udpfd + 1, &r, 0, 0, &timeout);
-               if (n <= 0)
-               {
-                       printf("Timeout waiting for packet\n");
-                       return 0;
-               }
+           fprintf(stderr, "Sending ");
+           dump_control(&req, stderr);
        }
-       if ((len = read_packet(udpfd, packet)))
+    }
+
+    if (send(fd, buf, sz, 0) < 0)
+    {
+       fprintf(stderr, "%s: error sending request (%s)\n", me, strerror(errno));
+       return 0;
+    }
+
+    /* set timer */
+    if (timeout)
+    {
+       struct sigaction alrm;
+       alrm.sa_handler = sigalrm_handler;
+       sigemptyset(&alrm.sa_mask);
+       alrm.sa_flags = 0;
+
+       sigaction(SIGALRM, &alrm, 0);
+       alarm(timeout);
+    }
+
+    sz = recv(fd, buf, sizeof(buf), 0);
+    alarm(0);
+
+    if (sz < 0)
+    {
+       fprintf(stderr, "%s: error receiving response (%s)\n", me,
+           errno == EINTR ? "timed out" : strerror(errno));
+
+       return 0;
+    }
+
+    if ((type = unpack_control(&res, buf, sz)) > 0 && type & NSCTL_RESPONSE)
+    {
+       if (debug)
        {
-               printf("Received ");
-               dump_packet(packet, stdout);
+           fprintf(stderr, "Received ");
+           dump_control(&res, stderr);
        }
 
-       return 0;
-}
+       return &res;
+    }
 
+    err = "unknown error";
+    switch (type)
+    {
+    case NSCTL_ERR_SHORT:  err = "short packet"; break;
+    case NSCTL_ERR_LONG:   err = "extra data";   break;
+    case NSCTL_ERR_MAGIC:  err = "bad magic";    break;
+    case NSCTL_ERR_TYPE:   err = "invalid type"; break;
+    }
+
+    fprintf(stderr, "%s: %s\n", me, err);
+    return 0;
+}
index be92047..b751a1d 100644 (file)
--- a/plugin.h
+++ b/plugin.h
@@ -1,7 +1,7 @@
 #ifndef __PLUGIN_H__
 #define __PLUGIN_H__
 
-#define PLUGIN_API_VERSION     2
+#define PLUGIN_API_VERSION     3
 #define MAX_PLUGIN_TYPES       30
 
 enum
@@ -79,17 +79,10 @@ struct param_timer
 
 struct param_control
 {
-       char *buf;
-       int l;
-       unsigned int source_ip;
-       unsigned short source_port;
-       char *response;
-       int response_length;
-       int send_response;
-       short type;
-       int id;
-       char *data;
-       int data_length;
+       int argc;
+       char **argv;
+       int response;
+       char *additional;
 };
 
 struct param_new_session
index 9d20915..9842e78 100644 (file)
@@ -4,9 +4,9 @@
 
 /* fudge up session rx speed if not set */
 
-char const *cvs_id = "$Id: setrxspeed.c,v 1.2 2004-11-09 08:05:03 bodea Exp $";
+char const *cvs_id = "$Id: setrxspeed.c,v 1.3 2004-11-17 08:23:35 bodea Exp $";
 
-int __plugin_api_version = PLUGIN_API_VERSION;
+int plugin_api_version = PLUGIN_API_VERSION;
 static struct pluginfuncs *p = 0;
 
 int plugin_post_auth(struct param_post_auth *data)
index 1c315c8..1013b7b 100644 (file)
@@ -4,9 +4,9 @@
 
 /* strip domain part of username before sending RADIUS requests */
 
-char const *cvs_id = "$Id: stripdomain.c,v 1.5 2004-11-09 08:05:03 bodea Exp $";
+char const *cvs_id = "$Id: stripdomain.c,v 1.6 2004-11-17 08:23:35 bodea Exp $";
 
-int __plugin_api_version = PLUGIN_API_VERSION;
+int plugin_api_version = PLUGIN_API_VERSION;
 static struct pluginfuncs *p = 0;
 
 int plugin_pre_auth(struct param_pre_auth *data)