- 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
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue