To support proxy LCP negotiation. Note: we *have* to take the auth id from the proxy answer, otherwise we would replay previous ids, for which the client might cache the answer and thus ignore our new challenge and just repeat their outdated answer.
663 lines
20 KiB
C
663 lines
20 KiB
C
/*
|
|
* Fernando ALVES 2013
|
|
* Add functionality "LAC" to l2tpns.
|
|
* Used to forward a ppp session to another "LNS".
|
|
* GPL licenced
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <netinet/ip6.h>
|
|
|
|
#include "md5.h"
|
|
#include "dhcp6.h"
|
|
#include "l2tpns.h"
|
|
#include "util.h"
|
|
#include "cluster.h"
|
|
|
|
#include "l2tplac.h"
|
|
#include "pppoe.h"
|
|
|
|
/* sequence diagram: Client <--> LAC <--> LNS1 <--> LNS2
|
|
*
|
|
* LCP Negotiation
|
|
* Client <-------------------> LAC
|
|
* Challenge (CHAP/PAP)
|
|
* Client <-------------------> LAC
|
|
* SCCRQ
|
|
* LAC --------------------> LNS1 (Tunnel Open)
|
|
* SCCRP
|
|
* LAC <-------------------- LNS1 (Tunnel Open)
|
|
* SCCCN
|
|
* LAC --------------------> LNS1 (Tunnel Open)
|
|
* ZLB
|
|
* LAC <-------------------- LNS1 (Tunnel Open)
|
|
* ICRQ
|
|
* LAC --------------------> LNS1 (Session Open)
|
|
* ICRP
|
|
* LAC <-------------------- LNS1 (Session Open)
|
|
* ICCN
|
|
* LAC --------------------> LNS1 (Session Open)
|
|
* ZLB
|
|
* LAC <-------------------- LNS1 (Session Open)
|
|
* LCP Negotiation
|
|
* Client <---------------------------------------------> LNS1
|
|
* Challenge (CHAP/PAP)
|
|
* Client <---------------------------------------------> LNS1
|
|
* SCCRQ
|
|
* LNS1 --------------------> LNS2 (Tunnel Open)
|
|
* SCCRP
|
|
* LNS1 <-------------------- LNS2 (Tunnel Open)
|
|
* SCCCN
|
|
* LNS1 --------------------> LNS2 (Tunnel Open)
|
|
* ZLB
|
|
* LNS1 <-------------------- LNS2 (Tunnel Open)
|
|
* ICRQ
|
|
* LNS1 --------------------> LNS2 (Session Open)
|
|
* ICRP
|
|
* LNS1 <-------------------- LNS2 (Session Open)
|
|
* ICCN
|
|
* LNS1 --------------------> LNS2 (Session Open)
|
|
* ZLB
|
|
* LNS1 <-------------------- LNS2 (Session Open)
|
|
* LCP Renegotiation (unless proxied)
|
|
* Client <------------------------------------------------------------------------> LNS2
|
|
* PAP (Ack only if proxied) / CHAP Authentification
|
|
* Client <------------------------------------------------------------------------> LNS2
|
|
* DATA (ppp)
|
|
* Client <------------------------------------------------------------------------> LNS2
|
|
* */
|
|
|
|
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;
|
|
|
|
// Max Radius Tunnels by remote LNS
|
|
#define MAXTAGTUNNEL 0x20
|
|
static tunnelrlnst ptunnelrlns[MAXTAGTUNNEL];
|
|
|
|
/*
|
|
* Possible configrlns states
|
|
* CONFRLNSFREE -> CONFRLNSSET -> CONFRLNSFREE
|
|
*/
|
|
enum
|
|
{
|
|
CONFRLNSFREE = 0, // Not in use
|
|
CONFRLNSSET, // Config Set
|
|
CONFRLNSSETBYRADIUS // Config Set
|
|
};
|
|
|
|
// struct remote lns
|
|
typedef struct
|
|
{
|
|
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 tunnel_assignment_id[256];
|
|
}
|
|
configrlns;
|
|
|
|
configrlns *pconfigrlns = NULL;
|
|
|
|
// Init data structures
|
|
void lac_initremotelnsdata()
|
|
{
|
|
confrlnsidt i;
|
|
|
|
if ( !(pconfigrlns = shared_malloc(sizeof(pconfigrlns[0]) * MAXRLNSTUNNEL)) )
|
|
{
|
|
LOG(0, 0, 0, "Error doing malloc for tunnels lac: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
memset(pconfigrlns, 0, sizeof(pconfigrlns[0]) * MAXRLNSTUNNEL);
|
|
|
|
// 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();
|
|
}
|
|
|
|
// Reset Radius TAG tunnel context
|
|
void lac_reset_rad_tag_tunnel_ctxt()
|
|
{
|
|
memset(ptunnelrlns, 0, sizeof(ptunnelrlns[0]) * MAXTAGTUNNEL);
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
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)
|
|
{
|
|
bufidtag[nbtagfound] = idtag;
|
|
nbtagfound++;
|
|
}
|
|
}
|
|
|
|
if (nbtagfound > 0)
|
|
{
|
|
// random between 0 and nbtagfound-1
|
|
idtag = (rand() % nbtagfound);
|
|
|
|
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;
|
|
|
|
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 if (ptunnelrlns[idtag].tunnel_server_endpoint == ntohl(config->bind_address))
|
|
LOG(0, s, session[s].tunnel, "Error, IP Remote LNS == IP local bind address (%s) !!!\n", fmtaddr(config->bind_address, 0));
|
|
else
|
|
{
|
|
for (idrlns = 1; idrlns < MAXRLNSTUNNEL; ++idrlns)
|
|
{
|
|
if (pconfigrlns[idrlns].state == CONFRLNSFREE)
|
|
{
|
|
pconfigrlns[idrlns].ip = ptunnelrlns[idtag].tunnel_server_endpoint;
|
|
pconfigrlns[idrlns].port = L2TPPORT; //Default L2TP port
|
|
strcpy(pconfigrlns[idrlns].l2tp_secret, ptunnelrlns[idtag].tunnel_password);
|
|
strcpy(pconfigrlns[idrlns].tunnel_assignment_id, ptunnelrlns[idtag].tunnel_assignment_id);
|
|
|
|
config->highest_rlnsid = idrlns;
|
|
|
|
pconfigrlns[idrlns].state = CONFRLNSSETBYRADIUS;
|
|
|
|
break;
|
|
}
|
|
else if (pconfigrlns[idrlns].state == CONFRLNSSETBYRADIUS)
|
|
{
|
|
if ( (pconfigrlns[idrlns].ip == ptunnelrlns[idtag].tunnel_server_endpoint) &&
|
|
(strcmp(pconfigrlns[idrlns].tunnel_assignment_id, ptunnelrlns[idtag].tunnel_assignment_id) == 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (idrlns >= MAXRLNSTUNNEL)
|
|
{
|
|
LOG(0, s, session[s].tunnel, "No more Remote LNS Conf Free\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create Remote LNS Session
|
|
int lac_create_session(tunnelidt t, sessionidt s, char * puser)
|
|
{
|
|
if (main_quit != QUIT_SHUTDOWN)
|
|
{
|
|
|
|
/**********************/
|
|
/** Open New session **/
|
|
/**********************/
|
|
sessionidt new_sess = sessionfree;
|
|
|
|
sessionfree = session[new_sess].next;
|
|
memset(&session[new_sess], 0, sizeof(session[new_sess]));
|
|
|
|
if (new_sess > config->cluster_highest_sessionid)
|
|
config->cluster_highest_sessionid = new_sess;
|
|
|
|
session[new_sess].opened = time_now;
|
|
session[new_sess].tunnel = t;
|
|
session[new_sess].last_packet = session[s].last_data = time_now;
|
|
|
|
session[new_sess].ppp.phase = Establish;
|
|
session[new_sess].ppp.lcp = Starting;
|
|
session[s].ppp.phase = Establish;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
|
|
// 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;
|
|
tunnel[t].indexudp = config->indexlacudpfd;
|
|
tunn_local[t].initialsession = s;
|
|
strncpy(tunn_local[t].initialuser, puser, sizeof(tunn_local[t].initialuser) - 1);
|
|
STAT(tunnel_created);
|
|
|
|
random_data(pconfigrlns[i_conf].auth, sizeof(pconfigrlns[i_conf].auth));
|
|
|
|
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)
|
|
{
|
|
lac_create_session(t, s, puser);
|
|
}
|
|
else
|
|
{
|
|
/** TODO: ideally we would queue all sessions waiting for the tunnel to
|
|
* be finished creating, to trigger forwarding them all on SCCCN ack,
|
|
* not just the initial one **/
|
|
LOG(1, 0, t, "(REMOTE LNS) tunnel is not open\n");
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
// 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)
|
|
{
|
|
tunnelidt t, j;
|
|
confrlnsidt i;
|
|
|
|
for (i = 1; i <= config->highest_rlnsid ; ++i)
|
|
{
|
|
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;
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
tunnelidt t, j;
|
|
confrlnsidt i;
|
|
|
|
for (i = 1; i <= config->highest_rlnsid ; ++i)
|
|
{
|
|
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;
|
|
}
|
|
|
|
// Calcul the remote LNS auth
|
|
void lac_calc_rlns_auth(tunnelidt t, uint8_t id, uint8_t *out)
|
|
{
|
|
MD5_CTX ctx;
|
|
confrlnsidt idrlns;
|
|
|
|
idrlns = tunnel[t].isremotelns;
|
|
|
|
MD5_Init(&ctx);
|
|
MD5_Update(&ctx, &id, 1);
|
|
MD5_Update(&ctx, pconfigrlns[idrlns].l2tp_secret, strlen(pconfigrlns[idrlns].l2tp_secret));
|
|
MD5_Update(&ctx, pconfigrlns[idrlns].auth, 16);
|
|
MD5_Final(out, &ctx);
|
|
}
|
|
|
|
// Calcul our LNS auth
|
|
void lac_calc_our_auth(tunnelidt t, uint8_t *challenge, uint8_t id, uint16_t challenge_length, uint8_t *out)
|
|
{
|
|
MD5_CTX ctx;
|
|
confrlnsidt idrlns;
|
|
|
|
idrlns = tunnel[t].isremotelns;
|
|
|
|
MD5_Init(&ctx);
|
|
MD5_Update(&ctx, &id, 1);
|
|
MD5_Update(&ctx, pconfigrlns[idrlns].l2tp_secret, strlen(pconfigrlns[idrlns].l2tp_secret));
|
|
MD5_Update(&ctx, challenge, challenge_length);
|
|
MD5_Final(out, &ctx);
|
|
}
|
|
|
|
// 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, uint16_t indexudpfd)
|
|
{
|
|
uint16_t t = 0, s = 0;
|
|
uint8_t *p = buf + 2; // First word L2TP options
|
|
|
|
s = session[sess].forwardtosession;
|
|
if (session[s].forwardtosession != sess)
|
|
{
|
|
LOG(0, sess, session[sess].tunnel, "Link Session (%u) broken\n", s);
|
|
return 0;
|
|
}
|
|
|
|
t = session[s].tunnel;
|
|
if (t >= MAXTUNNEL)
|
|
{
|
|
LOG(1, s, t, "Session with invalid tunnel ID\n");
|
|
return 0;
|
|
}
|
|
|
|
if ((!tunnel[t].isremotelns) && (!tunnel[session[sess].tunnel].isremotelns))
|
|
{
|
|
LOG(0, sess, session[sess].tunnel, "Link Tunnel Session (%u/%u) broken\n", s, t);
|
|
return 0;
|
|
}
|
|
|
|
if (!config->cluster_iam_master)
|
|
{
|
|
if ( (proto == PPPIPCP) || (proto == PPPLCP) ||
|
|
(proto == PPPPAP) || (proto == PPPCHAP) ||
|
|
(proto == PPPIPV6CP && config->ipv6_prefix.s6_addr[0]) ||
|
|
(proto == PPPCCP) )
|
|
{
|
|
session[sess].last_packet = time_now;
|
|
master_forward_packet(buf, len, s_addr, sin_port, indexudpfd);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (t == TUNNEL_ID_PPPOE)
|
|
{
|
|
pppoe_forwardto_session_pppoe(buf, len, sess, proto);
|
|
return 1;
|
|
}
|
|
|
|
if (*buf & 0x40)
|
|
{ // length
|
|
p += 2;
|
|
}
|
|
|
|
*(uint16_t *) p = htons(tunnel[t].far); // tunnel
|
|
p += 2;
|
|
*(uint16_t *) p = htons(session[s].far); // session
|
|
p += 2;
|
|
|
|
if (*buf & 0x08)
|
|
{ // ns/nr
|
|
*(uint16_t *) p = htons(tunnel[t].ns); // sequence
|
|
p += 2;
|
|
*(uint16_t *) p = htons(tunnel[t].nr); // sequence
|
|
p += 2;
|
|
}
|
|
|
|
if ((proto == PPPIP) || (proto == PPPMP) ||(proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0]))
|
|
{
|
|
session[sess].last_packet = session[sess].last_data = time_now;
|
|
update_session_in_stat(sess, 1, len);
|
|
update_session_out_stat(s, 1, len);
|
|
}
|
|
else
|
|
session[sess].last_packet = time_now;
|
|
|
|
tunnelsend(buf, len, t); // send it...
|
|
|
|
return 1;
|
|
}
|
|
|
|
// 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;
|
|
|
|
for (idrlns = 1; idrlns < MAXRLNSTUNNEL; ++idrlns)
|
|
{
|
|
if (pconfigrlns[idrlns].state == CONFRLNSFREE)
|
|
{
|
|
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);
|
|
|
|
config->highest_rlnsid = idrlns;
|
|
|
|
pconfigrlns[idrlns].state = CONFRLNSSET;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
LOG(0, 0, 0, "No more Remote LNS Conf Free\n");
|
|
|
|
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 %3s %-32s %-32s %11s %7s %10s",
|
|
"IP Remote LNS",
|
|
"TID",
|
|
"l2tp secret",
|
|
"assignment Id",
|
|
"File/Radius",
|
|
"State",
|
|
"Count Sess");
|
|
else
|
|
{
|
|
tunnelidt t, tfound = 0;
|
|
sessionidt s;
|
|
int countsess = 0;
|
|
char state[20];
|
|
|
|
strcpy(state, "Close");
|
|
for (t = 0; t <= config->cluster_highest_tunnelid ; ++t)
|
|
{
|
|
if ((tunnel[t].isremotelns == idrlns) &&
|
|
(tunnel[t].ip == pconfigrlns[idrlns].ip) &&
|
|
(tunnel[t].port == pconfigrlns[idrlns].port) &&
|
|
(tunnel[t].state != TUNNELDIE))
|
|
{
|
|
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++;
|
|
tfound = t;
|
|
break;
|
|
}
|
|
}
|
|
|
|
sprintf(strout, "%15s %3u %-32s %-32s %11s %7s %10u",
|
|
fmtaddr(htonl(pconfigrlns[idrlns].ip), 0),
|
|
tfound,
|
|
pconfigrlns[idrlns].l2tp_secret,
|
|
pconfigrlns[idrlns].tunnel_assignment_id,
|
|
(pconfigrlns[idrlns].state == CONFRLNSSET?"File":(pconfigrlns[idrlns].state == CONFRLNSSETBYRADIUS?"Radius":"Free")),
|
|
state,
|
|
countsess);
|
|
}
|
|
|
|
return 1;
|
|
}
|