If no address is given to iftun_address and bind_address, 1.1.1.1 is used.
</LI>
+<LI><B>bind_multi_address</B> (ip address)<BR>
+This parameter permit to listen several addresss of the l2tp udp protocol
+(and set several address to the tun interface).
+<BR>
+WHEN this parameter is set, It OVERWRITE the parameters "bind_address"
+and "iftun_address".
+<BR>
+these can be interesting when you want do load-balancing in cluster mode
+of the uploaded from the LAC. For example you can set a bgp.prepend(MY_AS)
+for Address1 on LNS1 and a bgp.prepend(MY_AS) for Address2 on LNS2
+(see BGP AS-path prepending).
+<BR>
+example of use with 2 address:
+<BR>
+set bind_multi_address "64.14.13.41, 64.14.13.42"
+
+</LI>
+
<LI><B>tundevicename</B> (string)<BR>
Name of the tun interface (default: "tun0").
</LI>
l2tpns.LIBS = -lm -lcli -ldl
OBJS = arp.o cli.o cluster.o constants.o control.o icmp.o l2tpns.o \
- ll.o md5.o ppp.o radius.o tbf.o util.o pppoe.o
+ ll.o md5.o ppp.o radius.o tbf.o util.o pppoe.o l2tplac.o grpsess.o
PROGRAMS = l2tpns nsctl
PLUGINS = autosnoop.so autothrottle.so garden.so sessionctl.so \
DEFINES += -DBGP
OBJS += bgp.o
-DEFINES += -DLAC
-OBJS += l2tplac.o
-
all: programs plugins
programs: $(PROGRAMS)
plugins: $(PLUGINS)
tbf.o: tbf.c l2tpns.h util.h tbf.h
util.o: util.c l2tpns.h bgp.h
pppoe.o: pppoe.c l2tpns.h cluster.h constants.h md5.h util.h
-bgp.o: bgp.c l2tpns.h bgp.h util.h
l2tplac.o: l2tplac.c md5.h l2tpns.h util.h cluster.h l2tplac.h pppoe.h
+grpsess.o: grpsess.c l2tpns.h util.h cluster.h bgp.h
+bgp.o: bgp.c l2tpns.h bgp.h util.h
autosnoop.so: autosnoop.c l2tpns.h plugin.h
autothrottle.so: autothrottle.c l2tpns.h plugin.h
garden.so: garden.c l2tpns.h plugin.h control.h
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <linux/if_packet.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "bgp.h"
#include <dlfcn.h>
#include <netdb.h>
#include <libcli.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "constants.h"
#ifdef BGP
#include "bgp.h"
#endif
-#ifdef LAC
#include "l2tplac.h"
-#endif
extern tunnelt *tunnel;
extern bundlet *bundle;
#endif
static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int argc);
+static int cmd_show_group(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_users(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_radius(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_uptime(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_shutdown(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_reload(struct cli_def *cli, char *command, char **argv, int argc);
-#ifdef LAC
static int cmd_setforward(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_show_rmtlnsconf(struct cli_def *cli, char *command, char **argv, int argc);
-#endif
static int regular_stuff(struct cli_def *cli);
cli_register_command(cli, c, "pool", cmd_show_pool, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show the IP address allocation pool");
cli_register_command(cli, c, "radius", cmd_show_radius, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show active radius queries");
cli_register_command(cli, c, "running-config", cmd_show_run, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Show the currently running configuration");
-#ifdef LAC
cli_register_command(cli, c, "remotelns-conf", cmd_show_rmtlnsconf, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Show a list of remote LNS configuration");
-#endif
cli_register_command(cli, c, "session", cmd_show_session, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show a list of sessions or details for a single session");
+ cli_register_command(cli, c, "group", cmd_show_group, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show a list of groups or details for a single group");
cli_register_command(cli, c, "tbf", cmd_show_tbf, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "List all token bucket filters in use");
cli_register_command(cli, c, "throttle", cmd_show_throttle, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "List all throttled sessions and associated TBFs");
cli_register_command(cli, c, "tunnels", cmd_show_tunnels, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show a list of tunnels or details for a single tunnel");
cli_register_command(cli, NULL, "set", cmd_set, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Set a configuration variable");
-#ifdef LAC
cli_register_command(cli, NULL, "setforward", cmd_setforward, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Set the Remote LNS Forward");
-#endif
c = cli_register_command(cli, NULL, "ip", NULL, PRIVILEGE_PRIVILEGED, MODE_CONFIG, NULL);
cli_register_command(cli, c, "access-list", cmd_ip_access_list, PRIVILEGE_PRIVILEGED, MODE_CONFIG, "Add named access-list");
}
// Show Summary
-#ifdef LAC
cli_print(cli, "%5s %7s %4s %-32s %-15s %s %s %s %s %10s %10s %10s %4s %10s %-18s %s",
-#else
- cli_print(cli, "%5s %4s %-32s %-15s %s %s %s %s %10s %10s %10s %4s %10s %-15s %s",
-#endif
"SID",
-#ifdef LAC
"LkToSID",
-#endif
"TID",
"Username",
"IP",
"uploaded",
"idle",
"Rem.Time",
-#ifdef LAC
"LAC(L)/RLNS(R)/PPPOE(P)",
-#else
- "LAC(L)/PPPOE(P)",
-#endif
"CLI");
for (i = 1; i < MAXSESSION; i++)
rem_time = session[i].timeout ? (session[i].timeout - bundle[session[i].bundle].online_time) : 0;
else
rem_time = session[i].timeout ? (session[i].timeout - (time_now-session[i].opened)) : 0;
-#ifdef LAC
cli_print(cli, "%5d %7d %4d %-32s %-15s %s %s %s %s %10u %10lu %10lu %4u %10lu %3s%-20s %s",
-#else
- cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %s %10u %10lu %10lu %4u %10lu %3s%-20s %s",
-#endif
i,
-#ifdef LAC
session[i].forwardtosession,
-#endif
session[i].tunnel,
session[i].user[0] ? session[i].user : "*",
fmtaddr(htonl(session[i].ip), 0),
(unsigned long)session[i].cin,
abs(time_now - (session[i].last_packet ? session[i].last_packet : time_now)),
(unsigned long)(rem_time),
-#ifdef LAC
(session[i].tunnel == TUNNEL_ID_PPPOE)?"(P)":(tunnel[session[i].tunnel].isremotelns?"(R)":"(L)"),
-#else
- (session[i].tunnel == TUNNEL_ID_PPPOE)?"(P)":"(L)",
-#endif
(session[i].tunnel == TUNNEL_ID_PPPOE)?fmtMacAddr(session[i].src_hwaddr):fmtaddr(htonl(tunnel[session[i].tunnel].ip), 1),
session[i].calling[0] ? session[i].calling : "*");
}
fmtaddr(htonl(tunnel[i].ip), 0),
states[tunnel[i].state],
sessions
-#ifdef LAC
,(i == TUNNEL_ID_PPPOE)?"Tunnel pppoe":(tunnel[i].isremotelns?"Tunnel To Remote LNS":"Tunnel To LAC")
-#else
- ,(i == TUNNEL_ID_PPPOE)?"Tunnel pppoe":"Tunnel To LAC"
-#endif
);
}
cli_print(cli, "Dropping session %d", s);
cli_session_actions[s].action |= CLI_SESS_KILL;
}
-#ifdef LAC
else if (session[s].forwardtosession && session[s].opened && !session[s].die)
{
cli_print(cli, "Dropping session %d", s);
cli_session_actions[s].action |= CLI_SESS_KILL;
}
-#endif
else
{
cli_error(cli, "Session %d is not active.", s);
}
if (i)
- cli_print(cli, "");
+ cli_print(cli, " ");
cli_print(cli, "%s IP access list %s",
ip_filters[f].extended ? "Extended" : "Standard",
return CLI_OK;
}
-#ifdef LAC
+static int cmd_show_group(struct cli_def *cli, char *command, char **argv, int argc)
+{
+ int i;
+ groupidt g;
+
+ if (CLI_HELP_REQUESTED)
+ return cli_arg_help(cli, 1,
+ "<1-%d>", MAXGROUPE-1, "Show specific group by id",
+ NULL);
+
+ time(&time_now);
+ if (argc > 0)
+ {
+ // Show individual group
+ for (i = 0; i < argc; i++)
+ {
+ sessionidt s;
+
+ g = atoi(argv[i]);
+ if (g <= 0 || g >= MAXGROUPE)
+ {
+ cli_print(cli, "Invalid group id \"%s\"", argv[i]);
+ continue;
+ }
+
+ cli_print(cli, "\r\nGroup %d:", g);
+ cli_print(cli, "\tNb Session:\t\t%d", grpsession[g].nbsession);
+ cli_print(cli, "\tNb Routes:\t\t%d", grpsession[g].nbroutesgrp);
+ cli_print(cli, "\ttime_changed:\t\t%d\n", grpsession[g].time_changed);
+
+ for (i = 0; i < grpsession[g].nbsession; i++)
+ {
+ if ((s = grpsession[g].sesslist[i].sid))
+ {
+ cli_print(cli, "\tSession:\t%d\tTx Rate:%d Kbps\t\t\tweight:\t%d",
+ s,
+ grpsession[g].sesslist[i].tx_rate/(1024/8),
+ grpsession[g].sesslist[i].weight);
+ }
+ }
+
+ for (i = 0; i < grpsession[g].nbroutesgrp; i++)
+ {
+ if (grpsession[g].route[i].ip != 0)
+ {
+ cli_print(cli, "\tRoute:\t%s/%d", fmtaddr(htonl(grpsession[g].route[i].ip), 0), grpsession[g].route[i].prefixlen);
+ }
+ }
+ }
+ return CLI_OK;
+ }
+
+ // Show Summary
+ cli_print(cli, "%5s %7s %9s %12s",
+ "GID",
+ "Nb Sess",
+ "Nb Routes",
+ "Time changed");
+
+ for (g = gnextgrpid; g != 0; g = grpsession[g].prev)
+ {
+ cli_print(cli, "%5d %7d %9d %12d",
+ g,
+ grpsession[g].nbsession,
+ grpsession[g].nbroutesgrp,
+ grpsession[g].time_changed);
+ }
+
+ return CLI_OK;
+}
static int cmd_setforward(struct cli_def *cli, char *command, char **argv, int argc)
{
return CLI_OK;
}
-#endif
#include <malloc.h>
#include <errno.h>
#include <libcli.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "cluster.h"
static int walk_session_number = 0; // The next session to send when doing the slow table walk.
static int walk_bundle_number = 0; // The next bundle to send when doing the slow table walk.
static int walk_tunnel_number = 0; // The next tunnel to send when doing the slow table walk.
+static int walk_groupe_number = 0; // The next groupe to send when doing the slow table walk.
int forked = 0; // Sanity check: CLI must not diddle with heartbeat table
#define MAX_HEART_SIZE (8192) // Maximum size of heartbeat packet. Must be less than max IP packet size :)
config->cluster_undefined_sessions = MAXSESSION-1;
config->cluster_undefined_bundles = MAXBUNDLE-1;
config->cluster_undefined_tunnels = MAXTUNNEL-1;
+ config->cluster_undefined_groupes = MAXGROUPE-1;
if (!config->cluster_address)
return 0;
if (config->cluster_iam_uptodate)
return;
- if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles)
+ if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels ||
+ config->cluster_undefined_bundles || config->cluster_undefined_groupes)
return;
config->cluster_iam_uptodate = 1;
// The master just processes the payload as if it had
// received it off the tun device.
//(note: THIS ROUTINE WRITES TO pack[-6]).
-int master_forward_packet(uint8_t *data, int size, in_addr_t addr, int port)
+int master_forward_packet(uint8_t *data, int size, in_addr_t addr, uint16_t port, uint16_t indexudp)
{
uint8_t *p = data - (3 * sizeof(uint32_t));
uint8_t *psave = p;
+ uint32_t indexandport = port | ((indexudp << 16) & 0xFFFF0000);
if (!config->cluster_master_address) // No election has been held yet. Just skip it.
return -1;
LOG(4, 0, 0, "Forwarding packet from %s to master (size %d)\n", fmtaddr(addr, 0), size);
STAT(c_forwarded);
- add_type(&p, C_FORWARD, addr, (uint8_t *) &port, sizeof(port)); // ick. should be uint16_t
+ add_type(&p, C_FORWARD, addr, (uint8_t *) &indexandport, sizeof(indexandport));
return peer_send_data(config->cluster_master_address, psave, size + (3 * sizeof(uint32_t)));
}
x.ver = 1;
x.addr = config->bind_address;
- x.undef = config->cluster_undefined_sessions + config->cluster_undefined_tunnels + config->cluster_undefined_bundles;
+ x.undef = config->cluster_undefined_sessions + config->cluster_undefined_tunnels +
+ config->cluster_undefined_groupes + config->cluster_undefined_bundles;
x.basetime = basetime;
add_type(&p, C_PING, basetime, (uint8_t *) &x, sizeof(x));
config->cluster_highest_bundleid = i;
}
+ //
+ // Go through and mark all the groupes as defined.
+ // Count the highest used groupe number as well.
+ //
+ config->cluster_highest_groupeid = 0;
+ for (i = 0; i < MAXGROUPE; ++i)
+ {
+ if (grpsession[i].state == GROUPEUNDEF)
+ grpsession[i].state = GROUPEFREE;
+
+ if (grpsession[i].state != GROUPEFREE && i > config->cluster_highest_groupeid)
+ config->cluster_highest_groupeid = i;
+ }
+
//
// Go through and mark all the sessions as being defined.
// reset the idle timeouts.
config->cluster_undefined_sessions = 0;
config->cluster_undefined_bundles = 0;
config->cluster_undefined_tunnels = 0;
+ config->cluster_undefined_groupes = 0;
config->cluster_iam_uptodate = 1; // assume all peers are up-to-date
// FIXME. We need to fix up the tunnel control message
// we fix it up here, and we ensure that the 'first free session'
// pointer is valid.
//
-static void cluster_check_sessions(int highsession, int freesession_ptr, int highbundle, int hightunnel)
+static void cluster_check_sessions(int highsession, int freesession_ptr, int highbundle, int hightunnel, int highgroupe)
{
int i;
if (config->cluster_iam_uptodate)
return;
- if (highsession > config->cluster_undefined_sessions && highbundle > config->cluster_undefined_bundles && hightunnel > config->cluster_undefined_tunnels)
+ if (highsession > config->cluster_undefined_sessions && highbundle > config->cluster_undefined_bundles &&
+ highgroupe > config->cluster_undefined_groupes && hightunnel > config->cluster_undefined_tunnels)
return;
// Clear out defined sessions, counting the number of
++config->cluster_undefined_tunnels;
}
+ // Clear out defined groupe, counting the number of
+ // undefs remaining.
+ config->cluster_undefined_groupes = 0;
+ for (i = 1 ; i < MAXGROUPE; ++i) {
+ if (i > highgroupe) {
+ if (grpsession[i].state == GROUPEUNDEF) grpsession[i].state = GROUPEFREE; // Defined.
+ continue;
+ }
- if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles) {
- LOG(2, 0, 0, "Cleared undefined sessions/bundles/tunnels. %d sess (high %d), %d bund (high %d), %d tunn (high %d)\n",
- config->cluster_undefined_sessions, highsession, config->cluster_undefined_bundles, highbundle, config->cluster_undefined_tunnels, hightunnel);
+ if (grpsession[i].state == GROUPEUNDEF)
+ ++config->cluster_undefined_groupes;
+ }
+
+ if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles || config->cluster_undefined_groupes) {
+ LOG(2, 0, 0, "Cleared undefined sessions/bundles/tunnels. %d sess (high %d), %d bund (high %d), %d grp (high %d), %d tunn (high %d)\n",
+ config->cluster_undefined_sessions, highsession, config->cluster_undefined_bundles, highbundle,
+ config->cluster_undefined_groupes, highgroupe, config->cluster_undefined_tunnels, hightunnel);
return;
}
add_type(p, C_BUNDLE, id, (uint8_t *) &bundle[id], sizeof(bundlet));
break;
+ case C_CGROUPE: { // Compressed C_GROUPE
+ uint8_t c[sizeof(groupsesst) * 2]; // Bigger than worst case.
+ uint8_t *d = (uint8_t *) &grpsession[id];
+ uint8_t *orig = d;
+ int size;
+
+ size = rle_compress( &d, sizeof(groupsesst), c, sizeof(c) );
+
+ // Did we compress the full structure, and is the size actually
+ // reduced??
+ if ( (d - orig) == sizeof(groupsesst) && size < sizeof(groupsesst) )
+ {
+ add_type(p, C_CGROUPE, id, c, size);
+ break;
+ }
+ // Failed to compress : Fall through.
+ }
+ case C_GROUPE:
+ add_type(p, C_GROUPE, id, (uint8_t *) &grpsession[id], sizeof(groupsesst));
+ break;
+
case C_CTUNNEL: { // Compressed C_TUNNEL
uint8_t c[sizeof(tunnelt) * 2]; // Bigger than worst case.
uint8_t *d = (uint8_t *) &tunnel[id];
//
void cluster_heartbeat()
{
- int i, count = 0, tcount = 0, bcount = 0;
+ int i, count = 0, tcount = 0, bcount = 0, gcount = 0;
uint8_t buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
heartt h;
uint8_t *p = buff;
h.freesession = sessionfree;
h.hightunnel = config->cluster_highest_tunnelid;
h.highbundle = config->cluster_highest_bundleid;
+ h.highgroupe = config->cluster_highest_groupeid;
h.size_sess = sizeof(sessiont); // Just in case.
h.size_bund = sizeof(bundlet);
h.size_tunn = sizeof(tunnelt);
+ h.nextgrpid = gnextgrpid;
h.interval = config->cluster_hb_interval;
h.timeout = config->cluster_hb_timeout;
h.table_version = config->cluster_table_version;
//
// Fill out the packet with sessions from the session table...
- // (not forgetting to leave space so we can get some tunnels in too )
+ // (not forgetting to leave space so we can get some tunnels,bundle,groupe in too )
while ( (p + sizeof(uint32_t) * 2 + sizeof(sessiont) * 2 ) < (buff + MAX_HEART_SIZE) ) {
if (!walk_session_number) // session #0 isn't valid.
++count; // Count the number of extra sessions we're sending.
}
- //
- // Fill out the packet with tunnels from the tunnel table...
- // This effectively means we walk the tunnel table more quickly
- // than the session table. This is good because stuffing up a
- // tunnel is a much bigger deal than stuffing up a session.
- //
- while ( (p + sizeof(uint32_t) * 2 + sizeof(tunnelt) ) < (buff + MAX_HEART_SIZE) ) {
+ //
+ // Fill out the packet with tunnels from the tunnel table...
+ // This effectively means we walk the tunnel table more quickly
+ // than the session table. This is good because stuffing up a
+ // tunnel is a much bigger deal than stuffing up a session.
+ //
+ int maxsize = (sizeof(tunnelt) < sizeof(bundlet)) ? sizeof(bundlet):sizeof(tunnelt);
+ maxsize = (sizeof(groupsesst) < maxsize) ? maxsize:sizeof(groupsesst);
+ maxsize += (sizeof(uint32_t) * 2);
+
+ // Fill out the packet with tunnels,bundlets, groupes from the tables...
+ while ( (p + maxsize) < (buff + MAX_HEART_SIZE) )
+ {
+ if ((tcount >= config->cluster_highest_tunnelid) &&
+ (bcount >= config->cluster_highest_bundleid) &&
+ (gcount >= config->cluster_highest_groupeid))
+ break;
- if (!walk_tunnel_number) // tunnel #0 isn't valid.
- ++walk_tunnel_number;
+ if ( ((p + sizeof(uint32_t) * 2 + sizeof(tunnelt) ) < (buff + MAX_HEART_SIZE)) &&
+ (tcount < config->cluster_highest_tunnelid))
+ {
+ if (!walk_tunnel_number) // tunnel #0 isn't valid.
+ ++walk_tunnel_number;
- if (tcount >= config->cluster_highest_tunnelid)
- break;
+ hb_add_type(&p, C_CTUNNEL, walk_tunnel_number);
+ walk_tunnel_number = (1+walk_tunnel_number)%(config->cluster_highest_tunnelid+1); // +1 avoids divide by zero.
- hb_add_type(&p, C_CTUNNEL, walk_tunnel_number);
- walk_tunnel_number = (1+walk_tunnel_number)%(config->cluster_highest_tunnelid+1); // +1 avoids divide by zero.
+ ++tcount;
+ }
- ++tcount;
- }
+ if ( ((p + sizeof(uint32_t) * 2 + sizeof(bundlet) ) < (buff + MAX_HEART_SIZE)) &&
+ (bcount < config->cluster_highest_bundleid))
+ {
+ if (!walk_bundle_number) // bundle #0 isn't valid.
+ ++walk_bundle_number;
- //
- // Fill out the packet with bundles from the bundle table...
- while ( (p + sizeof(uint32_t) * 2 + sizeof(bundlet) ) < (buff + MAX_HEART_SIZE) ) {
+ hb_add_type(&p, C_CBUNDLE, walk_bundle_number);
+ walk_bundle_number = (1+walk_bundle_number)%(config->cluster_highest_bundleid+1); // +1 avoids divide by zero.
- if (!walk_bundle_number) // bundle #0 isn't valid.
- ++walk_bundle_number;
+ ++bcount;
+ }
- if (bcount >= config->cluster_highest_bundleid)
- break;
+ if ( ((p + sizeof(uint32_t) * 2 + sizeof(groupsesst) ) < (buff + MAX_HEART_SIZE)) &&
+ (gcount < config->cluster_highest_groupeid))
+ {
+ if (!walk_groupe_number) // groupe #0 isn't valid.
+ ++walk_groupe_number;
- hb_add_type(&p, C_CBUNDLE, walk_bundle_number);
- walk_bundle_number = (1+walk_bundle_number)%(config->cluster_highest_bundleid+1); // +1 avoids divide by zero.
- ++bcount;
- }
+ hb_add_type(&p, C_CGROUPE, walk_groupe_number);
+ walk_groupe_number = (1+walk_groupe_number)%(config->cluster_highest_groupeid+1); // +1 avoids divide by zero.
+ ++gcount;
+ }
+ }
//
// Did we do something wrong?
}
LOG(4, 0, 0, "Sending v%d heartbeat #%d, change #%" PRIu64 " with %d changes "
- "(%d x-sess, %d x-bundles, %d x-tunnels, %d highsess, %d highbund, %d hightun, size %d)\n",
+ "(%d x-sess, %d x-bundles, %d x-tunnels, %d x-groupes, %d highsess, %d highbund, %d hightun, %d highgrp, size %d)\n",
HB_VERSION, h.seq, h.table_version, config->cluster_num_changes,
- count, bcount, tcount, config->cluster_highest_sessionid, config->cluster_highest_bundleid,
- config->cluster_highest_tunnelid, (int) (p - buff));
+ count, bcount, tcount, gcount, config->cluster_highest_sessionid, config->cluster_highest_bundleid,
+ config->cluster_highest_tunnelid, config->cluster_highest_groupeid, (int) (p - buff));
config->cluster_num_changes = 0;
return type_changed(C_CBUNDLE, bid);
}
+// A particular groupe has been changed!
+int cluster_send_groupe(int gid)
+{
+ if (!config->cluster_iam_master)
+ {
+ LOG(0, 0, gid, "I'm not a master, but I just tried to change a groupe!\n");
+ return -1;
+ }
+
+ return type_changed(C_CGROUPE, gid);
+}
+
// A particular tunnel has been changed!
int cluster_send_tunnel(int tid)
{
return 0;
}
+static int cluster_recv_groupe(int more, uint8_t *p)
+{
+ if (more >= MAXGROUPE) {
+ LOG(0, 0, 0, "DANGER: Received a group id > MAXGROUPE!\n");
+ return -1;
+ }
+
+ if (grpsession[more].state == GROUPEUNDEF) {
+ if (config->cluster_iam_uptodate) { // Sanity.
+ LOG(0, 0, 0, "I thought I was uptodate but I just found an undefined group!\n");
+ } else {
+ --config->cluster_undefined_groupes;
+ }
+ }
+
+ grp_cluster_load_groupe(more, (groupsesst *) p); // Copy groupe into groupe table..
+
+ LOG(5, 0, more, "Received group update (%d undef)\n", config->cluster_undefined_groupes);
+
+ if (!config->cluster_iam_uptodate)
+ cluster_uptodate(); // Check to see if we're up to date.
+
+ return 0;
+}
+
static int cluster_recv_tunnel(int more, uint8_t *p)
{
if (more >= MAXTUNNEL) {
int i, type;
int hb_ver = more;
-#ifdef LAC
#if HB_VERSION != 7
# error "need to update cluster_process_heartbeat()"
#endif
-#else
-#if HB_VERSION != 6
-# error "need to update cluster_process_heartbeat()"
-#endif
-#endif
-
// we handle versions 5 through 7
if (hb_ver < 5 || hb_ver > HB_VERSION) {
memcpy(&past_hearts[i].data, data, size); // Save it.
- // Check that we don't have too many undefined sessions, and
- // that the free session pointer is correct.
- cluster_check_sessions(h->highsession, h->freesession, h->highbundle, h->hightunnel);
+ // Check that we don't have too many undefined sessions, and
+ // that the free session pointer is correct.
+ gnextgrpid = h->nextgrpid;
+ cluster_check_sessions(h->highsession, h->freesession, h->highbundle, h->hightunnel, h->highgroupe);
if (h->interval != config->cluster_hb_interval)
{
size = rle_decompress((uint8_t **) &p, s, c, sizeof(c));
s -= (p - orig_p);
-#ifdef LAC
if ( ((hb_ver >= HB_VERSION) && (size != sizeof(tunnelt))) ||
((hb_ver < HB_VERSION) && (size > sizeof(tunnelt))) )
-#else
- if (size != sizeof(tunnelt) )
-#endif
{ // Ouch! Very very bad!
LOG(0, 0, 0, "DANGER: Received a CTUNNEL that didn't decompress correctly!\n");
// Now what? Should exit! No-longer up to date!
p += sizeof(bundle[more]);
s -= sizeof(bundle[more]);
break;
+
+ case C_CGROUPE:
+ { // Compressed Groupe structure.
+ uint8_t c[ sizeof(groupsesst) + 2];
+ int size;
+ uint8_t *orig_p = p;
+
+ size = rle_decompress((uint8_t **) &p, s, c, sizeof(c));
+ s -= (p - orig_p);
+
+ if (size != sizeof(groupsesst) )
+ { // Ouch! Very very bad!
+ LOG(0, 0, 0, "DANGER: Received a C_CGROUPE that didn't decompress correctly!\n");
+ // Now what? Should exit! No-longer up to date!
+ break;
+ }
+
+ cluster_recv_groupe(more, c);
+ break;
+ }
+ case C_GROUPE:
+ if ( s < sizeof(grpsession[more]))
+ goto shortpacket;
+
+ cluster_recv_groupe(more, p);
+
+ p += sizeof(grpsession[more]);
+ s -= sizeof(grpsession[more]);
+ break;
+
default:
LOG(0, 0, 0, "DANGER: I received a heartbeat element where I didn't understand the type! (%d)\n", type);
return -1; // can't process any more of the packet!!
else
{
struct sockaddr_in a;
+ uint16_t indexudp;
a.sin_addr.s_addr = more;
- a.sin_port = *(int *) p;
+ a.sin_port = (*(int *) p) & 0xFFFF;
+ indexudp = ((*(int *) p) >> 16) & 0xFFFF;
s -= sizeof(int);
p += sizeof(int);
processdae(p, s, &a, sizeof(a), &local);
}
else
- processudp(p, s, &a);
+ processudp(p, s, &a, indexudp);
return 0;
}
cli_print(cli, "Next sequence number expected: %d", config->cluster_seq_number);
cli_print(cli, "%d sessions undefined of %d", config->cluster_undefined_sessions, config->cluster_highest_sessionid);
cli_print(cli, "%d bundles undefined of %d", config->cluster_undefined_bundles, config->cluster_highest_bundleid);
+ cli_print(cli, "%d groupes undefined of %d", config->cluster_undefined_groupes, config->cluster_highest_groupeid);
cli_print(cli, "%d tunnels undefined of %d", config->cluster_undefined_tunnels, config->cluster_highest_tunnelid);
} else {
cli_print(cli, "Table version # : %" PRIu64, config->cluster_table_version);
cli_print(cli, "Next heartbeat # : %d", config->cluster_seq_number);
cli_print(cli, "Highest session : %d", config->cluster_highest_sessionid);
cli_print(cli, "Highest bundle : %d", config->cluster_highest_bundleid);
+ cli_print(cli, "Highest groupe : %d", config->cluster_highest_groupeid);
cli_print(cli, "Highest tunnel : %d", config->cluster_highest_tunnelid);
cli_print(cli, "%d changes queued for sending", config->cluster_num_changes);
}
#define C_CBUNDLE 18 // Compressed bundle structure.
#define C_MPPP_FORWARD 19 // MPPP Forwarded packet..
#define C_PPPOE_FORWARD 20 // PPPOE Forwarded packet..
+#define C_GROUPE 21 // Groupe structure.
+#define C_CGROUPE 22 // Compressed groupe structure.
+
-#ifdef LAC
#define HB_VERSION 7 // Protocol version number..
-#else
-#define HB_VERSION 6 // Protocol version number..
-#endif
#define HB_MAX_SEQ (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!)
#define HB_HISTORY_SIZE 64 // How many old heartbeats we remember?? (Must be a factor of HB_MAX_SEQ)
uint64_t table_version; // # state changes processed by cluster
- char reserved[128 - 13*sizeof(uint32_t) - sizeof(uint64_t)]; // Pad out to 128 bytes.
+ uint32_t highgroupe; // Id of the highest used groupe.
+ uint32_t nextgrpid; // nextgrpid to set gnextgrpid on slave
+
+ char reserved[128 - 15*sizeof(uint32_t) - sizeof(uint64_t)]; // Pad out to 128 bytes.
} heartt;
typedef struct { /* Used to update byte counters on the */
int processcluster(uint8_t *buf, int size, in_addr_t addr);
int cluster_send_session(int sid);
int cluster_send_bundle(int bid);
+int cluster_send_groupe(int gid);
int cluster_send_tunnel(int tid);
-int master_forward_packet(uint8_t *data, int size, in_addr_t addr, int port);
+int master_forward_packet(uint8_t *data, int size, in_addr_t addr, uint16_t port, uint16_t indexudp);
int master_forward_dae_packet(uint8_t *data, int size, in_addr_t addr, int port);
int master_throttle_packet(int tid, uint8_t *data, int size);
int master_garden_packet(sessionidt s, uint8_t *data, int size);
// L2TPNS: control
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "control.h"
-l2tpns (2.2.1-2fdn3.6) unstable; urgency=low
+l2tpns (2.2.1-2sames3.7) unstable; urgency=low
+ * Merge from master
* Fix Warning: dereferencing type-punned pointer will break strict...
* Fix: Tunnel creation does not work when the length of the hostname is odd. (revert fix: Add a uint16_t control buffer type, as a union)
-- Fernando Alves <fernando.alves@sameswireless.fr> Tue, 26 Feb 2013 09:07:16 +0100
+l2tpns (2.2.1-2sames3.6) unstable; urgency=low
+
+ * Sames l2tpns version.
+
+ -- Fernando Alves <fernando.alves@sameswireless.fr> Tue, 12 Feb 2013 20:20:17 +0100
+
l2tpns (2.2.1-2fdn3.5) unstable; urgency=low
* Update debian/changelog
--- /dev/null
+# -*- text -*-
+##############################################################################
+# Vendor specific attributes SamesWireless
+# http://www.sameswireless.fr
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR SAMES 64520
+
+BEGIN-VENDOR SAMES
+
+ATTRIBUTE SAMES-Group-Framed-Route 22 string
+ATTRIBUTE SAMES-Group-Session-Weight 23 string
+
+END-VENDOR SAMES
+
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include "control.h"
--- /dev/null
+/*
+ * Fernando ALVES 2013
+ * Grouped session for load balancing and fail-over
+ * GPL licenced
+ */
+
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
+#include "l2tpns.h"
+#include "util.h"
+#include "cluster.h"
+
+#ifdef BGP
+#include "bgp.h"
+#endif
+
+union grp_iphash {
+ groupidt grp;
+ union grp_iphash *idx;
+} grp_ip_hash[256]; // Mapping from IP address to group structures.
+
+groupidt gnextgrpid = 0;
+
+// Find gruop by IP, < 1 for not found
+//
+// Confusingly enough, this 'ip' must be
+// in _network_ order. This being the common
+// case when looking it up from IP packet headers.
+static groupidt grp_lookup_ipmap(in_addr_t ip)
+{
+ uint8_t *a = (uint8_t *) &ip;
+ union grp_iphash *h = grp_ip_hash;
+
+ if (!(h = h[*a++].idx)) return 0;
+ if (!(h = h[*a++].idx)) return 0;
+ if (!(h = h[*a++].idx)) return 0;
+
+ return h[*a].grp;
+}
+
+//
+// Take an IP address in HOST byte order and
+// add it to the grouid by IP cache.
+//
+// (It's actually cached in network order)
+//
+static void grp_cache_ipmap(in_addr_t ip, groupidt g)
+{
+ in_addr_t nip = htonl(ip); // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0]
+ uint8_t *a = (uint8_t *) &nip;
+ union grp_iphash *h = grp_ip_hash;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (!(h[a[i]].idx || (h[a[i]].idx = calloc(256, sizeof(union grp_iphash)))))
+ return;
+
+ h = h[a[i]].idx;
+ }
+
+ h[a[3]].grp = g;
+
+ if (g > 0)
+ LOG(4, 0, 0, "Caching Group:%d ip address %s\n", g, fmtaddr(nip, 0));
+ else if (g == 0)
+ LOG(4, 0, 0, "Un-caching Group ip address %s\n", fmtaddr(nip, 0));
+}
+
+groupidt grp_groupbyip(in_addr_t ip)
+{
+ groupidt g = grp_lookup_ipmap(ip);
+
+ if (g > 0 && g < MAXGROUPE)
+ return g;
+
+ return 0;
+}
+
+// Add a route
+//
+// This adds it to the routing table, advertises it
+// via BGP if enabled, and stuffs it into the
+// 'groupbyip' cache.
+//
+// 'ip' must be in _host_ order.
+//
+static void grp_routeset(groupidt g, in_addr_t ip, int prefixlen, int add)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct rtmsg rt;
+ char buf[32];
+ } req;
+ int i;
+ in_addr_t n_ip;
+
+ if (!prefixlen) prefixlen = 32;
+
+ ip &= 0xffffffff << (32 - prefixlen);; // Force the ip to be the first one in the route.
+
+ memset(&req, 0, sizeof(req));
+
+ if (add)
+ {
+ req.nh.nlmsg_type = RTM_NEWROUTE;
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE;
+ }
+ else
+ {
+ req.nh.nlmsg_type = RTM_DELROUTE;
+ req.nh.nlmsg_flags = NLM_F_REQUEST;
+ }
+
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt));
+
+ req.rt.rtm_family = AF_INET;
+ req.rt.rtm_dst_len = prefixlen;
+ req.rt.rtm_table = RT_TABLE_MAIN;
+ req.rt.rtm_protocol = 42;
+ req.rt.rtm_scope = RT_SCOPE_LINK;
+ req.rt.rtm_type = RTN_UNICAST;
+
+ netlink_addattr(&req.nh, RTA_OIF, &tunidx, sizeof(int));
+ n_ip = htonl(ip);
+ netlink_addattr(&req.nh, RTA_DST, &n_ip, sizeof(n_ip));
+
+ LOG(3, 0, 0, "Route (Group) %s %s/%d\n", add ? "add" : "del", fmtaddr(htonl(ip), 0), prefixlen);
+
+ if (netlink_send(&req.nh) < 0)
+ LOG(0, 0, 0, "grp_routeset() error in sending netlink message: %s\n", strerror(errno));
+
+#ifdef BGP
+ if (add)
+ bgp_add_route(htonl(ip), prefixlen);
+ else
+ bgp_del_route(htonl(ip), prefixlen);
+#endif /* BGP */
+
+ // Add/Remove the IPs to the 'groupbyip' cache.
+ // Note that we add the zero address in the case of
+ // a network route. Roll on CIDR.
+
+ // Note that 'g == 0' implies this is the address pool.
+ // We still cache it here, because it will pre-fill
+ // the malloc'ed tree.
+ if (g)
+ {
+ if (!add) // Are we deleting a route?
+ g = 0; // Caching the session as '0' is the same as uncaching.
+
+ for (i = ip; i < ip+(1<<(32-prefixlen)) ; ++i)
+ {
+ grp_cache_ipmap(i, g);
+ if (!g) cache_ipmap(i, 0);
+ }
+ }
+}
+
+// Set all route of a group
+void grp_setgrouproute(groupidt g, int add)
+{
+ int i;
+ for (i = 0; i < grpsession[g].nbroutesgrp; i++)
+ {
+ if (grpsession[g].route[i].ip != 0)
+ {
+ grp_routeset(g, grpsession[g].route[i].ip, grpsession[g].route[i].prefixlen, add);
+ }
+ }
+}
+
+// return group id by session
+groupidt grp_groupbysession(sessionidt s)
+{
+ groupidt g = 0;
+ int i;
+ for (g = gnextgrpid; g != 0; g = grpsession[g].prev)
+ {
+ for (i = 0; i < grpsession[g].nbsession; i++)
+ {
+ if (grpsession[g].sesslist[i].sid == s)
+ { // session found in group
+ return g;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// Remove a session to a group
+// return 1 if OK
+void grp_removesession(groupidt g, sessionidt s)
+{
+ int i;
+
+ if (grpsession[g].nbsession <= 0)
+ return;
+
+ for (i = 0; i < grpsession[g].nbsession; i++)
+ {
+ if (grpsession[g].sesslist[i].sid == s)
+ { // session found on group
+ --grpsession[g].nbsession;
+ if (grpsession[g].nbsession == 0)
+ {
+ // Group is empty, remove it
+
+ // Del all routes
+ grp_setgrouproute(g, 0);
+
+ if (gnextgrpid == g)
+ {
+ gnextgrpid = grpsession[g].prev;
+ }
+ else
+ {
+ groupidt g2;
+ for (g2 = gnextgrpid; g2 != 0; g2 = grpsession[g2].prev)
+ {
+ if (grpsession[g2].prev == g)
+ {
+ grpsession[g2].prev = grpsession[g].prev;
+ break;
+ }
+ }
+ }
+
+ memset(&grpsession[g], 0, sizeof(grpsession[0]));
+ grpsession[g].state = GROUPEFREE;
+ }
+ else
+ {
+ // remove the session
+ memmove(&grpsession[g].sesslist[i],
+ &grpsession[g].sesslist[i+1],
+ (grpsession[g].nbsession - i) * sizeof(grpsession[g].sesslist[i]));
+ }
+
+ cluster_send_groupe(g);
+ return;
+ }
+ }
+}
+
+// Add a session to a group
+// return 1 if OK
+static int grp_addsession(groupidt g, sessionidt s, uint8_t weight)
+{
+ int i;
+
+ for (i = 0; i < grpsession[g].nbsession; i++)
+ {
+ if (grpsession[g].sesslist[i].sid == s)
+ { // already in group
+ if ((!grpsession[g].sesslist[i].weight) || (weight > 1))
+ grpsession[g].sesslist[i].weight = weight; // update Weight session (for load-balancing)
+
+ return 1;
+ }
+ }
+
+ if (i >= MAXSESSINGRP)
+ {
+ LOG(1, s, session[s].tunnel, " Too many session for Group %d\n", g);
+ return 0;
+ }
+ else
+ { // add session id to group
+ if (i == 0)
+ {
+ // it's the first session of the group, set to next group
+ grpsession[g].prev = gnextgrpid;
+ gnextgrpid = g;
+ grpsession[g].state = GROUPEOPEN;
+ }
+ grpsession[g].sesslist[i].sid = s;
+ grpsession[g].sesslist[i].weight = weight;
+ grpsession[g].nbsession++;
+
+ return 1;
+ }
+ return 0;
+}
+
+// Add a route to a group
+// return 1 if OK
+static int grp_addroute(groupidt g, sessionidt s, in_addr_t ip, int prefixlen)
+{
+ int i;
+
+ for (i = 0; i < MAXROUTEINGRP; i++)
+ {
+ if ((i >= grpsession[g].nbroutesgrp))
+ {
+ LOG(3, s, session[s].tunnel, " Radius reply Group %d contains route for %s/%d\n",
+ g, fmtaddr(htonl(ip), 0), prefixlen);
+
+ grpsession[g].route[i].ip = ip;
+ grpsession[g].route[i].prefixlen = prefixlen;
+ grpsession[g].nbroutesgrp++;
+ return 1;
+ }
+ else if ((grpsession[g].route[i].ip == ip) && (grpsession[g].route[i].prefixlen == prefixlen))
+ {
+ // route already defined in group
+ LOG(3, s, session[s].tunnel,
+ " Radius reply Group %d contains route for %s/%d (this already defined)\n",
+ g, fmtaddr(htonl(ip), 0), prefixlen);
+
+ return 1;
+ }
+ else if (grpsession[g].route[i].ip == 0)
+ {
+ LOG(3, s, session[s].tunnel, " Radius reply Group %d contains route for %s/%d (find empty on list!!!)\n",
+ g, fmtaddr(htonl(ip), 0), prefixlen);
+
+ grpsession[g].route[i].ip = ip;
+ grpsession[g].route[i].prefixlen = prefixlen;
+ return 1;
+ }
+ }
+
+ if (i >= MAXROUTEINGRP)
+ {
+ LOG(1, s, session[s].tunnel, " Too many routes for Group %d\n", g);
+ }
+ return 0;
+}
+
+// Process Sames vendor specific attribut radius
+void grp_processvendorspecific(sessionidt s, uint8_t *pvs)
+{
+ uint8_t attrib = *pvs;
+ groupidt grpid = 0;
+ uint8_t *n = pvs + 2;
+ uint8_t *e = pvs + pvs[1];
+
+ if ((attrib >= 22) && (attrib <= 23))
+ {
+ while (n < e && isdigit(*n))
+ {
+ grpid = grpid * 10 + *n - '0';
+ n++;
+ }
+ if ((grpid == 0) || (grpid >= MAXGROUPE))
+ {
+ LOG(1, s, session[s].tunnel, " Group Attribute Id %d not allowed\n", grpid);
+ return;
+ }
+ else if (*n != ',')
+ {
+ LOG(1, s, session[s].tunnel, " Group Attribute Id not defined\n");
+ return;
+ }
+
+ if (!grp_addsession(grpid, s, 1))
+ {
+ return;
+ }
+
+ if (grpid > config->cluster_highest_groupeid)
+ config->cluster_highest_groupeid = grpid;
+
+ n++;
+ }
+
+ //process, Sames vendor-specific 64520
+ if (attrib == 22) //SAMES-Group-Framed-Route
+ {
+ in_addr_t ip = 0;
+ uint8_t u = 0;
+ uint8_t bits = 0;
+
+ while (n < e && (isdigit(*n) || *n == '.'))
+ {
+ if (*n == '.')
+ {
+ ip = (ip << 8) + u;
+ u = 0;
+ }
+ else
+ u = u * 10 + *n - '0';
+ n++;
+ }
+ ip = (ip << 8) + u;
+ if (*n == '/')
+ {
+ n++;
+ while (n < e && isdigit(*n))
+ bits = bits * 10 + *n++ - '0';
+ }
+ else if ((ip >> 24) < 128)
+ bits = 8;
+ else if ((ip >> 24) < 192)
+ bits = 16;
+ else
+ bits = 24;
+
+ if (!grp_addroute(grpid, s, ip, bits))
+ return;
+ }
+ else if (attrib == 23) //SAMES-Group-Session-Weight
+ {
+ uint8_t weight = 0;
+
+ while (n < e && isdigit(*n))
+ weight = weight * 10 + *n++ - '0';
+
+ if (!weight)
+ {
+ LOG(1, s, session[s].tunnel, " Group-Session-Weight 0 GroupId %d not allowed\n", grpid);
+ return;
+ }
+ if (!grp_addsession(grpid, s, weight))
+ {
+ return;
+ }
+ }
+ else
+ {
+ LOG(3, s, session[s].tunnel, " Unknown vendor-specific: 64520, Attrib: %d\n", attrib);
+ }
+}
+
+// Init data structures
+void grp_initdata()
+{
+ int i;
+
+ // Set default value (10s)
+ config->grp_txrate_average_time = 10;
+
+ if (!(grpsession = shared_malloc(sizeof(groupsesst) * MAXGROUPE)))
+ {
+ LOG(0, 0, 0, "Error doing malloc for grouped session: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ memset(grpsession, 0, sizeof(grpsession[0]) * MAXGROUPE);
+ for (i = 1; i < MAXGROUPE; i++)
+ {
+ grpsession[i].state = GROUPEUNDEF;
+ }
+}
+
+// Update time_changed of the group
+void grp_time_changed()
+{
+ groupidt g;
+
+ for (g = gnextgrpid; g != 0; g = grpsession[g].prev)
+ {
+ grpsession[g].time_changed++;
+ }
+}
+
+// Uncache all IP of a session
+static void grp_uncache_ipsession(groupidt g, sessionidt s)
+{
+ int i;
+ uint8_t *a;
+ in_addr_t ip;
+ in_addr_t n_ip, j;
+ int prefixlen;
+ union iphash *h;
+
+ for (i = 0; i < grpsession[g].nbroutesgrp; i++)
+ {
+ if (grpsession[g].route[i].ip != 0)
+ {
+ prefixlen = grpsession[g].route[i].prefixlen;
+ ip = grpsession[g].route[i].ip & (0xffffffff << (32 - prefixlen)); // Force the ip to be the first one in the route.
+
+ for (j = ip; j < ip+(1<<(32-prefixlen)) ; ++j)
+ {
+ n_ip = htonl(j); // To network order
+ a = (uint8_t *) &n_ip;
+ h = ip_hash;
+
+ if (!(h = h[*a++].idx)) continue;
+ if (!(h = h[*a++].idx)) continue;
+ if (!(h = h[*a++].idx)) continue;
+
+ if (s == h[*a].sess)
+ {
+ h[*a].sess = 0;
+ //LOG(3, s, session[s].tunnel, "UnCaching ip address %s\n", fmtaddr(n_ip, 0));
+ }
+ }
+ }
+ }
+}
+
+// return the next session can be used on the group
+sessionidt grp_getnextsession(groupidt g, in_addr_t ip)
+{
+ sessionidt s = 0, s2 = 0, s3 = 0;
+ int i;
+ uint32_t ltime_changed = 0, mintxrate = 0xFFFFFFFF, maxtxrate = 0;
+ uint32_t txrate;
+
+ if (g >= MAXGROUPE)
+ return 0;
+
+ if (grpsession[g].time_changed >= config->grp_txrate_average_time)
+ {
+ // recalculation txrate
+ ltime_changed = grpsession[g].time_changed;
+ grpsession[g].time_changed = 0;
+ for (i = 0; i < grpsession[g].nbsession; i++)
+ {
+ if ((s2 = grpsession[g].sesslist[i].sid))
+ {
+ uint32_t coutgrp_delta = 0;
+
+ if (session[s2].cout >= grpsession[g].sesslist[i].prev_coutgrp)
+ coutgrp_delta = session[s2].cout - grpsession[g].sesslist[i].prev_coutgrp;
+ grpsession[g].sesslist[i].prev_coutgrp = session[s2].cout;
+
+ grpsession[g].sesslist[i].tx_rate = coutgrp_delta/ltime_changed;
+
+ txrate = grpsession[g].sesslist[i].tx_rate/grpsession[g].sesslist[i].weight;
+ if (txrate < mintxrate)
+ {
+ if ( session[s2].ppp.phase > Establish &&
+ (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
+ {
+ grpsession[g].smin = s2;
+ mintxrate = txrate;
+ }
+ }
+
+ if (txrate > maxtxrate)
+ {
+ if ( session[s2].ppp.phase > Establish &&
+ (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
+ {
+ grpsession[g].smax = s2;
+ maxtxrate = txrate;
+ }
+ }
+ }
+ }
+ }
+
+ if ((s = sessionbyip(ip)))
+ {
+ if (s == grpsession[g].smax)
+ {
+ s = grpsession[g].smin;
+ grpsession[g].smax = 0;
+ }
+ else if ( (session[s].ppp.phase > Establish) &&
+ (time_now - session[s].last_packet <= (config->echo_timeout + 1)) )
+ {
+ return s;
+ }
+ else
+ {
+ s = 0;
+ }
+ }
+
+ if (!s)
+ {
+ // random between 0 and nbsession-1
+ uint indexsess = (rand() % grpsession[g].nbsession);
+
+ if (indexsess >= grpsession[g].nbsession)
+ indexsess = 0; //Sanity checks.
+
+ s2 = grpsession[g].sesslist[indexsess].sid;
+ if (s2 &&
+ (session[s2].ppp.phase > Establish) &&
+ (time_now - session[s2].last_packet <= (config->echo_timeout + 1)))
+ {
+ s = s2;
+ }
+ else
+ {
+ for (i = 0; i < grpsession[g].nbsession; i++)
+ {
+ if ((s2 = grpsession[g].sesslist[i].sid))
+ {
+ s3 = s2;
+
+ if ( session[s2].ppp.phase > Establish &&
+ (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
+ {
+ s = s2;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!s)
+ s = s3;
+
+ if (s)
+ cache_ipmap(ntohl(ip), s);
+
+ return s;
+}
+
+// load a groupe receive from master
+int grp_cluster_load_groupe(groupidt g, groupsesst *new)
+{
+ int i;
+ int updategroup = 0;
+
+ if (g >= MAXGROUPE)
+ {
+ LOG(0, 0, 0, "ERROR: Received a group id > MAXGROUPE!\n");
+ return 0;
+ }
+
+ if ((grpsession[g].nbroutesgrp != new->nbroutesgrp) ||
+ (grpsession[g].nbsession != new->nbsession))
+ {
+ updategroup = 1;
+ }
+
+ if (!updategroup)
+ {
+ // Check session list
+ for (i = 0; i < grpsession[g].nbsession; i++)
+ {
+ if (grpsession[g].sesslist[i].sid != new->sesslist[i].sid)
+ {
+ updategroup = 1;
+ break;
+ }
+ }
+ }
+
+ if (!updategroup)
+ {
+ // Check routes list
+ for (i = 0; i < grpsession[g].nbroutesgrp; i++)
+ {
+ if (grpsession[g].route[i].ip != new->route[i].ip)
+ {
+ updategroup = 1;
+ break;
+ }
+ }
+ }
+
+ // needs update
+ if (updategroup)
+ {
+ // Del all routes
+ grp_setgrouproute(g, 0);
+ }
+
+ memcpy(&grpsession[g], new, sizeof(grpsession[g])); // Copy over..
+
+ // needs update
+ if (updategroup)
+ {
+ // Add all routes
+ grp_setgrouproute(g, 1);
+ }
+
+ return 1;
+}
#include <sys/types.h>
#include <sys/wait.h>
#include <memory.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "pppoe.h"
#include <errno.h>
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
#include "md5.h"
#include "l2tpns.h"
tunnel[t].port = pconfigrlns[i_conf].port;
tunnel[t].window = 4; // default window
tunnel[t].isremotelns = i_conf;
+ tunnel[t].indexudp = config->indexlacudpfd;
STAT(tunnel_created);
random_data(pconfigrlns[i_conf].auth, sizeof(pconfigrlns[i_conf].auth));
}
// Forward session to LAC or Remote LNS
-int lac_session_forward(uint8_t *buf, int len, sessionidt sess, uint16_t proto, in_addr_t s_addr, int sin_port)
+int lac_session_forward(uint8_t *buf, int len, sessionidt sess, uint16_t proto, in_addr_t s_addr, int sin_port, uint16_t indexudpfd)
{
uint16_t t = 0, s = 0;
uint8_t *p = buf + 2; // First word L2TP options
(proto == PPPCCP) )
{
session[sess].last_packet = time_now;
- master_forward_packet(buf, len, s_addr, sin_port);
+ master_forward_packet(buf, len, s_addr, sin_port, indexudpfd);
return 1;
}
}
// l2tplac.c
void lac_initremotelnsdata();
-int lac_session_forward(uint8_t *buf, int len, sessionidt sess, uint16_t proto, in_addr_t s_addr, int sin_port);
+int lac_session_forward(uint8_t *buf, int len, sessionidt sess, uint16_t proto, in_addr_t s_addr, int sin_port, uint16_t indexudpfd);
int lac_conf_forwardtoremotelns(sessionidt s, char * puser);
void lac_calc_rlns_auth(tunnelidt t, uint8_t id, uint8_t *out);
int lac_addremotelns(char *mask, char *IP_RemoteLNS, char *Port_RemoteLNS, char *SecretRemoteLNS);
#include "bgp.h"
#endif
-#ifdef LAC
#include "l2tplac.h"
-#endif
#include "pppoe.h"
-#ifdef LAC
char * Vendor_name = "Linux L2TPNS";
uint32_t call_serial_number = 0;
-#endif
// Globals
configt *config = NULL; // all configuration
int nlfd = -1; // netlink socket
int tunfd = -1; // tun interface file handle. (network device)
-int udpfd = -1; // UDP file handle
-#ifdef LAC
+int udpfd[MAX_UDPFD + 1] = INIT_TABUDPFD; // array UDP file handle + 1 for lac udp
int udplacfd = -1; // UDP LAC file handle
-#endif
int controlfd = -1; // Control signal handle
int clifd = -1; // Socket listening for CLI connections.
int daefd = -1; // Socket listening for DAE connections.
int epollfd = -1; // event polling
time_t basetime = 0; // base clock
char hostname[MAXHOSTNAME] = ""; // us.
-static int tunidx; // ifr_ifindex of tun device
+int tunidx; // ifr_ifindex of tun device
int nlseqnum = 0; // netlink sequence number
int min_initok_nlseqnum = 0; // minimun seq number for messages after init is ok
static int syslog_log = 0; // are we logging to syslog
struct cli_session_actions *cli_session_actions = NULL; // Pending session changes requested by CLI
struct cli_tunnel_actions *cli_tunnel_actions = NULL; // Pending tunnel changes required by CLI
-union iphash {
- sessionidt sess;
- union iphash *idx;
-} ip_hash[256]; // Mapping from IP address to session structures.
+union iphash ip_hash[256]; // Mapping from IP address to session structures.
struct ipv6radix {
sessionidt sess;
CONFIG("idle_echo_timeout", idle_echo_timeout, INT),
CONFIG("iftun_address", iftun_address, IPv4),
CONFIG("tundevicename", tundevicename, STRING),
-#ifdef LAC
CONFIG("disable_lac_func", disable_lac_func, BOOL),
CONFIG("auth_tunnel_change_addr_src", auth_tunnel_change_addr_src, BOOL),
CONFIG("bind_address_remotelns", bind_address_remotelns, IPv4),
CONFIG("bind_portremotelns", bind_portremotelns, SHORT),
-#endif
CONFIG("pppoe_if_to_bind", pppoe_if_to_bind, STRING),
CONFIG("pppoe_service_name", pppoe_service_name, STRING),
CONFIG("pppoe_ac_name", pppoe_ac_name, STRING),
CONFIG("disable_sending_hello", disable_sending_hello, BOOL),
CONFIG("disable_no_spoof", disable_no_spoof, BOOL),
+ CONFIG("bind_multi_address", bind_multi_address, STRING),
+ CONFIG("grp_txrate_average_time", grp_txrate_average_time, INT),
{ NULL, 0, 0, 0 }
};
bundlet *bundle = NULL; // Array of bundle structures.
fragmentationt *frag = NULL; // Array of fragmentation structures.
sessiont *session = NULL; // Array of session structures.
+groupsesst *grpsession = NULL; // Array of groupsesst structures.
sessionlocalt *sess_local = NULL; // Array of local per-session counters.
radiust *radius = NULL; // Array of radius structures.
ippoolt *ip_address_pool = NULL; // Array of dynamic IP addresses.
struct Tringbuffer *ringbuffer = NULL;
#endif
-static ssize_t netlink_send(struct nlmsghdr *nh);
-static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen);
-static void cache_ipmap(in_addr_t ip, sessionidt s);
static void uncache_ipmap(in_addr_t ip);
static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s);
static void free_ip_address(sessionidt s);
if (f) *f = t.tv_sec + t.tv_usec / 1000000.0;
if (t.tv_sec != time_now)
{
- time_now = t.tv_sec;
- time_changed++;
+ time_now = t.tv_sec;
+ time_changed++;
+ grp_time_changed();
}
// Time in milliseconds
}
}
-static ssize_t netlink_send(struct nlmsghdr *nh)
+ssize_t netlink_send(struct nlmsghdr *nh)
{
struct sockaddr_nl nladdr;
struct iovec iov;
}
/* adapted from iproute2 */
-static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen)
+void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen)
{
int len = RTA_LENGTH(alen);
struct rtattr *rta;
}
if (*config->tundevicename)
- strncpy(ifr.ifr_name, config->tundevicename, IFNAMSIZ);
+ strncpy(ifr.ifr_name, config->tundevicename, IFNAMSIZ);
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0)
{
req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_UNIVERSE;
req.ifmsg.ifaddr.ifa_index = tunidx;
- if (config->iftun_address)
- ip = config->iftun_address;
+ if (config->nbmultiaddress > 1)
+ {
+ int i;
+ for (i = 0; i < config->nbmultiaddress ; i++)
+ {
+ ip = config->iftun_n_address[i];
+ netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip));
+ if (netlink_send(&req.nh) < 0)
+ goto senderror;
+ }
+ }
else
- ip = 0x01010101; // 1.1.1.1
- netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip));
+ {
+ if (config->iftun_address)
+ ip = config->iftun_address;
+ else
+ ip = 0x01010101; // 1.1.1.1
+ netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip));
+
+ if (netlink_send(&req.nh) < 0)
+ goto senderror;
+ }
+
- if (netlink_send(&req.nh) < 0)
- goto senderror;
// Only setup IPv6 on the tun device if we have a configured prefix
if (config->ipv6_prefix.s6_addr[0]) {
exit(1);
}
-// set up UDP ports
-static void initudp(void)
+// set up LAC UDP ports
+static void initlacudp(void)
{
int on = 1;
struct sockaddr_in addr;
- // Tunnel
+ // Tunnel to Remote LNS
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
- addr.sin_port = htons(L2TPPORT);
- addr.sin_addr.s_addr = config->bind_address;
- udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ addr.sin_port = htons(config->bind_portremotelns);
+ addr.sin_addr.s_addr = config->bind_address_remotelns;
+ udplacfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ setsockopt(udplacfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
{
- int flags = fcntl(udpfd, F_GETFL, 0);
- fcntl(udpfd, F_SETFL, flags | O_NONBLOCK);
+ int flags = fcntl(udplacfd, F_GETFL, 0);
+ fcntl(udplacfd, F_SETFL, flags | O_NONBLOCK);
}
- if (bind(udpfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ if (bind(udplacfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
- LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno));
+ LOG(0, 0, 0, "Error in UDP REMOTE LNS bind: %s\n", strerror(errno));
exit(1);
}
+}
+
+// set up control ports
+static void initcontrol(void)
+{
+ int on = 1;
+ struct sockaddr_in addr;
// Control
memset(&addr, 0, sizeof(addr));
LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno));
exit(1);
}
+}
+
+// set up Dynamic Authorization Extensions to RADIUS port
+static void initdae(void)
+{
+ int on = 1;
+ struct sockaddr_in addr;
// Dynamic Authorization Extensions to RADIUS
memset(&addr, 0, sizeof(addr));
LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno));
exit(1);
}
+}
-#ifdef LAC
- // Tunnel to Remote LNS
+// set up UDP ports
+static void initudp(int * pudpfd, in_addr_t ip_bind)
+{
+ int on = 1;
+ struct sockaddr_in addr;
+
+ // Tunnel
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
- addr.sin_port = htons(config->bind_portremotelns);
- addr.sin_addr.s_addr = config->bind_address_remotelns;
- udplacfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- setsockopt(udplacfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ addr.sin_port = htons(L2TPPORT);
+ addr.sin_addr.s_addr = ip_bind;
+ (*pudpfd) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ setsockopt((*pudpfd), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
{
- int flags = fcntl(udplacfd, F_GETFL, 0);
- fcntl(udplacfd, F_SETFL, flags | O_NONBLOCK);
+ int flags = fcntl((*pudpfd), F_GETFL, 0);
+ fcntl((*pudpfd), F_SETFL, flags | O_NONBLOCK);
}
- if (bind(udplacfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ if (bind((*pudpfd), (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
- LOG(0, 0, 0, "Error in UDP REMOTE LNS bind: %s\n", strerror(errno));
+ LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno));
exit(1);
}
-#endif
-
- // Intercept
- snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
//
//
// (It's actually cached in network order)
//
-static void cache_ipmap(in_addr_t ip, sessionidt s)
+void cache_ipmap(in_addr_t ip, sessionidt s)
{
in_addr_t nip = htonl(ip); // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0]
uint8_t *a = (uint8_t *) &nip;
LOG(3, 0, t, "Control message resend try %d\n", tunnel[t].try);
}
}
-#ifdef LAC
- if (sendto((tunnel[t].isremotelns?udplacfd:udpfd), buf, l, 0, (void *) &addr, sizeof(addr)) < 0)
-#else
- if (sendto(udpfd, buf, l, 0, (void *) &addr, sizeof(addr)) < 0)
-#endif
+
+ if (sendto(udpfd[tunnel[t].indexudp], buf, l, 0, (void *) &addr, sizeof(addr)) < 0)
{
LOG(0, ntohs((*(uint16_t *) (buf + 6))), t, "Error sending data out tunnel: %s (udpfd=%d, buf=%p, len=%d, dest=%s)\n",
- strerror(errno), udpfd, buf, l, inet_ntoa(addr.sin_addr));
+ strerror(errno), udpfd[tunnel[t].indexudp], buf, l, inet_ntoa(addr.sin_addr));
STAT(tunnel_tx_errors);
return;
}
void processipout(uint8_t *buf, int len)
{
sessionidt s;
+ groupidt g;
sessiont *sp;
tunnelidt t;
in_addr_t ip;
}
ip = *(uint32_t *)(buf + 16);
- if (!(s = sessionbyip(ip)))
+ if ((g = grp_groupbyip(ip)))
+ {
+ s = grp_getnextsession(g, ip);
+ if (!s)
+ {
+ // Is this a packet for a session that doesn't exist?
+ static int rate = 0; // Number of ICMP packets we've sent this second.
+ static int last = 0; // Last time we reset the ICMP packet counter 'rate'.
+
+ if (last != time_now)
+ {
+ last = time_now;
+ rate = 0;
+ }
+
+ if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second.
+ {
+ LOG(4, 0, 0, "IP: Sending ICMP host unreachable to %s\n", fmtaddr(*(in_addr_t *)(buf + 12), 0));
+ host_unreachable(*(in_addr_t *)(buf + 12), *(uint16_t *)(buf + 4),
+ config->bind_address ? config->bind_address : my_address, buf, len);
+ }
+ return;
+ }
+ }
+ else if (!(s = sessionbyip(ip)))
{
// Is this a packet for a session that doesn't exist?
static int rate = 0; // Number of ICMP packets we've sent this second.
session[s].die = TIME + 150; // Clean up in 15 seconds
if (session[s].ip)
- { // IP allocated, clear and unroute
+ { // IP allocated, clear and unroute
int r;
int routed = 0;
for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
q[4] = 3; // ip address option
q[5] = 6; // option length
*(in_addr_t *) (q + 6) = config->peer_address ? config->peer_address :
- config->iftun_address ? config->iftun_address :
+ config->iftun_n_address[tunnel[t].indexudp] ? config->iftun_n_address[tunnel[t].indexudp] :
my_address; // send my IP
tunnelsend(buf, 10 + (q - buf), t); // send it
// kill a session now
void sessionkill(sessionidt s, char *reason)
{
+ groupidt g;
+
CSTAT(sessionkill);
if (!session[s].opened) // not alive
if (sess_local[s].radius)
radiusclear(sess_local[s].radius, s); // cant send clean accounting data, session is killed
-#ifdef LAC
if (session[s].forwardtosession)
{
sessionidt sess = session[s].forwardtosession;
sessionshutdown(sess, reason, CDN_ADMIN_DISC, TERM_ADMIN_RESET);
}
}
-#endif
LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
+
+ if ((g = grp_groupbysession(s)))
+ {
+ grp_removesession(g, s);
+ }
+
sessionclear(s);
cluster_send_session(s);
}
}
// read and process packet on tunnel (UDP)
-void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
+void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexudpfd)
{
uint8_t *chapresponse = NULL;
uint16_t l = len, t = 0, s = 0, ns = 0, nr = 0;
if (!config->cluster_iam_master)
{
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
tunnel[t].ip = ntohl(*(in_addr_t *) & addr->sin_addr);
tunnel[t].port = ntohs(addr->sin_port);
tunnel[t].window = 4; // default window
+ tunnel[t].indexudp = indexudpfd;
STAT(tunnel_created);
LOG(1, 0, t, " New tunnel from %s:%u ID %u\n",
fmtaddr(htonl(tunnel[t].ip), 0), tunnel[t].port, t);
}
break;
case 13: // Response
-#ifdef LAC
if (tunnel[t].isremotelns)
{
chapresponse = calloc(17, 1);
LOG(3, s, t, "received challenge response from REMOTE LNS\n");
}
else
-#endif /* LAC */
// Why did they send a response? We never challenge.
LOG(2, s, t, " received unexpected challenge response\n");
break;
case 2: // SCCRP
tunnel[t].state = TUNNELOPEN;
tunnel[t].lastrec = time_now;
-#ifdef LAC
LOG(3, s, t, "Received SCCRP\n");
if (main_quit != QUIT_SHUTDOWN)
{
{
tunnelshutdown(t, "Shutting down", 6, 0, 0);
}
-#endif /* LAC */
break;
case 3: // SCCN
LOG(3, s, t, "Received SCCN\n");
}
return;
case 11: // ICRP
-#ifdef LAC
LOG(3, s, t, "Received ICRP\n");
if (session[s].forwardtosession)
{
controladd(c, asession, t); // send the message
LOG(3, s, t, "Sending ICCN\n");
}
-#endif /* LAC */
break;
case 12: // ICCN
LOG(3, s, t, "Received ICCN\n");
// Set multilink options before sending initial LCP packet
sess_local[s].mp_mrru = 1614;
- sess_local[s].mp_epdis = ntohl(config->iftun_address ? config->iftun_address : my_address);
+ sess_local[s].mp_epdis = ntohl(config->iftun_n_address[tunnel[t].indexudp] ? config->iftun_n_address[tunnel[t].indexudp] : my_address);
sendlcp(s, t);
change_state(s, lcp, RequestSent);
l -= 2;
}
-#ifdef LAC
if (session[s].forwardtosession)
{
LOG(5, s, t, "Forwarding data session to session %u\n", session[s].forwardtosession);
// Forward to LAC/BAS or Remote LNS session
- lac_session_forward(buf, len, s, proto, addr->sin_addr.s_addr, addr->sin_port);
+ lac_session_forward(buf, len, s, proto, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
else if (config->auth_tunnel_change_addr_src)
tunnel[t].ip = ntohl(addr->sin_addr.s_addr);
}
}
-#endif /* LAC */
if (s && !session[s].opened) // Is something wrong??
{
if (!config->cluster_iam_master)
{
// Pass it off to the master to deal with..
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
if (proto == PPPPAP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processpap(s, t, p, l);
}
else if (proto == PPPCHAP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processchap(s, t, p, l);
}
else if (proto == PPPLCP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processlcp(s, t, p, l);
}
else if (proto == PPPIPCP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processipcp(s, t, p, l);
}
else if (proto == PPPIPV6CP && config->ipv6_prefix.s6_addr[0])
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processipv6cp(s, t, p, l);
}
else if (proto == PPPCCP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processccp(s, t, p, l);
}
else if (proto == PPPIP)
session[s].last_packet = session[s].last_data = time_now;
if (session[s].walled_garden && !config->cluster_iam_master)
{
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
if (!config->cluster_iam_master)
{
// The fragments reconstruction is managed by the Master.
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
session[s].last_packet = session[s].last_data = time_now;
if (session[s].walled_garden && !config->cluster_iam_master)
{
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
else if (session[s].ppp.lcp == Opened)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
protoreject(s, t, p, l, proto);
}
else
// No data in ECHO_TIMEOUT seconds, send LCP ECHO
if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) &&
- (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT))
+ (time_now - sess_local[s].last_echo >= config->echo_timeout))
{
uint8_t b[MAXETHER];
# include "fake_epoll.h"
#endif
-#ifdef LAC
-// the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink, udplac, pppoedisc, pppoesess
-#define BASE_FDS 10
-#else
-// the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink, pppoedisc, pppoesess
-#define BASE_FDS 9
-#endif
+// the base set of fds polled: cli, cluster, tun, udp (MAX_UDPFD), control, dae, netlink, udplac, pppoedisc, pppoesess
+#define BASE_FDS (9 + MAX_UDPFD)
// additional polled fds
#ifdef BGP
// main loop - gets packets on tun or udp and processes them
static void mainloop(void)
{
- int i;
+ int i, j;
uint8_t buf[65536];
uint8_t *p = buf + 32; // for the hearder of the forwarded MPPP packet (see C_MPPP_FORWARD)
// and the forwarded pppoe session
exit(1);
}
-#ifdef LAC
LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d , udplacfd=%d, pppoefd=%d, pppoesessfd=%d\n",
- clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd, udplacfd, pppoediscfd, pppoesessfd);
-#else
- LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d, pppoefd=%d, pppoesessfd=%d\n",
- clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd, pppoediscfd, pppoesessfd);
-#endif
+ clifd, cluster_sockfd, tunfd, udpfd[0], controlfd, daefd, nlfd, udplacfd, pppoediscfd, pppoesessfd);
/* setup our fds to poll for input */
{
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, tunfd, &e);
- d[i].type = FD_TYPE_UDP;
- e.data.ptr = &d[i++];
- epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd, &e);
-
d[i].type = FD_TYPE_CONTROL;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, controlfd, &e);
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, nlfd, &e);
-#ifdef LAC
- d[i].type = FD_TYPE_UDPLAC;
- e.data.ptr = &d[i++];
- epoll_ctl(epollfd, EPOLL_CTL_ADD, udplacfd, &e);
-#endif
-
d[i].type = FD_TYPE_PPPOEDISC;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, pppoediscfd, &e);
d[i].type = FD_TYPE_PPPOESESS;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, pppoesessfd, &e);
+
+ for (j = 0; j < config->nbudpfd; j++)
+ {
+ d[i].type = FD_TYPE_UDP;
+ d[i].index = j;
+ e.data.ptr = &d[i++];
+ epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd[j], &e);
+ }
}
#ifdef BGP
struct in_addr local;
socklen_t alen;
int c, s;
- int udp_ready = 0;
-#ifdef LAC
- int udplac_ready = 0;
- int udplac_pkts = 0;
-#endif
+ int udp_ready[MAX_UDPFD + 1] = INIT_TABUDPVAR;
int pppoesess_ready = 0;
int pppoesess_pkts = 0;
int tun_ready = 0;
int cluster_ready = 0;
- int udp_pkts = 0;
+ int udp_pkts[MAX_UDPFD + 1] = INIT_TABUDPVAR;
int tun_pkts = 0;
int cluster_pkts = 0;
#ifdef BGP
// these are handled below, with multiple interleaved reads
case FD_TYPE_CLUSTER: cluster_ready++; break;
case FD_TYPE_TUN: tun_ready++; break;
- case FD_TYPE_UDP: udp_ready++; break;
-#ifdef LAC
- case FD_TYPE_UDPLAC: udplac_ready++; break;
-#endif
+ case FD_TYPE_UDP: udp_ready[d->index]++; break;
case FD_TYPE_PPPOESESS: pppoesess_ready++; break;
case FD_TYPE_PPPOEDISC: // pppoe discovery
#ifdef BGP
case FD_TYPE_BGP:
- bgp_events[d->index] = events[i].events;
- n--;
+ bgp_events[d->index] = events[i].events;
+ n--;
break;
#endif /* BGP */
exit(1);
}
else
-
LOG(0, 0, 0, "Got a netlink error: %s\n", strerror(-errmsg->error));
}
// else it's a ack
}
default:
- LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type);
+ LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type);
}
}
for (c = 0; n && c < config->multi_read_count; c++)
{
- // L2TP
- if (udp_ready)
+ for (j = 0; j < config->nbudpfd; j++)
{
- alen = sizeof(addr);
- if ((s = recvfrom(udpfd, p, size_bufp, 0, (void *) &addr, &alen)) > 0)
+ // L2TP and L2TP REMOTE LNS
+ if (udp_ready[j])
{
- processudp(p, s, &addr);
- udp_pkts++;
- }
- else
- {
- udp_ready = 0;
- n--;
+ alen = sizeof(addr);
+ if ((s = recvfrom(udpfd[j], p, size_bufp, 0, (void *) &addr, &alen)) > 0)
+ {
+ processudp(p, s, &addr, j);
+ udp_pkts[j]++;
+ }
+ else
+ {
+ udp_ready[j] = 0;
+ n--;
+ }
}
}
-#ifdef LAC
- // L2TP REMOTE LNS
- if (udplac_ready)
- {
- alen = sizeof(addr);
- if ((s = recvfrom(udplacfd, p, size_bufp, 0, (void *) &addr, &alen)) > 0)
- {
- if (!config->disable_lac_func)
- processudp(p, s, &addr);
- udplac_pkts++;
- }
- else
- {
- udplac_ready = 0;
- n--;
- }
- }
-#endif
// incoming IP
if (tun_ready)
{
}
}
- if (udp_pkts > 1 || tun_pkts > 1 || cluster_pkts > 1)
+ if (udp_pkts[0] > 1 || tun_pkts > 1 || cluster_pkts > 1)
STAT(multi_read_used);
if (c >= config->multi_read_count)
{
-#ifdef LAC
- LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster %d rmlns and %d pppoe packets\n",
- config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, udplac_pkts, pppoesess_pkts);
-#else
LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster and %d pppoe packets\n",
- config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, pppoesess_pkts);
-#endif
+ config->multi_read_count, udp_pkts[0], tun_pkts, cluster_pkts, pppoesess_pkts);
STAT(multi_read_exceeded);
more++;
}
}
#endif /* BGP */
-#ifdef LAC
lac_initremotelnsdata();
-#endif
+
+ grp_initdata();
}
static int assign_ip_address(sessionidt s)
static int dump_session(FILE **f, sessiont *s)
{
-#ifdef LAC
if (!s->opened || (!s->ip && !s->forwardtosession) || !(s->cin_delta || s->cout_delta) || !*s->user || s->walled_garden)
-#else
- if (!s->opened || !s->ip || !(s->cin_delta || s->cout_delta) || !*s->user || s->walled_garden)
-#endif
return 1;
if (!*f)
"# uptime: %ld\n"
"# format: username ip qos uptxoctets downrxoctets\n",
hostname,
- fmtaddr(config->iftun_address ? config->iftun_address : my_address, 0),
+ fmtaddr(config->iftun_n_address[tunnel[s->tunnel].indexudp] ? config->iftun_n_address[tunnel[s->tunnel].indexudp] : my_address, 0),
now,
now - basetime);
}
init_pppoe();
LOG(1, 0, 0, "Set up on pppoe interface %s\n", config->pppoe_if_to_bind);
}
- initudp();
+
+ if (!config->nbmultiaddress)
+ {
+ config->bind_n_address[0] = config->bind_address;
+ config->nbmultiaddress++;
+ }
+ config->nbudpfd = config->nbmultiaddress;
+ for (i = 0; i < config->nbudpfd; i++)
+ initudp(&udpfd[i], config->bind_n_address[i]);
+ initlacudp();
+ config->indexlacudpfd = config->nbudpfd;
+ udpfd[config->indexlacudpfd] = udplacfd;
+ config->nbudpfd++;
+
+ initcontrol();
+ initdae();
+
+ // Intercept
+ snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
initrad();
initippool();
LOG(0, 0, 0, "Can't lock pages: %s\n", strerror(errno));
}
+ //LOG(3, 0, 0, "Debug sizeof struct: sessiont %lu, tunnelt %lu, bundlet %lu, groupsesst %lu\n",
+ // sizeof(sessiont), sizeof(tunnelt), sizeof(bundlet), sizeof(groupsesst));
+
mainloop();
/* remove plugins (so cleanup code gets run) */
if (!config->radius_dae_port)
config->radius_dae_port = DAEPORT;
-#ifdef LAC
if(!config->bind_portremotelns)
config->bind_portremotelns = L2TPLACPORT;
if(!config->bind_address_remotelns)
config->bind_address_remotelns = INADDR_ANY;
-#endif
+
+ if (*config->bind_multi_address)
+ {
+ char *sip = config->bind_multi_address;
+ char *n = sip;
+ char *e = config->bind_multi_address + strlen(config->bind_multi_address);
+ config->nbmultiaddress = 0;
+
+ while (*sip && (sip < e))
+ {
+ in_addr_t ip = 0;
+ uint8_t u = 0;
+
+ while (n < e && (*n == ',' || *n == ' ')) n++;
+
+ while (n < e && (isdigit(*n) || *n == '.'))
+ {
+ if (*n == '.')
+ {
+ ip = (ip << 8) + u;
+ u = 0;
+ }
+ else
+ u = u * 10 + *n - '0';
+ n++;
+ }
+ ip = (ip << 8) + u;
+ n++;
+
+ if (ip)
+ {
+ config->bind_n_address[config->nbmultiaddress] = htonl(ip);
+ config->iftun_n_address[config->nbmultiaddress] = htonl(ip);
+ config->nbmultiaddress++;
+ LOG(1, 0, 0, "Bind address %s\n", fmtaddr(htonl(ip), 0));
+ }
+
+ sip = n;
+ }
+
+ if (config->nbmultiaddress >= 1)
+ {
+ config->bind_address = config->bind_n_address[0];
+ config->iftun_address = config->bind_address;
+ }
+ }
+
if(!config->iftun_address)
+ {
config->iftun_address = config->bind_address;
+ config->iftun_n_address[0] = config->iftun_address;
+ }
if (!*config->pppoe_ac_name)
strncpy(config->pppoe_ac_name, DEFAULT_PPPOE_AC_NAME, sizeof(config->pppoe_ac_name) - 1);
if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1))
{
int routed = 0;
+ groupidt g;
// Add the route for this session.
for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
}
else
cache_ipmap(session[s].ip, s);
+
+ if ((g = grp_groupbysession(s)))
+ {
+ grp_setgrouproute(g, 1);
+ cluster_send_groupe(g);
+ }
}
sess_local[s].lcp_authtype = 0; // RADIUS authentication complete
return 0;
}
-#ifdef LAC
-
tunnelidt lac_new_tunnel()
{
return new_tunnel();
tunnelshutdown(t, reason, result, error, msg);
}
-#endif
#define MAXADDRESS 20 // Maximum length for the Endpoint Discrminiator address
#define MAXSESSION 60000 // could be up to 65535
#define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session.
+#define MAXSESSINGRP 12 // Maximum number of member links in grouped session
+#define MAXGROUPE 300 // could be up to 65535, Maximum number of grouped session
+#define MAXROUTEINGRP 15 // max static routes per group
// Tunnel Id reserved for pppoe
#define TUNNEL_ID_PPPOE 1
// it's not expected to have a space for more than 10 unassembled packets = 10 * MAXBUNDLESES
#define MAXFRAGNUM_MASK (MAXFRAGNUM - 1) // Must be equal to MAXFRAGNUM-1
+// Multi bind address constants
+#define MAX_UDPFD 4
+#define MAX_BINDADDR MAX_UDPFD
+// 4 + 1 for the udplac
+#define INIT_TABUDPFD {-1, -1, -1, -1, -1}
+#define INIT_TABUDPVAR {0, 0, 0, 0, 0}
+
// Constants
#ifndef ETCDIR
#define ETCDIR "/etc/l2tpns"
typedef uint16_t sessionidt;
typedef uint16_t bundleidt;
typedef uint16_t tunnelidt;
+typedef uint16_t groupidt;
typedef uint32_t clockt;
typedef uint8_t hasht[16];
char class[MAXCLASS];
uint8_t ipv6prefixlen; // IPv6 route prefix length
struct in6_addr ipv6route; // Static IPv6 route
-#ifdef LAC
sessionidt forwardtosession; // LNS id_session to forward
uint8_t src_hwaddr[ETH_ALEN]; // MAC addr source (for pppoe sessions 6 bytes)
- char reserved[4]; // Space to expand structure without changing HB_VERSION
-#else
- uint8_t src_hwaddr[ETH_ALEN]; // MAC addr source (for pppoe sessions 6 bytes)
- char reserved[6]; // Space to expand structure without changing HB_VERSION
-#endif
+ char reserved[4]; // Space to expand structure without changing HB_VERSION
}
sessiont;
+typedef struct
+{
+ uint32_t tx_rate;
+ uint32_t prev_coutgrp;
+ sessionidt sid;
+ uint8_t weight;
+}
+groupsesslistt;
+
+typedef struct
+{
+ int state; // current state (groupestate enum)
+ uint32_t time_changed;
+ groupidt prev;
+ sessionidt smax;
+ sessionidt smin;
+ groupsesslistt sesslist[MAXSESSINGRP];
+ routet route[MAXROUTEINGRP]; // static routes
+ uint8_t nbroutesgrp;
+ uint8_t nbsession;
+}
+groupsesst;
+
+union iphash
+{
+ sessionidt sess;
+ union iphash *idx;
+}; // Mapping from IP address to session structures.
+
typedef struct
{
int state; // current state (bundlestate enum)
uint16_t controlc; // outstaind messages in queue
controlt *controls; // oldest message
controlt *controle; // newest message
-#ifdef LAC
uint16_t isremotelns; // != 0 if the tunnel is to remote LNS (== index on the conf remote lns)
- char reserved[14]; // Space to expand structure without changing HB_VERSION
-#else
- char reserved[16]; // Space to expand structure without changing HB_VERSION
-#endif
+ uint16_t indexudp; // Index UDP file handle (in udpfd[])
+ char reserved[12]; // Space to expand structure without changing HB_VERSION
}
tunnelt;
BUNDLEUNDEF, // Undefined
};
+enum
+{
+ GROUPEFREE, // Not in use
+ GROUPEOPEN, // Active bundle
+ GROUPEUNDEF // Undefined
+};
+
enum
{
NULLCLASS = 0, //End Point Discriminator classes
int cluster_undefined_sessions; // How many sessions we're yet to receive from the master.
int cluster_undefined_bundles; // How many bundles we're yet to receive from the master.
int cluster_undefined_tunnels; // How many tunnels we're yet to receive from the master.
+ int cluster_undefined_groupes; // How many groupes we're yet to receive from the master.
int cluster_highest_sessionid;
int cluster_highest_bundleid;
+ int cluster_highest_groupeid;
int cluster_highest_tunnelid;
clockt cluster_last_hb; // Last time we saw a heartbeat from the master.
int cluster_last_hb_ver; // Heartbeat version last seen from master
int idle_echo_timeout; // Time between last packet seen and
// Drop sessions who have not responded within IDLE_ECHO_TIMEOUT seconds
in_addr_t iftun_address;
-#ifdef LAC
int disable_lac_func;
int auth_tunnel_change_addr_src;
int highest_rlnsid;
uint16_t bind_portremotelns;
in_addr_t bind_address_remotelns;
-#endif
char pppoe_if_to_bind[IFNAMSIZ]; // Name pppoe interface to bind
char pppoe_service_name[64]; // pppoe service name
char pppoe_ac_name[64];
uint8_t pppoe_hwaddr[ETH_ALEN]; // MAC addr of interface pppoe to bind
int disable_sending_hello; // Disable l2tp sending HELLO message for Apple compatibility.
int disable_no_spoof; // Disable no spoof (permit load balancing client --> internet)
+ int nbudpfd; // number UDP file handle
+ int nbmultiaddress; // number multi address to bind
+ int indexlacudpfd; // Index UDP LAC file handle (in udpfd[])
+ in_addr_t bind_n_address[MAX_BINDADDR];
+ in_addr_t iftun_n_address[MAX_BINDADDR];
+ char bind_multi_address[256];
+ int grp_txrate_average_time; // caculation txrate average time (default 10s)
} configt;
enum config_typet { INT, STRING, UNSIGNED_LONG, SHORT, BOOL, IPv4, IPv6 };
uint16_t radiusnew(sessionidt s);
void radiusclear(uint16_t r, sessionidt s);
void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struct in_addr *local);
-#ifdef LAC
int rad_tunnel_pwdecode(uint8_t *pl2tpsecret, size_t *pl2tpsecretlen, const char *radiussecret, const uint8_t * auth);
-#endif
// l2tpns.c
clockt backoff(uint8_t try);
void adjust_tcp_mss(sessionidt s, tunnelidt t, uint8_t *buf, int len, uint8_t *tcp);
void sendipcp(sessionidt s, tunnelidt t);
void sendipv6cp(sessionidt s, tunnelidt t);
-void processudp(uint8_t *buf, int len, struct sockaddr_in *addr);
+void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexudpfd);
void processipout(uint8_t *buf, int len);
void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, uint16_t port);
int find_filter(char const *name, size_t len);
int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc);
int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc);
int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc);
-#ifdef LAC
+void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen);
+ssize_t netlink_send(struct nlmsghdr *nh);
+void cache_ipmap(in_addr_t ip, sessionidt s);
+
tunnelidt lac_new_tunnel();
void lac_tunnelclear(tunnelidt t);
void lac_send_SCCRQ(tunnelidt t, uint8_t * auth, unsigned int auth_len);
void lac_send_ICRQ(tunnelidt t, sessionidt s);
void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char *msg);
-#endif
+
+// grpsess.c
+sessionidt grp_getnextsession(groupidt g, in_addr_t ip);
+void grp_initdata(void);
+void grp_processvendorspecific(sessionidt s, uint8_t *pvs);
+groupidt grp_groupbysession(sessionidt s);
+groupidt grp_groupbyip(in_addr_t ip);
+void grp_setgrouproute(groupidt g, int add);
+void grp_time_changed(void);
+void grp_removesession(groupidt g, sessionidt s);
+int grp_cluster_load_groupe(groupidt g, groupsesst *new);
#undef LOG
#undef LOG_HEX
extern sessiont *session;
extern sessionlocalt *sess_local;
extern ippoolt *ip_address_pool;
+extern groupsesst *grpsession;
+extern groupidt gnextgrpid;
#define sessionfree (session[0].next)
extern in_addr_t my_address;
extern int clifd;
extern int epollfd;
+extern int tunidx; // ifr_ifindex of tun device
+extern union iphash ip_hash[256];
struct event_data {
enum {
FD_TYPE_RADIUS,
FD_TYPE_BGP,
FD_TYPE_NETLINK,
-#ifdef LAC
- FD_TYPE_UDPLAC,
-#endif
FD_TYPE_PPPOEDISC,
FD_TYPE_PPPOESESS
} type;
- int index; // for RADIUS, BGP
+ int index; // for RADIUS, BGP, UDP
};
#define TIME (config->current_time)
#include <string.h>
#include <netdb.h>
#include <signal.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "control.h"
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "constants.h"
#include "plugin.h"
#include "tbf.h"
#include "cluster.h"
-#ifdef LAC
#include "l2tplac.h"
-#endif
#include "pppoe.h"
extern tunnelt *tunnel;
LOG(3, s, t, "PAP login %s/%s\n", user, pass);
}
-#ifdef LAC
if ((!config->disable_lac_func) && lac_conf_forwardtoremotelns(s, user))
{
// Creating a tunnel/session has been started
return;
}
-#endif
if (session[s].ip || !(r = radiusnew(s)))
{
packet.username = calloc(l + 1, 1);
memcpy(packet.username, p, l);
-#ifdef LAC
if ((!config->disable_lac_func) && lac_conf_forwardtoremotelns(s, packet.username))
{
free(packet.username);
// Creating a tunnel/session has been started
return;
}
-#endif
run_plugins(PLUGIN_PRE_AUTH, &packet);
if (!packet.continue_auth)
#include <netpacket/packet.h>
#include <arpa/inet.h>
#include <linux/if_pppox.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "cluster.h"
}
}
-#ifdef LAC
// Forward from pppoe to l2tp remote LNS
static void pppoe_forwardto_session_rmlns(uint8_t *pack, int size, sessionidt sess, uint16_t proto)
{
tunnelsend(p, lpppoe, t); // send it....
}
-#endif
void process_pppoe_sess(uint8_t *pack, int size)
{
lppp -= 2;
}
-#ifdef LAC
if (session[sid].forwardtosession)
{ // Must be forwaded to a remote lns tunnel l2tp
pppoe_forwardto_session_rmlns(pack, size, sid, proto);
return;
}
-#endif
if (proto == PPPPAP)
{
#include <ctype.h>
#include <netinet/in.h>
#include <errno.h>
+#include <linux/rtnetlink.h>
#include "md5.h"
#include "constants.h"
#include "util.h"
#include "cluster.h"
-#ifdef LAC
#include "l2tplac.h"
-#endif
#include "pppoe.h"
extern radiust *radius;
uint8_t routes = 0;
int r_code;
int r_id;
-#ifdef LAC
int OpentunnelReq = 0;
-#endif
CSTAT(processrad);
// Extract IP, routes, etc
uint8_t *p = buf + 20;
uint8_t *e = buf + len;
-#ifdef LAC
uint8_t tag;
uint8_t strtemp[256];
lac_reset_rad_tag_tunnel_ctxt();
-#endif
+
for (; p + 2 <= e && p[1] && p + p[1] <= e; p += p[1])
{
if (*p == 26 && p[1] >= 7)
else if (vendor == 529 && attrib >= 135 && attrib <= 136) // Ascend
{
// handle old-format ascend DNS attributes below
- p += 6;
+ p += 6;
+ }
+ else if (vendor == 64520) // Sames
+ {
+ //Sames vendor-specific 64520
+ uint8_t *pvs = p + 6; // pvs set to begin to attribute
+ LOG(3, s, session[s].tunnel, " Sames vendor-specific: %d, Attrib: %d, lenght: %d\n", vendor, attrib, attrib_length);
+ grp_processvendorspecific(s, pvs);
+ continue;
}
else
{
- LOG(3, s, session[s].tunnel, " Unknown vendor-specific\n");
+ LOG(3, s, session[s].tunnel, " Unknown vendor-specific: %d, Attrib: %d\n", vendor, attrib);
continue;
}
}
session[s].classlen = MAXCLASS;
memcpy(session[s].class, p + 2, session[s].classlen);
}
-#ifdef LAC
else if (*p == 64)
{
// Tunnel-Type
// Fill context
lac_set_rad_tag_tunnel_assignment_id(tag, (char *) strtemp);
}
-#endif
}
}
else if (r_code == AccessReject)
break;
}
-#ifdef LAC
if ((!config->disable_lac_func) && OpentunnelReq)
{
char assignment_id[256];
LOG(3, s, session[s].tunnel, " PAP User %s authentication %s.\n", session[s].user,
(r_code == AccessAccept) ? "allowed" : "denied");
}
-#endif
if (!session[s].dns1 && config->default_dns1)
{
LOG(0, 0, 0, "Error sending DAE response packet: %s\n", strerror(errno));
}
-#ifdef LAC
// Decrypte the encrypted Tunnel Password.
// Defined in RFC-2868.
// the pl2tpsecret buffer must set to 256 characters.
return decodedlen;
};
-#endif /* LAC */
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include "control.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include "control.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
// L2TPNS: token bucket filters
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "util.h"
#include "tbf.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include "control.h"
#include <arpa/inet.h>
#include <string.h>
#include <sys/mman.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#ifdef BGP
}
extern int forked;
-extern int cluster_sockfd, tunfd, udpfd, controlfd, daefd, snoopfd, ifrfd, ifr6fd, rand_fd;
+extern int cluster_sockfd, tunfd, controlfd, daefd, snoopfd, ifrfd, ifr6fd, rand_fd;
+extern int pppoediscfd, pppoesessfd;
extern int *radfds;
+extern int udpfd[MAX_UDPFD + 1];
pid_t fork_and_close()
{
- pid_t pid = fork();
- int i;
-
- if (pid)
- return pid;
-
- forked++;
- if (config->scheduler_fifo)
- {
- struct sched_param params = {0};
- params.sched_priority = 0;
- if (sched_setscheduler(0, SCHED_OTHER, ¶ms))
+ pid_t pid = fork();
+ int i;
+
+ if (pid)
+ return pid;
+
+ forked++;
+ if (config->scheduler_fifo)
+ {
+ struct sched_param params = {0};
+ params.sched_priority = 0;
+ if (sched_setscheduler(0, SCHED_OTHER, ¶ms))
+ {
+ LOG(0, 0, 0, "Error setting scheduler to OTHER after fork: %s\n", strerror(errno));
+ LOG(0, 0, 0, "This is probably really really bad.\n");
+ }
+ }
+
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGUSR1, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGKILL, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+
+ // Close sockets
+ if (clifd != -1) close(clifd);
+ if (cluster_sockfd != -1) close(cluster_sockfd);
+ if (tunfd != -1) close(tunfd);
+
+ for (i = 0; i < config->nbudpfd; i++)
{
- LOG(0, 0, 0, "Error setting scheduler to OTHER after fork: %s\n", strerror(errno));
- LOG(0, 0, 0, "This is probably really really bad.\n");
+ if (udpfd[i] != -1) close(udpfd[i]);
}
- }
-
- signal(SIGPIPE, SIG_DFL);
- signal(SIGCHLD, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
- signal(SIGUSR1, SIG_DFL);
- signal(SIGQUIT, SIG_DFL);
- signal(SIGKILL, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
-
- // Close sockets
- if (clifd != -1) close(clifd);
- if (cluster_sockfd != -1) close(cluster_sockfd);
- if (tunfd != -1) close(tunfd);
- if (udpfd != -1) close(udpfd);
- if (controlfd != -1) close(controlfd);
- if (daefd != -1) close(daefd);
- if (snoopfd != -1) close(snoopfd);
- if (rand_fd != -1) close(rand_fd);
- if (epollfd != -1) close(epollfd);
-
- for (i = 0; radfds && i < RADIUS_FDS; i++)
- close(radfds[i]);
+
+ if (pppoediscfd != -1) close(pppoediscfd);
+ if (pppoediscfd != -1) close(pppoediscfd);
+ if (controlfd != -1) close(controlfd);
+ if (daefd != -1) close(daefd);
+ if (snoopfd != -1) close(snoopfd);
+ if (rand_fd != -1) close(rand_fd);
+ if (epollfd != -1) close(epollfd);
+
+ for (i = 0; radfds && i < RADIUS_FDS; i++)
+ close(radfds[i]);
#ifdef BGP
- for (i = 0; i < BGP_NUM_PEERS; i++)
- if (bgp_peers[i].sock != -1)
- close(bgp_peers[i].sock);
+ for (i = 0; i < BGP_NUM_PEERS; i++)
+ if (bgp_peers[i].sock != -1)
+ close(bgp_peers[i].sock);
#endif /* BGP */
return pid;
}
ssize_t recvfromto(int s, void *buf, size_t len, int flags,
- struct sockaddr *from, socklen_t *fromlen, struct in_addr *toaddr)
+ struct sockaddr *from, socklen_t *fromlen, struct in_addr *toaddr)
{
- ssize_t r;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct iovec vec;
- char cbuf[128];
+ ssize_t r;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ char cbuf[128];
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = from;
- msg.msg_namelen = *fromlen;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = from;
+ msg.msg_namelen = *fromlen;
- vec.iov_base = buf;
- vec.iov_len = len;
- msg.msg_iov = &vec;
- msg.msg_iovlen = 1;
- msg.msg_flags = 0;
+ vec.iov_base = buf;
+ vec.iov_len = len;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
- msg.msg_control = cbuf;
- msg.msg_controllen = sizeof(cbuf);
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
- if ((r = recvmsg(s, &msg, flags)) < 0)
- return r;
+ if ((r = recvmsg(s, &msg, flags)) < 0)
+ return r;
- if (fromlen)
- *fromlen = msg.msg_namelen;
+ if (fromlen)
+ *fromlen = msg.msg_namelen;
- memset(toaddr, 0, sizeof(*toaddr));
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
- {
- if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO)
+ memset(toaddr, 0, sizeof(*toaddr));
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
{
- struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
- memcpy(toaddr, &i->ipi_addr, sizeof(*toaddr));
- break;
+ if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO)
+ {
+ struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
+ memcpy(toaddr, &i->ipi_addr, sizeof(*toaddr));
+ break;
+ }
}
- }
- return r;
+ return r;
}
ssize_t sendtofrom(int s, void const *buf, size_t len, int flags,