--- /dev/null
+* Fri Mar 5 2004 David Parrish <david@dparrish.com> 1.1.0
+- Change all strcpy() calls to strncpy() to avoid buffer overflow potential
+- Add ICMP host unreachable support
+- Logging to syslog if log_file = "syslog:facility"
+- Now requires libcli 1.5
+- All configuration moves to a config structure
+- Ability to modify and write config on the fly through command-line interface
+- Config file support is removed, and now handled by the cli
+- Show hostname in cli prompt
+- Keep current state type for tunnels
+- Add uptime command do CLI, which also shows real-time bandwidth utilisation
+- Add goodbye command to cluster master, which forces droppping a slave
+- Cache IP address allocation, so that reconnecting users get the same address
+- Fix tunnel resend timeouts, so that dead tunnels will be cleaned up
+- Allocate tunnels and radius without using a linked list which had issues
+- Fix some off-by-one errors in tunnel and session and radius arrays
+- Save and reload ip address pool when dieing
+- Check version and size of reloaded data when restarting
+- Remove plugin_config support
+- Remove old support for TBF which didn't work anyway. HTB is required to do throttling now.
+- Add COPYING and Changes files
+
1. Requirements
- * You must have libcli installed to enable the command-line
- interface. You can get it from http://sourceforge.net/projects/libcli.
- If you don't have it, command-line support will not be compiled in.
+ * libcli 1.5.0 or greater
+ You can get it from http://sourceforge.net/projects/libcli.
* A kernel with iptables support
DEFS = @DEFS@
OBJS= md5.o \
+ icmp.o \
cli.o \
l2tpns.o \
ppp.o \
memcpy(&buf.ar_sip, &ip, sizeof(ip));
memcpy(buf.ar_tha, mac, ETH_ALEN);
memcpy(&buf.ar_tip, &ip, sizeof(ip));
-
+
/* Now actually send the thing */
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_RARP));
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
- strncpy(sll.sll_addr, mac, sizeof(sll.sll_addr)); /* Null-pad */
+ strncpy(sll.sll_addr, mac, sizeof(sll.sll_addr) - 1);
sll.sll_halen = ETH_ALEN;
sll.sll_ifindex = ifr_idx;
sendto(fd, &buf, sizeof(buf), 0, (struct sockaddr*)&sll, sizeof(sll));
+ close(fd);
}
+++ /dev/null
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/if.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <signal.h>
-#include <getopt.h>
-
-#define PORT 39000
-
-void sigalarm(int junk);
-unsigned long long recv_count = 0;
-unsigned long pps = 0;
-unsigned long bytes = 0;
-unsigned port = PORT;
-
-int main(int argc, char *argv[])
-{
- int on = 1;
- struct sockaddr_in addr;
- int s;
- char *packet;
-
- while ((s = getopt(argc, argv, "?p:")) > 0)
- {
- switch (s)
- {
- case 'p' :
- port = atoi(optarg);
- break;
- case '?' :
- printf("Options:\n");
- printf("\t-p port to listen on\n");
- return(0);
- break;
- }
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
-
- s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- if (bind(s, (void *) &addr, sizeof(addr)) < 0)
- {
- perror("bind");
- return -1;
- }
-
- signal(SIGALRM, sigalarm);
- alarm(1);
-
- printf("Waiting on port %d\n", port);
- packet = (char *)malloc(65535);
- while (1)
- {
- struct sockaddr_in addr;
- int alen = sizeof(addr), l;
-
- l = recvfrom(s, packet, 65535, 0, (void *) &addr, &alen);
- if (l < 0) continue;
- recv_count++;
- pps++;
- bytes += l;
-
- sendto(s, packet, l, 0, (struct sockaddr *)&addr, alen);
- }
-
- free(packet);
-}
-
-void sigalarm(int junk)
-{
- printf("Recv: %10llu %0.1fMbits/s (%lu pps)\n", recv_count, (bytes / 1024.0 / 1024.0 * 8), pps);
- pps = bytes = 0;
- alarm(1);
-}
-
// L2TPNS Command Line Interface
-// $Id: cli.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: cli.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
// vim: sw=4 ts=8
#include <stdio.h>
#include <sys/file.h>
#include <sys/stat.h>
+#include <syslog.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
-#include <libcli.h>
#include "l2tpns.h"
+#include "libcli.h"
#include "util.h"
-#include "config.h"
-
-#ifdef HAVE_LIBCLI
extern tunnelt *tunnel;
extern sessiont *session;
extern sessionidt *cli_session_kill;
extern tunnelidt *cli_tunnel_kill;
extern tbft *filter_buckets;
+extern struct configt *config;
+extern struct config_descriptt config_values[];
+extern char hostname[];
#ifdef RINGBUFFER
extern struct Tringbuffer *ringbuffer;
#endif
-char *rcs_id = "$Id: cli.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $";
+char *rcs_id = "$Id: cli.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $";
char *debug_levels[] = {
"CRIT",
int debug_session;
int debug_tunnel;
int debug_rb_tail;
-
-int cmd_show_session(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_show_tunnels(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_show_users(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_show_counters(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_show_version(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_show_pool(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_show_banana(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_clear_counters(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_drop_user(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_drop_tunnel(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_drop_session(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_snoop(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_no_snoop(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_throttle(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_no_throttle(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_debug(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_no_debug(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_watch_session(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int cmd_watch_tunnel(struct cli_def *cli, FILE *w, char *command, char **argv, int argc);
-int regular_stuff(struct cli_def *cli, FILE *w);
+FILE *save_config_fh;
+
+int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_users(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_version(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_run(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_banana(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_show_plugins(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_drop_tunnel(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_snoop(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_no_snoop(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_debug(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_no_debug(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_watch_session(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_watch_tunnel(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_set(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_load_plugin(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_remove_plugin(struct cli_def *cli, char *command, char **argv, int argc);
+int cmd_uptime(struct cli_def *cli, char *command, char **argv, int argc);
+int regular_stuff(struct cli_def *cli);
void init_cli()
{
cli = cli_init();
c = cli_register_command(cli, NULL, "show", NULL, NULL);
- cli_register_command(cli, c, "session", cmd_show_session, "Show a list of sessions");
- cli_register_command(cli, c, "tunnels", cmd_show_tunnels, NULL);
- cli_register_command(cli, c, "users", cmd_show_users, NULL);
- cli_register_command(cli, c, "version", cmd_show_version, NULL);
+ cli_register_command(cli, c, "session", cmd_show_session, "Show a list of sessions or details for a single session");
+ cli_register_command(cli, c, "tunnels", cmd_show_tunnels, "Show a list of tunnels or details for a single tunnel");
+ cli_register_command(cli, c, "users", cmd_show_users, "Show a list of all connected users");
+ cli_register_command(cli, c, "version", cmd_show_version, "Show currently running software version");
cli_register_command(cli, c, "banana", cmd_show_banana, "Show a banana");
- cli_register_command(cli, c, "pool", cmd_show_pool, NULL);
+ cli_register_command(cli, c, "pool", cmd_show_pool, "Show the IP address allocation pool");
+ cli_register_command(cli, c, "running-config", cmd_show_run, "Show the currently running configuration");
+ cli_register_command(cli, c, "radius", cmd_show_radius, "Show active radius queries");
+ cli_register_command(cli, c, "plugins", cmd_show_plugins, "List all installed plugins");
#ifdef STATISTICS
- cli_register_command(cli, c, "counters", cmd_show_counters, NULL);
+ cli_register_command(cli, c, "counters", cmd_show_counters, "Display all the internal counters and running totals");
c = cli_register_command(cli, NULL, "clear", NULL, NULL);
- cli_register_command(cli, c, "counters", cmd_clear_counters, NULL);
+ cli_register_command(cli, c, "counters", cmd_clear_counters, "Clear internal counters");
#endif
- cli_register_command(cli, NULL, "snoop", cmd_snoop, NULL);
- cli_register_command(cli, NULL, "throttle", cmd_throttle, NULL);
+ cli_register_command(cli, NULL, "uptime", cmd_uptime, "Show uptime and bandwidth utilisation");
+
+ c = cli_register_command(cli, NULL, "write", NULL, NULL);
+ cli_register_command(cli, c, "memory", cmd_write_memory, "Save the running config to flash");
+ cli_register_command(cli, c, "terminal", cmd_show_run, "Show the running config");
+
+ cli_register_command(cli, NULL, "snoop", cmd_snoop, "Temporarily enable interception for a user");
+ cli_register_command(cli, NULL, "throttle", cmd_throttle, "Temporarily enable throttling for a user");
c = cli_register_command(cli, NULL, "no", NULL, NULL);
- cli_register_command(cli, c, "snoop", cmd_no_snoop, NULL);
- cli_register_command(cli, c, "throttle", cmd_no_throttle, NULL);
- cli_register_command(cli, c, "debug", cmd_no_debug, NULL);
+ cli_register_command(cli, c, "snoop", cmd_no_snoop, "Temporarily disable interception for a user");
+ cli_register_command(cli, c, "throttle", cmd_no_throttle, "Temporarily disable throttling for a user");
+ cli_register_command(cli, c, "debug", cmd_no_debug, "Turn off logging of a certain level of debugging");
c = cli_register_command(cli, NULL, "drop", NULL, NULL);
- cli_register_command(cli, c, "user", cmd_drop_user, NULL);
- cli_register_command(cli, c, "tunnel", cmd_drop_tunnel, NULL);
- cli_register_command(cli, c, "session", cmd_drop_session, NULL);
+ cli_register_command(cli, c, "user", cmd_drop_user, "Disconnect a user");
+ cli_register_command(cli, c, "tunnel", cmd_drop_tunnel, "Disconnect a tunnel and all sessions on that tunnel");
+ cli_register_command(cli, c, "session", cmd_drop_session, "Disconnect a session");
- cli_register_command(cli, NULL, "debug", cmd_debug, "Specify a debugging level");
+ cli_register_command(cli, NULL, "debug", cmd_debug, "Set the level of logging that is shown on the console");
+ /*
c = cli_register_command(cli, NULL, "watch", NULL, NULL);
- cli_register_command(cli, c, "session", cmd_watch_session, "Dump logs for a tunnel");
+ cli_register_command(cli, c, "session", cmd_watch_session, "Dump logs for a session");
cli_register_command(cli, c, "tunnel", cmd_watch_tunnel, "Dump logs for a tunnel");
+ */
+
+ c = cli_register_command(cli, NULL, "load", NULL, NULL);
+ cli_register_command(cli, c, "plugin", cmd_load_plugin, "Load a plugin");
+
+ c = cli_register_command(cli, NULL, "remove", NULL, NULL);
+ cli_register_command(cli, c, "plugin", cmd_remove_plugin, "Remove a plugin");
+
+ cli_register_command(cli, NULL, "set", cmd_set, "Set a configuration variable");
// Enable regular processing
cli_regular(cli, regular_stuff);
void cli_do(int sockfd)
{
- if ((cli_pid = fork())) return;
+ if (fork()) return;
// Close sockets
if (udpfd) close(udpfd); udpfd = 0;
memset(&debug_flags, 0, sizeof(debug_flags));
debug_flags.critical = 1;
- cli_loop(cli, sockfd, "l2tpns> ");
+ {
+ char prompt[1005];
+ snprintf(prompt, 1005, "%s> ", hostname);
+ cli_loop(cli, sockfd, prompt);
+ }
close(sockfd);
log(3, 0, 0, 0, "Closed CLI connection\n");
exit(0);
}
-int cmd_show_session(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+void cli_print_log(struct cli_def *cli, char *string)
+{
+ log(3, 0, 0, 0, "%s\n", string);
+}
+
+void cli_do_file(FILE *fh)
+{
+ log(3, 0, 0, 0, "Reading configuration file\n");
+ cli_print_callback(cli, cli_print_log);
+ cli_file(cli, fh);
+ cli_print_callback(cli, NULL);
+}
+
+int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
time_t time_now;
s = atoi(argv[i]);
if (!s || s > MAXSESSION)
{
- fprintf(w, "Invalid session id \"%s\"\r\n", argv[i]);
+ cli_print(cli, "Invalid session id \"%s\"", argv[i]);
continue;
}
- fprintf(w, "\r\nSession %d:\r\n", s);
- fprintf(w, " User: %s\r\n", session[s].user[0] ? session[s].user : "none");
- fprintf(w, " Calling Num: %s\r\n", session[s].calling);
- fprintf(w, " Called Num: %s\r\n", session[s].called);
- fprintf(w, " Tunnel ID: %d\r\n", session[s].tunnel);
- fprintf(w, " IP address: %s\r\n", inet_toa(htonl(session[s].ip)));
- fprintf(w, " HSD sid: %lu\r\n", session[s].sid);
- fprintf(w, " Idle time: %u seconds\r\n", abs(time_now - session[s].last_packet));
- fprintf(w, " Next Recv: %u\r\n", session[s].nr);
- fprintf(w, " Next Send: %u\r\n", session[s].ns);
- fprintf(w, " Bytes In/Out: %lu/%lu\r\n", (unsigned long)session[s].cin, (unsigned long)session[s].cout);
- fprintf(w, " Pkts In/Out: %lu/%lu\r\n", (unsigned long)session[s].pin, (unsigned long)session[s].pout);
- fprintf(w, " Radius Session: %u\r\n", session[s].radius);
- fprintf(w, " Rx Speed: %lu\r\n", session[s].rx_connect_speed);
- fprintf(w, " Tx Speed: %lu\r\n", session[s].tx_connect_speed);
- fprintf(w, " Intercepted: %s\r\n", session[s].snoop ? "YES" : "no");
- fprintf(w, " Throttled: %s\r\n", session[s].throttle ? "YES" : "no");
- fprintf(w, " Walled Garden: %s\r\n", session[s].walled_garden ? "YES" : "no");
- fprintf(w, " Filter Bucket: %s\r\n", session[s].tbf ? filter_buckets[session[s].tbf].handle : "none");
+ cli_print(cli, "\r\nSession %d:", s);
+ cli_print(cli, " User: %s", session[s].user[0] ? session[s].user : "none");
+ cli_print(cli, " Calling Num: %s", session[s].calling);
+ cli_print(cli, " Called Num: %s", session[s].called);
+ cli_print(cli, " Tunnel ID: %d", session[s].tunnel);
+ cli_print(cli, " IP address: %s", inet_toa(htonl(session[s].ip)));
+ cli_print(cli, " HSD sid: %lu", session[s].sid);
+ cli_print(cli, " Idle time: %u seconds", abs(time_now - session[s].last_packet));
+ cli_print(cli, " Next Recv: %u", session[s].nr);
+ cli_print(cli, " Next Send: %u", session[s].ns);
+ cli_print(cli, " Bytes In/Out: %lu/%lu", (unsigned long)session[s].cin, (unsigned long)session[s].total_cout);
+ cli_print(cli, " Pkts In/Out: %lu/%lu", (unsigned long)session[s].pin, (unsigned long)session[s].pout);
+ cli_print(cli, " Radius Session: %u", session[s].radius);
+ cli_print(cli, " Rx Speed: %lu", session[s].rx_connect_speed);
+ cli_print(cli, " Tx Speed: %lu", session[s].tx_connect_speed);
+ cli_print(cli, " Intercepted: %s", session[s].snoop ? "YES" : "no");
+ cli_print(cli, " Throttled: %s", session[s].throttle ? "YES" : "no");
+ cli_print(cli, " Servicenet: %s", session[s].servicenet ? "YES" : "no");
+ cli_print(cli, " Filter Bucket: %s", session[s].tbf ? filter_buckets[session[s].tbf].handle : "none");
}
return CLI_OK;
}
// Show Summary
- fprintf(w, " %s %4s %-32s %-15s %s %s %s %10s %10s %10s %4s %-15s %s\r\n",
+ cli_print(cli, " %s %4s %-32s %-15s %s %s %s %10s %10s %10s %4s %-15s %s",
"SID",
"TID",
"Username",
"idle",
"LAC",
"CLI");
- for (i = 0; i < MAXSESSION; i++)
+ for (i = 1; i < MAXSESSION; i++)
{
char *userip, *tunnelip;
if (!session[i].opened) continue;
userip = strdup(inet_toa(htonl(session[i].ip)));
tunnelip = strdup(inet_toa(htonl(tunnel[ session[i].tunnel ].ip)));
- fprintf(w, "%5d %4d %-32s %-15s %s %s %s %10lu %10lu %10lu %4u %-15s %s\r\n",
+ cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %10u %10lu %10lu %4u %-15s %s",
i,
session[i].tunnel,
session[i].user[0] ? session[i].user : "*",
userip,
(session[i].snoop) ? "Y" : "N",
(session[i].throttle) ? "Y" : "N",
- (session[i].walled_garden) ? "Y" : "N",
- (unsigned long)session[i].opened,
- (unsigned long)session[i].cout,
- (unsigned long)session[i].cin,
+ (session[i].servicenet) ? "Y" : "N",
+ abs(time_now - (unsigned long)session[i].opened),
+ (unsigned long)session[i].total_cout,
+ (unsigned long)session[i].total_cin,
abs(time_now - (session[i].last_packet ? session[i].last_packet : time_now)),
tunnelip,
session[i].calling[0] ? session[i].calling : "*");
return CLI_OK;
}
-int cmd_show_tunnels(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int argc)
{
- int i, x;
+ int i, x, show_all = 0;
time_t time_now;
+ char *states[] = {
+ "Free",
+ "Open",
+ "Closing",
+ "Opening",
+ };
time(&time_now);
if (argc > 0)
{
- // Show individual tunnel
- for (i = 0; i < argc; i++)
+ if (strcmp(argv[0], "all") == 0)
{
- char s[65535] = {0};
- unsigned int t;
- t = atoi(argv[i]);
- if (!t || t > MAXTUNNEL)
+ show_all = 1;
+ }
+ else
+ {
+ // Show individual tunnel
+ for (i = 0; i < argc; i++)
{
- fprintf(w, "Invalid tunnel id \"%s\"\r\n", argv[i]);
- continue;
+ char s[65535] = {0};
+ unsigned int t;
+ t = atoi(argv[i]);
+ if (!t || t > MAXTUNNEL)
+ {
+ cli_print(cli, "Invalid tunnel id \"%s\"", argv[i]);
+ continue;
+ }
+ cli_print(cli, "\r\nTunnel %d:", t);
+ cli_print(cli, " State: %s", states[tunnel[t].state]);
+ cli_print(cli, " Hostname: %s", tunnel[t].hostname[0] ? tunnel[t].hostname : "(none)");
+ cli_print(cli, " Remote IP: %s", inet_toa(htonl(tunnel[t].ip)));
+ cli_print(cli, " Remote Port: %d", tunnel[t].port);
+ cli_print(cli, " Rx Window: %u", tunnel[t].window);
+ cli_print(cli, " Next Recv: %u", tunnel[t].nr);
+ cli_print(cli, " Next Send: %u", tunnel[t].ns);
+ cli_print(cli, " Queue Len: %u", tunnel[t].controlc);
+ cli_print(cli, " Last Packet Age:%u", (unsigned)(time_now - tunnel[t].last));
+
+ for (x = 0; x < MAXSESSION; x++)
+ if (session[x].tunnel == t && session[x].opened && !session[x].die)
+ sprintf(s, "%s%u ", s, x);
+ cli_print(cli, " Sessions: %s", s);
}
- fprintf(w, "\r\nTunnel %d:\r\n", t);
- fprintf(w, " Hostname: %s\r\n", tunnel[t].hostname[0] ? tunnel[t].hostname : "(none)");
- fprintf(w, " Remote IP: %s\r\n", inet_toa(htonl(tunnel[t].ip)));
- fprintf(w, " Remote Port: %d\r\n", tunnel[t].port);
- fprintf(w, " Rx Window: %u\r\n", tunnel[t].window);
- fprintf(w, " Next Recv: %u\r\n", tunnel[t].nr);
- fprintf(w, " Next Send: %u\r\n", tunnel[t].ns);
- fprintf(w, " Queue Len: %u\r\n", tunnel[t].controlc);
- fprintf(w, " Last Packet Age:%u\r\n", (unsigned)(time_now - tunnel[t].last));
-
- for (x = 0; x < MAXSESSION; x++)
- if (session[x].tunnel == t && session[x].opened && !session[x].die)
- sprintf(s, "%s%u ", s, x);
- fprintf(w, " Sessions: %s\r\n", s);
+ return CLI_OK;
}
- return CLI_OK;
}
// Show tunnel summary
- fprintf(w, "%s %s %s %s\r\n",
+ cli_print(cli, "%s %s %s %s %s",
"TID",
"Hostname",
"IP",
+ "State",
"Sessions");
- for (i = 0; i < MAXTUNNEL; i++)
+ for (i = 1; i < MAXTUNNEL; i++)
{
int sessions = 0;
- if (!tunnel[i].ip || tunnel[i].die || !tunnel[i].hostname[0]) continue;
+ if (!show_all && (!tunnel[i].ip || tunnel[i].die || !tunnel[i].hostname[0])) continue;
for (x = 0; x < MAXSESSION; x++) if (session[x].tunnel == i && session[x].opened && !session[x].die) sessions++;
- fprintf(w, "%d %s %s %d\r\n",
+ cli_print(cli, "%d %s %s %s %d",
i,
- tunnel[i].hostname,
+ *tunnel[i].hostname ? tunnel[i].hostname : "(null)",
inet_toa(htonl(tunnel[i].ip)),
+ states[tunnel[i].state],
sessions);
}
return CLI_OK;
}
-int cmd_show_users(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_show_users(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
for (i = 0; i < MAXSESSION; i++)
{
if (!session[i].opened) continue;
if (!session[i].user[0]) continue;
- fprintf(w, "%s\r\n",
+ cli_print(cli, "%s",
session[i].user);
}
return CLI_OK;
}
-int cmd_show_counters(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_show_counters(struct cli_def *cli, char *command, char **argv, int argc)
{
- fprintf(w, "%-10s %-8s %-10s %-8s\r\n", "Ethernet", "Bytes", "Packets", "Errors");
- fprintf(w, "%-10s %8lu %8lu %8lu\r\n", "RX",
+ cli_print(cli, "%-10s %-8s %-10s %-8s", "Ethernet", "Bytes", "Packets", "Errors");
+ cli_print(cli, "%-10s %8lu %8lu %8lu", "RX",
GET_STAT(tap_rx_bytes),
GET_STAT(tap_rx_packets),
GET_STAT(tap_rx_errors));
- fprintf(w, "%-10s %8lu %8lu %8lu\r\n", "TX",
+ cli_print(cli, "%-10s %8lu %8lu %8lu", "TX",
GET_STAT(tap_tx_bytes),
GET_STAT(tap_tx_packets),
GET_STAT(tap_tx_errors));
- fprintf(w, "\r\n");
+ cli_print(cli, "");
- fprintf(w, "%-10s %-8s %-10s %-8s %-8s\r\n", "Tunnel", "Bytes", "Packets", "Errors", "Retries");
- fprintf(w, "%-10s %8lu %8lu %8lu %8lu\r\n", "RX",
+ cli_print(cli, "%-10s %-8s %-10s %-8s %-8s", "Tunnel", "Bytes", "Packets", "Errors", "Retries");
+ cli_print(cli, "%-10s %8lu %8lu %8lu %8lu", "RX",
GET_STAT(tunnel_rx_bytes),
GET_STAT(tunnel_rx_packets),
GET_STAT(tunnel_rx_errors),
0L);
- fprintf(w, "%-10s %8lu %8lu %8lu %8lu\r\n", "TX",
+ cli_print(cli, "%-10s %8lu %8lu %8lu %8lu", "TX",
GET_STAT(tunnel_tx_bytes),
GET_STAT(tunnel_tx_packets),
GET_STAT(tunnel_rx_errors),
GET_STAT(tunnel_retries));
- fprintf(w, "\r\n");
-
- fprintf(w, "%-30s%-10s\r\n", "Counter", "Value");
- fprintf(w, "-----------------------------------------\r\n");
- fprintf(w, "%-30s%lu\r\n", "radius_retries", GET_STAT(radius_retries));
- fprintf(w, "%-30s%lu\r\n", "arp_errors", GET_STAT(arp_errors));
- fprintf(w, "%-30s%lu\r\n", "arp_replies", GET_STAT(arp_replies));
- fprintf(w, "%-30s%lu\r\n", "arp_discarded", GET_STAT(arp_discarded));
- fprintf(w, "%-30s%lu\r\n", "arp_sent", GET_STAT(arp_sent));
- fprintf(w, "%-30s%lu\r\n", "arp_recv", GET_STAT(arp_recv));
- fprintf(w, "%-30s%lu\r\n", "packets_snooped", GET_STAT(packets_snooped));
- fprintf(w, "%-30s%lu\r\n", "tunnel_created", GET_STAT(tunnel_created));
- fprintf(w, "%-30s%lu\r\n", "session_created", GET_STAT(session_created));
- fprintf(w, "%-30s%lu\r\n", "tunnel_timeout", GET_STAT(tunnel_timeout));
- fprintf(w, "%-30s%lu\r\n", "session_timeout", GET_STAT(session_timeout));
- fprintf(w, "%-30s%lu\r\n", "radius_timeout", GET_STAT(radius_timeout));
- fprintf(w, "%-30s%lu\r\n", "radius_overflow", GET_STAT(radius_overflow));
- fprintf(w, "%-30s%lu\r\n", "tunnel_overflow", GET_STAT(tunnel_overflow));
- fprintf(w, "%-30s%lu\r\n", "session_overflow", GET_STAT(session_overflow));
- fprintf(w, "%-30s%lu\r\n", "ip_allocated", GET_STAT(ip_allocated));
- fprintf(w, "%-30s%lu\r\n", "ip_freed", GET_STAT(ip_freed));
+ cli_print(cli, "");
+
+ cli_print(cli, "%-30s%-10s", "Counter", "Value");
+ cli_print(cli, "-----------------------------------------");
+ cli_print(cli, "%-30s%lu", "radius_retries", GET_STAT(radius_retries));
+ cli_print(cli, "%-30s%lu", "arp_errors", GET_STAT(arp_errors));
+ cli_print(cli, "%-30s%lu", "arp_replies", GET_STAT(arp_replies));
+ cli_print(cli, "%-30s%lu", "arp_discarded", GET_STAT(arp_discarded));
+ cli_print(cli, "%-30s%lu", "arp_sent", GET_STAT(arp_sent));
+ cli_print(cli, "%-30s%lu", "arp_recv", GET_STAT(arp_recv));
+ cli_print(cli, "%-30s%lu", "packets_snooped", GET_STAT(packets_snooped));
+ cli_print(cli, "%-30s%lu", "tunnel_created", GET_STAT(tunnel_created));
+ cli_print(cli, "%-30s%lu", "session_created", GET_STAT(session_created));
+ cli_print(cli, "%-30s%lu", "tunnel_timeout", GET_STAT(tunnel_timeout));
+ cli_print(cli, "%-30s%lu", "session_timeout", GET_STAT(session_timeout));
+ cli_print(cli, "%-30s%lu", "radius_timeout", GET_STAT(radius_timeout));
+ cli_print(cli, "%-30s%lu", "radius_overflow", GET_STAT(radius_overflow));
+ cli_print(cli, "%-30s%lu", "tunnel_overflow", GET_STAT(tunnel_overflow));
+ cli_print(cli, "%-30s%lu", "session_overflow", GET_STAT(session_overflow));
+ cli_print(cli, "%-30s%lu", "ip_allocated", GET_STAT(ip_allocated));
+ cli_print(cli, "%-30s%lu", "ip_freed", GET_STAT(ip_freed));
#ifdef STAT_CALLS
- fprintf(w, "\n%-30s%-10s\r\n", "Counter", "Value");
- fprintf(w, "-----------------------------------------\r\n");
- fprintf(w, "%-30s%lu\r\n", "call_processtap", GET_STAT(call_processtap));
- fprintf(w, "%-30s%lu\r\n", "call_processarp", GET_STAT(call_processarp));
- fprintf(w, "%-30s%lu\r\n", "call_processipout", GET_STAT(call_processipout));
- fprintf(w, "%-30s%lu\r\n", "call_processudp", GET_STAT(call_processudp));
- fprintf(w, "%-30s%lu\r\n", "call_processpap", GET_STAT(call_processpap));
- fprintf(w, "%-30s%lu\r\n", "call_processchap", GET_STAT(call_processchap));
- fprintf(w, "%-30s%lu\r\n", "call_processlcp", GET_STAT(call_processlcp));
- fprintf(w, "%-30s%lu\r\n", "call_processipcp", GET_STAT(call_processipcp));
- fprintf(w, "%-30s%lu\r\n", "call_processipin", GET_STAT(call_processipin));
- fprintf(w, "%-30s%lu\r\n", "call_processccp", GET_STAT(call_processccp));
- fprintf(w, "%-30s%lu\r\n", "call_processrad", GET_STAT(call_processrad));
- fprintf(w, "%-30s%lu\r\n", "call_sendarp", GET_STAT(call_sendarp));
- fprintf(w, "%-30s%lu\r\n", "call_sendipcp", GET_STAT(call_sendipcp));
- fprintf(w, "%-30s%lu\r\n", "call_sendchap", GET_STAT(call_sendchap));
- fprintf(w, "%-30s%lu\r\n", "call_sessionbyip", GET_STAT(call_sessionbyip));
- fprintf(w, "%-30s%lu\r\n", "call_sessionbyuser", GET_STAT(call_sessionbyuser));
- fprintf(w, "%-30s%lu\r\n", "call_tunnelsend", GET_STAT(call_tunnelsend));
- fprintf(w, "%-30s%lu\r\n", "call_tunnelkill", GET_STAT(call_tunnelkill));
- fprintf(w, "%-30s%lu\r\n", "call_tunnelshutdown", GET_STAT(call_tunnelshutdown));
- fprintf(w, "%-30s%lu\r\n", "call_sessionkill", GET_STAT(call_sessionkill));
- fprintf(w, "%-30s%lu\r\n", "call_sessionshutdown", GET_STAT(call_sessionshutdown));
- fprintf(w, "%-30s%lu\r\n", "call_sessionsetup", GET_STAT(call_sessionsetup));
- fprintf(w, "%-30s%lu\r\n", "call_assign_ip_address",GET_STAT(call_assign_ip_address));
- fprintf(w, "%-30s%lu\r\n", "call_free_ip_address", GET_STAT(call_free_ip_address));
- fprintf(w, "%-30s%lu\r\n", "call_dump_acct_info", GET_STAT(call_dump_acct_info));
- fprintf(w, "%-30s%lu\r\n", "call_radiussend", GET_STAT(call_radiussend));
- fprintf(w, "%-30s%lu\r\n", "call_radiusretry", GET_STAT(call_radiusretry));
+ cli_print(cli, "\n%-30s%-10s", "Counter", "Value");
+ cli_print(cli, "-----------------------------------------");
+ cli_print(cli, "%-30s%lu", "call_processtap", GET_STAT(call_processtap));
+ cli_print(cli, "%-30s%lu", "call_processarp", GET_STAT(call_processarp));
+ cli_print(cli, "%-30s%lu", "call_processipout", GET_STAT(call_processipout));
+ cli_print(cli, "%-30s%lu", "call_processudp", GET_STAT(call_processudp));
+ cli_print(cli, "%-30s%lu", "call_processpap", GET_STAT(call_processpap));
+ cli_print(cli, "%-30s%lu", "call_processchap", GET_STAT(call_processchap));
+ cli_print(cli, "%-30s%lu", "call_processlcp", GET_STAT(call_processlcp));
+ cli_print(cli, "%-30s%lu", "call_processipcp", GET_STAT(call_processipcp));
+ cli_print(cli, "%-30s%lu", "call_processipin", GET_STAT(call_processipin));
+ cli_print(cli, "%-30s%lu", "call_processccp", GET_STAT(call_processccp));
+ cli_print(cli, "%-30s%lu", "call_processrad", GET_STAT(call_processrad));
+ cli_print(cli, "%-30s%lu", "call_sendarp", GET_STAT(call_sendarp));
+ cli_print(cli, "%-30s%lu", "call_sendipcp", GET_STAT(call_sendipcp));
+ cli_print(cli, "%-30s%lu", "call_sendchap", GET_STAT(call_sendchap));
+ cli_print(cli, "%-30s%lu", "call_sessionbyip", GET_STAT(call_sessionbyip));
+ cli_print(cli, "%-30s%lu", "call_sessionbyuser", GET_STAT(call_sessionbyuser));
+ cli_print(cli, "%-30s%lu", "call_tunnelsend", GET_STAT(call_tunnelsend));
+ cli_print(cli, "%-30s%lu", "call_tunnelkill", GET_STAT(call_tunnelkill));
+ cli_print(cli, "%-30s%lu", "call_tunnelshutdown", GET_STAT(call_tunnelshutdown));
+ cli_print(cli, "%-30s%lu", "call_sessionkill", GET_STAT(call_sessionkill));
+ cli_print(cli, "%-30s%lu", "call_sessionshutdown", GET_STAT(call_sessionshutdown));
+ cli_print(cli, "%-30s%lu", "call_sessionsetup", GET_STAT(call_sessionsetup));
+ cli_print(cli, "%-30s%lu", "call_assign_ip_address",GET_STAT(call_assign_ip_address));
+ cli_print(cli, "%-30s%lu", "call_free_ip_address", GET_STAT(call_free_ip_address));
+ cli_print(cli, "%-30s%lu", "call_dump_acct_info", GET_STAT(call_dump_acct_info));
+ cli_print(cli, "%-30s%lu", "call_radiussend", GET_STAT(call_radiussend));
+ cli_print(cli, "%-30s%lu", "call_radiusretry", GET_STAT(call_radiusretry));
#endif
return CLI_OK;
}
-int cmd_show_version(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_show_version(struct cli_def *cli, char *command, char **argv, int argc)
{
- fprintf(w, "L2TPNS %s\r\n", VERSION);
- fprintf(w, "ID: %s\r\n", rcs_id);
+ cli_print(cli, "L2TPNS %s", VERSION);
+ cli_print(cli, "ID: %s", rcs_id);
return CLI_OK;
}
-int cmd_show_pool(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+
+int cmd_show_pool(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
- int used = 0, free = 0;
+ int used = 0, free = 0, show_all = 0;
+ time_t time_now;
+
+ if (argc > 0 && strcmp(argv[0], "all") == 0)
+ show_all = 1;
- fprintf(w, "%-15s %4s %8s %s\r\n", "IP Address", "Used", "Session", "User");
+ time(&time_now);
+ cli_print(cli, "%-15s %4s %8s %s", "IP Address", "Used", "Session", "User");
for (i = 0; i < MAXIPPOOL; i++)
{
- sessionidt s = 0;
-
if (!ip_address_pool[i].address) continue;
if (ip_address_pool[i].assigned)
{
+ sessionidt s = sessionbyip(ip_address_pool[i].address);
+ cli_print(cli, "%-15s Y %8d %s",
+ inet_toa(ip_address_pool[i].address), s, session[s].user);
+
used++;
- s = sessionbyip(ip_address_pool[i].address);
}
else
{
+ if (ip_address_pool[i].last)
+ cli_print(cli, "%-15s N %8s [%s] %ds",
+ inet_toa(ip_address_pool[i].address), "",
+ ip_address_pool[i].user, time_now - ip_address_pool[i].last);
+ else if (show_all)
+ cli_print(cli, "%-15s N", inet_toa(ip_address_pool[i].address));
+
free++;
}
+ }
+
+ if (!show_all)
+ cli_print(cli, "(Not displaying unused addresses)");
+
+ cli_print(cli, "\r\nFree: %d\r\nUsed: %d", free, used);
+ return CLI_OK;
+}
+
+void print_save_config(struct cli_def *cli, char *string)
+{
+ if (save_config_fh)
+ fprintf(save_config_fh, "%s\n", string);
+}
+
+int cmd_write_memory(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ if ((save_config_fh = fopen(config->config_file, "w")))
+ {
+ cli_print(cli, "Writing configuration");
+ cli_print_callback(cli, print_save_config);
+ cmd_show_run(cli, command, argv, argc);
+ cli_print_callback(cli, NULL);
+ fclose(save_config_fh);
+ sleep(1);
+ }
+ else
+ {
+ cli_print(cli, "Error writing configuration: %s", strerror(errno));
+ }
+ return CLI_OK;
+}
+
+int cmd_show_run(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ int i;
+
+ cli_print(cli, "# Current configuration:");
+
+ for (i = 0; config_values[i].key; i++)
+ {
+ void *value = ((void *)config) + config_values[i].offset;
+ if (config_values[i].type == STRING)
+ cli_print(cli, "set %s \"%.*s\"", config_values[i].key, config_values[i].size, (char *)value);
+ else if (config_values[i].type == IP)
+ cli_print(cli, "set %s %s", config_values[i].key, inet_toa(*(unsigned *)value));
+ else if (config_values[i].type == SHORT)
+ cli_print(cli, "set %s %hu", config_values[i].key, *(short *)value);
+ else if (config_values[i].type == BOOL)
+ cli_print(cli, "set %s %s", config_values[i].key, (*(int *)value) ? "yes" : "no");
+ else if (config_values[i].type == INT)
+ cli_print(cli, "set %s %d", config_values[i].key, *(int *)value);
+ else if (config_values[i].type == UNSIGNED_LONG)
+ cli_print(cli, "set %s %lu", config_values[i].key, *(unsigned long *)value);
+ }
+
+ cli_print(cli, "# Plugins");
+ for (i = 0; i < MAXPLUGINS; i++)
+ {
+ if (*config->plugins[i])
+ {
+ cli_print(cli, "load plugin \"%s\"", config->plugins[i]);
+ }
+ }
+
+ cli_print(cli, "# end");
+ return CLI_OK;
+}
- fprintf(w, "%-15s %4s %8d %s\r\n",
- inet_toa(ip_address_pool[i].address),
- (s) ? "Y" : "N",
- s,
- session[s].user);
+int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ char *states[] = {
+ "NULL",
+ "CHAP",
+ "AUTH",
+ "IPCP",
+ "START",
+ "STOP",
+ "WAIT",
+ };
+ int i, free = 0, used = 0, show_all = 0;
+ time_t time_now;
+
+ cli_print(cli, "%6s%6s%9s%9s%4s", "Radius", "State", "Session", "Retry", "Try");
+
+ time(&time_now);
+
+ if (argc > 0 && strcmp(argv[0], "all") == 0)
+ show_all = 1;
+
+ for (i = 1; i < MAXRADIUS; i++)
+ {
+ if (radius[i].state == RADIUSNULL)
+ free++;
+ else
+ used++;
+
+ if (!show_all && radius[i].state == RADIUSNULL) continue;
+
+ cli_print(cli, "%6d%6s%9d%9u%4d",
+ i,
+ states[radius[i].state],
+ radius[i].session,
+ radius[i].retry,
+ radius[i].try);
}
- fprintf(w, "\r\nFree: %d\r\nUsed: %d\r\n", free, used);
+
+ cli_print(cli, "\r\nFree: %d\r\nUsed: %d", free, used);
+
return CLI_OK;
}
-int cmd_show_banana(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
-{
- fputs(" _\r\n"
- "//\\\r\n"
- "V \\\r\n"
- " \\ \\_\r\n"
- " \\,'.`-.\r\n"
- " |\\ `. `.\r\n"
- " ( \\ `. `-. _,.-:\\\r\n"
- " \\ \\ `. `-._ __..--' ,-';/\r\n"
- " \\ `. `-. `-..___..---' _.--' ,'/\r\n"
- " `. `. `-._ __..--' ,' /\r\n"
- " `. `-_ ``--..'' _.-' ,'\r\n"
- " `-_ `-.___ __,--' ,'\r\n"
- " `-.__ `----\"\"\" __.-'\r\n"
- "hh `--..____..--'\r\n", w);
+int cmd_show_plugins(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ int i;
+ cli_print(cli, "Plugins currently loaded:");
+ for (i = 0; i < MAXPLUGINS; i++)
+ {
+ if (*config->plugins[i])
+ {
+ cli_print(cli, " %s", config->plugins[i]);
+ }
+ }
return CLI_OK;
}
-int cmd_clear_counters(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_show_banana(struct cli_def *cli, char *command, char **argv, int argc)
{
- fprintf(w, "Counters cleared\r\n");
+ cli_print(cli, " _\n"
+ "//\\\n"
+ "V \\\n"
+ " \\ \\_\n"
+ " \\,'.`-.\n"
+ " |\\ `. `.\n"
+ " ( \\ `. `-. _,.-:\\\n"
+ " \\ \\ `. `-._ __..--' ,-';/\n"
+ " \\ `. `-. `-..___..---' _.--' ,'/\n"
+ " `. `. `-._ __..--' ,' /\n"
+ " `. `-_ ``--..'' _.-' ,'\n"
+ " `-_ `-.___ __,--' ,'\n"
+ " `-.__ `----\"\"\" __.-'\n"
+ "hh `--..____..--'");
+
+ return CLI_OK;
+}
+
+int cmd_clear_counters(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ cli_print(cli, "Counters cleared");
SET_STAT(last_reset, time(NULL));
return CLI_OK;
}
-int cmd_drop_user(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_drop_user(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
sessionidt s;
if (!argc)
{
- fprintf(w, "Specify a user to drop\r\n");
+ cli_print(cli, "Specify a user to drop");
return CLI_OK;
}
for (i = 0; i < argc; i++)
{
if (strchr(argv[i], '?'))
{
- fprintf(w, "username ...");
+ cli_print(cli, "username ...");
return CLI_OK;
}
}
{
if (!(s = sessionbyuser(argv[i])))
{
- fprintf(w, "User %s is not connected\r\n", argv[i]);
+ cli_print(cli, "User %s is not connected", argv[i]);
continue;
}
{
int x;
- fprintf(w, "Dropping user %s\r\n", session[s].user);
+ cli_print(cli, "Dropping user %s", session[s].user);
for (x = 0; x < MAXSESSION; x++)
{
if (!cli_session_kill[x])
return CLI_OK;
}
-int cmd_drop_tunnel(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_drop_tunnel(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
tunnelidt tid;
if (!argc)
{
- fprintf(w, "Specify a tunnel to drop\r\n");
+ cli_print(cli, "Specify a tunnel to drop");
return CLI_OK;
}
for (i = 0; i < argc; i++)
{
if (strchr(argv[i], '?'))
{
- fprintf(w, "tunnel_id ...");
+ cli_print(cli, "tunnel_id ...");
return CLI_OK;
}
}
if ((tid = atol(argv[i])) <= 0 || (tid > MAXTUNNEL))
{
- fprintf(w, "Invalid tunnel ID (%d - %d)\r\n", 0, MAXTUNNEL);
+ cli_print(cli, "Invalid tunnel ID (%d - %d)", 0, MAXTUNNEL);
continue;
}
if (!tunnel[tid].ip)
{
- fprintf(w, "Tunnel %d is not connected\r\n", tid);
+ cli_print(cli, "Tunnel %d is not connected", tid);
continue;
}
if (tunnel[tid].die)
{
- fprintf(w, "Tunnel %d is already being shut down\r\n", tid);
+ cli_print(cli, "Tunnel %d is already being shut down", tid);
continue;
}
if (!cli_tunnel_kill[x])
{
cli_tunnel_kill[x] = tid;
- fprintf(w, "Tunnel %d shut down (%s)\r\n", tid, tunnel[tid].hostname);
+ cli_print(cli, "Tunnel %d shut down (%s)", tid, tunnel[tid].hostname);
break;
}
}
return CLI_OK;
}
-int cmd_drop_session(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
sessionidt s;
if (!argc)
{
- fprintf(w, "Specify a session id to drop\r\n");
+ cli_print(cli, "Specify a session id to drop");
return CLI_OK;
}
for (i = 0; i < argc; i++)
{
if (strchr(argv[i], '?'))
{
- fprintf(w, "session_id ...");
+ cli_print(cli, "session_id ...");
return CLI_OK;
}
}
{
if ((s = atol(argv[i])) <= 0 || (s > MAXSESSION))
{
- fprintf(w, "Invalid session ID (%d - %d)\r\n", 0, MAXSESSION);
+ cli_print(cli, "Invalid session ID (%d - %d)", 0, MAXSESSION);
continue;
}
- if (session[s].ip && session[s].opened && !session[s].die)
+ if (session[s].opened && !session[s].die)
{
int x;
for (x = 0; x < MAXSESSION; x++)
break;
}
}
- fprintf(w, "Dropping session %d\r\n", s);
+ cli_print(cli, "Dropping session %d", s);
}
else
{
- fprintf(w, "Session %d is not active.\r\n", s);
+ cli_print(cli, "Session %d is not active.", s);
}
}
return CLI_OK;
}
-int cmd_snoop(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_snoop(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
sessionidt s;
if (!argc)
{
- fprintf(w, "Specify a user\r\n");
+ cli_print(cli, "Specify a user");
return CLI_OK;
}
for (i = 0; i < argc; i++)
{
if (strchr(argv[i], '?'))
{
- fprintf(w, "username ...");
+ cli_print(cli, "username ...");
return CLI_OK;
}
}
{
if (!(s = sessionbyuser(argv[i])))
{
- fprintf(w, "User %s is not connected\r\n", argv[i]);
+ cli_print(cli, "User %s is not connected", argv[i]);
continue;
}
session[s].snoop = 1;
- fprintf(w, "Snooping user %s\r\n", argv[i]);
+ cli_print(cli, "Snooping user %s", argv[i]);
}
return CLI_OK;
}
-int cmd_no_snoop(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_no_snoop(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
sessionidt s;
if (!argc)
{
- fprintf(w, "Specify a user\r\n");
+ cli_print(cli, "Specify a user");
return CLI_OK;
}
for (i = 0; i < argc; i++)
{
if (strchr(argv[i], '?'))
{
- fprintf(w, "username ...");
+ cli_print(cli, "username ...");
return CLI_OK;
}
}
{
if (!(s = sessionbyuser(argv[i])))
{
- fprintf(w, "User %s is not connected\r\n", argv[i]);
+ cli_print(cli, "User %s is not connected", argv[i]);
continue;
}
session[s].snoop = 0;
- fprintf(w, "Not snooping user %s\r\n", argv[i]);
+ cli_print(cli, "Not snooping user %s", argv[i]);
}
return CLI_OK;
}
-int cmd_throttle(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_throttle(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
sessionidt s;
if (!argc)
{
- fprintf(w, "Specify a user\r\n");
+ cli_print(cli, "Specify a user");
return CLI_OK;
}
for (i = 0; i < argc; i++)
{
if (strchr(argv[i], '?'))
{
- fprintf(w, "username ...");
+ cli_print(cli, "username ...");
return CLI_OK;
}
}
{
if (!(s = sessionbyuser(argv[i])))
{
- fprintf(w, "User %s is not connected\r\n", argv[i]);
+ cli_print(cli, "User %s is not connected", argv[i]);
continue;
}
throttle_session(s, 1);
- fprintf(w, "throttling user %s\r\n", argv[i]);
+ cli_print(cli, "throttling user %s", argv[i]);
}
return CLI_OK;
}
-int cmd_no_throttle(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_no_throttle(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
sessionidt s;
if (!argc)
{
- fprintf(w, "Specify a user\r\n");
+ cli_print(cli, "Specify a user");
return CLI_OK;
}
for (i = 0; i < argc; i++)
{
if (strchr(argv[i], '?'))
{
- fprintf(w, "username ...");
+ cli_print(cli, "username ...");
return CLI_OK;
}
}
{
if (!(s = sessionbyuser(argv[i])))
{
- fprintf(w, "User %s is not connected\r\n", argv[i]);
+ cli_print(cli, "User %s is not connected", argv[i]);
continue;
}
throttle_session(s, 0);
- fprintf(w, "unthrottling user %s\r\n", argv[i]);
+ cli_print(cli, "unthrottling user %s", argv[i]);
}
return CLI_OK;
}
-int cmd_debug(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_debug(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
if (!argc)
{
- fprintf(w, "Currently debugging: ");
- if (debug_flags.critical) fprintf(w, "critical ");
- if (debug_flags.error) fprintf(w, "error ");
- if (debug_flags.warning) fprintf(w, "warning ");
- if (debug_flags.info) fprintf(w, "info ");
- if (debug_flags.calls) fprintf(w, "calls ");
- if (debug_flags.data) fprintf(w, "data ");
- fprintf(w, "\r\n");
+ cli_print(cli, "Currently debugging: ");
+ if (debug_flags.critical) cli_print(cli, "critical ");
+ if (debug_flags.error) cli_print(cli, "error ");
+ if (debug_flags.warning) cli_print(cli, "warning ");
+ if (debug_flags.info) cli_print(cli, "info ");
+ if (debug_flags.calls) cli_print(cli, "calls ");
+ if (debug_flags.data) cli_print(cli, "data ");
+ cli_print(cli, "");
return CLI_OK;
}
{
if (*argv[i] == '?')
{
- fprintf(w, "Possible debugging states are:\r\n");
- fprintf(w, " critical\r\n");
- fprintf(w, " error\r\n");
- fprintf(w, " warning\r\n");
- fprintf(w, " info\r\n");
- fprintf(w, " calls\r\n");
- fprintf(w, " data\r\n");
+ cli_print(cli, "Possible debugging states are:");
+ cli_print(cli, " critical");
+ cli_print(cli, " error");
+ cli_print(cli, " warning");
+ cli_print(cli, " info");
+ cli_print(cli, " calls");
+ cli_print(cli, " data");
return CLI_OK;
}
}
return CLI_OK;
}
-int cmd_no_debug(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_no_debug(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
return CLI_OK;
}
-int cmd_watch_session(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_watch_session(struct cli_def *cli, char *command, char **argv, int argc)
{
sessionidt s;
if (argc != 1)
{
- fprintf(w, "Specify a single session to debug (0 to disable)\r\n");
+ cli_print(cli, "Specify a single session to debug (0 to disable)");
return CLI_OK;
}
s = atoi(argv[0]);
if (debug_session)
- fprintf(w, "No longer debugging session %d\r\n", debug_session);
+ cli_print(cli, "No longer debugging session %d", debug_session);
- if (s) fprintf(w, "Debugging session %d.\r\n", s);
+ if (s) cli_print(cli, "Debugging session %d.", s);
debug_session = s;
return CLI_OK;
}
-int cmd_watch_tunnel(struct cli_def *cli, FILE *w, char *command, char **argv, int argc)
+int cmd_watch_tunnel(struct cli_def *cli, char *command, char **argv, int argc)
{
tunnelidt s;
if (argc != 1)
{
- fprintf(w, "Specify a single tunnel to debug (0 to disable)\r\n");
+ cli_print(cli, "Specify a single tunnel to debug (0 to disable)");
return CLI_OK;
}
s = atoi(argv[0]);
if (debug_tunnel)
- fprintf(w, "No longer debugging tunnel %d\r\n", debug_tunnel);
+ cli_print(cli, "No longer debugging tunnel %d", debug_tunnel);
- if (s) fprintf(w, "Debugging tunnel %d.\r\n", s);
+ if (s) cli_print(cli, "Debugging tunnel %d.", s);
debug_tunnel = s;
return CLI_OK;
}
-int regular_stuff(struct cli_def *cli, FILE *w)
+int cmd_load_plugin(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ int i, firstfree = 0;
+ if (argc != 1)
+ {
+ cli_print(cli, "Specify a plugin to load");
+ return CLI_OK;
+ }
+
+ for (i = 0; i < MAXPLUGINS; i++)
+ {
+ if (!*config->plugins[i] && !firstfree)
+ firstfree = i;
+ if (strcmp(config->plugins[i], argv[0]) == 0)
+ {
+ cli_print(cli, "Plugin is already loaded");
+ return CLI_OK;
+ }
+ }
+
+ if (firstfree)
+ {
+ strncpy(config->plugins[firstfree], argv[0], sizeof(config->plugins[firstfree]) - 1);
+ config->reload_config = 1;
+ cli_print(cli, "Loading plugin %s", argv[0]);
+ }
+
+ return CLI_OK;
+}
+
+int cmd_remove_plugin(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ int i;
+
+ if (argc != 1)
+ {
+ cli_print(cli, "Specify a plugin to remove");
+ return CLI_OK;
+ }
+
+ for (i = 0; i < MAXPLUGINS; i++)
+ {
+ if (strcmp(config->plugins[i], argv[0]) == 0)
+ {
+ config->reload_config = 1;
+ memset(config->plugins[i], 0, sizeof(config->plugins[i]));
+ return CLI_OK;
+ }
+ }
+
+ cli_print(cli, "Plugin is not loaded");
+ return CLI_OK;
+}
+
+char *duration(time_t seconds)
+{
+ static char *buf = NULL;
+ if (!buf) buf = calloc(64, 1);
+
+ if (seconds > 86400)
+ sprintf(buf, "%d days", (int)(seconds / 86400.0));
+ else if (seconds > 60)
+ sprintf(buf, "%02d:%02lu", (int)(seconds / 3600.0), seconds % 60);
+ else
+ sprintf(buf, "%lu sec", seconds);
+ return buf;
+}
+
+int cmd_uptime(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ FILE *fh;
+ char buf[100], *p = buf, *loads[3];
+ int i, num_sessions = 0;
+ time_t time_now;
+
+ fh = fopen("/proc/loadavg", "r");
+ fgets(buf, 100, fh);
+ fclose(fh);
+
+ for (i = 0; i < 3; i++)
+ loads[i] = strdup(strsep(&p, " "));
+
+ time(&time_now);
+ strftime(buf, 99, "%H:%M:%S", localtime(&time_now));
+
+ for (i = 1; i < MAXSESSION; i++)
+ if (session[i].opened) num_sessions++;
+
+ cli_print(cli, "%s up %s, %d users, load average: %s, %s, %s",
+ buf,
+ duration(abs(time_now - config->start_time)),
+ num_sessions,
+ loads[0], loads[1], loads[2]
+ );
+ for (i = 0; i < 3; i++)
+ if (loads[i]) free(loads[i]);
+
+ cli_print(cli, "Bandwidth: %s", config->bandwidth);
+
+ return CLI_OK;
+}
+
+int cmd_set(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ int i;
+
+ if (argc != 2)
+ {
+ cli_print(cli, "Usage: set <variable> <value>");
+ return CLI_OK;
+ }
+
+ for (i = 0; config_values[i].key; i++)
+ {
+ void *value = ((void *)config) + config_values[i].offset;
+ if (strcmp(config_values[i].key, argv[0]) == 0)
+ {
+ // Found a value to set
+ cli_print(cli, "Setting \"%s\" to \"%s\"", argv[0], argv[1]);
+ switch (config_values[i].type)
+ {
+ case STRING:
+ strncpy((char *)value, argv[1], config_values[i].size - 1);
+ break;
+ case INT:
+ *(int *)value = atoi(argv[1]);
+ break;
+ case UNSIGNED_LONG:
+ *(unsigned long *)value = atol(argv[1]);
+ break;
+ case SHORT:
+ *(short *)value = atoi(argv[1]);
+ break;
+ case IP:
+ *(unsigned *)value = inet_addr(argv[1]);
+ break;
+ case BOOL:
+ if (strcasecmp(argv[1], "yes") == 0 || strcasecmp(argv[1], "true") == 0 || strcasecmp(argv[1], "1") == 0)
+ *(int *)value = 1;
+ else
+ *(int *)value = 0;
+ break;
+ default:
+ cli_print(cli, "Unknown variable type");
+ break;
+ }
+ config->reload_config = 1;
+ return CLI_OK;
+ }
+ }
+
+ cli_print(cli, "Unknown variable \"%s\"", argv[0]);
+ return CLI_OK;
+}
+
+int regular_stuff(struct cli_def *cli)
{
int i = debug_rb_tail;
+ int reprompt = 0;
#ifdef RINGBUFFER
while (i != ringbuffer->tail)
memcpy(&addr, &address, sizeof(ringbuffer->buffer[i].address));
ipaddr = inet_ntoa(addr);
- fprintf(w, "%s-%s-%u-%u %s\r",
+ cli_print(cli, "\r%s-%s-%u-%u %s",
debug_levels[(int)ringbuffer->buffer[i].level],
ipaddr,
ringbuffer->buffer[i].tunnel,
ringbuffer->buffer[i].session,
ringbuffer->buffer[i].message);
+
+ reprompt = 1;
}
if (++i == ringbuffer->tail) break;
}
debug_rb_tail = ringbuffer->tail;
+ if (reprompt)
+ cli_reprompt(cli);
#endif
return CLI_OK;
}
-
-#endif
// L2TPNS Clustering Stuff
-// $Id: cluster.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $ #include <stdio.h> #include <sys/file.h>
+// $Id: cluster.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $ #include <stdio.h> #include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
// L2TPNS Clustering Stuff
-// $Id: cluster.h,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: cluster.h,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#define C_HELLO 1
#define C_HELLO_RESPONSE 2
#define C_PING 3
#define C_TUNNEL 4
#define C_SESSION 5
+#define C_GOODBYE 6
#define CLUSTERPORT 32792
#define CLUSTERCLIENTPORT 32793
// L2TPNS Cluster Master
-// $Id: cluster_master.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: cluster_master.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#include <stdio.h>
#include <netinet/in.h>
int handle_tunnel(char *buf, int l, uint32_t addr);
int handle_session(char *buf, int l, uint32_t addr);
int handle_ping(char *buf, int l, uint32_t addr);
+int handle_goodbye(char *buf, int l, uint32_t addr);
int backup_up(slave *s);
int backup_down(slave *s);
int return_state(slave *s);
signal(SIGCHLD, sigchild_handler);
- log(0, "Cluster Manager $Id: cluster_master.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $ starting\n");
+ log(0, "Cluster Manager $Id: cluster_master.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $ starting\n");
to.tv_sec = 1;
to.tv_usec = 0;
int processmsg(char *buf, int l, struct sockaddr_in *src_addr)
{
+ slave *s;
char mtype;
uint32_t addr;
mtype = *buf; buf++; l--;
+ if (mtype != C_GOODBYE && (s = find_slave(addr)) && s->down)
+ {
+ char *hostname;
+ hostname = calloc(l + 1, 1);
+ memcpy(hostname, buf, l);
+ log(1, "Slave \"%s\" (for %s) has come back.\n", hostname, inet_toa(s->ip_address));
+ backup_down(s);
+ free(hostname);
+ }
+
switch (mtype)
{
case C_HELLO:
if (!find_slave(addr)) handle_hello((char *)(buf + 1), *(char *)buf, src_addr, addr);
handle_session(buf, l, addr);
break;
+ case C_GOODBYE:
+ if (!find_slave(addr)) break;
+ handle_goodbye(buf, l, addr);
+ break;
}
return mtype;
}
return 0;
}
+int handle_goodbye(char *buf, int l, uint32_t addr)
+{
+ int i;
+ slave *s;
+
+ // Is this a slave we have state information for?
+ if ((s = find_slave(addr)))
+ {
+ log(0, "Received goodbye for slave %s\n", s->hostname);
+ ll_delete(slaves, s);
+ for (i = 0; i < s->num_tunnels; i++)
+ if (s->tunnels[i]) free(s->tunnels[i]);
+ for (i = 0; i < s->num_sessions; i++)
+ if (s->sessions[i]) free(s->sessions[i]);
+ if (s->hostname) free(s->hostname);
+ free(s);
+ }
+
+ return 0;
+}
+
// L2TPNS Cluster Master
-// $Id: cluster_slave.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: cluster_slave.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#include <stdio.h>
#include <netinet/in.h>
#include "ll.h"
#include "util.h"
+// vim: sw=4 ts=8
+
extern int cluster_sockfd;
-extern tunnelt *tunnel;
-extern sessiont *session;
-extern uint32_t cluster_address;
extern char hostname[1000];
-extern int debug;
extern ippoolt *ip_address_pool;
extern uint32_t vip_address;
-extern tunnelidt tunnelfree;
-extern sessionidt sessionfree;
+extern struct configt *config;
int handle_tunnel(char *buf, int l);
int handle_session(char *buf, int l);
{
int t;
+ // Ignore tunnel message if NOSTATEFILE exists
+ if (config->ignore_cluster_updates)
+ {
+ log(1, 0, 0, 0, "Discarding tunnel message from cluster master.\n", l, sizeof(tunnelt));
+ return 0;
+ }
+
t = *(int *)buf;
log(1, 0, 0, t, "Receiving tunnel %d from cluster master (%d bytes)\n", t, l);
buf += sizeof(int); l -= sizeof(int);
return 0;
}
- if (t > 1)
- {
- tunnel[t-1].next = tunnel[t].next;
- }
-
- if (tunnelfree == t)
- {
- tunnelfree = tunnel[t].next;
- }
-
memcpy(&tunnel[t], buf, l);
log(3, 0, 0, t, "Cluster master sent tunnel for %s\n", tunnel[t].hostname);
{
int s;
+ // Ignore tunnel message if NOSTATEFILE exists
+ if (config->ignore_cluster_updates)
+ {
+ log(1, 0, 0, 0, "Discarding session message from cluster master.\n", l, sizeof(tunnelt));
+ return 0;
+ }
+
s = *(int *)buf;
log(1, 0, s, 0, "Receiving session %d from cluster master (%d bytes)\n", s, l);
buf += sizeof(int); l -= sizeof(int);
}
}
}
+ /*
+ if (session[s].servicenet)
+ servicenet_session(s, 1);
+ */
return 0;
}
memcpy((char *)(packet + len), &session[s], sizeof(sessiont));
len += sizeof(sessiont);
- cluster_send_message(cluster_address, vip_address, C_SESSION, packet, len);
+ cluster_send_message(config->cluster_address, vip_address, C_SESSION, packet, len);
free(packet);
return 1;
memcpy((char *)(packet + len), &tunnel[t], sizeof(tunnelt));
len += sizeof(tunnelt);
- cluster_send_message(cluster_address, vip_address, C_TUNNEL, packet, len);
+ cluster_send_message(config->cluster_address, vip_address, C_TUNNEL, packet, len);
+ free(packet);
+
+ return 1;
+}
+
+int cluster_send_goodbye()
+{
+ char *packet;
+ int len = 0;
+
+ packet = malloc(4096);
+
+ log(2, 0, 0, 0, "Sending goodbye to cluster master\n");
+ // Hostname
+ len = strlen(hostname);
+ *(char *)packet = len;
+ memcpy((char *)(packet + 1), hostname, len);
+ len++;
+
+ cluster_send_message(config->cluster_address, vip_address, C_GOODBYE, packet, len);
free(packet);
return 1;
int __plugin_api_version = 1;
struct pluginfuncs p;
-int garden_session(sessiont *s, int flag);
-
char *init_commands[] = {
// This is for incoming connections to a gardened user
"iptables -t nat -N garden_users 2>&1 >/dev/null",
- "iptables -t nat -F garden_users 2>&1 >/dev/null",
- "iptables -t nat -N garden 2>&1 >/dev/null",
+ "iptables -t nat -F garden_users",
+ "iptables -t nat -N garden 2>&1", /* Don't flush - init script sets this up */
"iptables -t nat -A l2tpns -j garden_users",
NULL
};
char *done_commands[] = {
"iptables -t nat -F garden_users 2>&1 >/dev/null",
- "iptables -t nat -D l2tpns -j garden_users 2>&1 >/dev/null",
+ "iptables -t nat -D l2tpns -j garden_users",
NULL
};
+int garden_session(sessiont *s, int flag);
+
int plugin_post_auth(struct param_post_auth *data)
{
// Ignore if user authentication was successful
if (data->auth_allowed) return PLUGIN_RET_OK;
- p.log(3, 0, 0, 0, "User allowed into walled garden\n");
+ p.log(3, 0, 0, 0, "Walled Garden allowing login\n");
data->auth_allowed = 1;
- data->s->walled_garden = 1;
+ data->s->garden = 1;
return PLUGIN_RET_OK;
}
int plugin_new_session(struct param_new_session *data)
{
- if (data->s->walled_garden) garden_session(data->s, 1);
+ if (data->s->garden) garden_session(data->s, 1);
return PLUGIN_RET_OK;
}
int plugin_kill_session(struct param_new_session *data)
{
- if (data->s->walled_garden) garden_session(data->s, 0);
+ if (data->s->garden) garden_session(data->s, 0);
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;
-
+ if (!session) return PLUGIN_RET_OK; // Really?
data->send_response = 1;
s = p.get_session_by_id(session);
if (!s || !s->ip)
return PLUGIN_RET_STOP;
}
-int plugin_config(struct param_config *data)
-{
- return PLUGIN_RET_OK;
-}
-
int garden_session(sessiont *s, int flag)
{
char cmd[2048];
if (!s) return 0;
if (!s->opened) return 0;
+ /* Note that we don't handle throttling/snooping/etc here
+ * To do that, we'd need to send an end accounting record
+ * then a radius auth, then start accouting again.
+ * That means that we need the password (which garden has)
+ * and a lot of code to check that the new set of params
+ * (routes, IP, ACLs, etc) 'matched' the old one in a
+ * 'compatable' way. (ie user's system doesn't need to be told
+ * of the change)
+ *
+ * Thats a lot of pain/code for very little gain.
+ * If we want them redone from scratch, just sessionkill them -
+ * a user on garden isn't going to have any open TCP
+ * connections which are worth caring about, anyway.
+ *
+ * Note that the user will be rethrottled shortly by the scan
+ * script thingy if appropriate.
+ *
+ * Currently, garden only directly ungardens someone if
+ * they haven't paid their bill, and then subsequently do so
+ * online. This isn't something which can be set up by a malicious
+ * customer at will.
+ */
if (flag == 1)
{
+ // Gardened User
p.log(2, 0, 0, s->tunnel, "Trap user %s (%s) in walled garden\n", s->user, p.inet_toa(ntohl(s->ip)));
snprintf(cmd, 2048, "iptables -t nat -A garden_users -s %s -j garden", p.inet_toa(ntohl(s->ip)));
p.log(3, 0, 0, s->tunnel, "%s\n", cmd);
system(cmd);
- s->walled_garden = 1;
+ s->garden = 1;
}
else
{
sessionidt other;
- int count = 10;
+ int count = 40;
// Normal User
p.log(2, 0, 0, s->tunnel, "Release user %s (%s) from walled garden\n", s->user, p.inet_toa(ntohl(s->ip)));
// Kick off any duplicate usernames
// but make sure not to kick off ourself
if (s->ip && !s->die && (other = p.get_session_by_username(s->user)) && s != p.get_session_by_id(other)) {
- p.sessionkill(other, "Duplicate session when user ungardened");
+ p.sessionkill(other, "Duplicate session when user un-gardened");
}
/* Clean up counters */
s->cin = s->cout = 0;
if (WEXITSTATUS(status) != 0) break;
}
- s->walled_garden = 0;
+ s->garden = 0;
if (!s->die) {
/* OK, we're up! */
p.radiussend(r, RADIUSSTART);
}
}
- s->walled_garden = flag;
+ s->garden = flag;
return 1;
}
if (!funcs) return 0;
memcpy(&p, funcs, sizeof(p));
- p.log(1, 0, 0, 0, "Enabling walled garden service\n");
-
for (i = 0; init_commands[i] && *init_commands[i]; i++)
{
- p.log(4, 0, 0, 0, "Running %s\n", init_commands[i]);
+ p.log(3, 0, 0, 0, "Running %s\n", init_commands[i]);
system(init_commands[i]);
}
int i;
for (i = 0; done_commands[i] && *done_commands[i]; i++)
{
- p.log(4, 0, 0, 0, "Running %s\n", done_commands[i]);
+ p.log(3, 0, 0, 0, "Running %s\n", done_commands[i]);
system(done_commands[i]);
}
}
--- /dev/null
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <linux/ip.h>
+#include <linux/icmp.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <memory.h>
+#include "l2tpns.h"
+
+extern ipt myip;
+
+__u16 _checksum(unsigned char *addr, int count);
+
+void host_unreachable(ipt destination, u16 id, ipt source, char *packet, int packet_len)
+{
+ char buf[128] = {0};
+ struct iphdr *iph;
+ struct icmphdr *icmp;
+ char *data;
+ int len = 0, on = 1, icmp_socket;
+ struct sockaddr_in whereto = {0};
+
+ if (!(icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)))
+ return;
+ setsockopt(icmp_socket, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on));
+
+ whereto.sin_addr.s_addr = destination;
+ whereto.sin_family = AF_INET;
+
+ iph = (struct iphdr *)(buf);
+ len = sizeof(struct iphdr);
+ icmp = (struct icmphdr *)(buf + len);
+ len += sizeof(struct icmphdr);
+ data = (char *)(buf + len);
+ len += (packet_len < 64) ? packet_len : 64;
+ memcpy(data, packet, (packet_len < 64) ? packet_len : 64);
+
+ iph->tos = 0;
+ iph->id = id;
+ iph->frag_off = 0;
+ iph->ttl = 30;
+ iph->check = 0;
+ iph->version = 4;
+ iph->ihl = 5;
+ iph->protocol = 1;
+ iph->check = 0;
+ iph->daddr = destination;
+ iph->saddr = source;
+
+ iph->tot_len = ntohs(len);
+
+ icmp->type = ICMP_DEST_UNREACH;
+ icmp->code = ICMP_HOST_UNREACH;
+ icmp->checksum = _checksum((char *)icmp, sizeof(struct icmphdr) + ((packet_len < 64) ? packet_len : 64));
+
+ iph->check = _checksum((char *)iph, sizeof(struct iphdr));
+
+ sendto(icmp_socket, (char *)buf, len, 0, (struct sockaddr *)&whereto, sizeof(struct sockaddr));
+ close(icmp_socket);
+}
+
+__u16 _checksum(unsigned char *addr, int count)
+{
+ register long sum = 0;
+
+ for (; count > 1; count -= 2)
+ {
+ sum += ntohs(*(u32 *)addr);
+ addr += 2;
+ }
+
+ if (count > 1) sum += *(unsigned char *)addr;
+
+ // take only 16 bits out of the 32 bit sum and add up the carries
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ // one's complement the result
+ sum = ~sum;
+
+ return htons((u16) sum);
+}
#include <errno.h>
#include <fcntl.h>
#include <linux/if_tun.h>
+#define SYSLOG_NAMES
+#include <syslog.h>
#include <malloc.h>
#include <math.h>
#include <net/route.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
+#define __USE_GNU
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <linux/if.h>
+#include <stddef.h>
#include <time.h>
#include <dlfcn.h>
#include <unistd.h>
-#ifdef HAVE_LIBCLI
-#include <libcli.h>
-#endif
#include "md5.h"
#include "l2tpns.h"
#include "cluster.h"
#include "control.h"
#include "util.h"
-ipt radiusserver[MAXRADSERVER]; // radius servers
-u8 numradiusservers = 0; // how many radius servers
-
// Globals
-char tapdevice[10] = ""; // tap device name
-int tapfd = -1; // tap interface file handle
-int udpfd = -1; // UDP file handle
-int controlfd = -1; // Control signal handle
-int snoopfd = -1; // UDP file handle for sending out intercept data
-int radfd = -1; // RADIUS requests file handle
-int ifrfd = -1; // File descriptor for routing, etc
-char debug = 0; // debug leveL
-time_t basetime = 0; // base clock
-char hostname[1000] = ""; // us.
-ipt myip = 0; // MY IP
-u16 tapmac[3]; // MAC of tap interface
-int tapidx; // ifr_ifindex of tap device
-char *radiussecret = 0; // RADIUS secret
-char *l2tpsecret = 0; // L2TP secret
-u32 sessionid = 0; // session id for radius accounting
-char *snoop_destination_host = NULL;
-u16 snoop_destination_port = 0;
-char *log_filename = NULL;
-char *config_file = CONFIGFILE;
+struct configt *config = NULL; // all configuration
+int tapfd = -1; // tap interface file handle
+int udpfd = -1; // UDP file handle
+int controlfd = -1; // Control signal handle
+int snoopfd = -1; // UDP file handle for sending out intercept data
+int radfd = -1; // RADIUS requests file handle
+int ifrfd = -1; // File descriptor for routing, etc
+time_t basetime = 0; // base clock
+char hostname[1000] = ""; // us.
+ipt myip = 0; // MY IP
+u16 tapmac[3]; // MAC of tap interface
+int tapidx; // ifr_ifindex of tap device
+u32 sessionid = 0; // session id for radius accounting
+int syslog_log = 0; // are we logging to syslog
FILE *log_stream = NULL;
-unsigned long default_dns1 = 0, default_dns2 = 0;
struct sockaddr_in snoop_addr = {0};
-extern unsigned long rl_rate;
extern int cluster_sockfd;
unsigned long last_sid = 0;
-int config_save_state = 0;
-int radius_accounting = 0;
-char *accounting_dir = NULL;
-uint32_t cluster_address = 0;
-uint32_t bind_address = INADDR_ANY;
int handle_interface = 0;
-#ifdef HAVE_LIBCLI
-pid_t cli_pid = 0;
int clifd = 0;
sessionidt *cli_session_kill = NULL;
tunnelidt *cli_tunnel_kill = NULL;
-#endif
static void *ip_hash[256];
unsigned long udp_tx = 0, udp_rx = 0, udp_rx_pkt = 0;
unsigned long eth_tx = 0, eth_rx = 0, eth_rx_pkt = 0;
-unsigned int ip_pool_index = 0;
unsigned int ip_pool_size = 0;
time_t time_now;
char time_now_string[64] = {0};
char main_quit = 0;
-int dump_speed = 0;
-int target_uid = 500;
char *_program_name = NULL;
linked_list *loaded_plugins;
linked_list *plugins[MAX_PLUGIN_TYPES];
+#define membersize(STRUCT, MEMBER) sizeof(((STRUCT *)0)->MEMBER)
+#define CONFIG(NAME, MEMBER, TYPE) { NAME, offsetof(struct configt, MEMBER), membersize(struct configt, MEMBER), TYPE }
+
+struct config_descriptt config_values[] = {
+ CONFIG("debug", debug, INT),
+ CONFIG("log_file", log_filename, STRING),
+ CONFIG("l2tp_secret", l2tpsecret, STRING),
+ CONFIG("primary_dns", default_dns1, IP),
+ CONFIG("secondary_dns", default_dns2, IP),
+ CONFIG("save_state", save_state, BOOL),
+ CONFIG("snoop_host", snoop_destination_host, IP),
+ CONFIG("snoop_port", snoop_destination_port, SHORT),
+ CONFIG("primary_radius", radiusserver[0], IP),
+ CONFIG("secondary_radius", radiusserver[1], IP),
+ CONFIG("radius_accounting", radius_accounting, BOOL),
+ CONFIG("radius_secret", radiussecret, STRING),
+ CONFIG("bind_address", bind_address, IP),
+ CONFIG("cluster_master", cluster_address, IP),
+ CONFIG("throttle_speed", rl_rate, UNSIGNED_LONG),
+ CONFIG("accounting_dir", accounting_dir, STRING),
+ CONFIG("setuid", target_uid, INT),
+ CONFIG("dump_speed", dump_speed, BOOL),
+ { NULL, 0, 0, 0 },
+};
+
char *plugin_functions[] = {
NULL,
"plugin_pre_auth",
"plugin_packet_rx",
"plugin_packet_tx",
"plugin_timer",
- "plugin_config",
"plugin_new_session",
"plugin_kill_session",
"plugin_control",
};
#define max_plugin_functions (sizeof(plugin_functions) / sizeof(char *))
-tunnelt *tunnel = NULL; // 1000 * 45 = 45000 = 45k
+tunnelt *tunnel = NULL; // 1000 * 45 = 45000 = 45k
sessiont *session = NULL; // 5000 * 213 = 1065000 = 1 Mb
radiust *radius = NULL;
ippoolt *ip_address_pool = NULL;
-tunnelidt tunnelfree; // free list link heads
-sessionidt sessionfree = 0;
-u8 radiusfree;
controlt *controlfree = 0;
struct Tstats *_statistics = NULL;
#ifdef RINGBUFFER
void read_config_file();
void read_state();
void dump_state();
+void tunnel_clean();
+tunnelidt new_tunnel();
+void update_config();
// return internal time (10ths since run)
clockt now(void)
void _log(int level, ipt address, sessionidt s, tunnelidt t, const char *format, ...)
{
+ static char message[65535] = {0};
+ static char message2[65535] = {0};
va_list ap;
#ifdef RINGBUFFER
}
#endif
- if (debug < level) return;
+ if (config->debug < level) return;
- if (!log_stream && log_filename)
+ va_start(ap, format);
+ if (log_stream)
{
- if ((log_stream = fopen(log_filename, "a")))
- fseek(log_stream, 0, SEEK_END);
- setbuf(log_stream, NULL);
+ vsnprintf(message2, 65535, format, ap);
+ snprintf(message, 65535, "%s %02d/%02d %s", time_now_string, t, s, message2);
+ fprintf(log_stream, message);
}
- if (!log_stream)
+ else if (syslog_log)
{
- log_stream = stderr;
- setbuf(log_stream, NULL);
+ vsnprintf(message2, 65535, format, ap);
+ snprintf(message, 65535, "%02d/%02d %s", t, s, message2);
+ syslog(level + 2, message); // We don't need LOG_EMERG or LOG_ALERT
}
-
- va_start(ap, format);
- fprintf(log_stream, "%s %02d/%02d ", time_now_string, t, s);
- vfprintf(log_stream, format, ap);
va_end(ap);
}
void _log_hex(int level, ipt address, sessionidt s, tunnelidt t, const char *title, const char *data, int maxsize)
{
- unsigned int i, j;
+ int i, j;
unsigned const char *d = (unsigned const char *)data;
- if (debug < level) return;
- log(level, address, s, t, "%s (%d bytes):\n", title, maxsize);
- setvbuf(log_stream, NULL, _IOFBF, 16384);
- for (i = 0; i < maxsize; )
+ if (config->debug < level) return;
+
+ // No support for log_hex to syslog
+ if (log_stream)
{
- fprintf(log_stream, "%4X: ", i);
- for (j = i; j < maxsize && j < (i + 16); j++)
- {
- fprintf(log_stream, "%02X ", d[j]);
- if (j == i + 7)
- fputs(": ", log_stream);
- }
+ log(level, address, s, t, "%s (%d bytes):\n", title, maxsize);
+ setvbuf(log_stream, NULL, _IOFBF, 16384);
- for (; j < i + 16; j++)
+ for (i = 0; i < maxsize; )
{
- fputs(" ", log_stream);
- if (j == i + 7)
- fputs(": ", log_stream);
- }
+ fprintf(log_stream, "%4X: ", i);
+ for (j = i; j < maxsize && j < (i + 16); j++)
+ {
+ fprintf(log_stream, "%02X ", d[j]);
+ if (j == i + 7)
+ fputs(": ", log_stream);
+ }
- fputs(" ", log_stream);
- for (j = i; j < maxsize && j < (i + 16); j++)
- {
- if (d[j] >= 0x20 && d[j] < 0x7f && d[j] != 0x20)
- fputc(d[j], log_stream);
- else
- fputc('.', log_stream);
+ for (; j < i + 16; j++)
+ {
+ fputs(" ", log_stream);
+ if (j == i + 7)
+ fputs(": ", log_stream);
+ }
- if (j == i + 7)
- fputs(" ", log_stream);
+ fputs(" ", log_stream);
+ for (j = i; j < maxsize && j < (i + 16); j++)
+ {
+ if (d[j] >= 0x20 && d[j] < 0x7f && d[j] != 0x20)
+ fputc(d[j], log_stream);
+ else
+ fputc('.', log_stream);
+
+ if (j == i + 7)
+ fputs(" ", log_stream);
+ }
+
+ i = j;
+ fputs("\n", log_stream);
}
- i = j;
- fputs("\n", log_stream);
+ fflush(log_stream);
+ setbuf(log_stream, NULL);
}
- fflush(log_stream);
- setbuf(log_stream, NULL);
}
{
struct rtentry r;
memset(&r, 0, sizeof(r));
- r.rt_dev = tapdevice;
+ r.rt_dev = config->tapdevice;
r.rt_dst.sa_family = AF_INET;
*(u32 *) & (((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr) = htonl(ip);
r.rt_gateway.sa_family = AF_INET;
*(u32 *) & (((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr) = htonl(gw);
r.rt_genmask.sa_family = AF_INET;
- *(u32 *) & (((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr) = htonl(mask ? : 0xFFFFFFF);
+ *(u32 *) & (((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr) = htonl(mask ? mask : 0xFFFFFFF);
r.rt_flags = (RTF_UP | RTF_STATIC);
if (gw)
r.rt_flags |= RTF_GATEWAY;
log(0, 0, 0, 0, "Can't set tap interface: %s\n", strerror(errno));
exit(-1);
}
- assert(strlen(ifr.ifr_name) < sizeof(tapdevice));
- strcpy(tapdevice, ifr.ifr_name);
+ assert(strlen(ifr.ifr_name) < sizeof(config->tapdevice));
+ strncpy(config->tapdevice, ifr.ifr_name, sizeof(config->tapdevice) - 1);
ifrfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = handle_interface ? bind_address : 0x01010101; // 1.1.1.1
+ sin.sin_addr.s_addr = handle_interface ? config->bind_address : 0x01010101; // 1.1.1.1
memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
if (ioctl(ifrfd, SIOCSIFADDR, (void *) &ifr) < 0)
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(L2TPPORT);
- addr.sin_addr.s_addr = bind_address;
+ addr.sin_addr.s_addr = config->bind_address;
udpfd = socket(AF_INET, SOCK_DGRAM, UDP);
setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (bind(udpfd, (void *) &addr, sizeof(addr)) < 0)
{
- perror("bind");
+ perror("udp bind");
exit( -1);
}
snoopfd = socket(AF_INET, SOCK_DGRAM, UDP);
// Find session by IP, 0 for not found
sessionidt sessionbyip(ipt ip)
{
- unsigned char *a = (char *)&ip;
+ unsigned char *a = (unsigned char *)&ip;
char **d = (char **) ip_hash;
#ifdef STAT_CALLS
void cache_sessionid(ipt ip, sessionidt s)
{
- unsigned char *a = (char *) &ip;
+ unsigned char *a = (unsigned char *) &ip;
char **d = (char **) ip_hash;
int i;
void uncache_sessionid(ipt ip)
{
- unsigned char *a = (char *) &ip;
+ unsigned char *a = (unsigned char *) &ip;
char **d = (char **) ip_hash;
int i;
}
// Find session by username, 0 for not found
-// walled garden'd users aren't authenticated, so the username is
+// walled garden users aren't authenticated, so the username is
// reasonably useless. Ignore them to avoid incorrect actions
sessionidt sessionbyuser(char *username)
{
#ifdef STAT_CALLS
STAT(call_sessionbyuser);
#endif
- for (s = 1; s < MAXSESSION && (session[s].walled_garden || strncmp(session[s].user, username, 128)); s++);
+ for (s = 1; s < MAXSESSION && (session[s].servicenet || strncmp(session[s].user, username, 128)); s++);
if (s < MAXSESSION)
return s;
return 0;
exit(-1);
}
memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, "eth0");
+ strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name) - 1);
if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
{
perror("get eth0 hwaddr");
ip = *(u32 *)(buf + 16);
if (!(s = sessionbyip(ip)))
{
-// log(4, 0, 0, 0, "IP: Can't find session for IP %s\n", inet_toa(ip));
+ log(4, 0, 0, 0, "IP: Sending ICMP host unreachable to %s\n", inet_toa(*(u32 *)(buf + 12)));
+ host_unreachable(*(u32 *)(buf + 12), *(u16 *)(buf + 4), ip, buf, (len < 64) ? 64 : len);
return;
}
t = session[s].tunnel;
u8 *p = makeppp(b, buf, len, t, s, PPPIP);
tunnelsend(b, len + (p-b), t); // send it...
sp->cout += len; // byte count
+ sp->total_cout += len; // byte count
sp->pout++;
udp_tx += len;
}
void sessionshutdown(sessionidt s, char *reason)
{
int dead = session[s].die;
- int walled_garden = session[s].walled_garden;
+ int servicenet = session[s].servicenet;
#ifdef STAT_CALLS
STAT(call_sessionshutdown);
}
// RADIUS Stop message
- if (session[s].opened && !walled_garden && !dead) {
+ if (session[s].opened && !servicenet && !dead) {
u8 r = session[s].radius;
if (!r)
{
- if (!radiusfree)
+ if (!(r = radiusnew(s)))
{
log(1, 0, s, session[s].tunnel, "No free RADIUS sessions for Stop message\n");
STAT(radius_overflow);
- } else {
+ }
+ else
+ {
int n;
- r = radiusnew(s);
for (n = 0; n < 15; n++)
radius[r].auth[n] = rand();
}
}
}
if (session[s].throttle) throttle_session(s, 0); session[s].throttle = 0;
- free_ip_address(session[s].ip);
- session[s].ip = 0;
+ free_ip_address(s);
}
{ // Send CDN
controlt *c = controlnew(14); // sending CDN
*(u16 *) (q + 2) = htons(10);
q[4] = 3;
q[5] = 6;
- *(u32 *) (q + 6) = htonl(myip ? : session[s].ip); // send my IP (use theirs if I dont have one)
+ *(u32 *) (q + 6) = htonl(myip ? myip : session[s].ip); // send my IP (use theirs if I dont have one)
tunnelsend(buf, 10 + (q - buf), t); // send it
}
#endif
sessionshutdown(s, reason); // close radius/routes, etc.
if (session[s].radius)
- radius[session[s].radius].session = 0; // cant send clean accounting data, session is killed
+ radiusclear(session[s].radius, 0); // cant send clean accounting data, session is killed
memset(&session[s], 0, sizeof(session[s]));
session[s].next = sessionfree;
sessionfree = s;
#ifdef STAT_CALLS
STAT(call_tunnelkill);
#endif
+
+ tunnel[t].state = TUNNELDIE;
+
// free control messages
while ((c = tunnel[t].controls))
{
controlfree = c;
}
// kill sessions
- for (s = 0; s < MAXSESSION; s++)
+ for (s = 1; s < MAXSESSION; s++)
if (session[s].tunnel == t)
sessionkill(s, reason);
+
// free tunnel
- memset(&tunnel[t], 0, sizeof(tunnel[t]));
- tunnel[t].next = tunnelfree;
+ tunnelclear(t);
cluster_send_tunnel(t);
log(1, 0, 0, t, "Kill tunnel %d: %s\n", t, reason);
- tunnelfree = t;
+ tunnel[t].die = 0;
+ tunnel[t].state = TUNNELFREE;
}
-// shut down a tunnel
+// shut down a tunnel cleanly
void tunnelshutdown(tunnelidt t, char *reason)
{
sessionidt s;
#ifdef STAT_CALLS
STAT(call_tunnelshutdown);
#endif
- if (!tunnel[t].last || !tunnel[t].far)
- { // never set up, can immediately kill
+ if (!tunnel[t].last || !tunnel[t].far || tunnel[t].state == TUNNELFREE)
+ {
+ // never set up, can immediately kill
tunnelkill(t, reason);
return;
}
log(1, 0, 0, t, "Shutting down tunnel %d (%s)\n", t, reason);
+
// close session
- for (s = 0; s < MAXSESSION; s++)
+ for (s = 1; s < MAXSESSION; s++)
if (session[s].tunnel == t)
sessionkill(s, reason);
+
+ tunnel[t].state = TUNNELDIE;
tunnel[t].die = now() + 700; // Clean up in 70 seconds
cluster_send_tunnel(t);
// TBA - should we wait for sessions to stop?
return;
}
l -= (p - buf);
- if (t) tunnel[t].last = time_now;
if (*buf & 0x80)
{ // control
u16 message = 0xFFFF; // message type
// if no tunnel specified, assign one
if (!t)
{
- /*
- ipt ip = ntohl(*(ipt *) & addr->sin_addr);
- portt port = ntohs(addr->sin_port);
-
- // find existing tunnel that was not fully set up
- for (t = 0; t < MAXTUNNEL; t++)
- {
- if ((tunnel[t].ip == ip && tunnel[t].port == port) &&
- (!tunnel[t].die || !tunnel[t].hostname[0]))
- {
- char buf[600] = {0};
- snprintf(buf, 600, "Duplicate tunnel with %d. ip=%u port=%d die=%d hostname=%s",
- t, tunnel[t].ip, tunnel[t].port, tunnel[t].die, tunnel[t].hostname);
- tunnelshutdown(t, buf);
- break;
- }
- }
- */
-
- t = tunnelfree;
- if (!t)
+ if (!(t = new_tunnel()))
{
log(1, ntohl(addr->sin_addr.s_addr), 0, 0, "No more tunnels\n");
STAT(tunnel_overflow);
return;
}
- tunnelfree = tunnel[t].next;
- memset(&tunnel[t], 0, sizeof(tunnelt));
+ tunnelclear(t);
tunnel[t].ip = ntohl(*(ipt *) & addr->sin_addr);
tunnel[t].port = ntohs(addr->sin_port);
tunnel[t].window = 4; // default window
log(1, ntohl(addr->sin_addr.s_addr), 0, t, " New tunnel from %u.%u.%u.%u/%u ID %d\n", tunnel[t].ip >> 24, tunnel[t].ip >> 16 & 255, tunnel[t].ip >> 8 & 255, tunnel[t].ip & 255, tunnel[t].port, t);
STAT(tunnel_created);
}
- { // check sequence of this message
+
+ // This is used to time out old tunnels
+ tunnel[t].lastrec = time_now;
+
+ // check sequence of this message
+ {
int skip = tunnel[t].window; // track how many in-window packets are still in queue
if (tunnel[t].controlc)
{ // some to clear maybe
// controlnull(t);
return;
}
- if (l)
- tunnel[t].nr++; // receiver advance (do here so quoted correctly in any sends below)
- if (skip < 0)
- skip = 0;
+ // receiver advance (do here so quoted correctly in any sends below)
+ if (l) tunnel[t].nr++;
+ if (skip < 0) skip = 0;
if (skip < tunnel[t].controlc)
- { // some control packets can now be sent that were previous stuck out of window
+ {
+ // some control packets can now be sent that were previous stuck out of window
int tosend = tunnel[t].window - skip;
controlt *c = tunnel[t].controls;
while (c && skip)
if (flags & 0x40)
{
// handle hidden AVPs
- if (!l2tpsecret)
+ if (!*config->l2tpsecret)
{
log(1, ntohl(addr->sin_addr.s_addr), s, t, "Hidden AVP requested, but no L2TP secret.\n");
fatal = flags;
}
if (n > 4) {
/* %*s doesn't work?? */
- char buf[n-4+2];
- memcpy(buf, b+4, n-4);
- buf[n-4+1] = '\0';
+ char *buf = (char *)strndup(b+4, n-4);
log(4, ntohl(addr->sin_addr.s_addr), s, t, " Error String: %s\n",
buf);
+ free(buf);
}
break;
}
// log(4, ntohl(addr->sin_addr.s_addr), s, t, "Bearer capabilities\n");
break;
case 5: // tie breaker
- // We never open tunnels, so we don't
- // care about tie breakers
+ // We never open tunnels, so we don't care about tie breakers
// log(4, ntohl(addr->sin_addr.s_addr), s, t, "Tie breaker\n");
continue;
case 6: // firmware revision
control16(c, 9, t, 1); // assigned tunnel
controladd(c, t, s); // send the resply
}
+ tunnel[t].state = TUNNELOPENING;
break;
case 2: // SCCRP
- // TBA
+ tunnel[t].state = TUNNELOPEN;
break;
case 3: // SCCN
+ tunnel[t].state = TUNNELOPEN;
controlnull(t); // ack
break;
case 4: // StopCCN
u8 r;
controlt *c;
+ s = sessionfree;
+ sessionfree = session[s].next;
+ memset(&session[s], 0, sizeof(session[s]));
+
// make a RADIUS session
- if (!radiusfree)
+ if (!(r = radiusnew(s)))
{
- STAT(radius_overflow);
log(1, ntohl(addr->sin_addr.s_addr), s, t, "No free RADIUS sessions for ICRQ\n");
+ sessionkill(s, "no free RADIUS sesions");
return;
}
c = controlnew(11); // sending ICRP
- s = sessionfree;
- sessionfree = session[s].next;
- memset(&session[s], 0, sizeof(session[s]));
session[s].id = sessionid++;
session[s].opened = time(NULL);
session[s].tunnel = t;
session[s].far = asession;
+ session[s].last_packet = time_now;
log(3, ntohl(addr->sin_addr.s_addr), s, t, "New session (%d/%d)\n", tunnel[t].far, session[s].far);
control16(c, 14, s, 1); // assigned session
controladd(c, t, s); // send the reply
- r = radiusfree;
- radiusfree = radius[r].next;
- memset(&radius[r], 0, sizeof(radius[r]));
- session[s].radius = r;
- radius[r].session = s;
{
// Generate a random challenge
int n;
for (n = 0; n < 15; n++)
radius[r].auth[n] = rand();
}
- strcpy(radius[r].calling, calling);
- strcpy(session[s].called, called);
- strcpy(session[s].calling, calling);
+ strncpy(radius[r].calling, calling, sizeof(radius[r].calling) - 1);
+ strncpy(session[s].called, called, sizeof(session[s].called) - 1);
+ strncpy(session[s].calling, calling, sizeof(session[s].calling) - 1);
STAT(session_created);
}
break;
FD_SET(tapfd, &cr);
FD_SET(radfd, &cr);
FD_SET(controlfd, &cr);
-#ifdef HAVE_LIBCLI
FD_SET(clifd, &cr);
-#endif
if (cluster_sockfd) FD_SET(cluster_sockfd, &cr);
cn = udpfd;
if (cn < radfd) cn = radfd;
if (cn < tapfd) cn = tapfd;
if (cn < controlfd) cn = controlfd;
-#ifdef HAVE_LIBCLI
if (cn < clifd) cn = clifd;
-#endif
if (cn < cluster_sockfd) cn = cluster_sockfd;
while (!main_quit)
{
fd_set r;
int n = cn;
+
+ if (config->reload_config)
+ {
+ // Update the config state based on config settings
+ update_config();
+ }
+
memcpy(&r, &cr, sizeof(fd_set));
n = select(n + 1, &r, 0, 0, &to);
if (n < 0)
processcluster(buf, recvfrom(cluster_sockfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen));
else if (FD_ISSET(controlfd, &r))
processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr);
-#ifdef HAVE_LIBCLI
else if (FD_ISSET(clifd, &r))
{
struct sockaddr_in addr;
close(sockfd);
}
}
-#endif
else
{
log(1, 0, 0, 0, "Main select() loop returned %d, but no fds have data waiting\n", n);
sessionidt s;
tunnelidt t;
u8 r;
- for (r = 0; r < MAXRADIUS; r++)
+
+ for (r = 1; r < MAXRADIUS; r++)
if (radius[r].state && radius[r].retry)
{
if (radius[r].retry <= when)
if (radius[r].retry && radius[r].retry < best)
best = radius[r].retry;
}
- for (t = 0; t < MAXTUNNEL; t++)
+ for (t = 1; t < MAXTUNNEL; t++)
{
// check for expired tunnels
if (tunnel[t].die && tunnel[t].die <= when)
best = tunnel[t].retry;
}
// Send hello
- if (tunnel[t].ip && !tunnel[t].die && tunnel[t].last < when + 600 && !tunnel[t].controlc)
+ if (tunnel[t].state == TUNNELOPEN && tunnel[t].lastrec < when + 600)
{
controlt *c = controlnew(6); // sending HELLO
controladd(c, t, 0); // send the message
}
}
-#ifdef HAVE_LIBCLI
// Check for sessions that have been killed from the CLI
if (cli_session_kill[0])
{
int i;
- for (i = 0; i < MAXSESSION && cli_session_kill[i]; i++)
+ for (i = 1; i < MAXSESSION && cli_session_kill[i]; i++)
{
log(2, 0, cli_session_kill[i], 0, "Dropping session by CLI\n");
- sessionshutdown(cli_session_kill[i], "Requested by CLI");
+ sessionshutdown(cli_session_kill[i], "Requested by administrator");
cli_session_kill[i] = 0;
}
}
if (cli_tunnel_kill[0])
{
int i;
- for (i = 0; i < MAXTUNNEL && cli_tunnel_kill[i]; i++)
+ for (i = 1; i < MAXTUNNEL && cli_tunnel_kill[i]; i++)
{
log(2, 0, cli_tunnel_kill[i], 0, "Dropping tunnel by CLI\n");
- tunnelshutdown(cli_tunnel_kill[i], "Requested by CLI");
+ tunnelshutdown(cli_tunnel_kill[i], "Requested by administrator");
cli_tunnel_kill[i] = 0;
}
}
-#endif
- for (s = 0; s < MAXSESSION; s++)
+ for (s = 1; s < MAXSESSION; s++)
{
// check for expired sessions
if (session[s].die && session[s].die <= when)
{
- STAT(session_timeout);
sessionkill(s, "Expired");
continue;
}
// Drop sessions who have not responded within IDLE_TIMEOUT seconds
- if (session[s].user[0] && (time_now - session[s].last_packet >= IDLE_TIMEOUT))
+ if (session[s].last_packet && (time_now - session[s].last_packet >= IDLE_TIMEOUT))
{
sessionkill(s, "No response to LCP ECHO requests");
+ STAT(session_timeout);
continue;
}
continue;
}
}
- if (accounting_dir && next_acct <= when)
+ if (config->accounting_dir && next_acct <= when)
{
// Dump accounting data
next_acct = when + ACCT_TIME;
{
// Dump accounting data
next_cluster_ping = when + 50;
- cluster_send_message(cluster_address, bind_address, C_PING, hostname, strlen(hostname));
+ cluster_send_message(config->cluster_address, config->bind_address, C_PING, hostname, strlen(hostname));
}
if (best <= when)
int i;
_statistics = mmap(NULL, sizeof(struct Tstats), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (_statistics <= 0)
+ if (_statistics == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for _statistics: %s\n", strerror(errno));
exit(1);
}
+ config = mmap(NULL, sizeof(struct configt), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
+ if (config == MAP_FAILED)
+ {
+ log(0, 0, 0, 0, "Error doing mmap for configuration: %s\n", strerror(errno));
+ exit(1);
+ }
+ memset(config, 0, sizeof(struct configt));
+ time(&config->start_time);
+ strncpy(config->config_file, CONFIGFILE, sizeof(config->config_file) - 1);
tunnel = mmap(NULL, sizeof(tunnelt) * MAXTUNNEL, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (tunnel <= 0)
+ if (tunnel == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for tunnels: %s\n", strerror(errno));
exit(1);
}
session = mmap(NULL, sizeof(sessiont) * MAXSESSION, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (session <= 0)
+ if (session == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for sessions: %s\n", strerror(errno));
exit(1);
}
radius = mmap(NULL, sizeof(radiust) * MAXRADIUS, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (radius <= 0)
+ if (radius == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for radius: %s\n", strerror(errno));
exit(1);
}
ip_address_pool = mmap(NULL, sizeof(ippoolt) * MAXIPPOOL, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (ip_address_pool <= 0)
+ if (ip_address_pool == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for radius: %s\n", strerror(errno));
exit(1);
}
#ifdef RINGBUFFER
ringbuffer = mmap(NULL, sizeof(struct Tringbuffer), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (ringbuffer <= 0)
+ if (ringbuffer == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for radius: %s\n", strerror(errno));
exit(1);
memset(ringbuffer, 0, sizeof(struct Tringbuffer));
#endif
-#ifdef HAVE_LIBCLI
cli_session_kill = mmap(NULL, sizeof(sessionidt) * MAXSESSION, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (cli_session_kill <= 0)
+ if (cli_session_kill == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for cli session kill: %s\n", strerror(errno));
exit(1);
}
memset(cli_session_kill, 0, sizeof(sessionidt) * MAXSESSION);
cli_tunnel_kill = mmap(NULL, sizeof(tunnelidt) * MAXSESSION, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (cli_tunnel_kill <= 0)
+ if (cli_tunnel_kill == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for cli tunnel kill: %s\n", strerror(errno));
exit(1);
memset(cli_tunnel_kill, 0, sizeof(tunnelidt) * MAXSESSION);
filter_buckets = mmap(NULL, sizeof(tbft) * MAXSESSION, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
- if (filter_buckets <= 0)
+ if (filter_buckets == MAP_FAILED)
{
log(0, 0, 0, 0, "Error doing mmap for filter buckets: %s\n", strerror(errno));
exit(1);
}
memset(filter_buckets, 0, sizeof(tbft) * MAXSESSION);
-#endif
-
memset(tunnel, 0, sizeof(tunnelt) * MAXTUNNEL);
memset(session, 0, sizeof(sessiont) * MAXSESSION);
memset(radius, 0, sizeof(radiust) * MAXRADIUS);
memset(ip_address_pool, 0, sizeof(ippoolt) * MAXIPPOOL);
- for (i = 1; i < MAXTUNNEL - 1; i++)
- tunnel[i].next = i + 1;
- tunnel[MAXTUNNEL - 1].next = 0;
- tunnelfree = 1;
for (i = 1; i < MAXSESSION - 1; i++)
session[i].next = i + 1;
session[MAXSESSION - 1].next = 0;
sessionfree = 1;
- for (i = 1; i < MAXRADIUS - 1; i++)
- radius[i].next = i + 1;
- radius[MAXRADIUS - 1].next = 0;
- radiusfree = 1;
if (!*hostname)
{
+ char *p;
// Grab my hostname unless it's been specified
gethostname(hostname, sizeof(hostname));
{
if (h)
myip = ntohl(*(u32 *) h->h_addr);
}
+
+ if ((p = strstr(hostname, ".optusnet.com.au"))) *p = 0;
}
_statistics->start_time = _statistics->last_reset = time(NULL);
-
- // Start the timer routine off
- time(&time_now);
- strftime(time_now_string, 64, "%Y-%m-%d %H:%M:%S", localtime(&time_now));
}
void initiptables(void)
system("iptables -t mangle -F l2tpns");
}
-ipt assign_ip_address()
+int assign_ip_address(sessionidt s)
{
- int c = 0;
+ unsigned i;
+ int best = -1;
+ clockt best_time = time_now;
+ char *u = session[s].user;
+ char reuse = 0;
+
#ifdef STAT_CALLS
STAT(call_assign_ip_address);
#endif
- ip_pool_index++;
- while (1)
+ for (i = 0; i < ip_pool_size; i++)
{
- if (ip_pool_index >= ip_pool_size)
+ if (!ip_address_pool[i].address || ip_address_pool[i].assigned)
+ continue;
+
+ if (!session[s].servicenet && ip_address_pool[i].user[0] && !strcmp(u, ip_address_pool[i].user))
{
- if (++c == 2)
- return 0;
- ip_pool_index = 0;
+ best = i;
+ reuse = 1;
+ break;
}
- if (!ip_address_pool[ip_pool_index].assigned && ip_address_pool[ip_pool_index].address)
+
+ if (ip_address_pool[i].last < best_time)
{
- ip_address_pool[ip_pool_index].assigned = 1;
- log(4, ip_address_pool[ip_pool_index].address, 0, 0, "assign_ip_address(): Allocating ip address %lu from pool\n", ip_pool_index);
- STAT(ip_allocated);
- return ntohl(ip_address_pool[ip_pool_index].address);
+ best = i;
+ if (!(best_time = ip_address_pool[i].last))
+ break; // never used, grab this one
}
- ip_pool_index++;
}
- return 0;
+
+ if (best < 0)
+ {
+ log(0, 0, s, session[s].tunnel, "assign_ip_address(): out of addresses\n");
+ return 0;
+ }
+
+ session[s].ip = ntohl(ip_address_pool[best].address);
+ session[s].ip_pool_index = best;
+ ip_address_pool[best].assigned = 1;
+ ip_address_pool[best].last = time_now;
+ if (session[s].servicenet)
+ /* Don't track addresses of users in walled garden (note: this
+ means that their address isn't "sticky" even if they get
+ un-gardened). */
+ ip_address_pool[best].user[0] = 0;
+ else
+ strncpy(ip_address_pool[best].user, u, sizeof(ip_address_pool[best].user) - 1);
+
+ STAT(ip_allocated);
+ log(4, ip_address_pool[best].address, s, session[s].tunnel,
+ "assign_ip_address(): %s ip address %lu from pool\n", reuse ? "Reusing" : "Allocating", best);
+
+ return 1;
}
-void free_ip_address(ipt address)
+void free_ip_address(sessionidt s)
{
- int i;
- ipt a;
+ int i = session[s].ip_pool_index;
+
#ifdef STAT_CALLS
STAT(call_free_ip_address);
#endif
- a = ntohl(address);
- for (i = 0; i <= ip_pool_size; i++)
- {
- if (ip_address_pool[i].address == a)
- {
- STAT(ip_freed);
- ip_address_pool[i].assigned = 0;
- }
- }
- uncache_sessionid(htonl(address));
+ if (!session[s].ip)
+ return; // what the?
+
+ STAT(ip_freed);
+ uncache_sessionid(session[s].ip);
+ session[s].ip = 0;
+ ip_address_pool[i].assigned = 0;
+ ip_address_pool[i].last = time_now;
}
// Initialize the IP address pool
exit(-1);
}
// This entry is for a specific IP only
- if (src != bind_address)
+ if (src != config->bind_address)
continue;
*p = ':';
pool = p+1;
// Add a static route for this pool
log(5, 0, 0, 0, "Adding route for address pool %s/%d\n", inet_toa(htonl(start)), 32+mask);
memset(&r, 0, sizeof(r));
- r.rt_dev = tapdevice;
+ r.rt_dev = config->tapdevice;
r.rt_dst.sa_family = AF_INET;
*(u32 *) & (((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr) = htonl(start);
r.rt_genmask.sa_family = AF_INET;
if (!snoop_addr.sin_port || snoopfd <= 0 || size <= 0 || !packet)
return;
+ log(5, 0, 0, 0, "Snooping packet at %p (%d bytes) to %s:%d\n", packet, size, inet_toa(snoop_addr.sin_addr.s_addr), htons(snoop_addr.sin_port));
if (sendto(snoopfd, packet, size, MSG_DONTWAIT | MSG_NOSIGNAL, (void *) &snoop_addr, sizeof(snoop_addr)) < 0)
log(0, 0, 0, 0, "Error sending intercept packet: %s\n", strerror(errno));
STAT(packets_snooped);
STAT(call_dump_acct_info);
#endif
strftime(timestr, 64, "%Y%m%d%H%M%S", localtime(&t));
- snprintf(filename, 1024, "%s/%s", accounting_dir, timestr);
+ snprintf(filename, 1024, "%s/%s", config->accounting_dir, timestr);
for (i = 0; i < MAXSESSION; i++)
{
- if (!session[i].opened || !session[i].cin || !session[i].cout || !*session[i].user || session[i].walled_garden)
+ if (!session[i].opened || !session[i].cin || !session[i].cout || !*session[i].user || session[i].servicenet)
continue;
if (!f)
{
time(&basetime); // start clock
// scan args
- while ((o = getopt(argc, argv, "vc:f:h:a:")) >= 0)
+ while ((o = getopt(argc, argv, "vc:h:a:")) >= 0)
{
switch (o)
{
case 'v':
- debug++;
+ config->debug++;
break;
case 'c':
- config_file = strdup(optarg);
- break;
- case 'f':
- log_filename = strdup(optarg);
+ strncpy(config->config_file, optarg, sizeof(config->config_file) - 1);
break;
case 'h':
- strncpy(hostname, optarg, 1000);
+ strncpy(hostname, optarg, 999);
break;
case 'a':
myip = inet_addr(optarg);
log(0, 0, 0, 0, "Invalid ip %s\n", optarg);
exit(-1);
}
- bind_address = myip;
+ config->bind_address = myip;
handle_interface = 1;
break;
case '?':
default:
- printf("Args are:\n\t-c <file>\tConfig file\n\t-h <hostname>\tForce hostname\n\t-a <address>\tUse specific address\n\t-f <file>\tLog File\n\t-v\t\tDebug\n");
+ printf("Args are:\n\t-c <file>\tConfig file\n\t-h <hostname>\tForce hostname\n\t-a <address>\tUse specific address\n\t-v\t\tDebug\n");
return (0);
break;
}
}
+ // Start the timer routine off
+ time(&time_now);
+ strftime(time_now_string, 64, "%Y-%m-%d %H:%M:%S", localtime(&time_now));
+
initiptables();
initplugins();
- read_config_file();
initdata();
- log(0, 0, 0, 0, "$Id: l2tpns.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $\n(c) Copyright 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n");
+ init_cli();
+ read_config_file();
+ log(0, 0, 0, 0, "$Id: l2tpns.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $\n(c) Copyright 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n");
/* Start up the cluster first, so that we don't have two machines with
* the same IP at once.
* This is still racy, but the second GARP should fix that
*/
- cluster_init(bind_address, 0);
- cluster_send_message(cluster_address, bind_address, C_HELLO, hostname, strlen(hostname));
+ cluster_init(config->bind_address, 0);
+ cluster_send_message(config->cluster_address, config->bind_address, C_HELLO, hostname, strlen(hostname));
inittap();
- log(1, 0, 0, 0, "Set up on interface %s\n", tapdevice);
+ log(1, 0, 0, 0, "Set up on interface %s\n", config->tapdevice);
initudp();
initrad();
initippool();
init_rl();
if (handle_interface) {
- send_garp(bind_address);
+ send_garp(config->bind_address);
}
- read_state();
-#ifdef HAVE_LIBCLI
- init_cli();
-#endif
+ // If NOSTATEFILE exists, we will ignore any updates from the cluster master for this execution
+ if (!unlink(NOSTATEFILE))
+ config->ignore_cluster_updates = 1;
+
+ read_state();
signal(SIGALRM, sigalrm_handler);
signal(SIGHUP, sighup_handler);
signal(SIGQUIT, sigquit_handler);
signal(SIGCHLD, sigchild_handler);
signal(SIGSEGV, sigsegv_handler);
- if (debug)
- {
- int n;
- for (n = 0; n < numradiusservers; n++)
- log(1, 0, 0, 0, "RADIUS to %s\n", inet_toa(htonl(radiusserver[n])));
- }
alarm(1);
// Drop privileges here
- if (target_uid > 0 && geteuid() == 0)
- setuid(target_uid);
+ if (config->target_uid > 0 && geteuid() == 0)
+ setuid(config->target_uid);
mainloop();
-
- if (l2tpsecret) free(l2tpsecret);
- if (log_filename) free(log_filename);
- if (snoop_destination_host) free(snoop_destination_host);
- if (radiussecret) free(radiussecret);
-
return 0;
}
void sighup_handler(int junk)
{
- if (log_stream != stderr)
+ if (log_stream && log_stream != stderr)
+ {
fclose(log_stream);
+ log_stream = NULL;
+ }
- log_stream = NULL;
read_config_file();
}
void sigalrm_handler(int junk)
{
// Log current traffic stats
- if (dump_speed)
- {
- printf("UDP-ETH:%1.0f/%1.0f ETH-UDP:%1.0f/%1.0f TOTAL:%0.1f IN:%lu OUT:%lu\n",
- (udp_rx / 1024.0 / 1024.0 * 8),
- (eth_tx / 1024.0 / 1024.0 * 8),
- (eth_rx / 1024.0 / 1024.0 * 8),
- (udp_tx / 1024.0 / 1024.0 * 8),
- ((udp_tx + udp_rx + eth_tx + eth_rx) / 1024.0 / 1024.0 * 8),
- udp_rx_pkt, eth_rx_pkt);
- udp_tx = udp_rx = 0;
- udp_rx_pkt = eth_rx_pkt = 0;
- eth_tx = eth_rx = 0;
- }
+ snprintf(config->bandwidth, sizeof(config->bandwidth),
+ "UDP-ETH:%1.0f/%1.0f ETH-UDP:%1.0f/%1.0f TOTAL:%0.1f IN:%lu OUT:%lu",
+ (udp_rx / 1024.0 / 1024.0 * 8),
+ (eth_tx / 1024.0 / 1024.0 * 8),
+ (eth_rx / 1024.0 / 1024.0 * 8),
+ (udp_tx / 1024.0 / 1024.0 * 8),
+ ((udp_tx + udp_rx + eth_tx + eth_rx) / 1024.0 / 1024.0 * 8),
+ udp_rx_pkt, eth_rx_pkt);
+
+ udp_tx = udp_rx = 0;
+ udp_rx_pkt = eth_rx_pkt = 0;
+ eth_tx = eth_rx = 0;
+
+ if (config->dump_speed)
+ printf("%s\n", config->bandwidth);
// Update the internal time counter
time(&time_now);
void sigterm_handler(int junk)
{
log(1, 0, 0, 0, "Shutting down cleanly\n");
- if (config_save_state)
+ if (config->save_state)
dump_state();
main_quit++;
}
void sigquit_handler(int junk)
{
+ FILE *f;
int i;
+
log(1, 0, 0, 0, "Shutting down without saving sessions\n");
- for (i = 0; i < MAXSESSION; i++)
+ for (i = 1; i < MAXSESSION; i++)
{
if (session[i].opened)
sessionkill(i, "L2TPNS Closing");
}
- for (i = 0; i < MAXTUNNEL; i++)
+ for (i = 1; i < MAXTUNNEL; i++)
{
- if (tunnel[i].ip)
+ if (tunnel[i].ip || tunnel[i].state)
tunnelshutdown(i, "L2TPNS Closing");
}
+
+ cluster_send_goodbye();
+
+ // Touch a file which says not to reload the state
+ f = fopen(NOSTATEFILE, "w");
+ if (f) fclose(f);
+
main_quit++;
}
void sigchild_handler(int signal)
{
- int status;
- int pid;
-
- pid = wait(&status);
-#ifdef HAVE_LIBCLI
- status = (WIFEXITED(status)) ? WEXITSTATUS(status) : 0;
- if (pid == cli_pid)
- {
- if (status == 0)
- log(3, 0, 0, 0, "CLI client closed connection\n");
- else
- log(2, 0, 0, 0, "CLI child died with rc %d!\n", status);
- }
-#endif
+ while (waitpid(-1, NULL, WNOHANG) > 0)
+ ;
}
-void *backtrace_buffer[30] = {0};
-
void sigsegv_handler(int signal)
{
log(0, 0, 0, 0, "----------------------------------------------\n");
void read_state()
{
- struct stat sb;
- FILE *f;
+ struct stat sb;
+ int i;
+ ippoolt itmp;
+ FILE *f;
+ char magic[sizeof(DUMP_MAGIC)-1];
+ u32 buf[2];
- if (!config_save_state) return;
+ if (!config->save_state)
+ return;
- if (stat(STATEFILE, &sb) < 0)
- return;
+ // Ignore saved state if NOSTATEFILE exists
+ if (config->ignore_cluster_updates)
+ {
+ unlink(STATEFILE);
+ return;
+ }
- if (sb.st_mtime < (time(NULL) - 60))
- {
- log(0, 0, 0, 0, "State file is too old to read\n");
- unlink(STATEFILE);
- return;
- }
+ if (stat(STATEFILE, &sb) < 0)
+ return;
- if (!(f = fopen(STATEFILE, "r")))
+ if (sb.st_mtime < (time(NULL) - 60))
+ {
+ log(0, 0, 0, 0, "State file is too old to read, ignoring\n");
+ unlink(STATEFILE);
+ return;
+ }
+
+ f = fopen(STATEFILE, "r");
+ unlink(STATEFILE);
+
+ if (!f)
+ {
+ log(0, 0, 0, 0, "Can't read state file: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (fread(magic, sizeof(magic), 1, f) != 1 || strncmp(magic, DUMP_MAGIC, sizeof(magic)))
+ {
+ log(0, 0, 0, 0, "Bad state file magic\n");
+ exit(1);
+ }
+
+ log(1, 0, 0, 0, "Reading state information\n");
+ if (fread(buf, sizeof(buf), 1, f) != 1 || buf[0] > MAXIPPOOL || buf[1] != sizeof(ippoolt))
+ {
+ log(0, 0, 0, 0, "Error/mismatch reading ip pool header from state file\n");
+ exit(1);
+ }
+
+ if (buf[0] > ip_pool_size)
+ {
+ log(0, 0, 0, 0, "ip pool has shrunk! state = %d, current = %d\n", buf[0], ip_pool_size);
+ exit(1);
+ }
+
+ log(2, 0, 0, 0, "Loading %u ip addresses\n", buf[0]);
+ for (i = 0; i < buf[0]; i++)
+ {
+ if (fread(&itmp, sizeof(itmp), 1, f) != 1)
{
- log(0, 0, 0, 0, "Can't read state file: %s\n", strerror(errno));
- unlink(STATEFILE);
- return;
+ log(0, 0, 0, 0, "Error reading ip %d from state file: %s\n", i, strerror(errno));
+ exit(1);
}
- fseek(f, 0, 0);
- log(1, 0, 0, 0, "Reading state information\n");
+ if (itmp.address != ip_address_pool[i].address)
{
- u32 i, numtunnels;
- if (fread(&numtunnels, sizeof(numtunnels), 1, f) <= 0)
- {
- log(0, 0, 0, 0, "Error reading saved state (tunnel count): %s\n", strerror(errno));
- fclose(f);
- unlink(STATEFILE);
- return;
- }
- log(2, 0, 0, 0, "Reading %lu tunnels\n", numtunnels);
- fread(tunnel, sizeof(tunnelt), numtunnels, f);
- tunnelfree = 0;
- for (i = 0; i < numtunnels; i++)
- {
- tunnel[i].controlc = 0;
- tunnel[i].controls = NULL;
- tunnel[i].controle = NULL;
- if (*tunnel[i].hostname)
- {
- log(3, 0, 0, 0, "Created tunnel for %s\n", tunnel[i].hostname);
- tunnelfree = i;
- }
- }
- tunnelfree++;
+ log(0, 0, 0, 0, "Mismatched ip %d from state file: pool may only be extended\n", i);
+ exit(1);
}
+
+ memcpy(&ip_address_pool[i], &itmp, sizeof(itmp));
+ }
+
+ if (fread(buf, sizeof(buf), 1, f) != 1 || buf[0] != MAXTUNNEL || buf[1] != sizeof(tunnelt))
+ {
+ log(0, 0, 0, 0, "Error/mismatch reading tunnel header from state file\n");
+ exit(1);
+ }
+
+ log(2, 0, 0, 0, "Loading %u tunnels\n", MAXTUNNEL);
+ if (fread(tunnel, sizeof(tunnelt), MAXTUNNEL, f) != MAXTUNNEL)
+ {
+ log(0, 0, 0, 0, "Error reading tunnel data from state file\n");
+ exit(1);
+ }
+
+ for (i = 0; i < MAXTUNNEL; i++)
+ {
+ tunnel[i].controlc = 0;
+ tunnel[i].controls = NULL;
+ tunnel[i].controle = NULL;
+ if (*tunnel[i].hostname)
+ log(3, 0, 0, 0, "Created tunnel for %s\n", tunnel[i].hostname);
+ }
+
+ if (fread(buf, sizeof(buf), 1, f) != 1 || buf[0] != MAXSESSION || buf[1] != sizeof(sessiont))
+ {
+ log(0, 0, 0, 0, "Error/mismatch reading session header from state file\n");
+ exit(1);
+ }
+
+ log(2, 0, 0, 0, "Loading %u sessions\n", MAXSESSION);
+ if (fread(session, sizeof(sessiont), MAXSESSION, f) != MAXSESSION)
+ {
+ log(0, 0, 0, 0, "Error reading session data from state file\n");
+ exit(1);
+ }
+
+ for (i = 0; i < MAXSESSION; i++)
+ {
+ session[i].tbf = 0;
+ session[i].throttle = 0;
+ if (session[i].opened)
{
- u32 i, numsessions;
- if (fread(&numsessions, sizeof(numsessions), 1, f) <= 0)
- {
- log(0, 0, 0, 0, "Error reading saved state (session count): %s\n", strerror(errno));
- fclose(f);
- unlink(STATEFILE);
- return;
- }
- log(2, 0, 0, 0, "Reading %lu sessions\n", numsessions);
- if (fread(session, sizeof(sessiont), numsessions, f) < numsessions)
- {
- log(0, 0, 0, 0, "Error reading saved state (%d sessions): %s\n", numsessions, strerror(errno));
- fclose(f);
- unlink(STATEFILE);
- return;
- }
- for (i = 0; i < numsessions; i++)
- {
- session[i].tbf = 0;
- session[i].throttle = 0;
- if (session[i].opened)
- {
- log(2, 0, i, 0, "Loaded active session for user %s\n", session[i].user);
- if (session[i].ip && session[i].ip != 0xFFFFFFFE)
- {
- int x;
- sessionsetup(session[i].tunnel, i, 0);
- for (x = 0; x < MAXIPPOOL && ip_address_pool[x].address; x++)
- {
- if (ip_address_pool[x].address == session[i].ip)
- {
- ip_address_pool[x].assigned = 1;
- break;
- }
- }
- }
- else
- {
- log(2, 0, i, 0, "No IP for session\n");
- }
- }
- }
- for (i = 0; i < numsessions && session[i].opened; i++)
- sessionfree = session[i].next;
+ log(2, 0, i, 0, "Loaded active session for user %s\n", session[i].user);
+ if (session[i].ip && session[i].ip != 0xFFFFFFFE)
+ sessionsetup(session[i].tunnel, i, 0);
}
- fclose(f);
- log(0, 0, 0, 0, "Loaded saved state information\n");
- unlink(STATEFILE);
+ }
+
+ fclose(f);
+ log(0, 0, 0, 0, "Loaded saved state information\n");
}
void dump_state()
{
- FILE *f;
+ FILE *f;
+ u32 buf[2];
- if (!config_save_state) return;
+ if (!config->save_state)
+ return;
- if ((f = fopen(STATEFILE, "w")))
- {
- u32 i;
- log(1, 0, 0, 0, "Dumping state information\n");
+ do {
+ if (!(f = fopen(STATEFILE, "w")))
+ break;
- i = MAXTUNNEL;
- fwrite(&i, sizeof(i), 1, f); // Number of tunnels
+ log(1, 0, 0, 0, "Dumping state information\n");
- log(2, 0, 0, 0, "Dumping %lu tunnels\n", i);
- fwrite(tunnel, sizeof(tunnelt), MAXTUNNEL, f);
+ if (fwrite(DUMP_MAGIC, sizeof(DUMP_MAGIC)-1, 1, f) != 1) break;
- i = MAXSESSION;
- fwrite(&i, sizeof(i), 1, f); // Number of sessions
- log(2, 0, 0, 0, "Dumping %lu sessions\n", i);
- fwrite(session, sizeof(sessiont), MAXSESSION, f);
+ log(2, 0, 0, 0, "Dumping %u ip addresses\n", ip_pool_size);
+ buf[0] = ip_pool_size;
+ buf[1] = sizeof(ippoolt);
+ if (fwrite(buf, sizeof(buf), 1, f) != 1) break;
+ if (fwrite(ip_address_pool, sizeof(ippoolt), ip_pool_size, f) != ip_pool_size) break;
- fclose(f);
- }
- else
- {
- log(0, 0, 0, 0, "Can't write state information: %s\n", strerror(errno));
- }
- return;
+ log(2, 0, 0, 0, "Dumping %u tunnels\n", MAXTUNNEL);
+ buf[0] = MAXTUNNEL;
+ buf[1] = sizeof(tunnelt);
+ if (fwrite(buf, sizeof(buf), 1, f) != 1) break;
+ if (fwrite(tunnel, sizeof(tunnelt), MAXTUNNEL, f) != MAXTUNNEL) break;
+
+ log(2, 0, 0, 0, "Dumping %u sessions\n", MAXSESSION);
+ buf[0] = MAXSESSION;
+ buf[1] = sizeof(sessiont);
+ if (fwrite(buf, sizeof(buf), 1, f) != 1) break;
+ if (fwrite(session, sizeof(sessiont), MAXSESSION, f) != MAXSESSION) break;
+
+ if (fclose(f) == 0) return; // OK
+ } while (0);
+
+ log(0, 0, 0, 0, "Can't write state information: %s\n", strerror(errno));
+ unlink(STATEFILE);
}
void build_chap_response(char *challenge, u8 id, u16 challenge_length, char **challenge_response)
MD5_CTX ctx;
*challenge_response = NULL;
- if (!l2tpsecret || !*l2tpsecret)
+ if (!*config->l2tpsecret)
{
log(0, 0, 0, 0, "LNS requested CHAP authentication, but no l2tp secret is defined\n");
return;
}
- /*
- if (challenge_length != 16)
- {
- log(0, 0, 0, 0, "Challenge length != 16.\n");
- return;
- }
- */
-
log(4, 0, 0, 0, " Building challenge response for CHAP request\n");
*challenge_response = (char *)calloc(17, 1);
MD5Init(&ctx);
MD5Update(&ctx, &id, 1);
- MD5Update(&ctx, l2tpsecret, strlen(l2tpsecret));
+ MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
MD5Update(&ctx, challenge, challenge_length);
MD5Final(*challenge_response, &ctx);
return;
}
-void read_config_file()
+static int facility_value(char *name)
{
- FILE *f;
- char *buf;
-
- if (!config_file) return;
- if (!(f = fopen(config_file, "r"))) {
- fprintf(stderr, "Can't open config file %s: %s\n", config_file, strerror(errno));
- return;
- }
+ int i;
+ for (i = 0; facilitynames[i].c_name; i++)
+ {
+ if (strcmp(facilitynames[i].c_name, name) == 0)
+ return facilitynames[i].c_val;
+ }
+ return 0;
+}
- if (radiussecret)
- {
- free(radiussecret);
- radiussecret = NULL;
- }
+void update_config()
+{
+ int i;
- if (l2tpsecret)
- {
- free(l2tpsecret);
- l2tpsecret = NULL;
- }
+ snoop_addr.sin_family = AF_INET;
+ snoop_addr.sin_addr.s_addr = config->snoop_destination_host;
+ snoop_addr.sin_port = htons(config->snoop_destination_port);
- if (log_filename)
+ // Update logging
+ closelog();
+ syslog_log = 0;
+ if (log_stream)
{
- free(log_filename);
- log_filename = NULL;
+ fclose(log_stream);
+ log_stream = NULL;
}
-
- if (snoop_destination_host)
+ if (*config->log_filename)
{
- free(snoop_destination_host);
- snoop_destination_host = NULL;
- }
-
- if (numradiusservers) {
- int n;
- for (n = 0; n < numradiusservers; n++)
- radiusserver[n] = 0;
- numradiusservers = 0;
- }
-
- snoop_destination_port = 0L;
- config_save_state = 0;
- rl_rate = 0L;
- debug = 1;
- default_dns1 = default_dns2 = 0;
- radius_accounting = 0;
-
- buf = (char *)malloc(4096);
-
- while (fgets(buf, 4096, f)) {
- char *p, *t;
-
- if (*buf == '#') continue;
- if ((p = strchr(buf, '\n'))) *p = 0;
- p = t = strchr(buf, '=');
- if (!p) continue;
- *p = 0; p++;
- t--;
- while (*p && *p == ' ') p++;
- while (*t && *t == ' ') *t-- = 0;
-
- if (strcmp(buf, "log file") == 0) {
- if (!log_filename)
- log_filename = strdup(p);
- } else if (strcmp(buf, "l2tp secret") == 0) {
- if (!l2tpsecret)
- l2tpsecret = strdup(p);
- log(0, 0, 0, 0, "L2TP Secret is \"%s\"\n", l2tpsecret);
- } else if (strcmp(buf, "radius secret") == 0) {
- if (!radiussecret)
- radiussecret = strdup(p);
- log(4, 0, 0, 0, "Radius Secret is \"%s\"\n", radiussecret);
- } else if (strcmp(buf, "radius accounting") == 0) {
- radius_accounting = atoi(p);
- log(4, 0, 0, 0, "Radius Account is %s\n", radius_accounting ? "on" : "off");
- } else if (strcmp(buf, "throttle rate") == 0) {
- rl_rate = atol(p);
- if (rl_rate == 0)
+ if (strstr(config->log_filename, "file:") == config->log_filename)
+ {
+ if ((log_stream = fopen((char *)(config->log_filename + 5), "a")))
{
- log(1, 0, 0, 0, "Disabled throttling.\n");
+ fseek(log_stream, 0, SEEK_END);
+ setbuf(log_stream, NULL);
}
else
{
- log(1, 0, 0, 0, "Enabled throttling (rate is %lu kbits/s)\n", rl_rate);
+ log_stream = stderr;
+ setbuf(log_stream, NULL);
}
- } else if (strcmp(buf, "debug") == 0) {
- debug = atoi(p);
- log(debug, 0, 0, 0, "Set debugging level to %d\n", debug);
- } else if (strcmp(buf, "accounting dir") == 0) {
- accounting_dir = strdup(p);
- log(debug, 0, 0, 0, "Will dump accounting information to %s\n", accounting_dir);
- } else if (strcmp(buf, "dns server") == 0) {
- unsigned long addr = 0;
- if (inet_aton(p, (struct in_addr *)&addr) < 0) {
- printf("Invalid DNS server %s\n", p);
- continue;
- }
- if (default_dns1 == 0)
- default_dns1 = addr;
- else if (default_dns2 == 0)
- default_dns2 = addr;
- } else if (strcmp(buf, "radius server") == 0) {
- struct hostent *h = gethostbyname(p);
- if (h)
- {
- while (*h->h_addr_list)
- {
- ipt ip = ntohl(*(u32 *) * h->h_addr_list);
- if (numradiusservers < MAXRADSERVER)
- radiusserver[numradiusservers++] = ip;
- else
- log(0, 0, 0, 0, "Too many RADIUS IPs\n");
- h->h_addr_list++;
- }
- }
- else
- { // may be IP?
- ipt ip = ntohl(inet_addr(p));
- if (ip && ip != 0xFFFFFFFF)
- {
- if (numradiusservers < MAXRADSERVER)
- radiusserver[numradiusservers++] = ip;
- else
- log(0, 0, 0, 0, "Too many RADIUS IPs\n");
- }
- else
- log(0, 0, 0, 0, "Unknown server %s\n", p);
- }
- } else if (strcmp(buf, "snoop host") == 0) {
- snoop_destination_host = strdup(p);
- } else if (strcmp(buf, "snoop port") == 0) {
- snoop_destination_port = atol(p);
- } else if (strcmp(buf, "bind address") == 0) {
- if (!bind_address)
- {
- // Already overridden on the command line
- bind_address = inet_addr(p);
- handle_interface = 1;
- }
- } else if (strcmp(buf, "dump speed") == 0) {
- dump_speed = atoi(p);
- } else if (strcmp(buf, "setuid") == 0) {
- target_uid = atoi(p);
- } else if (strcmp(buf, "cluster master") == 0) {
- struct hostent *h = gethostbyname(p);
- if (h)
+ }
+ else if (strstr(config->log_filename, "syslog:") == config->log_filename)
+ {
+ char *p = config->log_filename + 7;
+ if (*p)
{
- if (*h->h_addr_list)
- {
- cluster_address = *(u32 *) *h->h_addr_list;
- }
- }
- else
- { // may be IP?
- cluster_address = inet_addr(p);
- }
- } else if (strcmp(buf, "save state") == 0) {
- if (strcasecmp(p, "no") == 0) {
- config_save_state = 0;
- } else {
- config_save_state = 1;
+ openlog("l2tpns", LOG_PID, facility_value(p));
+ syslog_log = 1;
}
- } else if (strcmp(buf, "plugin") == 0) {
- add_plugin(p);
- } else {
- struct param_config cp = { buf, p };
- int rc = run_plugins(PLUGIN_CONFIG, &cp);
- if (rc == 0) log(0, 0, 0, 0, "Unknown config directive \"%s\"\n", buf);
}
}
+ else
+ {
+ log_stream = stderr;
+ setbuf(log_stream, NULL);
+ }
+
- if (snoop_destination_host)
+ // Update radius
+ config->numradiusservers = 0;
+ for (i = 0; i < MAXRADSERVER; i++)
+ if (config->radiusserver[i]) config->numradiusservers++;
+
+ if (!config->numradiusservers)
{
- if (inet_aton(snoop_destination_host, &snoop_addr.sin_addr))
+ log(0, 0, 0, 0, "No RADIUS servers defined!\n");
+ }
+
+ // Update plugins
+ for (i = 0; i < MAXPLUGINS; i++)
+ {
+ if (strcmp(config->plugins[i], config->old_plugins[i]) == 0)
+ continue;
+ if (*config->plugins[i])
{
- snoop_addr.sin_port = htons(snoop_destination_port);
- snoop_addr.sin_family = AF_INET;
+ // Plugin added
+ add_plugin(config->plugins[i]);
}
- else
+ else if (*config->old_plugins[i])
{
- log(0, 0, 0, 0, "Can't find address for snoop host %s\n", snoop_destination_host);
+ // Plugin removed
+ remove_plugin(config->old_plugins[i]);
}
}
+ memcpy(config->old_plugins, config->plugins, sizeof(config->plugins));
+ config->reload_config = 0;
+}
- free(buf);
+void read_config_file()
+{
+ FILE *f;
+
+ if (!config->config_file) return;
+ if (!(f = fopen(config->config_file, "r"))) {
+ fprintf(stderr, "Can't open config file %s: %s\n", config->config_file, strerror(errno));
+ return;
+ }
+
+ log(3, 0, 0, 0, "Reading config file %s\n", config->config_file);
+ cli_do_file(f);
+ log(3, 0, 0, 0, "Done reading config file\n");
fclose(f);
- log(2, 0, 0, 0, "Done reading config file\n");
+ update_config();
+ log_stream = NULL;
}
int sessionsetup(tunnelidt t, sessionidt s, u8 routes)
log(0, session[s].ip, s, t, "VERY VERY BAD! sessionsetup() called with no session[s].ip\n");
return 1;
}
- if (session[s].ip == 0xFFFFFFFE)
- {
- session[s].ip = assign_ip_address(); // Assign one from the pool;
-
- log(2, session[s].ip, s, t, "IP assigned is a magic token. Assign address from pool: %s\n",
- inet_toa(htonl(session[s].ip)));
- }
// Make sure this is right
session[s].tunnel = t;
// zap old sessions with same IP and/or username
- // Don't kill walled_garden sessions - doing so leads to a DoS
+ // Don't kill walled garden sessions - doing so leads to a DoS
// from someone who doesn't need to know the password
ip = session[s].ip;
user = session[s].user;
- for (i = 0; i < MAXSESSION; i++)
+ for (i = 1; i < MAXSESSION; i++)
{
if (i == s) continue;
if (ip == session[i].ip) sessionkill(i, "Duplicate IP address");
- if (!session[s].walled_garden && !session[i].walled_garden && strcasecmp(user, session[i].user) == 0)
+ if (!session[s].servicenet && !session[i].servicenet && strcasecmp(user, session[i].user) == 0)
sessionkill(i, "Duplicate session for user");
}
run_plugins(PLUGIN_NEW_SESSION, &data);
}
- session[s].sid = ++last_sid;
+ if (!session[s].sid)
+ session[s].sid = ++last_sid;
+
cache_sessionid(htonl(session[s].ip), s);
cluster_send_session(s);
struct param_control param = { buf, len, ntohl(addr->sin_addr.s_addr), ntohs(addr->sin_port), NULL, 0, 0 };
log(4, ntohl(addr->sin_addr.s_addr), 0, 0, "Received ");
- dump_packet(buf, log_stream);
+ if (log_stream)
+ dump_packet(buf, log_stream);
resp = calloc(1400, 1);
l = new_packet(PKT_RESP_ERROR, resp);
free(resp);
}
+/*
+ * HACK
+ * Go through all of the tunnels and do some cleanups
+ */
+void tunnel_clean()
+{
+ int i;
+
+ log(1, 0, 0, 0, "Cleaning tunnels array\n");
+
+ for (i = 1; i < MAXTUNNEL; i++)
+ {
+ if (!tunnel[i].ip
+ || !*tunnel[i].hostname
+ || (tunnel[i].state == TUNNELDIE && tunnel[i].die >= time_now))
+ {
+ tunnelclear(i);
+ }
+ }
+}
+
+void tunnelclear(tunnelidt t)
+{
+ if (!t) return;
+ memset(&tunnel[t], 0, sizeof(tunnel[t]));
+ tunnel[t].state = TUNNELFREE;
+}
+
+tunnelidt new_tunnel()
+{
+ tunnelidt i;
+ for (i = 1; i < MAXTUNNEL; i++)
+ {
+ if (tunnel[i].state == TUNNELFREE)
+ {
+ log(4, 0, 0, i, "Assigning tunnel ID %d\n", i);
+ return i;
+ }
+ }
+ log(0, 0, 0, 0, "Can't find a free tunnel! There shouldn't be this many in use!\n");
+ return 0;
+}
+
// L2TPNS Global Stuff
-// $Id: l2tpns.h,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: l2tpns.h,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#include <netinet/in.h>
#include <stdio.h>
-
#include "config.h"
-#define VERSION "1.0"
+#define VERSION "1.1.0"
// Limits
#define MAXTUNNEL 500 // could be up to 65535
#define MAXCONTROL 1000 // max length control message we ever send...
#define MAXETHER (1500+18) // max packet we try sending to tap
#define MAXTEL 96 // telephone number
+#define MAXPLUGINS 20 // maximum number of plugins to load
#define MAXRADSERVER 10 // max radius servers
#define MAXROUTE 10 // max static routes per session
#define MAXIPPOOL 131072 // max number of ip addresses in pool
#define STATISTICS
#define STAT_CALLS
#define RINGBUFFER
-#define UDP 17
#define TAPDEVICE "/dev/net/tun"
-#define CLIUSERS ETCDIR "l2tpns.users" // CLI Users file
+#define UDP 17
+#define HOMEDIR "/home/l2tpns/" // Base dir for data
+#define STATEFILE "/tmp/l2tpns.dump" // State dump file
+#define NOSTATEFILE "/tmp/l2tpns.no_state_reload" // If exists, state will not be reloaded
#define CONFIGFILE ETCDIR "l2tpns.cfg" // Configuration file
-#define IPPOOLFILE ETCDIR "l2tpns.ip_pool" // Address pool configuration
-#define STATEFILE "/tmp/l2tpns.dump" // State dump file
-
+#define CLIUSERS ETCDIR "l2tpns.users" // CLI Users file
+#define IPPOOLFILE ETCDIR "l2tpns.ip_pool" // Address pool configuration
#ifndef LIBDIR
#define LIBDIR "/usr/lib/l2tpns"
#endif
-
#define ACCT_TIME 3000 // 5 minute accounting interval
#define L2TPPORT 1701 // L2TP port
#define RADPORT 1645 // old radius port...
#define PPPCCP 0x80FD
#define PPPIP 0x0021
#define PPPMP 0x003D
-#define ConfigReq 1
-#define ConfigAck 2
-#define ConfigNak 3
-#define ConfigRej 4
-#define TerminateReq 5
-#define TerminateAck 6
-#define CodeRej 7
-#define ProtocolRej 8
-#define EchoReq 9
-#define EchoReply 10
-#define DiscardRequest 11
-
-#undef TC_TBF
-#define TC_HTB
+enum
+{
+ ConfigReq = 1,
+ ConfigAck,
+ ConfigNak,
+ ConfigRej,
+ TerminateReq,
+ TerminateAck,
+ CodeRej,
+ ProtocolRej,
+ EchoReq,
+ EchoReply,
+ DiscardRequest
+};
// Types
typedef unsigned short u16;
typedef u32 clockt;
typedef u8 hasht[16];
+// dump header: update number if internal format changes
+#define DUMP_MAGIC "L2TPNS#" VERSION "#"
+
// structures
typedef struct routes // route
{
typedef struct controls // control message
{
- struct controls *next; // next in queue
+ struct controls *next; // next in queue
u16 length; // length
u8 buf[MAXCONTROL];
}
// 336 bytes per session
typedef struct sessions
{
- sessionidt next; // next session in linked list
- sessionidt far; // far end session ID
- tunnelidt tunnel; // tunnel ID
- ipt ip; // IP of session set by RADIUS response
- unsigned long sid; // session id for hsddb
- u16 nr; // next receive
- u16 ns; // next send
- u32 magic; // ppp magic number
- u32 cin, cout; // byte counts
- u32 pin, pout; // packet counts
- u32 id; // session id
- clockt opened; // when started
- clockt die; // being closed, when to finally free
- time_t last_packet; // Last packet from the user (used for idle timeouts)
- ipt dns1, dns2; // DNS servers
- routet route[MAXROUTE]; // static routes
- u8 radius; // which radius session is being used (0 for not waiting on authentication)
- u8 flags; // various bit flags
- u8 snoop; // are we snooping this session?
- u8 throttle; // is this session throttled?
- u8 walled_garden; // is this session stuck in the walled garden?
- u16 mru; // maximum receive unit
- u16 tbf; // filter bucket for throttling
+ sessionidt next; // next session in linked list
+ sessionidt far; // far end session ID
+ tunnelidt tunnel; // tunnel ID
+ ipt ip; // IP of session set by RADIUS response
+ int ip_pool_index; // index to IP pool
+ unsigned long sid; // session id for hsddb
+ u16 nr; // next receive
+ u16 ns; // next send
+ u32 magic; // ppp magic number
+ u32 cin, cout; // byte counts
+ u32 pin, pout; // packet counts
+ u32 total_cin; // This counter is never reset while a session is open
+ u32 total_cout; // This counter is never reset while a session is open
+ u32 id; // session id
+ clockt opened; // when started
+ clockt die; // being closed, when to finally free
+ time_t last_packet; // Last packet from the user (used for idle timeouts)
+ ipt dns1, dns2; // DNS servers
+ routet route[MAXROUTE]; // static routes
+ u8 radius; // which radius session is being used (0 for not waiting on authentication)
+ u8 flags; // various bit flags
+ u8 snoop; // are we snooping this session?
+ u8 throttle; // is this session throttled?
+ u8 servicenet; // is this session servicenetted?
+ u16 mru; // maximum receive unit
+ u16 tbf; // filter bucket for throttling
char random_vector[MAXTEL];
int random_vector_length;
- char user[129]; // user (needed in seesion for radius stop messages)
- char called[MAXTEL]; // called number
- char calling[MAXTEL]; // calling number
+ char user[129]; // user (needed in seesion for radius stop messages)
+ char called[MAXTEL]; // called number
+ char calling[MAXTEL]; // calling number
unsigned long tx_connect_speed;
unsigned long rx_connect_speed;
}
// 168 bytes per tunnel
typedef struct tunnels
{
- tunnelidt next; // next tunnel in linked list
tunnelidt far; // far end tunnel ID
ipt ip; // Ip for far end
portt port; // port for far end
u16 window; // Rx window
u16 nr; // next receive
u16 ns; // next send
+ int state; // current state (tunnelstate enum)
clockt last; // when last control message sent (used for resend timeout)
clockt retry; // when to try resenting pending control
clockt die; // being closed, when to finally free
+ clockt lastrec; // when the last control message was received
char hostname[128]; // tunnel hostname
char vendor[128]; // LAC vendor
u8 try; // number of retrys on a control message
// 180 bytes per radius session
typedef struct radiuss // outstanding RADIUS requests
{
- u8 next; // next in free list
sessionidt session; // which session this applies to
hasht auth; // request authenticator
- clockt retry; // ehwne to try next
+ clockt retry; // when to try next
char calling[MAXTEL]; // calling number
char pass[129]; // password
u8 id; // ID for PPP response
{
ipt address;
char assigned; // 1 if assigned, 0 if free
+ clockt last; // last used
+ char user[129]; // user (try to have ip addresses persistent)
}
ippoolt;
};
#endif
+/*
+ * Possible tunnel states
+ * TUNNELFREE -> TUNNELOPEN -> TUNNELDIE -> TUNNELFREE
+ */
enum
{
- RADIUSNULL, // Not in use
- RADIUSCHAP, // sending CHAP down PPP
- RADIUSAUTH, // sending auth to RADIUS server
- RADIUSIPCP, // sending IPCP to end user
- RADIUSSTART, // sending start accounting to RADIUS server
- RADIUSSTOP, // sending stop accounting to RADIUS server
- RADIUSWAIT // waiting timeout before available, in case delayed replies
+ TUNNELFREE, // Not in use
+ TUNNELOPEN, // Active tunnel
+ TUNNELDIE, // Currently closing
+ TUNNELOPENING // Busy opening
+};
+
+enum
+{
+ RADIUSNULL, // Not in use
+ RADIUSCHAP, // sending CHAP down PPP
+ RADIUSAUTH, // sending auth to RADIUS server
+ RADIUSIPCP, // sending IPCP to end user
+ RADIUSSTART, // sending start accounting to RADIUS server
+ RADIUSSTOP, // sending stop accounting to RADIUS server
+ RADIUSWAIT // waiting timeout before available, in case delayed replies
};
struct Tstats
#define SET_STAT(x, y)
#endif
+struct configt
+{
+ int debug; // debugging level
+ time_t start_time; // time when l2tpns was started
+ char bandwidth[256]; // current bandwidth
+
+ char config_file[128];
+ int reload_config; // flag to re-read config (set by cli)
+
+ char tapdevice[10]; // tap device name
+ char log_filename[128];
+ char l2tpsecret[64];
+
+ char radiussecret[64];
+ int radius_accounting;
+ ipt radiusserver[MAXRADSERVER]; // radius servers
+ u8 numradiusservers; // radius server count
+
+ ipt default_dns1, default_dns2;
+
+ ipt snoop_destination_host;
+ u16 snoop_destination_port;
+
+ unsigned long rl_rate;
+ int save_state;
+ uint32_t cluster_address;
+ int ignore_cluster_updates;
+ char accounting_dir[128];
+ ipt bind_address;
+ int target_uid;
+ int dump_speed;
+ char plugins[64][MAXPLUGINS];
+ char old_plugins[64][MAXPLUGINS];
+};
+
+struct config_descriptt
+{
+ char *key;
+ int offset;
+ int size;
+ enum { INT, STRING, UNSIGNED_LONG, SHORT, BOOL, IP } type;
+};
+
// arp.c
void sendarp(int ifr_idx, const unsigned char* mac, ipt ip);
void processrad(u8 *buf, int len);
void radiusretry(u8 r);
u8 radiusnew(sessionidt s);
+void radiusclear(u8 r, sessionidt s);
// throttle.c
int throttle_session(sessionidt s, int throttle);
void initdata(void);
void initippool();
sessionidt sessionbyip(ipt ip);
-/* NB - sessionbyuser ignores walled garden'd sessions */
sessionidt sessionbyuser(char *username);
void sessionshutdown(sessionidt s, char *reason);
void sessionsendarp(sessionidt s);
void processudp(u8 * buf, int len, struct sockaddr_in *addr);
void processtap(u8 * buf, int len);
void processcontrol(u8 * buf, int len, struct sockaddr_in *addr);
-ipt assign_ip_address();
-void free_ip_address(ipt address);
+int assign_ip_address(sessionidt s);
+void free_ip_address(sessionidt s);
void snoop_send_packet(char *packet, u16 size);
void dump_acct_info();
void mainloop(void);
#define log _log
#ifndef log_hex
-#define log_hex(a,b,c,d) do{if (a <= debug) _log_hex(a,0,0,0,b,c,d);}while (0)
+#define log_hex(a,b,c,d) do{if (a <= config->debug) _log_hex(a,0,0,0,b,c,d);}while (0)
#endif
void _log(int level, ipt address, sessionidt s, tunnelidt t, const char *format, ...);
void _log_hex(int level, ipt address, sessionidt s, tunnelidt t, const char *title, const char *data, int maxsize);
int sessionsetup(tunnelidt t, sessionidt s, u8 routes);
int cluster_send_session(int s);
int cluster_send_tunnel(int t);
-#ifdef HAVE_LIBCLI
+int cluster_send_goodbye();
void init_cli();
+void cli_do_file(FILE *fh);
void cli_do(int sockfd);
-#endif
#ifdef RINGBUFFER
void ringbuffer_dump(FILE *stream);
#endif
int run_plugins(int plugin_type, void *data);
void add_plugin(char *plugin_name);
void remove_plugin(char *plugin_name);
+void tunnelclear(tunnelidt t);
+void host_unreachable(ipt destination, u16 id, ipt source, char *packet, int packet_len);
+
+extern tunnelt *tunnel;
+extern sessiont *session;
+#define sessionfree (session[0].next)
// L2TPNS Linked List Stuff
-// $Id: ll.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: ll.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#include <stdio.h>
#include <sys/file.h>
/* GLOBAL.H - RSAREF types and constants
*/
-#include "config.h"
-
/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 0 if it has not already
}
for (p = 0; p < commands[i].params; p++)
{
- strncpy((packet + len), argv[p + 3], 1400 - len);
+ strncpy((packet + len), argv[p + 3], 1400 - len - 1);
len += strlen(argv[p + 3]) + 1;
}
break;
#define PLUGIN_API_VERSION 1
#define MAX_PLUGIN_TYPES 30
-#define PLUGIN_PRE_AUTH 1
-#define PLUGIN_POST_AUTH 2
-#define PLUGIN_PACKET_RX 3
-#define PLUGIN_PACKET_TX 4
-#define PLUGIN_TIMER 5
-#define PLUGIN_CONFIG 6
-#define PLUGIN_NEW_SESSION 7
-#define PLUGIN_KILL_SESSION 8
-#define PLUGIN_CONTROL 9
-#define PLUGIN_RADIUS_RESPONSE 10
+enum
+{
+ PLUGIN_PRE_AUTH = 1,
+ PLUGIN_POST_AUTH,
+ PLUGIN_PACKET_RX,
+ PLUGIN_PACKET_TX,
+ PLUGIN_TIMER,
+ PLUGIN_NEW_SESSION,
+ PLUGIN_KILL_SESSION,
+ PLUGIN_CONTROL,
+ PLUGIN_RADIUS_RESPONSE
+};
#define PLUGIN_RET_ERROR 0
#define PLUGIN_RET_OK 1
// L2TPNS PPP Stuff
-// $Id: ppp.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: ppp.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#include <stdio.h>
#include <string.h>
#include "plugin.h"
#include "util.h"
-extern char debug;
extern tunnelt *tunnel;
extern sessiont *session;
extern radiust *radius;
-extern u16 tapmac[3];
extern int tapfd;
extern char hostname[1000];
extern struct Tstats *_statistics;
extern unsigned long eth_tx;
extern time_t time_now;
+extern struct configt *config;
// Process PAP messages
void processpap(tunnelidt t, sessionidt s, u8 * p, u16 l)
p[4] = 0; // no message
if (session[s].ip)
{
- log(3, session[s].ip, s, t, "%d Already an IP allocated: %s (%d)\n", getpid(), inet_toa(htonl(session[s].ip)), session[s].ip);
+ log(3, session[s].ip, s, t, "%d Already an IP allocated: %s (%d)\n", getpid(), inet_toa(htonl(session[s].ip)), session[s].ip_pool_index);
}
else
{
return;
}
- strncpy(session[s].user, packet.username, sizeof(session[s].user));
- strncpy(radius[r].pass, packet.password, sizeof(radius[r].pass));
+ strncpy(session[s].user, packet.username, sizeof(session[s].user) - 1);
+ strncpy(radius[r].pass, packet.password, sizeof(radius[r].pass) - 1);
free(packet.username);
free(packet.password);
return;
}
- strncpy(session[s].user, packet.username, sizeof(session[s].user));
+ strncpy(session[s].user, packet.username, sizeof(session[s].user) - 1);
memcpy(radius[r].pass, packet.password, 16);
free(packet.username);
*p = EchoReply; // reply
*(u32 *) (p + 4) = htonl(session[s].magic); // our magic number
q = makeppp(b, p, l, t, s, PPPLCP);
- log(3, session[s].ip, s, t, "LCP: Received EchoReq. Sending EchoReply\n");
+ log(4, session[s].ip, s, t, "LCP: Received EchoReq. Sending EchoReply\n");
tunnelsend(b, l + (q - b), t); // send it
}
else if (*p == EchoReply)
if (*p == ConfigAck)
{ // happy with our IPCP
u8 r = session[s].radius;
- if ((!r || radius[r].state == RADIUSIPCP) && !session[s].walled_garden)
+ if ((!r || radius[r].state == RADIUSIPCP) && !session[s].servicenet)
if (!r)
r = radiusnew(s);
if (r)
}
session[s].cin += l;
+ session[s].total_cin += l;
session[s].pin++;
eth_tx += l;
// L2TPNS Radius Stuff
-// $Id: radius.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: radius.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#include <time.h>
#include <stdio.h>
#include "plugin.h"
#include "util.h"
-extern char *radiussecret;
extern radiust *radius;
extern sessiont *session;
extern tunnelt *tunnel;
-extern ipt radiusserver[MAXRADSERVER]; // radius servers
extern u32 sessionid;
-extern u8 radiusfree;
extern int radfd;
-extern u8 numradiusservers;
-extern char debug;
-extern unsigned long default_dns1, default_dns2;
extern struct Tstats *_statistics;
-extern int radius_accounting;
-extern uint32_t bind_address;
+extern struct configt *config;
const char *radius_state(int state)
{
void radiusclear(u8 r, sessionidt s)
{
- radius[r].state = RADIUSNULL;
if (s) session[s].radius = 0;
- memset(&radius[r], 0, sizeof(radius[r]));
- radius[r].next = radiusfree;
- radiusfree = r;
+ memset(&radius[r], 0, sizeof(radius[r])); // radius[r].state = RADIUSNULL;
+}
+
+static u8 new_radius()
+{
+ u8 i;
+ for (i = 1; i < MAXRADIUS; i++)
+ {
+ if (radius[i].state == RADIUSNULL)
+ return i;
+ }
+ log(0, 0, 0, 0, "Can't find a free radius session! This could be bad!\n");
+ return 0;
}
u8 radiusnew(sessionidt s)
{
u8 r;
- if (!radiusfree)
+ if (!(r = new_radius()))
{
log(1, 0, s, session[s].tunnel, "No free RADIUS sessions\n");
STAT(radius_overflow);
return 0;
};
- r = radiusfree;
- session[s].radius = r;
- radiusfree = radius[r].next;
memset(&radius[r], 0, sizeof(radius[r]));
+ session[s].radius = r;
radius[r].session = s;
+ radius[r].state = RADIUSWAIT;
return r;
}
#ifdef STAT_CALLS
STAT(call_radiussend);
#endif
- if (!numradiusservers)
+ s = radius[r].session;
+ if (!config->numradiusservers)
{
- log(0, 0, 0, 0, "No RADIUS servers\n");
+ log(0, 0, s, session[s].tunnel, "No RADIUS servers\n");
return;
}
- if (!radiussecret)
+ if (!*config->radiussecret)
{
- log(0, 0, 0, 0, "No RADIUS secret\n");
+ log(0, 0, s, session[s].tunnel, "No RADIUS secret\n");
return;
}
- s = radius[r].session;
- if (state != RADIUSAUTH && !radius_accounting)
+ if (state != RADIUSAUTH && !config->radius_accounting)
{
// Radius accounting is turned off
radiusclear(r, s);
radius[r].state = state;
radius[r].retry = backoff(radius[r].try++);
log(4, 0, s, session[s].tunnel, "Send RADIUS %d state %s try %d\n", r, radius_state(radius[r].state), radius[r].try);
- if (radius[r].try > numradiusservers * 2)
+ if (radius[r].try > config->numradiusservers * 2)
{
if (s)
{
{
MD5_CTX ctx;
MD5Init(&ctx);
- MD5Update(&ctx, radiussecret, strlen(radiussecret));
+ MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
if (p)
MD5Update(&ctx, pass + p - 16, 16);
else
// NAS-IP-Address
*p = 4;
p[1] = 6;
- *(u32 *)(p + 2) = bind_address;
+ *(u32 *)(p + 2) = config->bind_address;
p += p[1];
// All AVpairs added
MD5Update(&ctx, b, 4);
MD5Update(&ctx, z, 16);
MD5Update(&ctx, b + 20, (p - b) - 20);
- MD5Update(&ctx, radiussecret, strlen(radiussecret));
+ MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
MD5Final(hash, &ctx);
memcpy(b + 4, hash, 16);
memcpy(radius[r].auth, hash, 16);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
- *(u32 *) & addr.sin_addr = htonl(radiusserver[(radius[r].try - 1) % numradiusservers]);
+ *(u32 *) & addr.sin_addr = config->radiusserver[(radius[r].try - 1) % config->numradiusservers];
addr.sin_port = htons((state == RADIUSAUTH) ? RADPORT : RADAPORT);
log_hex(5, "RADIUS Send", b, (p - b));
MD5Update(&ctx, buf, 4);
MD5Update(&ctx, radius[r].auth, 16);
MD5Update(&ctx, buf + 20, len - 20);
- MD5Update(&ctx, radiussecret, strlen(radiussecret));
+ MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
MD5Final(hash, &ctx);
do {
if (memcmp(hash, buf + 4, 16))
// Check for Assign-IP-Address
if (!session[s].ip || session[s].ip == 0xFFFFFFFE)
{
- session[s].ip = assign_ip_address();
+ assign_ip_address(s);
if (session[s].ip)
log(3, 0, s, t, " No IP allocated by radius. Assigned %s from pool\n",
inet_toa(htonl(session[s].ip)));
else
log(3, 0, s, t, " No IP allocated by radius. None available in pool\n");
}
- if (!session[s].dns1 && default_dns1)
+ if (!session[s].dns1 && config->default_dns1)
{
- session[s].dns1 = htonl(default_dns1);
- log(3, 0, s, t, " Sending dns1 = %s\n", inet_toa(default_dns1));
+ session[s].dns1 = htonl(config->default_dns1);
+ log(3, 0, s, t, " Sending dns1 = %s\n", inet_toa(config->default_dns1));
}
- if (!session[s].dns2 && default_dns2)
+ if (!session[s].dns2 && config->default_dns2)
{
- session[s].dns2 = htonl(default_dns2);
- log(3, 0, s, t, " Sending dns2 = %s\n", inet_toa(default_dns2));
+ session[s].dns2 = htonl(config->default_dns2);
+ log(3, 0, s, t, " Sending dns2 = %s\n", inet_toa(config->default_dns2));
}
if (session[s].ip)
}
}
+void radius_clean()
+{
+ int i;
+
+ log(1, 0, 0, 0, "Cleaning radius session array\n");
+
+ for (i = 1; i < MAXRADIUS; i++)
+ {
+ if (radius[i].retry == 0
+ || !session[radius[i].session].opened
+ || session[radius[i].session].die
+ || session[radius[i].session].tunnel == 0)
+ radiusclear(i, 0);
+ }
+}
// L2TPNS Rate Limiting Stuff
-// $Id: rl.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: rl.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#include <stdio.h>
#include <sys/file.h>
#include <malloc.h>
#include "l2tpns.h"
-extern char *radiussecret;
extern radiust *radius;
extern sessiont *session;
-extern ipt radiusserver[MAXRADSERVER]; // radius servers
extern u32 sessionid;
-extern u8 radiusfree;
extern int radfd;
-extern u8 numradiusservers;
-extern char debug;
-extern char *tapdevice;
extern tbft *filter_buckets;
+extern struct configt *config;
#define DEVICE "tun0"
-unsigned long rl_rate = 0;
int next_tbf = 1;
void init_rl()
{
-#ifdef TC_TBF
- system("tc qdisc del dev " DEVICE " root");
- system("tc qdisc add dev " DEVICE " root handle 1: cbq avpkt 10000 bandwidth 100mbit");
- system("tc filter del dev " DEVICE " protocol ip pref 1 fw");
- system("iptables -t mangle -N throttle 2>&1 > /dev/null");
- system("iptables -t mangle -F throttle");
- system("iptables -t mangle -A l2tpns -j throttle");
-#endif
-#ifdef TC_HTB
char *commands[] = {
"tc qdisc add dev " DEVICE " root handle 1: htb default 1",
"tc class add dev " DEVICE " parent 1: classid 1:1 htb rate 100mbit burst 300k",
"tc filter del dev " DEVICE " protocol ip pref 1 fw",
- "iptables -t mangle -N throttle 2>&1 > /dev/null",
- "iptables -t mangle -F throttle",
- "iptables -t mangle -A l2tpns -j throttle",
+ "iptables -t mangle -N throttle 2>&1 >/dev/null",
+ "iptables -t mangle -F throttle 2>&1 >/dev/null",
+ "iptables -t mangle -A l2tpns -j throttle 2>&1 >/dev/null",
NULL
};
int i;
- if (!rl_rate) return;
-
log(2, 0, 0, 0, "Initializing HTB\n");
for (i = 0; commands[i] && *commands[i]; i++)
{
system(commands[i]);
}
log(2, 0, 0, 0, "Done initializing HTB\n");
-#endif
}
u16 rl_create_tbf()
{
u16 t;
char cmd[2048];
- if (!rl_rate) return 0;
+ if (!config->rl_rate) return 0;
if (next_tbf >= MAXSESSION) return 0;
t = next_tbf++;
snprintf(filter_buckets[t].handle, 9, "1:%d0", t);
-#ifdef TC_TBF
- log(2, 0, 0, 0, "Creating new tbf %s\n", filter_buckets[t].handle);
- snprintf(cmd, 2048, "tc class add dev " DEVICE " parent 1: classid 1:%d cbq bandwidth 100Mbit rate 100Mbit "
- "weight 1 prio 8 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded isolated",
- t);
- log(3, 0, 0, 0, "%s\n", cmd);
- system(cmd);
-
- snprintf(cmd, 2048, "tc qdisc add dev " DEVICE " parent 1:%d handle %s tbf rate %dkbit buffer 1600 limit 3000",
- t, filter_buckets[t].handle, rl_rate);
- log(3, 0, 0, 0, "%s\n", cmd);
- system(cmd);
-
- snprintf(cmd, 2048, "tc filter add dev " DEVICE " protocol ip parent 1:0 prio 1 handle %d fw flowid 1:%d",
- t, t);
- log(3, 0, 0, 0, "%s\n", cmd);
- system(cmd);
-#endif
-#ifdef TC_HTB
log(2, 0, 0, 0, "Creating new htb %s\n", filter_buckets[t].handle);
snprintf(cmd, 2048, "tc class add dev " DEVICE " parent 1: classid %s htb rate %lukbit burst 15k",
- filter_buckets[t].handle, rl_rate);
+ filter_buckets[t].handle, config->rl_rate);
log(3, 0, 0, 0, "%s\n", cmd);
system(cmd);
t, filter_buckets[t].handle);
log(3, 0, 0, 0, "%s\n", cmd);
system(cmd);
-#endif
next_tbf++;
return t;
u16 rl_get_tbf()
{
int i;
- if (!rl_rate) return 0;
+ if (!config->rl_rate) return 0;
for (i = 1; i < MAXSESSION; i++)
{
void rl_done_tbf(u16 t)
{
if (!t) return;
- if (!rl_rate) return;
- log(2, 0, 0, 0, "Freeing up TBF %s\n", filter_buckets[t].handle);
+ if (!config->rl_rate) return;
+ log(2, 0, 0, 0, "Freeing up HTB %s\n", filter_buckets[t].handle);
filter_buckets[t].in_use = 0;
}
void rl_destroy_tbf(u16 t)
{
char cmd[2048];
- if (!rl_rate) return;
+ if (!config->rl_rate) return;
if (filter_buckets[t].in_use)
{
- log(0, 0, 0, 0, "Trying to destroy an in-use TBF %s\n", filter_buckets[t].handle);
+ log(0, 0, 0, 0, "Trying to destroy an in-use HTB %s\n", filter_buckets[t].handle);
return;
}
-#ifdef TC_TBF
- snprintf(cmd, 2048, "tc qdisc del dev " DEVICE " handle %s", filter_buckets[t].handle);
- system(cmd);
-#endif
-#ifdef TC_HTB
snprintf(cmd, 2048, "tc qdisc del dev " DEVICE " handle %s", filter_buckets[t].handle);
system(cmd);
-#endif
- system("iptables -t mangle -D l2tpns -j throttle");
- system("iptables -t mangle -X throttle");
+ system("iptables -t mangle -D l2tpns -j throttle 2>&1 >/dev/null");
+ system("iptables -t mangle -X throttle 2>&1 >/dev/null");
memset(filter_buckets[t].handle, 0, sizeof(filter_buckets[t].handle));
}
// L2TPNS Throttle Stuff
-// $Id: throttle.c,v 1.1 2003-12-16 07:07:39 fred_nerk Exp $
+// $Id: throttle.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
#include <stdio.h>
#include <sys/file.h>
#include "l2tpns.h"
#include "util.h"
-extern char *radiussecret;
extern radiust *radius;
extern sessiont *session;
-extern ipt radiusserver[MAXRADSERVER]; // radius servers
extern u32 sessionid;
-extern u8 radiusfree;
extern int radfd;
-extern u8 numradiusservers;
-extern char debug;
-extern unsigned long rl_rate;
extern tbft *filter_buckets;
+extern struct configt *config;
// Throttle or Unthrottle a session
int throttle_session(sessionidt s, int throttle)
{
- if (!rl_rate) return 0;
+ if (!config->rl_rate) return 0;
if (!*session[s].user)
return 0; // User not logged in
{
// Throttle them
char cmd[2048] = {0};
- log(2, 0, s, session[s].tunnel, "Throttling session %d for user %s\n", s, session[s].user);
if (!session[s].tbf) session[s].tbf = rl_get_tbf();
- snprintf(cmd, 2048, "iptables -t mangle -A throttle -d %s -j MARK --set-mark %d", inet_toa(ntohl(session[s].ip)),
+ if (!session[s].tbf)
+ {
+ log(1, 0, s, session[s].tunnel, "Error creating a filtering bucket for user %s\n", session[s].user);
+ return 0;
+ }
+ log(2, 0, s, session[s].tunnel, "Throttling session %d for user %s\n", s, session[s].user);
+ snprintf(cmd, 2048, "iptables -t mangle -A throttle -d %s -j MARK --set-mark %d",
+ inet_toa(ntohl(session[s].ip)),
session[s].tbf);
log(4, 0, s, session[s].tunnel, "Running %s\n", cmd);
system(cmd);