- 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
274 lines
5.8 KiB
C
274 lines
5.8 KiB
C
// L2TPNS Cluster Master
|
|
// $Id: cluster_slave.c,v 1.2 2004-03-05 00:09:03 fred_nerk Exp $
|
|
|
|
#include <stdio.h>
|
|
#include <netinet/in.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <malloc.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/file.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <arpa/inet.h>
|
|
#include "l2tpns.h"
|
|
#include "cluster.h"
|
|
#include "ll.h"
|
|
#include "util.h"
|
|
|
|
// vim: sw=4 ts=8
|
|
|
|
extern int cluster_sockfd;
|
|
extern char hostname[1000];
|
|
extern ippoolt *ip_address_pool;
|
|
extern uint32_t vip_address;
|
|
extern struct configt *config;
|
|
|
|
int handle_tunnel(char *buf, int l);
|
|
int handle_session(char *buf, int l);
|
|
int handle_hello_response(char *buf, int l);
|
|
|
|
int processcluster(char *buf, int l)
|
|
{
|
|
char mtype;
|
|
uint32_t addr;
|
|
|
|
log_hex(4, "Cluster receive", buf, l);
|
|
if (!buf || l <= sizeof(uint32_t)) return 0;
|
|
|
|
addr = ntohl(*(uint32_t*)buf);
|
|
buf += sizeof(uint32_t);
|
|
l -= sizeof(uint32_t);
|
|
|
|
if (addr != vip_address)
|
|
{
|
|
log(0, 0, 0, 0, "Received cluster message for VIP %s, which isn't ours\n", inet_toa(addr));
|
|
}
|
|
|
|
mtype = *buf; buf++; l--;
|
|
|
|
switch (mtype)
|
|
{
|
|
case C_HELLO:
|
|
break;
|
|
case C_HELLO_RESPONSE:
|
|
handle_hello_response(buf, l);
|
|
break;
|
|
case C_PING:
|
|
break;
|
|
case C_TUNNEL:
|
|
handle_tunnel(buf, l);
|
|
break;
|
|
case C_SESSION:
|
|
handle_session(buf, l);
|
|
break;
|
|
}
|
|
return mtype;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int handle_tunnel(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);
|
|
|
|
if (t > MAXTUNNEL)
|
|
{
|
|
log(0, 0, 0, t, "Cluster master tried to send tunnel %d, which is bigger than MAXTUNNEL (%d)\n", t, MAXTUNNEL);
|
|
return 0;
|
|
}
|
|
|
|
if (l != sizeof(tunnelt))
|
|
{
|
|
log(1, 0, 0, t, "Discarding bogus tunnel message (%d bytes instead of %d).\n", l, sizeof(tunnelt));
|
|
return 0;
|
|
}
|
|
|
|
memcpy(&tunnel[t], buf, l);
|
|
log(3, 0, 0, t, "Cluster master sent tunnel for %s\n", tunnel[t].hostname);
|
|
|
|
tunnel[t].controlc = 0;
|
|
tunnel[t].controls = NULL;
|
|
tunnel[t].controle = NULL;
|
|
return 0;
|
|
}
|
|
|
|
int handle_session(char *buf, int l)
|
|
{
|
|
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 (s > MAXSESSION)
|
|
{
|
|
log(0, 0, s, 0, "Cluster master tried to send session %d, which is bigger than MAXSESSION (%d)\n", s, MAXSESSION);
|
|
return 0;
|
|
}
|
|
|
|
if (l != sizeof(sessiont))
|
|
{
|
|
log(1, 0, s, 0, "Discarding short session message (%d bytes instead of %d).\n", l, sizeof(sessiont));
|
|
return 0;
|
|
}
|
|
|
|
if (s > 1)
|
|
{
|
|
session[s-1].next = session[s].next;
|
|
}
|
|
|
|
if (sessionfree == s)
|
|
{
|
|
sessionfree = session[s].next;
|
|
}
|
|
|
|
memcpy(&session[s], buf, l);
|
|
session[s].tbf = 0;
|
|
session[s].throttle = 0;
|
|
if (session[s].opened)
|
|
{
|
|
log(2, 0, s, session[s].tunnel, "Cluster master sent active session for user %s\n", session[s].user);
|
|
sessionsetup(session[s].tunnel, s, 0);
|
|
if (session[s].ip && session[s].ip != 0xFFFFFFFE)
|
|
{
|
|
int x;
|
|
for (x = 0; x < MAXIPPOOL && ip_address_pool[x].address; x++)
|
|
{
|
|
if (ip_address_pool[x].address == session[s].ip)
|
|
{
|
|
ip_address_pool[x].assigned = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
if (session[s].servicenet)
|
|
servicenet_session(s, 1);
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
int handle_hello_response(char *buf, int l)
|
|
{
|
|
int numtunnels, numsessions;
|
|
|
|
/* The cluster master has downed the address, so send another garp */
|
|
send_garp(vip_address);
|
|
|
|
if (!l) return 0;
|
|
|
|
if (l < (4 * IL))
|
|
{
|
|
log(1, 0, 0, 0, "Cluster master sent invalid hello response: %d bytes instead of %d\n", l, (4 * IL));
|
|
return 0;
|
|
}
|
|
numtunnels = *(int *)(buf + IL * 0);
|
|
numsessions = *(int *)(buf + IL * 1);
|
|
if (numtunnels == 0 && numsessions == 0)
|
|
{
|
|
log(2, 0, 0, 0, "Cluster master has no state information for us.\n");
|
|
return 0;
|
|
}
|
|
log(2, 0, 0, 0, "The cluster master will send %d tunnels and %d sessions.\n", numtunnels, numsessions);
|
|
return 0;
|
|
}
|
|
|
|
int cluster_send_session(int s)
|
|
{
|
|
char *packet;
|
|
int len = 0;
|
|
|
|
if (!cluster_sockfd) return 1;
|
|
|
|
packet = malloc(4096);
|
|
|
|
// Hostname
|
|
len = strlen(hostname);
|
|
*(char *)packet = len;
|
|
memcpy((char *)(packet + 1), hostname, len);
|
|
len++;
|
|
|
|
// Session ID
|
|
*(int *)(packet + len) = s;
|
|
len += sizeof(int);
|
|
|
|
// Session data
|
|
memcpy((char *)(packet + len), &session[s], sizeof(sessiont));
|
|
len += sizeof(sessiont);
|
|
|
|
cluster_send_message(config->cluster_address, vip_address, C_SESSION, packet, len);
|
|
free(packet);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int cluster_send_tunnel(int t)
|
|
{
|
|
char *packet;
|
|
int len = 0;
|
|
|
|
packet = malloc(4096);
|
|
|
|
// Hostname
|
|
len = strlen(hostname);
|
|
*(char *)packet = len;
|
|
memcpy((char *)(packet + 1), hostname, len);
|
|
len++;
|
|
|
|
// Tunnel ID
|
|
*(int *)(packet + len) = t;
|
|
len += sizeof(int);
|
|
|
|
// Tunnel data
|
|
memcpy((char *)(packet + len), &tunnel[t], sizeof(tunnelt));
|
|
len += sizeof(tunnelt);
|
|
|
|
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;
|
|
}
|
|
|