- Add startup-config(5) manpage [FIXME].
- Revise nsctl to allow arbitrary strings/args to be passed to plugins.
This commit is contained in:
parent
5d4d6bb059
commit
5e01d2924d
17 changed files with 796 additions and 415 deletions
10
Changes
10
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)
|
||||
|
|
|
|||
64
Docs/l2tpns.8
Normal file
64
Docs/l2tpns.8
Normal file
|
|
@ -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).
|
||||
67
Docs/nsctl.8
Normal file
67
Docs/nsctl.8
Normal file
|
|
@ -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).
|
||||
14
Makefile
14
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
195
control.c
195
control.c
|
|
@ -1,74 +1,163 @@
|
|||
// L2TPNS: control
|
||||
|
||||
char const *cvs_id_control = "$Id: control.c,v 1.2 2004-06-28 02:43:13 fred_nerk Exp $";
|
||||
char const *cvs_id_control = "$Id: control.c,v 1.3 2004-11-17 08:23:34 bodea Exp $";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.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 <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);
|
||||
|
||||
*(short *)(packet + 0) = ntohs(0x9012);
|
||||
*(short *)(packet + 2) = ntohs(type);
|
||||
*(int *)(packet + 6) = ntohl(id);
|
||||
if (len > sizeof(pkt))
|
||||
len = sizeof(pkt);
|
||||
|
||||
return 10;
|
||||
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
|
||||
|
||||
if (arg.len)
|
||||
memcpy(arg.value, a, arg.len);
|
||||
|
||||
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;
|
||||
|
||||
*(short *)(packet + 4) = ntohs(len);
|
||||
if (len < sz)
|
||||
return NSCTL_ERR_SHORT;
|
||||
|
||||
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)
|
||||
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;
|
||||
|
||||
default:
|
||||
return NSCTL_ERR_TYPE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
perror("sendto");
|
||||
return 0;
|
||||
if (len < sz + s)
|
||||
return NSCTL_ERR_SHORT;
|
||||
|
||||
control->argv[i] = p;
|
||||
p += s;
|
||||
sz += s;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void dump_packet(char *packet, FILE *stream)
|
||||
{
|
||||
if (htons(*(short *)(packet + 0)) != 0x9012)
|
||||
else
|
||||
{
|
||||
fprintf(stream, "Invalid packet identifier %x\n", htons(*(short *)(packet + 0)));
|
||||
return;
|
||||
/* check for terminator */
|
||||
if (s != 0xff)
|
||||
return NSCTL_ERR_SHORT;
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
if (sz != len)
|
||||
return NSCTL_ERR_LONG; // trailing cr*p
|
||||
|
||||
return control->type;
|
||||
}
|
||||
|
||||
void dump_control(struct nsctl *control, FILE *stream)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
|
|
|||
56
control.h
56
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__ */
|
||||
|
|
|
|||
79
garden.c
79
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;
|
||||
|
||||
if (data->type != PKT_GARDEN && data->type != PKT_UNGARDEN)
|
||||
return PLUGIN_RET_OK;
|
||||
|
||||
if (!data->data && data->data_length)
|
||||
return PLUGIN_RET_OK;
|
||||
|
||||
session = atoi((char*)(data->data));
|
||||
if (!session)
|
||||
return PLUGIN_RET_OK;
|
||||
|
||||
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 = "must be run on the cluster master";
|
||||
return PLUGIN_RET_STOP;
|
||||
}
|
||||
*(short *)(data->response + 2) = ntohs(PKT_RESP_OK);
|
||||
|
||||
if (!(garden_session(s, (data->type == PKT_GARDEN))))
|
||||
if (data->argc != 2)
|
||||
{
|
||||
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 = "one argument required: username or session id";
|
||||
return PLUGIN_RET_STOP;
|
||||
}
|
||||
|
||||
if (!(session = strtol(data->argv[0], &end, 10)) || *end)
|
||||
session = p->get_session_by_username(data->argv[0]);
|
||||
|
||||
if (session)
|
||||
s = p->get_session_by_id(session);
|
||||
|
||||
if (!s || !s->ip)
|
||||
{
|
||||
data->response = NSCTL_RES_ERR;
|
||||
data->additional = "session not found";
|
||||
return PLUGIN_RET_STOP;
|
||||
}
|
||||
|
||||
if (s->walled_garden == flag)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
68
l2tpns.8
68
l2tpns.8
|
|
@ -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).
|
||||
|
||||
256
l2tpns.c
256
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");
|
||||
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;
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
run_plugins(PLUGIN_CONTROL, ¶m);
|
||||
|
||||
if (param.send_response)
|
||||
switch (type)
|
||||
{
|
||||
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");
|
||||
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, ¶m))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
response.type = NSCTL_RES_ERR;
|
||||
response.argc = 1;
|
||||
response.argv[0] = "error unpacking control packet";
|
||||
}
|
||||
|
||||
free(resp);
|
||||
buf = calloc(NSCTL_MAX_PKT_SZ, 1);
|
||||
if (!buf)
|
||||
{
|
||||
LOG(2, ntohl(addr->sin_addr.s_addr), 0, 0, "Failed to allocate nsctl response\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
41
nsctl.8
41
nsctl.8
|
|
@ -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).
|
||||
|
||||
325
nsctl.c
325
nsctl.c
|
|
@ -1,138 +1,239 @@
|
|||
/* l2tpns plugin control */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.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 <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.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;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
if ((p = strrchr((me = argv[0]), '/')))
|
||||
me = p + 1;
|
||||
|
||||
if (argc < 3)
|
||||
opterr = 0;
|
||||
while ((i = getopt(argc, argv, "dh:t:")) != -1)
|
||||
switch (i)
|
||||
{
|
||||
printf("Usage: %s <host> <command> [args...]\n", argv[0]);
|
||||
return 1;
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
host = optarg;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
timeout = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
USAGE();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dest_host = strdup(argv[1]);
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
fprintf(stderr, "%s: invalid port `%s'\n", me, p + 1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
*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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
stream = stdout;
|
||||
status = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!(packet = calloc(1400, 1)))
|
||||
{
|
||||
perror("calloc");
|
||||
return(1);
|
||||
}
|
||||
for (i = 0; i < res->argc; i++)
|
||||
fprintf(stream, "%s\n", res->argv[i]);
|
||||
|
||||
srand(time(NULL));
|
||||
return status;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
send_packet(udpfd, dest_ip, dest_port, packet, len);
|
||||
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
if ((len = read_packet(udpfd, packet)))
|
||||
{
|
||||
printf("Received ");
|
||||
dump_packet(packet, stdout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
fprintf(stderr, "Sending ");
|
||||
dump_control(&req, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
fprintf(stderr, "Received ");
|
||||
dump_control(&res, stderr);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
17
plugin.h
17
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue