From: fendo Date: Thu, 28 Mar 2013 09:29:32 +0000 (+0100) Subject: Merge branch 'master' into samesversion X-Git-Tag: 2.2.1-2sames3.8~3 X-Git-Url: http://git.sameswireless.fr/l2tpns.git/commitdiff_plain/58d994f8f4aa2a6465dc9a2f13e7ba8ddf412ec7?hp=4ac1a263960dd8d535dcc15f30856d07c01ac2e4 Merge branch 'master' into samesversion --- diff --git a/Docs/manual.html b/Docs/manual.html index 12180ea..384fe9a 100644 --- a/Docs/manual.html +++ b/Docs/manual.html @@ -265,6 +265,24 @@ from the address of "bind_address" (For use in cases of specific configuration). If no address is given to iftun_address and bind_address, 1.1.1.1 is used. +
  • bind_multi_address (ip address)
    +This parameter permit to listen several addresss of the l2tp udp protocol +(and set several address to the tun interface). +
    +WHEN this parameter is set, It OVERWRITE the parameters "bind_address" +and "iftun_address". +
    +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). +
    +example of use with 2 address: +
    +set bind_multi_address "64.14.13.41, 64.14.13.42" + +
  • +
  • tundevicename (string)
    Name of the tun interface (default: "tun0").
  • diff --git a/Makefile b/Makefile index 21221ab..b19dfcd 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ INSTALL = install -c -D -o root -g root 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 \ @@ -43,9 +43,6 @@ endif DEFINES += -DBGP OBJS += bgp.o -DEFINES += -DLAC -OBJS += l2tplac.o - all: programs plugins programs: $(PROGRAMS) plugins: $(PLUGINS) @@ -129,8 +126,9 @@ radius.o: radius.c md5.h constants.h l2tpns.h plugin.h util.h cluster.h \ 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 diff --git a/arp.c b/arp.c index 6d55756..e9c7584 100644 --- a/arp.c +++ b/arp.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "l2tpns.h" diff --git a/autosnoop.c b/autosnoop.c index ddc699f..5633824 100644 --- a/autosnoop.c +++ b/autosnoop.c @@ -1,4 +1,7 @@ #include +#include +#include + #include "l2tpns.h" #include "plugin.h" diff --git a/autothrottle.c b/autothrottle.c index 73f9a94..007f926 100644 --- a/autothrottle.c +++ b/autothrottle.c @@ -1,4 +1,7 @@ #include +#include +#include + #include "l2tpns.h" #include "plugin.h" diff --git a/bgp.c b/bgp.c index 7c1e6c0..36894be 100644 --- a/bgp.c +++ b/bgp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "l2tpns.h" #include "bgp.h" diff --git a/cli.c b/cli.c index 3f950e0..e5ac57c 100644 --- a/cli.c +++ b/cli.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "l2tpns.h" #include "constants.h" @@ -31,9 +32,7 @@ #ifdef BGP #include "bgp.h" #endif -#ifdef LAC #include "l2tplac.h" -#endif extern tunnelt *tunnel; extern bundlet *bundle; @@ -77,6 +76,7 @@ static char *debug_levels[] = { #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); @@ -102,10 +102,8 @@ static int cmd_remove_plugin(struct cli_def *cli, char *command, char **argv, in 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); @@ -156,10 +154,9 @@ void init_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"); @@ -231,9 +228,7 @@ void init_cli() 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"); @@ -542,15 +537,9 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int } // 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", @@ -563,11 +552,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int "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++) @@ -578,15 +563,9 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int 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), @@ -599,11 +578,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int (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 : "*"); } @@ -694,11 +669,7 @@ static int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int 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 ); } @@ -1309,13 +1280,11 @@ static int cmd_drop_session(struct cli_def *cli, char *command, char **argv, int 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); @@ -3106,7 +3075,7 @@ static int cmd_show_access_list(struct cli_def *cli, char *command, char **argv, } if (i) - cli_print(cli, ""); + cli_print(cli, " "); cli_print(cli, "%s IP access list %s", ip_filters[f].extended ? "Extended" : "Standard", @@ -3144,7 +3113,76 @@ static int cmd_reload(struct cli_def *cli, char *command, char **argv, int argc) 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) { @@ -3216,4 +3254,3 @@ static int cmd_show_rmtlnsconf(struct cli_def *cli, char *command, char **argv, return CLI_OK; } -#endif diff --git a/cluster.c b/cluster.c index 78de01b..fc4d58a 100644 --- a/cluster.c +++ b/cluster.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "l2tpns.h" #include "cluster.h" @@ -43,6 +44,7 @@ in_addr_t my_address = 0; // The network address of my ethernet port. 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 :) @@ -87,6 +89,7 @@ int cluster_init() 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; @@ -228,7 +231,8 @@ static void cluster_uptodate(void) 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; @@ -305,10 +309,11 @@ static int _forward_packet(uint8_t *data, int size, in_addr_t addr, int port, in // 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; @@ -316,7 +321,7 @@ int master_forward_packet(uint8_t *data, int size, in_addr_t addr, int port) 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))); } @@ -452,7 +457,8 @@ void cluster_send_ping(time_t basetime) 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)); @@ -674,6 +680,20 @@ void cluster_check_master(void) 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. @@ -741,6 +761,7 @@ void cluster_check_master(void) 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 @@ -757,7 +778,7 @@ void cluster_check_master(void) // 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; @@ -766,7 +787,8 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig 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 @@ -808,10 +830,23 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig ++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; } @@ -865,6 +900,27 @@ static int hb_add_type(uint8_t **p, int type, int id) 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]; @@ -897,7 +953,7 @@ static int hb_add_type(uint8_t **p, int type, int 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; @@ -919,9 +975,11 @@ void cluster_heartbeat() 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; @@ -940,7 +998,7 @@ void cluster_heartbeat() // // 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. @@ -955,40 +1013,59 @@ void cluster_heartbeat() ++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? @@ -999,10 +1076,10 @@ void cluster_heartbeat() } 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; @@ -1068,6 +1145,18 @@ int cluster_send_bundle(int bid) 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) { @@ -1332,6 +1421,31 @@ static int cluster_recv_bundle(int more, uint8_t *p) 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) { @@ -1503,16 +1617,9 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t 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) { @@ -1635,9 +1742,10 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t 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) { @@ -1726,12 +1834,8 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t 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! @@ -1779,6 +1883,36 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t 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!! @@ -1854,9 +1988,11 @@ int processcluster(uint8_t *data, int size, in_addr_t addr) 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); @@ -1871,7 +2007,7 @@ int processcluster(uint8_t *data, int size, in_addr_t addr) processdae(p, s, &a, sizeof(a), &local); } else - processudp(p, s, &a); + processudp(p, s, &a, indexudp); return 0; } @@ -1986,12 +2122,14 @@ int cmd_show_cluster(struct cli_def *cli, char *command, char **argv, int argc) 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); } diff --git a/cluster.h b/cluster.h index 6a769e4..794cc9d 100644 --- a/cluster.h +++ b/cluster.h @@ -25,12 +25,11 @@ #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) @@ -62,7 +61,10 @@ typedef struct { 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 */ @@ -85,8 +87,9 @@ int cluster_init(void); 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); diff --git a/control.c b/control.c index 3d38b22..092ab8e 100644 --- a/control.c +++ b/control.c @@ -1,6 +1,9 @@ // L2TPNS: control #include +#include +#include + #include "l2tpns.h" #include "control.h" diff --git a/debian/changelog b/debian/changelog index 1d9c0b7..5c63054 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,17 @@ -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 Tue, 26 Feb 2013 09:07:16 +0100 +l2tpns (2.2.1-2sames3.6) unstable; urgency=low + + * Sames l2tpns version. + + -- Fernando Alves Tue, 12 Feb 2013 20:20:17 +0100 + l2tpns (2.2.1-2fdn3.5) unstable; urgency=low * Update debian/changelog diff --git a/dictionary.sames b/dictionary.sames new file mode 100644 index 0000000..a8a244d --- /dev/null +++ b/dictionary.sames @@ -0,0 +1,18 @@ +# -*- 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 + diff --git a/garden.c b/garden.c index 994ecb5..63135ea 100644 --- a/garden.c +++ b/garden.c @@ -3,6 +3,9 @@ #include #include #include +#include +#include + #include "l2tpns.h" #include "plugin.h" #include "control.h" diff --git a/grpsess.c b/grpsess.c new file mode 100644 index 0000000..7f897b3 --- /dev/null +++ b/grpsess.c @@ -0,0 +1,674 @@ +/* + * Fernando ALVES 2013 + * Grouped session for load balancing and fail-over + * GPL licenced + */ + +#include +#include +#include +#include +#include + +#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; +} diff --git a/icmp.c b/icmp.c index fa947b7..5f05127 100644 --- a/icmp.c +++ b/icmp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "l2tpns.h" #include "pppoe.h" diff --git a/l2tplac.c b/l2tplac.c index 6ad4683..fd3a7e0 100644 --- a/l2tplac.c +++ b/l2tplac.c @@ -7,6 +7,8 @@ #include #include +#include +#include #include "md5.h" #include "l2tpns.h" @@ -295,6 +297,7 @@ static int lac_create_tunnelsession(tunnelidt t, sessionidt s, confrlnsidt i_con 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)); @@ -449,7 +452,7 @@ void lac_calc_rlns_auth(tunnelidt t, uint8_t id, uint8_t *out) } // 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 @@ -482,7 +485,7 @@ int lac_session_forward(uint8_t *buf, int len, sessionidt sess, uint16_t proto, (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; } } diff --git a/l2tplac.h b/l2tplac.h index 6177b0a..0ff7c5a 100644 --- a/l2tplac.h +++ b/l2tplac.h @@ -12,7 +12,7 @@ typedef uint16_t confrlnsidt; // 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); diff --git a/l2tpns.c b/l2tpns.c index 527175c..17c440b 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -53,24 +53,18 @@ #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. @@ -81,7 +75,7 @@ int cluster_sockfd = -1; // Intra-cluster communications socket. 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 @@ -98,10 +92,7 @@ uint16_t MSS = 0; // TCP MSS 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; @@ -181,17 +172,17 @@ config_descriptt config_values[] = { 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 } }; @@ -220,6 +211,7 @@ tunnelt *tunnel = NULL; // Array of tunnel structures. 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. @@ -230,9 +222,6 @@ struct Tstats *_statistics = NULL; 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); @@ -261,8 +250,9 @@ static clockt now(double *f) 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 @@ -621,7 +611,7 @@ static void initnetlink(void) } } -static ssize_t netlink_send(struct nlmsghdr *nh) +ssize_t netlink_send(struct nlmsghdr *nh) { struct sockaddr_nl nladdr; struct iovec iov; @@ -657,7 +647,7 @@ static ssize_t netlink_recv(void *buf, ssize_t len) } /* 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; @@ -700,7 +690,7 @@ static void inittun(void) } if (*config->tundevicename) - strncpy(ifr.ifr_name, config->tundevicename, IFNAMSIZ); + strncpy(ifr.ifr_name, config->tundevicename, IFNAMSIZ); if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) { @@ -762,14 +752,30 @@ static void inittun(void) 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]) { @@ -839,28 +845,35 @@ senderror: 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)); @@ -874,6 +887,13 @@ static void initudp(void) 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)); @@ -887,28 +907,30 @@ static void initudp(void) 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); } // @@ -1003,7 +1025,7 @@ sessionidt sessionbyipv6(struct in6_addr ip) // // (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; @@ -1233,14 +1255,11 @@ void tunnelsend(uint8_t * buf, uint16_t l, tunnelidt t) 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; } @@ -1388,6 +1407,7 @@ static void update_session_out_stat(sessionidt s, sessiont *sp, int len) void processipout(uint8_t *buf, int len) { sessionidt s; + groupidt g; sessiont *sp; tunnelidt t; in_addr_t ip; @@ -1424,7 +1444,31 @@ void processipout(uint8_t *buf, int len) } 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. @@ -2055,7 +2099,7 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e 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++) @@ -2208,7 +2252,7 @@ void sendipcp(sessionidt s, tunnelidt t) 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 @@ -2255,6 +2299,8 @@ static void sessionclear(sessionidt s) // kill a session now void sessionkill(sessionidt s, char *reason) { + groupidt g; + CSTAT(sessionkill); if (!session[s].opened) // not alive @@ -2272,7 +2318,6 @@ void sessionkill(sessionidt s, char *reason) 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; @@ -2282,9 +2327,14 @@ void sessionkill(sessionidt s, char *reason) 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); } @@ -2388,7 +2438,7 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha } // 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; @@ -2479,7 +2529,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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; } @@ -2529,6 +2579,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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); @@ -2800,7 +2851,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } break; case 13: // Response -#ifdef LAC if (tunnel[t].isremotelns) { chapresponse = calloc(17, 1); @@ -2808,7 +2858,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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; @@ -3054,7 +3103,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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) { @@ -3085,7 +3133,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { tunnelshutdown(t, "Shutting down", 6, 0, 0); } -#endif /* LAC */ break; case 3: // SCCN LOG(3, s, t, "Received SCCN\n"); @@ -3163,7 +3210,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } return; case 11: // ICRP -#ifdef LAC LOG(3, s, t, "Received ICRP\n"); if (session[s].forwardtosession) { @@ -3179,7 +3225,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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"); @@ -3195,7 +3240,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) // 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); @@ -3253,12 +3298,11 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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) @@ -3273,14 +3317,13 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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; } @@ -3292,37 +3335,37 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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) @@ -3336,7 +3379,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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; } @@ -3354,7 +3397,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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; } @@ -3371,7 +3414,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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; } @@ -3380,7 +3423,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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 @@ -3683,7 +3726,7 @@ static void regular_cleanups(double period) // 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]; @@ -3949,13 +3992,8 @@ static int still_busy(void) # 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 @@ -3967,7 +4005,7 @@ static int still_busy(void) // 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 @@ -3982,13 +4020,8 @@ static void mainloop(void) 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 */ { @@ -4013,10 +4046,6 @@ static void mainloop(void) 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); @@ -4029,12 +4058,6 @@ static void mainloop(void) 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); @@ -4042,6 +4065,14 @@ static void mainloop(void) 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 @@ -4103,16 +4134,12 @@ static void mainloop(void) 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 @@ -4146,10 +4173,7 @@ static void mainloop(void) // 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 @@ -4190,8 +4214,8 @@ static void mainloop(void) #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 */ @@ -4210,7 +4234,6 @@ static void mainloop(void) exit(1); } else - LOG(0, 0, 0, "Got a netlink error: %s\n", strerror(-errmsg->error)); } // else it's a ack @@ -4222,7 +4245,7 @@ static void mainloop(void) } 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); } } @@ -4232,40 +4255,25 @@ static void mainloop(void) 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) { @@ -4313,18 +4321,13 @@ static void mainloop(void) } } - 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++; } @@ -4659,9 +4662,9 @@ static void initdata(int optdebug, char *optconfig) } #endif /* BGP */ -#ifdef LAC lac_initremotelnsdata(); -#endif + + grp_initdata(); } static int assign_ip_address(sessionidt s) @@ -4948,11 +4951,7 @@ void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, ui 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) @@ -4978,7 +4977,7 @@ static int dump_session(FILE **f, sessiont *s) "# 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); } @@ -5132,7 +5131,26 @@ int main(int argc, char *argv[]) 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(); @@ -5158,6 +5176,9 @@ int main(int argc, char *argv[]) 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) */ @@ -5364,14 +5385,62 @@ static void update_config() 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); @@ -5583,6 +5652,7 @@ int sessionsetup(sessionidt s, tunnelidt t) 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++) @@ -5605,6 +5675,12 @@ int sessionsetup(sessionidt s, tunnelidt t) } 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 @@ -6429,8 +6505,6 @@ int ip_filter(uint8_t *buf, int len, uint8_t filter) return 0; } -#ifdef LAC - tunnelidt lac_new_tunnel() { return new_tunnel(); @@ -6476,4 +6550,3 @@ void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char * tunnelshutdown(t, reason, result, error, msg); } -#endif diff --git a/l2tpns.h b/l2tpns.h index 092c683..bce434f 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -24,6 +24,9 @@ #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 @@ -66,6 +69,13 @@ // 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" @@ -207,6 +217,7 @@ enum { 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]; @@ -322,17 +333,41 @@ typedef struct 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) @@ -449,12 +484,9 @@ typedef struct 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; @@ -518,6 +550,13 @@ enum BUNDLEUNDEF, // Undefined }; +enum +{ + GROUPEFREE, // Not in use + GROUPEOPEN, // Active bundle + GROUPEUNDEF // Undefined +}; + enum { NULLCLASS = 0, //End Point Discriminator classes @@ -725,8 +764,10 @@ typedef struct 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 @@ -765,19 +806,24 @@ typedef struct 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 }; @@ -913,9 +959,7 @@ void radiusretry(uint16_t r); 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); @@ -935,7 +979,7 @@ int tun_write(uint8_t *data, int size); 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); @@ -943,13 +987,26 @@ int ip_filter(uint8_t *buf, int len, uint8_t filter); 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 @@ -985,6 +1042,8 @@ extern bundlet *bundle; extern sessiont *session; extern sessionlocalt *sess_local; extern ippoolt *ip_address_pool; +extern groupsesst *grpsession; +extern groupidt gnextgrpid; #define sessionfree (session[0].next) @@ -997,6 +1056,8 @@ extern struct Tstats *_statistics; 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 { @@ -1009,13 +1070,10 @@ struct event_data { 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) diff --git a/nsctl.c b/nsctl.c index 59ad0c6..98785cd 100644 --- a/nsctl.c +++ b/nsctl.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "l2tpns.h" #include "control.h" diff --git a/ppp.c b/ppp.c index bd70e4d..cb8512f 100644 --- a/ppp.c +++ b/ppp.c @@ -5,6 +5,9 @@ #include #include #include +#include +#include + #include "l2tpns.h" #include "constants.h" #include "plugin.h" @@ -12,9 +15,7 @@ #include "tbf.h" #include "cluster.h" -#ifdef LAC #include "l2tplac.h" -#endif #include "pppoe.h" extern tunnelt *tunnel; @@ -105,13 +106,11 @@ void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) 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))) { @@ -264,7 +263,6 @@ void processchap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) 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); @@ -272,7 +270,6 @@ void processchap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) // Creating a tunnel/session has been started return; } -#endif run_plugins(PLUGIN_PRE_AUTH, &packet); if (!packet.continue_auth) diff --git a/pppoe.c b/pppoe.c index 4b196ea..61b881b 100644 --- a/pppoe.c +++ b/pppoe.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "l2tpns.h" #include "cluster.h" @@ -902,7 +903,6 @@ void process_pppoe_disc(uint8_t *pack, int size) } } -#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) { @@ -1036,7 +1036,6 @@ void pppoe_forwardto_session_pppoe(uint8_t *pack, int size, sessionidt sess, uin tunnelsend(p, lpppoe, t); // send it.... } -#endif void process_pppoe_sess(uint8_t *pack, int size) { @@ -1101,13 +1100,11 @@ 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) { diff --git a/radius.c b/radius.c index 34806c5..266f100 100644 --- a/radius.c +++ b/radius.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "md5.h" #include "constants.h" @@ -19,9 +20,7 @@ #include "util.h" #include "cluster.h" -#ifdef LAC #include "l2tplac.h" -#endif #include "pppoe.h" extern radiust *radius; @@ -537,9 +536,7 @@ void processrad(uint8_t *buf, int len, char socket_index) uint8_t routes = 0; int r_code; int r_id; -#ifdef LAC int OpentunnelReq = 0; -#endif CSTAT(processrad); @@ -641,11 +638,10 @@ void processrad(uint8_t *buf, int len, char socket_index) // 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) @@ -668,11 +664,19 @@ void processrad(uint8_t *buf, int len, char socket_index) 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; } } @@ -840,7 +844,6 @@ void processrad(uint8_t *buf, int len, char socket_index) session[s].classlen = MAXCLASS; memcpy(session[s].class, p + 2, session[s].classlen); } -#ifdef LAC else if (*p == 64) { // Tunnel-Type @@ -929,7 +932,6 @@ void processrad(uint8_t *buf, int len, char socket_index) // Fill context lac_set_rad_tag_tunnel_assignment_id(tag, (char *) strtemp); } -#endif } } else if (r_code == AccessReject) @@ -939,7 +941,6 @@ void processrad(uint8_t *buf, int len, char socket_index) break; } -#ifdef LAC if ((!config->disable_lac_func) && OpentunnelReq) { char assignment_id[256]; @@ -996,7 +997,6 @@ void processrad(uint8_t *buf, int len, char socket_index) 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) { @@ -1341,7 +1341,6 @@ void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struc 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. @@ -1432,4 +1431,3 @@ int rad_tunnel_pwdecode(uint8_t *pl2tpsecret, size_t *pl2tpsecretlen, return decodedlen; }; -#endif /* LAC */ diff --git a/sessionctl.c b/sessionctl.c index 805b794..a8c11bd 100644 --- a/sessionctl.c +++ b/sessionctl.c @@ -1,4 +1,7 @@ #include +#include +#include + #include "l2tpns.h" #include "plugin.h" #include "control.h" diff --git a/setrxspeed.c b/setrxspeed.c index 52fcf4a..f987378 100644 --- a/setrxspeed.c +++ b/setrxspeed.c @@ -1,4 +1,7 @@ #include +#include +#include + #include "l2tpns.h" #include "plugin.h" diff --git a/snoopctl.c b/snoopctl.c index d538a23..97d4bd0 100644 --- a/snoopctl.c +++ b/snoopctl.c @@ -1,4 +1,7 @@ #include +#include +#include + #include "l2tpns.h" #include "plugin.h" #include "control.h" diff --git a/stripdomain.c b/stripdomain.c index 877617e..c251dba 100644 --- a/stripdomain.c +++ b/stripdomain.c @@ -1,4 +1,7 @@ #include +#include +#include + #include "l2tpns.h" #include "plugin.h" diff --git a/tbf.c b/tbf.c index c6273ce..8b488d6 100644 --- a/tbf.c +++ b/tbf.c @@ -1,6 +1,9 @@ // L2TPNS: token bucket filters #include +#include +#include + #include "l2tpns.h" #include "util.h" #include "tbf.h" diff --git a/throttlectl.c b/throttlectl.c index adcff27..bcc0478 100644 --- a/throttlectl.c +++ b/throttlectl.c @@ -1,4 +1,7 @@ #include +#include +#include + #include "l2tpns.h" #include "plugin.h" #include "control.h" diff --git a/util.c b/util.c index d4dbd4f..e412fc1 100644 --- a/util.c +++ b/util.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "l2tpns.h" #ifdef BGP @@ -51,100 +52,109 @@ void *shared_malloc(unsigned int size) } 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,