From 5e65215ed4758c8fcd26ecaadc4b6121b93dab1c Mon Sep 17 00:00:00 2001 From: fendo Date: Thu, 6 Dec 2012 01:40:12 +0100 Subject: [PATCH] Following development LAC functionality --- Changes | 7 + Docs/manual.html | 14 ++ cli.c | 71 ++++++- cluster.c | 18 +- cluster.h | 4 + l2tplac.c | 488 ++++++++++++++++++++++++++++++++++++++--------- l2tplac.h | 31 ++- l2tpns.c | 146 +++++++++++--- l2tpns.h | 17 +- ppp.c | 11 +- radius.c | 221 +++++++++++++++++++++ 11 files changed, 890 insertions(+), 138 deletions(-) diff --git a/Changes b/Changes index decb16e..6e98ab6 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,10 @@ +* 2012 Fernando Alves 2.2.1-2fdn x +- Fix MLPPP functionality. +- Fix the inverted "delete/add" of the routes, in cluster mode. +- Add a echo_timeout configuration option. +- Add a idle_echo_timeout configuration option. +- Add LAC functionality, possibility to forward ppp to Remote LNS. + * Sun Sep 11 2011 Brendan O'Dea 2.2.x - Apply MLPPP patch from Muhammad Tayseer Alquoatli. - Apply patch from Michael O to avoid sending multiple CDNs. diff --git a/Docs/manual.html b/Docs/manual.html index e3e19db..f52ad29 100644 --- a/Docs/manual.html +++ b/Docs/manual.html @@ -368,8 +368,22 @@ Drop sessions who have not responded within idle_echo_timeout seconds (default: 240 (seconds)) +
  • bind_portremotelns (short)
    +Port to bind for the Remote LNS (default: 65432). +
  • + +

    The REMOTES LNS configuration is entered by the command: +

    setforward MASK IP PORT SECRET
    + +where MASK specifies the mask of users who have forwarded to +remote LNS (ex: /myISP@company.com).
    +where IP specifies the IP of the remote LNS (ex: 66.66.66.55).
    +where PORT specifies the L2TP Port of the remote LNS +(Normally should be 1701) (ex: 1701).
    +where SECRET specifies the secret password the remote LNS (ex: mysecret).
    +

    BGP routing configuration is entered by the command: The routing configuration section is entered by the command

    router bgp as
    diff --git a/cli.c b/cli.c index 5b0bcbc..09ea768 100644 --- a/cli.c +++ b/cli.c @@ -104,6 +104,7 @@ static int cmd_shutdown(struct cli_def *cli, char *command, char **argv, int arg 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); @@ -155,6 +156,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, "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"); @@ -538,8 +542,15 @@ 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", @@ -552,7 +563,11 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int "uploaded", "idle", "Rem.Time", +#ifdef LAC + "LAC(L)/R LNS(R)", +#else "LAC", +#endif "CLI"); for (i = 1; i < MAXSESSION; i++) @@ -563,9 +578,15 @@ 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%-15s %s", +#else cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %s %10u %10lu %10lu %4u %10lu %-15s %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), @@ -578,6 +599,9 @@ 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 + tunnel[session[i].tunnel].isremotelns?"(R)":"(L)", +#endif fmtaddr(htonl(tunnel[ session[i].tunnel ].ip), 1), session[i].calling[0] ? session[i].calling : "*"); } @@ -662,12 +686,20 @@ static int cmd_show_tunnels(struct cli_def *cli, char *command, char **argv, int if (!show_all && (!tunnel[i].ip || tunnel[i].die)) continue; for (x = 0; x < MAXSESSION; x++) if (session[x].tunnel == i && session[x].opened && !session[x].die) sessions++; +#ifdef LAC + cli_print(cli, "%4d %20s %20s %6s %6d %s", +#else cli_print(cli, "%4d %20s %20s %6s %6d", +#endif i, *tunnel[i].hostname ? tunnel[i].hostname : "(null)", fmtaddr(htonl(tunnel[i].ip), 0), states[tunnel[i].state], - sessions); + sessions +#ifdef LAC + ,(tunnel[i].isremotelns?"Tunnel To Remote LNS":"Tunnel To LAC") +#endif + ); } return CLI_OK; @@ -1277,6 +1309,13 @@ 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); @@ -3142,15 +3181,39 @@ static int cmd_setforward(struct cli_def *cli, char *command, char **argv, int a return CLI_OK; } - // adremotelns(mask, IP_RemoteLNS, Port_RemoteLNS, SecretRemoteLNS) - ret = addremotelns(argv[0], argv[1], argv[2], argv[3]); + // lac_addremotelns(mask, IP_RemoteLNS, Port_RemoteLNS, SecretRemoteLNS) + ret = lac_addremotelns(argv[0], argv[1], argv[2], argv[3]); if (ret) + { cli_print(cli, "setforward %s %s %s %s", argv[0], argv[1], argv[2], argv[3]); + if (ret == 2) + cli_print(cli, "%s Updated, the tunnel must be dropped", argv[0]); + } else cli_error(cli, "ERROR setforward %s %s %s %s", argv[0], argv[1], argv[2], argv[3]); return CLI_OK; } +static int cmd_show_rmtlnsconf(struct cli_def *cli, char *command, char **argv, int argc) +{ + confrlnsidt idrlns; + char strdisp[1024]; + + if (CLI_HELP_REQUESTED) + { + return cli_arg_help(cli, 0, "remotelns-conf", "Show a list of remote LNS configurations", NULL); + } + + for (idrlns = 0; idrlns < MAXRLNSTUNNEL; idrlns++) + { + if (lac_cli_show_remotelns(idrlns, strdisp) != 0) + cli_print(cli, "%s", strdisp); + else + break; + } + + return CLI_OK; +} #endif diff --git a/cluster.c b/cluster.c index 67d8d5e..b2a244e 100644 --- a/cluster.c +++ b/cluster.c @@ -1487,6 +1487,7 @@ static uint8_t *convert_session(struct oldsession *old) // Process a heartbeat.. // // v6: added RADIUS class attribute, re-ordered session structure +// v7: added tunnelt attribute at the end of struct (tunnelt size change) static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t *p, in_addr_t addr) { heartt *h; @@ -1494,11 +1495,18 @@ 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 6 + + // we handle versions 5 through 7 if (hb_ver < 5 || hb_ver > HB_VERSION) { LOG(0, 0, 0, "Received a heartbeat version that I don't support (%d)!\n", hb_ver); return -1; // Ignore it?? @@ -1710,7 +1718,13 @@ 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); - if (size != sizeof(tunnelt) ) { // Ouch! Very very bad! +#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! break; diff --git a/cluster.h b/cluster.h index c1aa574..0581647 100644 --- a/cluster.h +++ b/cluster.h @@ -25,7 +25,11 @@ #define C_CBUNDLE 18 // Compressed bundle structure. #define C_MPPP_FORWARD 19 // MPPP Forwarded packet.. +#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) diff --git a/l2tplac.c b/l2tplac.c index 11ac963..7fa8e87 100644 --- a/l2tplac.c +++ b/l2tplac.c @@ -12,7 +12,7 @@ #include "l2tplac.h" /* sequence diagram: Client <--> LAC <--> LNS1 <--> LNS2 - * + * * LCP Negotiation * Client <-------------------> LAC * Challenge (CHAP/PAP) @@ -61,38 +61,47 @@ * Client <------------------------------------------------------------------------> LNS2 * */ -// Limits -#define MAXRLNSTUNNEL 101 +typedef struct +{ + uint32_t tunnel_type; + uint32_t tunnel_medium_type; + in_addr_t tunnel_server_endpoint; /* IP remote LNS */ + char tunnel_password[64]; /* l2tpsecret remote LNS */ + char tunnel_assignment_id[256]; +} tunnelrlnst; -typedef uint16_t confrlnsidt; +// Max Radius Tunnels by remote LNS +#define MAXTAGTUNNEL 0x20 +static tunnelrlnst ptunnelrlns[MAXTAGTUNNEL]; /* * Possible configrlns states - * TUNNELFREE -> TUNNELOPEN -> TUNNELDIE -> TUNNELFREE + * CONFRLNSFREE -> CONFRLNSSET -> CONFRLNSFREE */ enum { CONFRLNSFREE = 0, // Not in use - CONFRLNSSET // Config Set + CONFRLNSSET, // Config Set + CONFRLNSSETBYRADIUS // Config Set }; // struct remote lns typedef struct { - tunnelidt tid; // near end tunnel ID int state; // conf state (tunnelstate enum) in_addr_t ip; // Ip for far end uint16_t port; // port for far end hasht auth; // request authenticator char strmaskuser[MAXUSER]; - char l2tp_secret[64]; // L2TP shared secret + char l2tp_secret[64]; // L2TP shared secret + char tunnel_assignment_id[256]; } configrlns; -configrlns *pconfigrlns = NULL; // Array of tunnel structures. +configrlns *pconfigrlns = NULL; // Init data structures -void initremotelnsdata() +void lac_initremotelnsdata() { confrlnsidt i; @@ -104,135 +113,324 @@ void initremotelnsdata() memset(pconfigrlns, 0, sizeof(pconfigrlns[0]) * MAXRLNSTUNNEL); - // Mark all the tunnels as undefined (waiting to be filled in by a download). + // Mark all the conf as free. for (i = 1; i < MAXRLNSTUNNEL; i++) pconfigrlns[i].state = CONFRLNSFREE; // mark it as not filled in. config->highest_rlnsid = 0; + + lac_reset_rad_tag_tunnel_ctxt(); } -// Check if must be forwarded to another LNS -int forwardtolns(sessionidt s, char * puser) +// Reset Radius TAG tunnel context +void lac_reset_rad_tag_tunnel_ctxt() { - tunnelidt t; - confrlnsidt i; + memset(ptunnelrlns, 0, sizeof(ptunnelrlns[0]) * MAXTAGTUNNEL); +} - for (i = 1; i <= config->highest_rlnsid ; ++i) +// Add tunnel_type radius TAG tunnel to context +void lac_set_rad_tag_tunnel_type(uint8_t tag, uint32_t tunnel_type) +{ + if (tag < MAXTAGTUNNEL) + ptunnelrlns[tag].tunnel_type = tunnel_type; +} + +// Add tunnel_medium_type Radius TAG tunnel to context +void lac_set_rad_tag_tunnel_medium_type(uint8_t tag, uint32_t tunnel_medium_type) +{ + if (tag < MAXTAGTUNNEL) + ptunnelrlns[tag].tunnel_medium_type = tunnel_medium_type; +} + +// Add tunnel_server_endpoint Radius TAG tunnel to context +void lac_set_rad_tag_tunnel_serv_endpt(uint8_t tag, char *tunnel_server_endpoint) +{ + if (tag < MAXTAGTUNNEL) { - if ( NULL != strstr(puser, pconfigrlns[i].strmaskuser)) + ptunnelrlns[tag].tunnel_server_endpoint = ntohl(inet_addr(tunnel_server_endpoint)); + } +} + +// Add tunnel_password Radius TAG tunnel to context +void lac_set_rad_tag_tunnel_password(uint8_t tag, char *tunnel_password) +{ + if ((tag < MAXTAGTUNNEL) && (strlen(tunnel_password) < 64)) + { + strcpy(ptunnelrlns[tag].tunnel_password, tunnel_password); + } +} + +// Add tunnel_assignment_id Radius TAG tunnel to context +void lac_set_rad_tag_tunnel_assignment_id(uint8_t tag, char *tunnel_assignment_id) +{ + if ((tag < MAXTAGTUNNEL) && (strlen(tunnel_assignment_id) < 256)) + { + strcpy(ptunnelrlns[tag].tunnel_assignment_id, tunnel_assignment_id); + } +} + +// Select a tunnel_assignment_id +int lac_rad_select_assignment_id(sessionidt s, char *assignment_id) +{ + int idtag; + int nbtagfound = 0; + int bufidtag[MAXTAGTUNNEL]; + + for (idtag = 0; idtag < MAXTAGTUNNEL; ++idtag) + { + if (ptunnelrlns[idtag].tunnel_type == 0) + continue; + else if (ptunnelrlns[idtag].tunnel_type != 3) // 3 == L2TP tunnel type + LOG(1, s, session[s].tunnel, "Error, Only L2TP tunnel type supported\n"); + else if (ptunnelrlns[idtag].tunnel_medium_type != 1) + LOG(1, s, session[s].tunnel, "Error, Only IP tunnel medium type supported\n"); + else if (ptunnelrlns[idtag].tunnel_server_endpoint == 0) + LOG(1, s, session[s].tunnel, "Error, Bad IP tunnel server endpoint \n"); + else if (strlen(ptunnelrlns[idtag].tunnel_assignment_id) > 0) { - t = pconfigrlns[i].tid; + bufidtag[nbtagfound] = idtag; + nbtagfound++; + } + } - if ((t != 0) && (tunnel[t].ip != pconfigrlns[i].ip)) - { - pconfigrlns[i].tid = t = 0; - LOG(1, 0, t, "Tunnel ID inconsistency\n"); - } + if (nbtagfound > 0) + { + // random between 0 and nbtagfound-1 + idtag = (nbtagfound*rand()/(RAND_MAX+1.0)); + if (idtag >= nbtagfound) + idtag = 0; //Sanity checks. + + strcpy(assignment_id, ptunnelrlns[bufidtag[idtag]].tunnel_assignment_id); + return 1; + } + + // Error no tunnel_assignment_id found + return 0; +} + +// Save the 'radius tag tunnels' context on global configuration +void lac_save_rad_tag_tunnels(sessionidt s) +{ + confrlnsidt idrlns; + int idtag; - if (t == 0) + for (idtag = 0; idtag < MAXTAGTUNNEL; ++idtag) + { + if (ptunnelrlns[idtag].tunnel_type == 0) + continue; + else if (ptunnelrlns[idtag].tunnel_type != 3) // 3 == L2TP tunnel type + LOG(1, s, session[s].tunnel, "Error, Only L2TP tunnel type supported\n"); + else if (ptunnelrlns[idtag].tunnel_medium_type != 1) + LOG(1, s, session[s].tunnel, "Error, Only IP tunnel medium type supported\n"); + else if (ptunnelrlns[idtag].tunnel_server_endpoint == 0) + LOG(1, s, session[s].tunnel, "Error, Bad IP tunnel server endpoint \n"); + else if (strlen(ptunnelrlns[idtag].tunnel_assignment_id) <= 0) + LOG(1, s, session[s].tunnel, "Error, No tunnel_assignment_id \n"); + else + for (idrlns = 1; idrlns < MAXRLNSTUNNEL; ++idrlns) { - if (main_quit == QUIT_SHUTDOWN) return 0; + if (pconfigrlns[idrlns].state == CONFRLNSFREE) + { + pconfigrlns[idrlns].ip = ptunnelrlns[idtag].tunnel_server_endpoint; + pconfigrlns[idrlns].port = L2TPPORT; //Default L2TP poart + strcpy(pconfigrlns[idrlns].l2tp_secret, ptunnelrlns[idtag].tunnel_password); + strcpy(pconfigrlns[idrlns].tunnel_assignment_id, ptunnelrlns[idtag].tunnel_assignment_id); + + config->highest_rlnsid = idrlns; - // Start Open Tunnel - if (!(t = lac_new_tunnel())) + pconfigrlns[idrlns].state = CONFRLNSSETBYRADIUS; + + break; + } + else if (pconfigrlns[idrlns].state == CONFRLNSSETBYRADIUS) { - LOG(1, 0, 0, "No more tunnels\n"); - STAT(tunnel_overflow); - return 0; + if ( (pconfigrlns[idrlns].ip == ptunnelrlns[idtag].tunnel_server_endpoint) && + (strcmp(pconfigrlns[idrlns].tunnel_assignment_id, ptunnelrlns[idtag].tunnel_assignment_id) == 0) ) + { + LOG(3, s, session[s].tunnel, "Tunnel IP %s already defined\n", fmtaddr(htonl(pconfigrlns[idrlns].ip), 0)); + // l2tp_secret may be changed + strcpy(pconfigrlns[idrlns].l2tp_secret, ptunnelrlns[idtag].tunnel_password); + pconfigrlns[idrlns].port = L2TPPORT; //Default L2TP poart + + if (config->highest_rlnsid < idrlns) config->highest_rlnsid = idrlns; + + break; + } } - lac_tunnelclear(t); - tunnel[t].ip = pconfigrlns[i].ip; - tunnel[t].port = pconfigrlns[i].port; - tunnel[t].window = 4; // default window - STAT(tunnel_created); - LOG(1, 0, t, "New (REMOTE LNS) tunnel to %s:%u ID %u\n", fmtaddr(htonl(tunnel[t].ip), 0), tunnel[t].port, t); + } - random_data(pconfigrlns[i].auth, sizeof(pconfigrlns[i].auth)); + if (idrlns >= MAXRLNSTUNNEL) + { + LOG(0, s, session[s].tunnel, "No more Remote LNS Conf Free\n"); + return; + } + } +} - pconfigrlns[i].tid = t; +// Create Remote LNS a Tunnel or Session +static int lac_create_tunnelsession(tunnelidt t, sessionidt s, confrlnsidt i_conf, char * puser) +{ + if (t == 0) + { + if (main_quit == QUIT_SHUTDOWN) return 0; - lac_send_SCCRQ(t, pconfigrlns[i].auth, sizeof(pconfigrlns[i].auth)); - } - else if (tunnel[t].state == TUNNELOPEN) - { - if (main_quit != QUIT_SHUTDOWN) - { - /**********************/ - /** Open New session **/ - /**********************/ - sessionidt new_sess = sessionfree; + // Start Open Tunnel + if (!(t = lac_new_tunnel())) + { + LOG(1, 0, 0, "No more tunnels\n"); + STAT(tunnel_overflow); + return 0; + } + lac_tunnelclear(t); + tunnel[t].ip = pconfigrlns[i_conf].ip; + tunnel[t].port = pconfigrlns[i_conf].port; + tunnel[t].window = 4; // default window + tunnel[t].isremotelns = i_conf; + STAT(tunnel_created); - sessionfree = session[new_sess].next; - memset(&session[new_sess], 0, sizeof(session[new_sess])); + random_data(pconfigrlns[i_conf].auth, sizeof(pconfigrlns[i_conf].auth)); - if (new_sess > config->cluster_highest_sessionid) - config->cluster_highest_sessionid = new_sess; + LOG(2, 0, t, "Create New tunnel to REMOTE LNS %s for user %s\n", fmtaddr(htonl(tunnel[t].ip), 0), puser); + lac_send_SCCRQ(t, pconfigrlns[i_conf].auth, sizeof(pconfigrlns[i_conf].auth)); + } + else if (tunnel[t].state == TUNNELOPEN) + { + if (main_quit != QUIT_SHUTDOWN) + { - session[new_sess].opened = time_now; - session[new_sess].tunnel = t; - session[new_sess].last_packet = session[s].last_data = time_now; + /**********************/ + /** Open New session **/ + /**********************/ + sessionidt new_sess = sessionfree; - session[new_sess].ppp.phase = Establish; - session[new_sess].ppp.lcp = Starting; + sessionfree = session[new_sess].next; + memset(&session[new_sess], 0, sizeof(session[new_sess])); - // Sent ICRQ Incoming-call-request - lac_send_ICRQ(t, new_sess); + if (new_sess > config->cluster_highest_sessionid) + config->cluster_highest_sessionid = new_sess; - // Set session to forward to another LNS - session[s].forwardtosession = new_sess; - session[new_sess].forwardtosession = s; + session[new_sess].opened = time_now; + session[new_sess].tunnel = t; + session[new_sess].last_packet = session[s].last_data = time_now; - STAT(session_created); - } - else - { - lac_tunnelshutdown(t, "Shutting down", 6, 0, 0); - pconfigrlns[i].tid = 0; - } - } - else - { - /** TODO **/ - LOG(1, 0, t, "(REMOTE LNS) tunnel is not open\n"); - } + session[new_sess].ppp.phase = Establish; + session[new_sess].ppp.lcp = Starting; + session[s].ppp.phase = Establish; - return 1; + LOG(2, 0, t, "Open New session to REMOTE LNS %s for user: %s\n", fmtaddr(htonl(tunnel[t].ip), 0), puser); + // Sent ICRQ Incoming-call-request + lac_send_ICRQ(t, new_sess); + + // Set session to forward to another LNS + session[s].forwardtosession = new_sess; + session[new_sess].forwardtosession = s; + strncpy(session[s].user, puser, sizeof(session[s].user) - 1); + strncpy(session[new_sess].user, puser, sizeof(session[new_sess].user) - 1); + + STAT(session_created); + } + else + { + lac_tunnelshutdown(t, "Shutting down", 6, 0, 0); } } + else + { + /** TODO **/ + LOG(1, 0, t, "(REMOTE LNS) tunnel is not open\n"); + } - return 0; + return 1; } - -static tunnelidt getidrlns(tunnelidt t) +// Check if session must be forwarded to another LNS +// return 1 if the session must be forwarded (and Creating a tunnel/session has been started) +// else 0. +// Note: check from the configuration read on the startup-config (see setforward) +int lac_conf_forwardtoremotelns(sessionidt s, char * puser) { - confrlnsidt idrlns; + tunnelidt t, j; + confrlnsidt i; - for (idrlns = 1; idrlns <= config->highest_rlnsid ; ++idrlns) + for (i = 1; i <= config->highest_rlnsid ; ++i) { - if (pconfigrlns[idrlns].tid == t) return idrlns; + if ( (pconfigrlns[i].state == CONFRLNSSET) && (NULL != strstr(puser, pconfigrlns[i].strmaskuser)) ) + { + t = 0; + for (j = 0; j <= config->cluster_highest_tunnelid ; ++j) + { + if ((tunnel[j].isremotelns) && + (tunnel[j].ip == pconfigrlns[i].ip) && + (tunnel[j].port == pconfigrlns[i].port) && + (tunnel[j].state != TUNNELDIE)) + { + t = j; + if (tunnel[t].isremotelns != i) + { + if ( (tunnel[t].state == TUNNELOPEN) || (tunnel[t].state == TUNNELOPENING) ) + { + LOG(1, 0, t, "Tunnel Remote LNS ID inconsistency (IP RLNS:%s)\n", + fmtaddr(htonl(pconfigrlns[i].ip), 0)); + + tunnel[t].isremotelns = i; + } + else t = 0; + } + break; + } + } + + return lac_create_tunnelsession(t, s, i, puser); + } } return 0; } -int istunneltolns(tunnelidt t) +// return 1 if the session must be forwarded (and Creating a tunnel/session has been started) +// else 0. +// Note: Started from a radius response +int lac_rad_forwardtoremotelns(sessionidt s, char *assignment_id, char * puser) { - confrlnsidt idrlns; + tunnelidt t, j; + confrlnsidt i; - for (idrlns = 1; idrlns <= config->highest_rlnsid ; ++idrlns) + for (i = 1; i <= config->highest_rlnsid ; ++i) { - if (pconfigrlns[idrlns].tid == t) return 1; + if ((pconfigrlns[i].state == CONFRLNSSETBYRADIUS) && + (strcmp(pconfigrlns[i].tunnel_assignment_id, assignment_id) == 0)) + { + t = 0; + for (j = 1; j <= config->cluster_highest_tunnelid ; ++j) + { + if ((tunnel[j].isremotelns == i) && + (tunnel[j].ip == pconfigrlns[i].ip) && + (tunnel[j].port == pconfigrlns[i].port) && + (tunnel[j].state != TUNNELDIE)) + { + if ( (tunnel[j].state == TUNNELOPEN) || + (tunnel[j].state == TUNNELOPENING) ) + { + t = j; + LOG(3, 0, t, "Tunnel Remote LNS already open(ing) (RLNS IP:%s)\n", fmtaddr(htonl(pconfigrlns[i].ip), 0)); + break; + } + } + } + + return lac_create_tunnelsession(t, s, i, puser); + } } return 0; } -void calc_lac_auth(tunnelidt t, uint8_t id, uint8_t *out) +// Calcul the remote LNS auth +void lac_calc_rlns_auth(tunnelidt t, uint8_t id, uint8_t *out) { MD5_CTX ctx; confrlnsidt idrlns; - idrlns = getidrlns(t); + idrlns = tunnel[t].isremotelns; MD5_Init(&ctx); MD5_Update(&ctx, &id, 1); @@ -241,8 +439,8 @@ void calc_lac_auth(tunnelidt t, uint8_t id, uint8_t *out) MD5_Final(out, &ctx); } -// Forward session to external LNS -int session_forward_tolns(uint8_t *buf, int len, sessionidt sess, uint16_t proto) +// Forward session to LAC or Remote LNS +int lac_session_forward(uint8_t *buf, int len, sessionidt sess, uint16_t proto) { uint16_t t = 0, s = 0; uint8_t *p = buf + 2; // First word L2TP options @@ -261,8 +459,14 @@ int session_forward_tolns(uint8_t *buf, int len, sessionidt sess, uint16_t proto return 0; } + if ((!tunnel[t].isremotelns) && (!tunnel[session[sess].tunnel].isremotelns)) + { + LOG(0, sess, session[sess].tunnel, "Link Tunnel Session (%u) broken\n", s); + return 0; + } + if (*buf & 0x40) - { // length + { // length p += 2; } @@ -282,6 +486,20 @@ int session_forward_tolns(uint8_t *buf, int len, sessionidt sess, uint16_t proto if ((proto == PPPIP) || (proto == PPPMP) ||(proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0])) { session[sess].last_packet = session[sess].last_data = time_now; + // Update STAT IN + increment_counter(&session[sess].cin, &session[sess].cin_wrap, len); + session[sess].cin_delta += len; + session[sess].pin++; + sess_local[sess].cin += len; + sess_local[sess].pin++; + + session[s].last_data = time_now; + // Update STAT OUT + increment_counter(&session[s].cout, &session[s].cout_wrap, len); // byte count + session[s].cout_delta += len; + session[s].pout++; + sess_local[s].cout += len; + sess_local[s].pout++; } else session[sess].last_packet = time_now; @@ -291,7 +509,12 @@ int session_forward_tolns(uint8_t *buf, int len, sessionidt sess, uint16_t proto return 1; } -int addremotelns(char *mask, char *IP_RemoteLNS, char *Port_RemoteLNS, char *SecretRemoteLNS) +// Add new Remote LNS from CLI +// return: +// 0 = Error +// 1 = New Remote LNS conf ADD +// 2 = Remote LNS Conf Updated +int lac_addremotelns(char *mask, char *IP_RemoteLNS, char *Port_RemoteLNS, char *SecretRemoteLNS) { confrlnsidt idrlns; @@ -308,9 +531,26 @@ int addremotelns(char *mask, char *IP_RemoteLNS, char *Port_RemoteLNS, char *Sec pconfigrlns[idrlns].state = CONFRLNSSET; - LOG(1, 0, 0, "New Remote LNS conf (count %u) mask:%s IP:%s Port:%u l2tpsecret:*****\n", idrlns, - pconfigrlns[idrlns].strmaskuser, fmtaddr(htonl(pconfigrlns[idrlns].ip), 0), - pconfigrlns[idrlns].port); + return 1; + } + else if ((pconfigrlns[idrlns].state == CONFRLNSSET) && (strcmp(pconfigrlns[idrlns].strmaskuser, mask) == 0)) + { + if ( (pconfigrlns[idrlns].ip != ntohl(inet_addr(IP_RemoteLNS))) || + (pconfigrlns[idrlns].port != atoi(Port_RemoteLNS)) || + (strcmp(pconfigrlns[idrlns].l2tp_secret, SecretRemoteLNS) != 0) ) + { + memset(&pconfigrlns[idrlns], 0, sizeof(pconfigrlns[idrlns])); + snprintf((char *) pconfigrlns[idrlns].strmaskuser, sizeof(pconfigrlns[idrlns].strmaskuser), "%s", mask); + pconfigrlns[idrlns].ip = ntohl(inet_addr(IP_RemoteLNS)); + pconfigrlns[idrlns].port = atoi(Port_RemoteLNS); + snprintf((char *) pconfigrlns[idrlns].l2tp_secret, sizeof(pconfigrlns[idrlns].l2tp_secret), "%s", SecretRemoteLNS); + + if (config->highest_rlnsid < idrlns) config->highest_rlnsid = idrlns; + + pconfigrlns[idrlns].state = CONFRLNSSET; + // Conf Updated, the tunnel must be dropped + return 2; + } return 1; } @@ -320,3 +560,61 @@ int addremotelns(char *mask, char *IP_RemoteLNS, char *Port_RemoteLNS, char *Sec return 0; } + +// Cli Show remote LNS defined +int lac_cli_show_remotelns(confrlnsidt idrlns, char *strout) +{ + if (idrlns > config->highest_rlnsid) + return 0; + + if (idrlns == 0) + // Show Summary + sprintf(strout, "%15s %-32s %-32s %11s %7s %10s", + "IP Remote LNS", + "l2tp secret", + "assignment Id", + "File/Radius", + "State", + "Count Sess"); + else + { + tunnelidt t; + sessionidt s; + int countsess = 0; + char state[20]; + + strcpy(state, "Close"); + for (t = 0; t <= config->cluster_highest_tunnelid ; ++t) + { + if ((tunnel[t].isremotelns) && + (tunnel[t].ip == pconfigrlns[idrlns].ip) && + (tunnel[t].port == pconfigrlns[idrlns].port) && + (tunnel[t].state != TUNNELDIE)) + { + if (tunnel[t].isremotelns) + { + if (tunnel[t].state == TUNNELOPENING) + strcpy(state, "Opening"); + else if (tunnel[t].state == TUNNELOPEN) + strcpy(state, "Open"); + + for (s = 1; s <= config->cluster_highest_sessionid ; ++s) + if (session[s].tunnel == t) + countsess++; + + break; + } + } + } + + sprintf(strout, "%15s %-32s %-32s %11s %7s %10u", + fmtaddr(htonl(pconfigrlns[idrlns].ip), 0), + pconfigrlns[idrlns].l2tp_secret, + pconfigrlns[idrlns].tunnel_assignment_id, + (pconfigrlns[idrlns].state == CONFRLNSSET?"File":(pconfigrlns[idrlns].state == CONFRLNSSETBYRADIUS?"Radius":"Free")), + state, + countsess); + } + + return 1; +} diff --git a/l2tplac.h b/l2tplac.h index ba81a8e..3b3f583 100644 --- a/l2tplac.h +++ b/l2tplac.h @@ -4,11 +4,30 @@ #ifndef __L2TPLAC_H__ #define __L2TPLAC_H__ +#define L2TPLACPORT 65432 // L2TP port for Remote LNS +// Limits +#define MAXRLNSTUNNEL 201 + +typedef uint16_t confrlnsidt; + // l2tplac.c -void initremotelnsdata(); -int session_forward_tolns(uint8_t *buf, int len, sessionidt sess, uint16_t proto); -int forwardtolns(sessionidt s, char * puser); -void calc_lac_auth(tunnelidt t, uint8_t id, uint8_t *out); -int istunneltolns(tunnelidt t); -int addremotelns(char *mask, char *IP_RemoteLNS, char *Port_RemoteLNS, char *SecretRemoteLNS); +void lac_initremotelnsdata(); +int lac_session_forward(uint8_t *buf, int len, sessionidt sess, uint16_t proto); +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); + +/* Function for Tunnels creating from radius reponses */ +void lac_reset_rad_tag_tunnel_ctxt(); +void lac_set_rad_tag_tunnel_type(uint8_t tag, uint32_t tunnel_type); +void lac_set_rad_tag_tunnel_medium_type(uint8_t tag, uint32_t tunnel_medium_type); +void lac_set_rad_tag_tunnel_serv_endpt(uint8_t tag, char *tunnel_server_endpoint); +void lac_set_rad_tag_tunnel_password(uint8_t tag, char *tunnel_password); +void lac_set_rad_tag_tunnel_assignment_id(uint8_t tag, char *tunnel_assignment_id); +void lac_save_rad_tag_tunnels(sessionidt s); +int lac_rad_select_assignment_id(sessionidt s, char *assignment_id); + +int lac_rad_forwardtoremotelns(sessionidt s, char *assignment_id, char * puser); + +int lac_cli_show_remotelns(confrlnsidt idrlns, char *strout); #endif /* __L2TPLAC_H__ */ diff --git a/l2tpns.c b/l2tpns.c index d4bb9ca..694726d 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -67,6 +67,9 @@ 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 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. @@ -175,6 +178,10 @@ config_descriptt config_values[] = { #endif CONFIG("echo_timeout", echo_timeout, INT), CONFIG("idle_echo_timeout", idle_echo_timeout, INT), +#ifdef LAC + CONFIG("disable_lac_func", disable_lac_func, BOOL), + CONFIG("bind_portremotelns", bind_portremotelns, SHORT), +#endif { NULL, 0, 0, 0 }, }; @@ -866,6 +873,24 @@ static void initudp(void) exit(1); } +#ifdef LAC + // Tunnel to Remote LNS + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(config->bind_portremotelns); + udplacfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + setsockopt(udplacfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + { + int flags = fcntl(udplacfd, F_GETFL, 0); + fcntl(udplacfd, F_SETFL, flags | O_NONBLOCK); + } + if (bind(udplacfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + { + LOG(0, 0, 0, "Error in UDP REMOTE LNS bind: %s\n", strerror(errno)); + exit(1); + } +#endif + // Intercept snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); } @@ -1186,8 +1211,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 { 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)); @@ -2213,6 +2241,18 @@ 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; + if (session[sess].forwardtosession == s) + { + // Shutdown the linked session also. + 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); sessionclear(s); cluster_send_session(s); @@ -2724,11 +2764,11 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) break; case 13: // Response #ifdef LAC - if (istunneltolns(t)) + if (tunnel[t].isremotelns) { chapresponse = calloc(17, 1); memcpy(chapresponse, b, (n < 17) ? n : 16); - LOG(1, s, t, "received challenge response from (REMOTE LNS)\n"); + LOG(3, s, t, "received challenge response from REMOTE LNS\n"); } else #endif /* LAC */ @@ -2957,8 +2997,10 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { case 1: // SCCRQ - Start Control Connection Request tunnel[t].state = TUNNELOPENING; + LOG(3, s, t, "Received SCCRQ\n"); if (main_quit != QUIT_SHUTDOWN) { + LOG(3, s, t, "sending SCCRP\n"); controlt *c = controlnew(2); // sending SCCRP control16(c, 2, version, 1); // protocol version control32(c, 3, 3, 1); // framing @@ -2976,17 +3018,18 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) tunnel[t].state = TUNNELOPEN; tunnel[t].lastrec = time_now; #ifdef LAC - LOG(1, s, t, "Recieved SCCRP (REMOTE LNS)\n"); + LOG(3, s, t, "Received SCCRP\n"); if (main_quit != QUIT_SHUTDOWN) { - if (istunneltolns(t) && chapresponse) + if (tunnel[t].isremotelns && chapresponse) { hasht hash; - calc_lac_auth(t, 2, hash); // id = 2 (SCCRP) + lac_calc_rlns_auth(t, 2, hash); // id = 2 (SCCRP) // check authenticator if (memcmp(hash, chapresponse, 16) == 0) { + LOG(3, s, t, "sending SCCCN to REMOTE LNS\n"); controlt *c = controlnew(3); // sending SCCCN controls(c, 7, hostname, 1); // host name controls(c, 8, Vendor_name, 1); // Vendor name @@ -2994,12 +3037,10 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) control32(c, 3, 3, 1); // framing Capabilities control16(c, 9, t, 1); // assigned tunnel controladd(c, 0, t); // send - - LOG(1, s, t, "sending SCCCN (REMOTE LNS)\n"); } else { - tunnelshutdown(t, "(REMOTE LNS) Bad chap response", 4, 0, 0); + tunnelshutdown(t, "Bad chap response from REMOTE LNS", 4, 0, 0); } } } @@ -3010,11 +3051,13 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) #endif /* LAC */ break; case 3: // SCCN + LOG(3, s, t, "Received SCCN\n"); tunnel[t].state = TUNNELOPEN; tunnel[t].lastrec = time_now; controlnull(t); // ack break; case 4: // StopCCN + LOG(3, s, t, "Received StopCCN\n"); controlnull(t); // ack tunnelshutdown(t, "Stopped", 0, 0, 0); // Shut down cleanly break; @@ -3023,18 +3066,24 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) break; case 7: // OCRQ // TBA + LOG(3, s, t, "Received OCRQ\n"); break; case 8: // OCRO // TBA + LOG(3, s, t, "Received OCRO\n"); break; case 9: // OCCN // TBA + LOG(3, s, t, "Received OCCN\n"); break; case 10: // ICRQ + LOG(3, s, t, "Received ICRQ\n"); if (sessionfree && main_quit != QUIT_SHUTDOWN) { controlt *c = controlnew(11); // ICRP + LOG(3, s, t, "Sending ICRP\n"); + s = sessionfree; sessionfree = session[s].next; memset(&session[s], 0, sizeof(session[s])); @@ -3062,6 +3111,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { controlt *c = controlnew(14); // CDN + LOG(3, s, t, "Sending CDN\n"); if (!sessionfree) { STAT(session_overflow); @@ -3076,7 +3126,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) return; case 11: // ICRP #ifdef LAC - LOG(1, s, t, "Recieved ICRP (REMOTE LNS)\n"); + LOG(3, s, t, "Received ICRP\n"); if (session[s].forwardtosession) { controlt *c = controlnew(12); // ICCN @@ -3089,11 +3139,12 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) control32(c, 19, 1, 1); // Framing Type control32(c, 24, 10000000, 1); // Tx Connect Speed controladd(c, asession, t); // send the message - LOG(1, s, t, "Sending ICCN (REMOTE LNS)\n"); + LOG(3, s, t, "Sending ICCN\n"); } #endif /* LAC */ break; case 12: // ICCN + LOG(3, s, t, "Received ICCN\n"); if (amagic == 0) amagic = time_now; session[s].magic = amagic; // set magic number session[s].flags = aflags; // set flags received @@ -3113,10 +3164,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) break; case 14: // CDN + LOG(3, s, t, "Received CDN\n"); controlnull(t); // ack -#ifdef LAC - -#endif /* LAC */ sessionshutdown(s, disc_reason, CDN_NONE, disc_cause); break; case 0xFFFF: @@ -3169,9 +3218,9 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) #ifdef LAC if (session[s].forwardtosession) { - LOG(4, s, t, "Forwarding data session to %u (REMOTE LNS)\n", session[s].forwardtosession); - // Forward to Remote LNS - session_forward_tolns(buf, len, s, proto); + LOG(5, s, t, "Forwarding data session to session %u\n", session[s].forwardtosession); + // Forward to LAC or Remote LNS session + lac_session_forward(buf, len, s, proto); return; } #endif /* LAC */ @@ -3843,8 +3892,13 @@ 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 +#define BASE_FDS 8 +#else // the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink #define BASE_FDS 7 +#endif // additional polled fds #ifdef BGP @@ -3870,8 +3924,13 @@ 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\n", + clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd, udplacfd); +#else LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d\n", clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd); +#endif /* setup our fds to poll for input */ { @@ -3911,6 +3970,12 @@ static void mainloop(void) d[i].type = FD_TYPE_NETLINK; 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 } #ifdef BGP @@ -3973,6 +4038,10 @@ static void mainloop(void) socklen_t alen; int c, s; int udp_ready = 0; +#ifdef LAC + int udplac_ready = 0; + int udplac_pkts = 0; +#endif int tun_ready = 0; int cluster_ready = 0; int udp_pkts = 0; @@ -4010,7 +4079,9 @@ static void mainloop(void) 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_CONTROL: // nsctl commands alen = sizeof(addr); s = recvfromto(controlfd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local); @@ -4100,7 +4171,25 @@ static void mainloop(void) n--; } } +#ifdef LAC + // L2TP REMOTE LNS + if (udplac_ready) + { + alen = sizeof(addr); + if ((s = recvfrom(udplacfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0) + { + if (!config->disable_lac_func) + processudp(buf, s, &addr); + udplac_pkts++; + } + else + { + udplac_ready = 0; + n--; + } + } +#endif // incoming IP if (tun_ready) { @@ -4138,9 +4227,13 @@ static void mainloop(void) if (c >= config->multi_read_count) { +#ifdef LAC + LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun and %d cluster %d rmlns packets\n", + config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, udplac_pkts); +#else LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun and %d cluster packets\n", config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts); - +#endif STAT(multi_read_exceeded); more++; } @@ -4476,7 +4569,7 @@ static void initdata(int optdebug, char *optconfig) #endif /* BGP */ #ifdef LAC - initremotelnsdata(); + lac_initremotelnsdata(); #endif } @@ -4764,7 +4857,11 @@ 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) @@ -5171,6 +5268,11 @@ static void update_config() if (!config->radius_dae_port) config->radius_dae_port = DAEPORT; +#ifdef LAC + if(!config->bind_portremotelns) + config->bind_portremotelns = L2TPLACPORT; +#endif + // re-initialise the random number source initrandom(config->random_device); @@ -6251,7 +6353,7 @@ void lac_send_SCCRQ(tunnelidt t, uint8_t * auth, unsigned int auth_len) control32(c, 3, 3, 1); // framing Capabilities control16(c, 9, t, 1); // assigned tunnel controlb(c, 11, (uint8_t *) auth, auth_len, 1); // CHAP Challenge - LOG(1, 0, t, "Sent SCCRQ tunnel (REMOTE LNS)\n"); + LOG(3, 0, t, "Sent SCCRQ to REMOTE LNS\n"); controladd(c, 0, t); // send } @@ -6263,7 +6365,7 @@ void lac_send_ICRQ(tunnelidt t, sessionidt s) control16(c, 14, s, 1); // assigned sesion call_serial_number++; control32(c, 15, call_serial_number, 1); // call serial number - LOG(1, s, t, "Sent ICRQ (REMOTE LNS) (tunnel far ID %u)\n", tunnel[t].far); + LOG(3, s, t, "Sent ICRQ to REMOTE LNS (far ID %u)\n", tunnel[t].far); controladd(c, 0, t); // send } diff --git a/l2tpns.h b/l2tpns.h index e83234d..33b4cfc 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -426,7 +426,7 @@ typedef struct #define SESSION_ACFC (1 << 1) // use Address-and-Control-Field-Compression #define SESSION_STARTED (1 << 2) // RADIUS Start record sent -// 168 bytes per tunnel +// 328 bytes per tunnel typedef struct { tunnelidt far; // far end tunnel ID @@ -446,6 +446,12 @@ 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 } tunnelt; @@ -756,7 +762,9 @@ typedef struct int idle_echo_timeout; // Time between last packet seen and // Drop sessions who have not responded within IDLE_ECHO_TIMEOUT seconds #ifdef LAC + int disable_lac_func; int highest_rlnsid; + uint16_t bind_portremotelns; #endif } configt; @@ -891,7 +899,9 @@ 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); @@ -985,6 +995,9 @@ struct event_data { FD_TYPE_RADIUS, FD_TYPE_BGP, FD_TYPE_NETLINK, +#ifdef LAC + FD_TYPE_UDPLAC, +#endif } type; int index; // for RADIUS, BGP }; diff --git a/ppp.c b/ppp.c index 518f6ec..fb74ba9 100644 --- a/ppp.c +++ b/ppp.c @@ -1,7 +1,5 @@ // L2TPNS PPP Stuff -//#define LAC - #include #include #include @@ -107,9 +105,9 @@ void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) } #ifdef LAC - if (forwardtolns(s, user)) + if ((!config->disable_lac_func) && lac_conf_forwardtoremotelns(s, user)) { - LOG(3, s, t, "Forwarding login for %s to other LNS\n", user); + // Creating a tunnel/session has been started return; } #endif @@ -266,12 +264,11 @@ void processchap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) memcpy(packet.username, p, l); #ifdef LAC - if (forwardtolns(s, packet.username)) + if ((!config->disable_lac_func) && lac_conf_forwardtoremotelns(s, packet.username)) { - LOG(3, s, t, "Forwarding login for %s to other LNS\n", packet.username); - free(packet.username); free(packet.password); + // Creating a tunnel/session has been started return; } #endif diff --git a/radius.c b/radius.c index 02b29b7..5c2ab46 100644 --- a/radius.c +++ b/radius.c @@ -11,6 +11,7 @@ #include #include #include + #include "md5.h" #include "constants.h" #include "l2tpns.h" @@ -18,6 +19,10 @@ #include "util.h" #include "cluster.h" +#ifdef LAC +#include "l2tplac.h" +#endif + extern radiust *radius; extern sessiont *session; extern tunnelt *tunnel; @@ -230,6 +235,7 @@ void radiussend(uint16_t r, uint8_t state) } b[1] = r >> RADIUS_SHIFT; // identifier memcpy(b + 4, radius[r].auth, 16); + p = b + 20; if (s) { @@ -530,6 +536,9 @@ 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); @@ -629,6 +638,11 @@ 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) @@ -823,6 +837,96 @@ 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 + if (p[1] != 6) continue; + tag = p[2]; + LOG(3, s, session[s].tunnel, " Radius reply Tunnel-Type:%d %d\n", + tag, ntohl(*(uint32_t *)(p + 2)) & 0xFFFFFF); + // Fill context + lac_set_rad_tag_tunnel_type(tag, ntohl(*(uint32_t *)(p + 2)) & 0xFFFFFF); + /* Request open tunnel to remote LNS*/ + OpentunnelReq = 1; + } + else if (*p == 65) + { + // Tunnel-Medium-Type + if (p[1] < 6) continue; + tag = p[2]; + LOG(3, s, session[s].tunnel, " Radius reply Tunnel-Medium-Type:%d %d\n", + tag, ntohl(*(uint32_t *)(p + 2)) & 0xFFFFFF); + // Fill context + lac_set_rad_tag_tunnel_medium_type(tag, ntohl(*(uint32_t *)(p + 2)) & 0xFFFFFF); + } + else if (*p == 67) + { + // Tunnel-Server-Endpoint + if (p[1] < 3) continue; + tag = p[2]; + //If the Tag field is greater than 0x1F, + // it SHOULD be interpreted as the first byte of the following String field. + memset(strtemp, 0, 256); + if (tag > 0x1F) + { + tag = 0; + memcpy(strtemp, (p + 2), p[1]-2); + } + else + memcpy(strtemp, (p + 3), p[1]-3); + + LOG(3, s, session[s].tunnel, " Radius reply Tunnel-Server-Endpoint:%d %s\n", tag, strtemp); + // Fill context + lac_set_rad_tag_tunnel_serv_endpt(tag, (char *) strtemp); + } + else if (*p == 69) + { + // Tunnel-Password + size_t lentemp; + + if (p[1] < 5) continue; + tag = p[2]; + + memset(strtemp, 0, 256); + lentemp = p[1]-3; + memcpy(strtemp, (p + 3), lentemp); + if (!rad_tunnel_pwdecode(strtemp, &lentemp, config->radiussecret, radius[r].auth)) + { + LOG_HEX(3, "Error Decode Tunnel-Password, Dump Radius reponse:", p, p[1]); + continue; + } + + LOG(3, s, session[s].tunnel, " Radius reply Tunnel-Password:%d %s\n", tag, strtemp); + if (strlen((char *) strtemp) > 63) + { + LOG(1, s, session[s].tunnel, "tunnel password is too long (>63)\n"); + continue; + } + // Fill context + lac_set_rad_tag_tunnel_password(tag, (char *) strtemp); + } + else if (*p == 82) + { + // Tunnel-Assignment-Id + if (p[1] < 3) continue; + tag = p[2]; + //If the Tag field is greater than 0x1F, + // it SHOULD be interpreted as the first byte of the following String field. + memset(strtemp, 0, 256); + if (tag > 0x1F) + { + tag = 0; + memcpy(strtemp, (p + 2), p[1]-2); + } + else + memcpy(strtemp, (p + 3), p[1]-3); + + LOG(3, s, session[s].tunnel, " Radius reply Tunnel-Assignment-Id:%d %s\n", tag, strtemp); + // Fill context + lac_set_rad_tag_tunnel_assignment_id(tag, (char *) strtemp); + } +#endif } } else if (r_code == AccessReject) @@ -832,6 +936,30 @@ void processrad(uint8_t *buf, int len, char socket_index) break; } +#ifdef LAC + if ((!config->disable_lac_func) && OpentunnelReq) + { + char assignment_id[256]; + // Save radius tag context to conf + lac_save_rad_tag_tunnels(s); + + memset(assignment_id, 0, 256); + if (!lac_rad_select_assignment_id(s, assignment_id)) + break; // Error no assignment_id + + if (lac_rad_forwardtoremotelns(s, assignment_id, session[s].user)) + { + int ro; + // Sanity check, no local IP to session forwarded + session[s].ip = 0; + for (ro = 0; r < MAXROUTE && session[s].route[ro].ip; r++) + { + session[s].route[ro].ip = 0; + } + break; + } + } +#endif if (!session[s].dns1 && config->default_dns1) { session[s].dns1 = ntohl(config->default_dns1); @@ -1174,3 +1302,96 @@ void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struc if (sendtofrom(daefd, buf, len, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) addr, alen, local) < 0) LOG(0, 0, 0, "Error sending DAE response packet: %s\n", strerror(errno)); } + +#ifdef LAC +// Decrypte the encrypted Tunnel Password. +// Defined in RFC-2868. +// the pl2tpsecret buffer must set to 256 characters. +// return 0 on decoding error else length of decoded l2tpsecret +int rad_tunnel_pwdecode(uint8_t *pl2tpsecret, size_t *pl2tpsecretlen, + const char *radiussecret, const uint8_t * auth) +{ + MD5_CTX ctx, oldctx; + hasht hash; + int secretlen; + unsigned i, n, len, decodedlen; + +/* 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 6 7 +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Salt | Salt | String .......... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ + + len = *pl2tpsecretlen; + + if (len < 2) + { + LOG(1, 0, 0, "tunnel password is too short, We need at least a salt\n"); + return 0; + } + + if (len <= 3) + { + pl2tpsecret[0] = 0; + *pl2tpsecretlen = 0; + LOG(1, 0, 0, "tunnel passwd is empty !!!\n"); + return 0; + } + + len -= 2; /* discount the salt */ + + //Use the secret to setup the decryption + secretlen = strlen(radiussecret); + + MD5_Init(&ctx); + MD5_Update(&ctx, (void *) radiussecret, secretlen); + oldctx = ctx; /* save intermediate work */ + + // Set up the initial key: + // b(1) = MD5(radiussecret + auth + salt) + MD5_Update(&ctx, (void *) auth, 16); + MD5_Update(&ctx, pl2tpsecret, 2); + + decodedlen = 0; + for (n = 0; n < len; n += 16) + { + int base = 0; + + if (n == 0) + { + MD5_Final(hash, &ctx); + + ctx = oldctx; + + // the first octet, it's the 'data_len' + // Check is correct + decodedlen = pl2tpsecret[2] ^ hash[0]; + if (decodedlen >= len) + { + LOG(1, 0, 0, "tunnel password is too long !!!\n"); + return 0; + } + + MD5_Update(&ctx, pl2tpsecret + 2, 16); + base = 1; + } else + { + MD5_Final(hash, &ctx); + + ctx = oldctx; + MD5_Update(&ctx, pl2tpsecret + n + 2, 16); + } + + for (i = base; i < 16; i++) + { + pl2tpsecret[n + i - 1] = pl2tpsecret[n + i + 2] ^ hash[i]; + } + } + + if (decodedlen > 239) decodedlen = 239; + + *pl2tpsecretlen = decodedlen; + pl2tpsecret[decodedlen] = 0; + + return decodedlen; +}; +#endif /* LAC */ -- 2.20.1