add Multilink support from Khaled Al Hamwi
This commit is contained in:
parent
57a847d9a3
commit
5faf075c8d
13 changed files with 1021 additions and 97 deletions
3
Changes
3
Changes
|
|
@ -1,6 +1,7 @@
|
||||||
* Tue Apr 25 2006 Brendan O'Dea <bod@optus.net> 2.1.19
|
* Thu Apr 27 2006 Brendan O'Dea <bod@optus.net> 2.2.0
|
||||||
- Only poll clifd if successfully bound.
|
- Only poll clifd if successfully bound.
|
||||||
- Add "Practical VPNs" document from Liran Tal as Docs/vpn .
|
- Add "Practical VPNs" document from Liran Tal as Docs/vpn .
|
||||||
|
- Add Multilink support from Khaled Al Hamwi.
|
||||||
|
|
||||||
* Tue Apr 18 2006 Brendan O'Dea <bod@optus.net> 2.1.18
|
* Tue Apr 18 2006 Brendan O'Dea <bod@optus.net> 2.1.18
|
||||||
- Don't shutdown on TerminateReq, wait for CDN.
|
- Don't shutdown on TerminateReq, wait for CDN.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
.de Id
|
.de Id
|
||||||
.ds Dt \\$4 \\$5
|
.ds Dt \\$4 \\$5
|
||||||
..
|
..
|
||||||
.Id $Id: startup-config.5,v 1.15 2005-09-16 05:04:31 bodea Exp $
|
.Id $Id: startup-config.5,v 1.16 2006-04-27 09:53:50 bodea Exp $
|
||||||
.TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
|
.TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
startup\-config \- configuration file for l2tpns
|
startup\-config \- configuration file for l2tpns
|
||||||
|
|
@ -123,6 +123,9 @@ Allow multiple logins with the same username. If false (the default),
|
||||||
any prior session with the same username will be dropped when a new
|
any prior session with the same username will be dropped when a new
|
||||||
session is established.
|
session is established.
|
||||||
.TP
|
.TP
|
||||||
|
.B guest_account
|
||||||
|
Allow multiple logins matching this specific username.
|
||||||
|
.TP
|
||||||
.B bind_address
|
.B bind_address
|
||||||
When the tun interface is created, it is assigned the address
|
When the tun interface is created, it is assigned the address
|
||||||
specified here. If no address is given, 1.1.1.1 is used. Packets
|
specified here. If no address is given, 1.1.1.1 is used. Packets
|
||||||
|
|
|
||||||
1
THANKS
1
THANKS
|
|
@ -26,3 +26,4 @@ Jon Morby <jon@fido.net>
|
||||||
Paul Martin <pm@zetnet.net>
|
Paul Martin <pm@zetnet.net>
|
||||||
Jonathan Yarden <jyarden@bluegrass.net>
|
Jonathan Yarden <jyarden@bluegrass.net>
|
||||||
Patrick Cole <z@amused.net>
|
Patrick Cole <z@amused.net>
|
||||||
|
Khaled Al Hamwi <kh.alhamwi@gmail.com>
|
||||||
|
|
|
||||||
23
cli.c
23
cli.c
|
|
@ -2,7 +2,7 @@
|
||||||
// vim: sw=8 ts=8
|
// vim: sw=8 ts=8
|
||||||
|
|
||||||
char const *cvs_name = "$Name: $";
|
char const *cvs_name = "$Name: $";
|
||||||
char const *cvs_id_cli = "$Id: cli.c,v 1.71 2005-12-06 09:43:42 bodea Exp $";
|
char const *cvs_id_cli = "$Id: cli.c,v 1.72 2006-04-27 09:53:49 bodea Exp $";
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
@ -36,6 +36,7 @@ char const *cvs_id_cli = "$Id: cli.c,v 1.71 2005-12-06 09:43:42 bodea Exp $";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern tunnelt *tunnel;
|
extern tunnelt *tunnel;
|
||||||
|
extern bundlet *bundle;
|
||||||
extern sessiont *session;
|
extern sessiont *session;
|
||||||
extern radiust *radius;
|
extern radiust *radius;
|
||||||
extern ippoolt *ip_address_pool;
|
extern ippoolt *ip_address_pool;
|
||||||
|
|
@ -426,6 +427,14 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
|
||||||
cli_print(cli, "\tOpened:\t\t%u seconds", session[s].opened ? abs(time_now - session[s].opened) : 0);
|
cli_print(cli, "\tOpened:\t\t%u seconds", session[s].opened ? abs(time_now - session[s].opened) : 0);
|
||||||
cli_print(cli, "\tIdle time:\t%u seconds", session[s].last_packet ? abs(time_now - session[s].last_packet) : 0);
|
cli_print(cli, "\tIdle time:\t%u seconds", session[s].last_packet ? abs(time_now - session[s].last_packet) : 0);
|
||||||
cli_print(cli, "\tBytes In/Out:\t%u/%u", session[s].cout, session[s].cin);
|
cli_print(cli, "\tBytes In/Out:\t%u/%u", session[s].cout, session[s].cin);
|
||||||
|
if (session[s].timeout)
|
||||||
|
{
|
||||||
|
cli_print(cli, "\tRemaing time:\t%u",
|
||||||
|
(session[s].bundle && bundle[session[s].bundle].num_of_links > 1)
|
||||||
|
? (unsigned) (session[s].timeout - bundle[session[s].bundle].online_time)
|
||||||
|
: (unsigned) (session[s].timeout - (time_now - session[s].opened)));
|
||||||
|
}
|
||||||
|
|
||||||
cli_print(cli, "\tPkts In/Out:\t%u/%u", session[s].pout, session[s].pin);
|
cli_print(cli, "\tPkts In/Out:\t%u/%u", session[s].pout, session[s].pin);
|
||||||
cli_print(cli, "\tMRU:\t\t%d", session[s].mru);
|
cli_print(cli, "\tMRU:\t\t%d", session[s].mru);
|
||||||
cli_print(cli, "\tRx Speed:\t%u", session[s].rx_connect_speed);
|
cli_print(cli, "\tRx Speed:\t%u", session[s].rx_connect_speed);
|
||||||
|
|
@ -492,7 +501,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show Summary
|
// Show Summary
|
||||||
cli_print(cli, "%5s %4s %-32s %-15s %s %s %s %s %10s %10s %10s %4s %-15s %s",
|
cli_print(cli, "%5s %4s %-32s %-15s %s %s %s %s %10s %10s %10s %4s %10s %-15s %s",
|
||||||
"SID",
|
"SID",
|
||||||
"TID",
|
"TID",
|
||||||
"Username",
|
"Username",
|
||||||
|
|
@ -505,13 +514,20 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
|
||||||
"downloaded",
|
"downloaded",
|
||||||
"uploaded",
|
"uploaded",
|
||||||
"idle",
|
"idle",
|
||||||
|
"Rem.Time",
|
||||||
"LAC",
|
"LAC",
|
||||||
"CLI");
|
"CLI");
|
||||||
|
|
||||||
for (i = 1; i < MAXSESSION; i++)
|
for (i = 1; i < MAXSESSION; i++)
|
||||||
{
|
{
|
||||||
|
uint32_t rem_time;
|
||||||
if (!session[i].opened) continue;
|
if (!session[i].opened) continue;
|
||||||
cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %s %10u %10lu %10lu %4u %-15s %s",
|
if (session[i].bundle && bundle[session[i].bundle].num_of_links > 1)
|
||||||
|
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;
|
||||||
|
|
||||||
|
cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %s %10u %10lu %10lu %4u %10lu %-15s %s",
|
||||||
i,
|
i,
|
||||||
session[i].tunnel,
|
session[i].tunnel,
|
||||||
session[i].user[0] ? session[i].user : "*",
|
session[i].user[0] ? session[i].user : "*",
|
||||||
|
|
@ -524,6 +540,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
|
||||||
(unsigned long)session[i].cout,
|
(unsigned long)session[i].cout,
|
||||||
(unsigned long)session[i].cin,
|
(unsigned long)session[i].cin,
|
||||||
abs(time_now - (session[i].last_packet ? session[i].last_packet : time_now)),
|
abs(time_now - (session[i].last_packet ? session[i].last_packet : time_now)),
|
||||||
|
(unsigned long)(rem_time),
|
||||||
fmtaddr(htonl(tunnel[ session[i].tunnel ].ip), 1),
|
fmtaddr(htonl(tunnel[ session[i].tunnel ].ip), 1),
|
||||||
session[i].calling[0] ? session[i].calling : "*");
|
session[i].calling[0] ? session[i].calling : "*");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
160
cluster.c
160
cluster.c
|
|
@ -1,6 +1,6 @@
|
||||||
// L2TPNS Clustering Stuff
|
// L2TPNS Clustering Stuff
|
||||||
|
|
||||||
char const *cvs_id_cluster = "$Id: cluster.c,v 1.50 2006-04-05 02:13:48 bodea Exp $";
|
char const *cvs_id_cluster = "$Id: cluster.c,v 1.51 2006-04-27 09:53:49 bodea Exp $";
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -42,6 +42,7 @@ extern int cluster_sockfd; // The filedescriptor for the cluster communications
|
||||||
|
|
||||||
in_addr_t my_address = 0; // The network address of my ethernet port.
|
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_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_tunnel_number = 0; // The next tunnel to send when doing the slow table walk.
|
||||||
int forked = 0; // Sanity check: CLI must not diddle with heartbeat table
|
int forked = 0; // Sanity check: CLI must not diddle with heartbeat table
|
||||||
|
|
||||||
|
|
@ -85,6 +86,7 @@ int cluster_init()
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
config->cluster_undefined_sessions = MAXSESSION-1;
|
config->cluster_undefined_sessions = MAXSESSION-1;
|
||||||
|
config->cluster_undefined_bundles = MAXBUNDLE-1;
|
||||||
config->cluster_undefined_tunnels = MAXTUNNEL-1;
|
config->cluster_undefined_tunnels = MAXTUNNEL-1;
|
||||||
|
|
||||||
if (!config->cluster_address)
|
if (!config->cluster_address)
|
||||||
|
|
@ -227,7 +229,7 @@ static void cluster_uptodate(void)
|
||||||
if (config->cluster_iam_uptodate)
|
if (config->cluster_iam_uptodate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels)
|
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
config->cluster_iam_uptodate = 1;
|
config->cluster_iam_uptodate = 1;
|
||||||
|
|
@ -520,7 +522,7 @@ void cluster_check_slaves(void)
|
||||||
//
|
//
|
||||||
void cluster_check_master(void)
|
void cluster_check_master(void)
|
||||||
{
|
{
|
||||||
int i, count, tcount, high_unique_id = 0;
|
int i, count, tcount, bcount, high_unique_id = 0;
|
||||||
int last_free = 0;
|
int last_free = 0;
|
||||||
clockt t = TIME;
|
clockt t = TIME;
|
||||||
static int probed = 0;
|
static int probed = 0;
|
||||||
|
|
@ -614,6 +616,19 @@ void cluster_check_master(void)
|
||||||
config->cluster_highest_tunnelid = i;
|
config->cluster_highest_tunnelid = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Go through and mark all the bundles as defined.
|
||||||
|
// Count the highest used bundle number as well.
|
||||||
|
//
|
||||||
|
config->cluster_highest_bundleid = 0;
|
||||||
|
for (i = 0, bcount = 0; i < MAXBUNDLE; ++i) {
|
||||||
|
if (bundle[i].state == BUNDLEUNDEF)
|
||||||
|
bundle[i].state = BUNDLEFREE;
|
||||||
|
|
||||||
|
if (bundle[i].state != BUNDLEFREE && i > config->cluster_highest_bundleid)
|
||||||
|
config->cluster_highest_bundleid = i;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Go through and mark all the sessions as being defined.
|
// Go through and mark all the sessions as being defined.
|
||||||
// reset the idle timeouts.
|
// reset the idle timeouts.
|
||||||
|
|
@ -675,10 +690,11 @@ void cluster_check_master(void)
|
||||||
rebuild_address_pool();
|
rebuild_address_pool();
|
||||||
|
|
||||||
// If we're not the very first master, this is a big issue!
|
// If we're not the very first master, this is a big issue!
|
||||||
if(count>0)
|
if (count > 0)
|
||||||
LOG(0, 0, 0, "Warning: Fixed %d uninitialized sessions in becoming master!\n", count);
|
LOG(0, 0, 0, "Warning: Fixed %d uninitialized sessions in becoming master!\n", count);
|
||||||
|
|
||||||
config->cluster_undefined_sessions = 0;
|
config->cluster_undefined_sessions = 0;
|
||||||
|
config->cluster_undefined_bundles = 0;
|
||||||
config->cluster_undefined_tunnels = 0;
|
config->cluster_undefined_tunnels = 0;
|
||||||
config->cluster_iam_uptodate = 1; // assume all peers are up-to-date
|
config->cluster_iam_uptodate = 1; // assume all peers are up-to-date
|
||||||
|
|
||||||
|
|
@ -696,7 +712,7 @@ void cluster_check_master(void)
|
||||||
// we fix it up here, and we ensure that the 'first free session'
|
// we fix it up here, and we ensure that the 'first free session'
|
||||||
// pointer is valid.
|
// pointer is valid.
|
||||||
//
|
//
|
||||||
static void cluster_check_sessions(int highsession, int freesession_ptr, int hightunnel)
|
static void cluster_check_sessions(int highsession, int freesession_ptr, int highbundle, int hightunnel)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -705,7 +721,7 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig
|
||||||
if (config->cluster_iam_uptodate)
|
if (config->cluster_iam_uptodate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (highsession > config->cluster_undefined_sessions && hightunnel > config->cluster_undefined_tunnels)
|
if (highsession > config->cluster_undefined_sessions && highbundle > config->cluster_undefined_bundles && hightunnel > config->cluster_undefined_tunnels)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Clear out defined sessions, counting the number of
|
// Clear out defined sessions, counting the number of
|
||||||
|
|
@ -721,6 +737,19 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig
|
||||||
++config->cluster_undefined_sessions;
|
++config->cluster_undefined_sessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear out defined bundles, counting the number of
|
||||||
|
// undefs remaining.
|
||||||
|
config->cluster_undefined_bundles = 0;
|
||||||
|
for (i = 1 ; i < MAXBUNDLE; ++i) {
|
||||||
|
if (i > highbundle) {
|
||||||
|
if (bundle[i].state == BUNDLEUNDEF) bundle[i].state = BUNDLEFREE; // Defined.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bundle[i].state == BUNDLEUNDEF)
|
||||||
|
++config->cluster_undefined_bundles;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear out defined tunnels, counting the number of
|
// Clear out defined tunnels, counting the number of
|
||||||
// undefs remaining.
|
// undefs remaining.
|
||||||
config->cluster_undefined_tunnels = 0;
|
config->cluster_undefined_tunnels = 0;
|
||||||
|
|
@ -735,9 +764,9 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels) {
|
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles) {
|
||||||
LOG(2, 0, 0, "Cleared undefined sessions/tunnels. %d sess (high %d), %d tunn (high %d)\n",
|
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_tunnels, hightunnel);
|
config->cluster_undefined_sessions, highsession, config->cluster_undefined_bundles, highbundle, config->cluster_undefined_tunnels, hightunnel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -770,6 +799,27 @@ static int hb_add_type(uint8_t **p, int type, int id)
|
||||||
add_type(p, C_SESSION, id, (uint8_t *) &session[id], sizeof(sessiont));
|
add_type(p, C_SESSION, id, (uint8_t *) &session[id], sizeof(sessiont));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case C_CBUNDLE: { // Compressed C_BUNDLE
|
||||||
|
uint8_t c[sizeof(bundlet) * 2]; // Bigger than worst case.
|
||||||
|
uint8_t *d = (uint8_t *) &bundle[id];
|
||||||
|
uint8_t *orig = d;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
size = rle_compress( &d, sizeof(bundlet), c, sizeof(c) );
|
||||||
|
|
||||||
|
// Did we compress the full structure, and is the size actually
|
||||||
|
// reduced??
|
||||||
|
if ( (d - orig) == sizeof(bundlet) && size < sizeof(bundlet) ) {
|
||||||
|
add_type(p, C_CBUNDLE, id, c, size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Failed to compress : Fall through.
|
||||||
|
}
|
||||||
|
|
||||||
|
case C_BUNDLE:
|
||||||
|
add_type(p, C_BUNDLE, id, (uint8_t *) &bundle[id], sizeof(bundlet));
|
||||||
|
break;
|
||||||
|
|
||||||
case C_CTUNNEL: { // Compressed C_TUNNEL
|
case C_CTUNNEL: { // Compressed C_TUNNEL
|
||||||
uint8_t c[sizeof(tunnelt) * 2]; // Bigger than worst case.
|
uint8_t c[sizeof(tunnelt) * 2]; // Bigger than worst case.
|
||||||
uint8_t *d = (uint8_t *) &tunnel[id];
|
uint8_t *d = (uint8_t *) &tunnel[id];
|
||||||
|
|
@ -802,7 +852,7 @@ static int hb_add_type(uint8_t **p, int type, int id)
|
||||||
//
|
//
|
||||||
void cluster_heartbeat()
|
void cluster_heartbeat()
|
||||||
{
|
{
|
||||||
int i, count = 0, tcount = 0;
|
int i, count = 0, tcount = 0, bcount = 0;
|
||||||
uint8_t buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
|
uint8_t buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
|
||||||
heartt h;
|
heartt h;
|
||||||
uint8_t *p = buff;
|
uint8_t *p = buff;
|
||||||
|
|
@ -823,7 +873,9 @@ void cluster_heartbeat()
|
||||||
h.highsession = config->cluster_highest_sessionid;
|
h.highsession = config->cluster_highest_sessionid;
|
||||||
h.freesession = sessionfree;
|
h.freesession = sessionfree;
|
||||||
h.hightunnel = config->cluster_highest_tunnelid;
|
h.hightunnel = config->cluster_highest_tunnelid;
|
||||||
|
h.highbundle = config->cluster_highest_bundleid;
|
||||||
h.size_sess = sizeof(sessiont); // Just in case.
|
h.size_sess = sizeof(sessiont); // Just in case.
|
||||||
|
h.size_bund = sizeof(bundlet);
|
||||||
h.size_tunn = sizeof(tunnelt);
|
h.size_tunn = sizeof(tunnelt);
|
||||||
h.interval = config->cluster_hb_interval;
|
h.interval = config->cluster_hb_interval;
|
||||||
h.timeout = config->cluster_hb_timeout;
|
h.timeout = config->cluster_hb_timeout;
|
||||||
|
|
@ -878,6 +930,22 @@ void cluster_heartbeat()
|
||||||
++tcount;
|
++tcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fill out the packet with bundles from the bundle table...
|
||||||
|
while ( (p + sizeof(uint32_t) * 2 + sizeof(bundlet) ) < (buff + MAX_HEART_SIZE) ) {
|
||||||
|
|
||||||
|
if (!walk_bundle_number) // bundle #0 isn't valid.
|
||||||
|
++walk_bundle_number;
|
||||||
|
|
||||||
|
if (bcount >= config->cluster_highest_bundleid)
|
||||||
|
break;
|
||||||
|
|
||||||
|
hb_add_type(&p, C_CTUNNEL, walk_bundle_number);
|
||||||
|
walk_tunnel_number = (1+walk_bundle_number)%(config->cluster_highest_bundleid+1); // +1 avoids divide by zero.
|
||||||
|
|
||||||
|
++bcount;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Did we do something wrong?
|
// Did we do something wrong?
|
||||||
if (p > (buff + sizeof(buff))) { // Did we somehow manage to overun the buffer?
|
if (p > (buff + sizeof(buff))) { // Did we somehow manage to overun the buffer?
|
||||||
|
|
@ -887,9 +955,9 @@ void cluster_heartbeat()
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(3, 0, 0, "Sending v%d heartbeat #%d, change #%" PRIu64 " with %d changes "
|
LOG(3, 0, 0, "Sending v%d heartbeat #%d, change #%" PRIu64 " with %d changes "
|
||||||
"(%d x-sess, %d x-tunnels, %d highsess, %d hightun, size %d)\n",
|
"(%d x-sess, %d x-bundles, %d x-tunnels, %d highsess, %d highbund, %d hightun, size %d)\n",
|
||||||
HB_VERSION, h.seq, h.table_version, config->cluster_num_changes,
|
HB_VERSION, h.seq, h.table_version, config->cluster_num_changes,
|
||||||
count, tcount, config->cluster_highest_sessionid,
|
count, bcount, tcount, config->cluster_highest_sessionid, config->cluster_highest_bundleid,
|
||||||
config->cluster_highest_tunnelid, (int) (p - buff));
|
config->cluster_highest_tunnelid, (int) (p - buff));
|
||||||
|
|
||||||
config->cluster_num_changes = 0;
|
config->cluster_num_changes = 0;
|
||||||
|
|
@ -938,6 +1006,17 @@ int cluster_send_session(int sid)
|
||||||
return type_changed(C_CSESSION, sid);
|
return type_changed(C_CSESSION, sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A particular bundle has been changed!
|
||||||
|
int cluster_send_bundle(int bid)
|
||||||
|
{
|
||||||
|
if (!config->cluster_iam_master) {
|
||||||
|
LOG(0, 0, bid, "I'm not a master, but I just tried to change a bundle!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_changed(C_CBUNDLE, bid);
|
||||||
|
}
|
||||||
|
|
||||||
// A particular tunnel has been changed!
|
// A particular tunnel has been changed!
|
||||||
int cluster_send_tunnel(int tid)
|
int cluster_send_tunnel(int tid)
|
||||||
{
|
{
|
||||||
|
|
@ -1175,6 +1254,31 @@ static int cluster_recv_session(int more, uint8_t *p)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cluster_recv_bundle(int more, uint8_t *p)
|
||||||
|
{
|
||||||
|
if (more >= MAXBUNDLE) {
|
||||||
|
LOG(0, 0, 0, "DANGER: Received a bundle id > MAXBUNDLE!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bundle[more].state == BUNDLEUNDEF) {
|
||||||
|
if (config->cluster_iam_uptodate) { // Sanity.
|
||||||
|
LOG(0, 0, 0, "I thought I was uptodate but I just found an undefined bundle!\n");
|
||||||
|
} else {
|
||||||
|
--config->cluster_undefined_bundles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&bundle[more], p, sizeof(bundle[more]) );
|
||||||
|
|
||||||
|
LOG(5, 0, more, "Received bundle update\n");
|
||||||
|
|
||||||
|
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)
|
static int cluster_recv_tunnel(int more, uint8_t *p)
|
||||||
{
|
{
|
||||||
if (more >= MAXTUNNEL) {
|
if (more >= MAXTUNNEL) {
|
||||||
|
|
@ -1461,7 +1565,7 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t
|
||||||
|
|
||||||
// Check that we don't have too many undefined sessions, and
|
// Check that we don't have too many undefined sessions, and
|
||||||
// that the free session pointer is correct.
|
// that the free session pointer is correct.
|
||||||
cluster_check_sessions(h->highsession, h->freesession, h->hightunnel);
|
cluster_check_sessions(h->highsession, h->freesession, h->highbundle, h->hightunnel);
|
||||||
|
|
||||||
if (h->interval != config->cluster_hb_interval)
|
if (h->interval != config->cluster_hb_interval)
|
||||||
{
|
{
|
||||||
|
|
@ -1569,6 +1673,34 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t
|
||||||
p += sizeof(tunnel[more]);
|
p += sizeof(tunnel[more]);
|
||||||
s -= sizeof(tunnel[more]);
|
s -= sizeof(tunnel[more]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case C_CBUNDLE: { // Compressed bundle structure.
|
||||||
|
uint8_t c[ sizeof(bundlet) + 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(bundlet) ) { // Ouch! Very very bad!
|
||||||
|
LOG(0, 0, 0, "DANGER: Received a CBUNDLE that didn't decompress correctly!\n");
|
||||||
|
// Now what? Should exit! No-longer up to date!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster_recv_bundle(more, c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
case C_BUNDLE:
|
||||||
|
if ( s < sizeof(bundle[more]))
|
||||||
|
goto shortpacket;
|
||||||
|
|
||||||
|
cluster_recv_bundle(more, p);
|
||||||
|
|
||||||
|
p += sizeof(bundle[more]);
|
||||||
|
s -= sizeof(bundle[more]);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG(0, 0, 0, "DANGER: I received a heartbeat element where I didn't understand the type! (%d)\n", type);
|
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!!
|
return -1; // can't process any more of the packet!!
|
||||||
|
|
@ -1754,11 +1886,13 @@ int cmd_show_cluster(struct cli_def *cli, char *command, char **argv, int argc)
|
||||||
cli_print(cli, "Table version # : %" PRIu64, config->cluster_table_version);
|
cli_print(cli, "Table version # : %" PRIu64, config->cluster_table_version);
|
||||||
cli_print(cli, "Next sequence number expected: %d", config->cluster_seq_number);
|
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 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 tunnels undefined of %d", config->cluster_undefined_tunnels, config->cluster_highest_tunnelid);
|
cli_print(cli, "%d tunnels undefined of %d", config->cluster_undefined_tunnels, config->cluster_highest_tunnelid);
|
||||||
} else {
|
} else {
|
||||||
cli_print(cli, "Table version # : %" PRIu64, config->cluster_table_version);
|
cli_print(cli, "Table version # : %" PRIu64, config->cluster_table_version);
|
||||||
cli_print(cli, "Next heartbeat # : %d", config->cluster_seq_number);
|
cli_print(cli, "Next heartbeat # : %d", config->cluster_seq_number);
|
||||||
cli_print(cli, "Highest session : %d", config->cluster_highest_sessionid);
|
cli_print(cli, "Highest session : %d", config->cluster_highest_sessionid);
|
||||||
|
cli_print(cli, "Highest bundle : %d", config->cluster_highest_bundleid);
|
||||||
cli_print(cli, "Highest tunnel : %d", config->cluster_highest_tunnelid);
|
cli_print(cli, "Highest tunnel : %d", config->cluster_highest_tunnelid);
|
||||||
cli_print(cli, "%d changes queued for sending", config->cluster_num_changes);
|
cli_print(cli, "%d changes queued for sending", config->cluster_num_changes);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// L2TPNS Clustering Stuff
|
// L2TPNS Clustering Stuff
|
||||||
// $Id: cluster.h,v 1.14 2005-07-31 10:04:10 bodea Exp $
|
// $Id: cluster.h,v 1.15 2006-04-27 09:53:49 bodea Exp $
|
||||||
|
|
||||||
#ifndef __CLUSTER_H__
|
#ifndef __CLUSTER_H__
|
||||||
#define __CLUSTER_H__
|
#define __CLUSTER_H__
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
#define C_GARDEN 14 // Gardened packet
|
#define C_GARDEN 14 // Gardened packet
|
||||||
#define C_MASTER 15 // Tell a slave the address of the master.
|
#define C_MASTER 15 // Tell a slave the address of the master.
|
||||||
#define C_FORWARD_DAE 16 // A DAE packet for the master to handle
|
#define C_FORWARD_DAE 16 // A DAE packet for the master to handle
|
||||||
|
#define C_BUNDLE 17 // Bundle structure.
|
||||||
|
#define C_CBUNDLE 18 // Compressed bundle structure.
|
||||||
|
|
||||||
#define HB_VERSION 5 // Protocol version number..
|
#define HB_VERSION 5 // Protocol version number..
|
||||||
#define HB_MAX_SEQ (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!)
|
#define HB_MAX_SEQ (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!)
|
||||||
|
|
@ -43,9 +45,11 @@ typedef struct {
|
||||||
|
|
||||||
uint32_t highsession; // Id of the highest in-use session.
|
uint32_t highsession; // Id of the highest in-use session.
|
||||||
uint32_t freesession; // Id of the first free session.
|
uint32_t freesession; // Id of the first free session.
|
||||||
|
uint32_t highbundle; // Id of the highest used bundle.
|
||||||
uint32_t hightunnel; // Id of the highest used tunnel.
|
uint32_t hightunnel; // Id of the highest used tunnel.
|
||||||
uint32_t size_sess; // Size of the session structure.
|
uint32_t size_sess; // Size of the session structure.
|
||||||
|
|
||||||
|
uint32_t size_bund; // size of the bundle structure.
|
||||||
uint32_t size_tunn; // size of the tunnel structure.
|
uint32_t size_tunn; // size of the tunnel structure.
|
||||||
uint32_t interval; // ping/heartbeat interval
|
uint32_t interval; // ping/heartbeat interval
|
||||||
uint32_t timeout; // heartbeat timeout
|
uint32_t timeout; // heartbeat timeout
|
||||||
|
|
@ -74,6 +78,7 @@ typedef struct {
|
||||||
int cluster_init(void);
|
int cluster_init(void);
|
||||||
int processcluster(uint8_t *buf, int size, in_addr_t addr);
|
int processcluster(uint8_t *buf, int size, in_addr_t addr);
|
||||||
int cluster_send_session(int sid);
|
int cluster_send_session(int sid);
|
||||||
|
int cluster_send_bundle(int bid);
|
||||||
int cluster_send_tunnel(int tid);
|
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, int port);
|
||||||
int master_forward_dae_packet(uint8_t *data, int size, in_addr_t addr, int port);
|
int master_forward_dae_packet(uint8_t *data, int size, in_addr_t addr, int port);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ set radius_secret "secret"
|
||||||
# Allow multiple logins for the same username
|
# Allow multiple logins for the same username
|
||||||
#set allow_duplicate_users no
|
#set allow_duplicate_users no
|
||||||
|
|
||||||
|
# Allow multiple logins for specific username
|
||||||
|
#set guest_account ""
|
||||||
|
|
||||||
# Write usage accounting files into specified directory
|
# Write usage accounting files into specified directory
|
||||||
set accounting_dir "/var/run/l2tpns/acct"
|
set accounting_dir "/var/run/l2tpns/acct"
|
||||||
|
|
||||||
|
|
@ -96,6 +99,9 @@ set accounting_dir "/var/run/l2tpns/acct"
|
||||||
# Minimum number of slaves before master withdraws routes
|
# Minimum number of slaves before master withdraws routes
|
||||||
#set cluster_master_min_adv 1
|
#set cluster_master_min_adv 1
|
||||||
|
|
||||||
|
# IPv6 address prefix
|
||||||
|
#set ipv6_prefix ::
|
||||||
|
|
||||||
# Drop/kill sessions
|
# Drop/kill sessions
|
||||||
#load plugin "sessionctl"
|
#load plugin "sessionctl"
|
||||||
|
|
||||||
|
|
|
||||||
4
icmp.c
4
icmp.c
|
|
@ -1,6 +1,6 @@
|
||||||
// L2TPNS: icmp
|
// L2TPNS: icmp
|
||||||
|
|
||||||
char const *cvs_id_icmp = "$Id: icmp.c,v 1.10 2005-08-10 11:25:56 bodea Exp $";
|
char const *cvs_id_icmp = "$Id: icmp.c,v 1.11 2006-04-27 09:53:49 bodea Exp $";
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
@ -114,7 +114,7 @@ void send_ipv6_ra(sessionidt s, tunnelidt t, struct in6_addr *ip)
|
||||||
LOG(3, s, t, "Sending IPv6 RA\n");
|
LOG(3, s, t, "Sending IPv6 RA\n");
|
||||||
|
|
||||||
memset(b, 0, sizeof(b));
|
memset(b, 0, sizeof(b));
|
||||||
o = makeppp(b, sizeof(b), 0, 0, s, t, PPPIPV6);
|
o = makeppp(b, sizeof(b), 0, 0, s, t, PPPIPV6, 0, 0, 0);
|
||||||
|
|
||||||
if (!o)
|
if (!o)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
244
l2tpns.c
244
l2tpns.c
|
|
@ -4,7 +4,7 @@
|
||||||
// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
|
// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
|
||||||
// vim: sw=8 ts=8
|
// vim: sw=8 ts=8
|
||||||
|
|
||||||
char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.162 2006-04-23 23:18:31 bodea Exp $";
|
char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.163 2006-04-27 09:53:49 bodea Exp $";
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
@ -127,6 +127,7 @@ config_descriptt config_values[] = {
|
||||||
CONFIG("radius_authtypes", radius_authtypes_s, STRING),
|
CONFIG("radius_authtypes", radius_authtypes_s, STRING),
|
||||||
CONFIG("radius_dae_port", radius_dae_port, SHORT),
|
CONFIG("radius_dae_port", radius_dae_port, SHORT),
|
||||||
CONFIG("allow_duplicate_users", allow_duplicate_users, BOOL),
|
CONFIG("allow_duplicate_users", allow_duplicate_users, BOOL),
|
||||||
|
CONFIG("guest_account", guest_user, STRING),
|
||||||
CONFIG("bind_address", bind_address, IPv4),
|
CONFIG("bind_address", bind_address, IPv4),
|
||||||
CONFIG("peer_address", peer_address, IPv4),
|
CONFIG("peer_address", peer_address, IPv4),
|
||||||
CONFIG("send_garp", send_garp, BOOL),
|
CONFIG("send_garp", send_garp, BOOL),
|
||||||
|
|
@ -174,6 +175,8 @@ static sessiont shut_acct[8192];
|
||||||
static sessionidt shut_acct_n = 0;
|
static sessionidt shut_acct_n = 0;
|
||||||
|
|
||||||
tunnelt *tunnel = NULL; // Array of tunnel structures.
|
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.
|
sessiont *session = NULL; // Array of session structures.
|
||||||
sessionlocalt *sess_local = NULL; // Array of local per-session counters.
|
sessionlocalt *sess_local = NULL; // Array of local per-session counters.
|
||||||
radiust *radius = NULL; // Array of radius structures.
|
radiust *radius = NULL; // Array of radius structures.
|
||||||
|
|
@ -203,6 +206,7 @@ static void plugins_done(void);
|
||||||
static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struct in_addr *local);
|
static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struct in_addr *local);
|
||||||
static tunnelidt new_tunnel(void);
|
static tunnelidt new_tunnel(void);
|
||||||
static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vector, size_t vec_len);
|
static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vector, size_t vec_len);
|
||||||
|
static void bundleclear(bundleidt b);
|
||||||
|
|
||||||
// on slaves, alow BGP to withdraw cleanly before exiting
|
// on slaves, alow BGP to withdraw cleanly before exiting
|
||||||
#define QUIT_DELAY 5
|
#define QUIT_DELAY 5
|
||||||
|
|
@ -1051,6 +1055,54 @@ void adjust_tcp_mss(sessionidt s, tunnelidt t, uint8_t *buf, int len, uint8_t *t
|
||||||
*(uint16_t *) (tcp + 16) = htons(sum + (sum >> 16));
|
*(uint16_t *) (tcp + 16) = htons(sum + (sum >> 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void processmpframe(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint8_t extra)
|
||||||
|
{
|
||||||
|
uint16_t proto;
|
||||||
|
if (extra) {
|
||||||
|
// Skip the four extra bytes
|
||||||
|
p += 4;
|
||||||
|
l -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process this frame
|
||||||
|
if (*p & 1)
|
||||||
|
{
|
||||||
|
proto = *p++;
|
||||||
|
l--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proto = ntohs(*(uint16_t *) p);
|
||||||
|
p += 2;
|
||||||
|
l -= 2;
|
||||||
|
}
|
||||||
|
if (proto == PPPIP)
|
||||||
|
{
|
||||||
|
if (session[s].die)
|
||||||
|
{
|
||||||
|
LOG(4, s, t, "MPPP: Session %d is closing. Don't process PPP packets\n", s);
|
||||||
|
return; // closing session, PPP not processed
|
||||||
|
}
|
||||||
|
session[s].last_packet = time_now;
|
||||||
|
processipin(s, t, p, l);
|
||||||
|
}
|
||||||
|
else if (proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0])
|
||||||
|
{
|
||||||
|
if (session[s].die)
|
||||||
|
{
|
||||||
|
LOG(4, s, t, "MPPP: Session %d is closing. Don't process PPP packets\n", s);
|
||||||
|
return; // closing session, PPP not processed
|
||||||
|
}
|
||||||
|
|
||||||
|
session[s].last_packet = time_now;
|
||||||
|
processipv6in(s, t, p, l);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "MPPP: Unsupported MP protocol 0x%04X received\n",proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// process outgoing (to tunnel) IP
|
// process outgoing (to tunnel) IP
|
||||||
//
|
//
|
||||||
static void processipout(uint8_t *buf, int len)
|
static void processipout(uint8_t *buf, int len)
|
||||||
|
|
@ -1063,7 +1115,8 @@ static void processipout(uint8_t *buf, int len)
|
||||||
uint8_t *data = buf; // Keep a copy of the originals.
|
uint8_t *data = buf; // Keep a copy of the originals.
|
||||||
int size = len;
|
int size = len;
|
||||||
|
|
||||||
uint8_t b[MAXETHER + 20];
|
uint8_t b1[MAXETHER + 20];
|
||||||
|
uint8_t b2[MAXETHER + 20];
|
||||||
|
|
||||||
CSTAT(processipout);
|
CSTAT(processipout);
|
||||||
|
|
||||||
|
|
@ -1183,13 +1236,43 @@ static void processipout(uint8_t *buf, int len)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(5, s, t, "Ethernet -> Tunnel (%d bytes)\n", len);
|
|
||||||
|
|
||||||
// Add on L2TP header
|
// Add on L2TP header
|
||||||
{
|
{
|
||||||
uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP);
|
bundleidt bid = 0;
|
||||||
|
if (session[s].bundle && bundle[session[s].bundle].num_of_links > 1)
|
||||||
|
{
|
||||||
|
bid = session[s].bundle;
|
||||||
|
s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links];
|
||||||
|
LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s);
|
||||||
|
if (len > 256)
|
||||||
|
{
|
||||||
|
// Partition the packet to 2 fragments
|
||||||
|
uint32_t frag1len = len / 2;
|
||||||
|
uint32_t frag2len = len - frag1len;
|
||||||
|
uint8_t *p = makeppp(b1, sizeof(b1), buf, frag1len, s, t, PPPIP, 0, bid, MP_BEGIN);
|
||||||
|
uint8_t *q;
|
||||||
|
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
tunnelsend(b, len + (p-b), t); // send it...
|
tunnelsend(b1, frag1len + (p-b1), t); // send it...
|
||||||
|
s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links];
|
||||||
|
LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s);
|
||||||
|
q = makeppp(b2, sizeof(b2), buf+frag1len, frag2len, s, t, PPPIP, 0, bid, MP_END);
|
||||||
|
if (!q) return;
|
||||||
|
tunnelsend(b2, frag2len + (q-b2), t); // send it...
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Send it as one frame
|
||||||
|
uint8_t *p = makeppp(b1, sizeof(b1), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS);
|
||||||
|
if (!p) return;
|
||||||
|
tunnelsend(b1, len + (p-b1), t); // send it...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8_t *p = makeppp(b1, sizeof(b1), buf, len, s, t, PPPIP, 0, 0, 0);
|
||||||
|
if (!p) return;
|
||||||
|
tunnelsend(b1, len + (p-b1), t); // send it...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snooping this session, send it to intercept box
|
// Snooping this session, send it to intercept box
|
||||||
|
|
@ -1273,6 +1356,12 @@ static void processipv6out(uint8_t * buf, int len)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (session[s].bundle && bundle[session[s].bundle].num_of_links > 1)
|
||||||
|
{
|
||||||
|
bundleidt bid = session[s].bundle;
|
||||||
|
s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links];
|
||||||
|
LOG(3, s, session[s].tunnel, "MPPP: Session number becomes: %d\n", s);
|
||||||
|
}
|
||||||
t = session[s].tunnel;
|
t = session[s].tunnel;
|
||||||
sp = &session[s];
|
sp = &session[s];
|
||||||
|
|
||||||
|
|
@ -1298,7 +1387,7 @@ static void processipv6out(uint8_t * buf, int len)
|
||||||
|
|
||||||
// Add on L2TP header
|
// Add on L2TP header
|
||||||
{
|
{
|
||||||
uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIPV6);
|
uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIPV6, 0, 0, 0);
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
tunnelsend(b, len + (p-b), t); // send it...
|
tunnelsend(b, len + (p-b), t); // send it...
|
||||||
}
|
}
|
||||||
|
|
@ -1350,7 +1439,7 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len)
|
||||||
|
|
||||||
// Add on L2TP header
|
// Add on L2TP header
|
||||||
{
|
{
|
||||||
uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP);
|
uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP, 0, 0, 0);
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
tunnelsend(b, len + (p-b), t); // send it...
|
tunnelsend(b, len + (p-b), t); // send it...
|
||||||
}
|
}
|
||||||
|
|
@ -1679,7 +1768,7 @@ void sendipcp(sessionidt s, tunnelidt t)
|
||||||
session[s].unique_id = last_id;
|
session[s].unique_id = last_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPIPCP);
|
q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPIPCP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
*q = ConfigReq;
|
*q = ConfigReq;
|
||||||
|
|
@ -1703,7 +1792,7 @@ void sendipv6cp(sessionidt s, tunnelidt t)
|
||||||
CSTAT(sendipv6cp);
|
CSTAT(sendipv6cp);
|
||||||
LOG(3, s, t, "IPV6CP: send ConfigReq\n");
|
LOG(3, s, t, "IPV6CP: send ConfigReq\n");
|
||||||
|
|
||||||
q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPIPV6CP);
|
q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPIPV6CP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
*q = ConfigReq;
|
*q = ConfigReq;
|
||||||
|
|
@ -1735,6 +1824,7 @@ static void sessionclear(sessionidt s)
|
||||||
// kill a session now
|
// kill a session now
|
||||||
void sessionkill(sessionidt s, char *reason)
|
void sessionkill(sessionidt s, char *reason)
|
||||||
{
|
{
|
||||||
|
bundleidt b;
|
||||||
|
|
||||||
CSTAT(sessionkill);
|
CSTAT(sessionkill);
|
||||||
|
|
||||||
|
|
@ -1753,6 +1843,38 @@ void sessionkill(sessionidt s, char *reason)
|
||||||
radiusclear(sess_local[s].radius, s); // cant send clean accounting data, session is killed
|
radiusclear(sess_local[s].radius, s); // cant send clean accounting data, session is killed
|
||||||
|
|
||||||
LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
|
LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
|
||||||
|
if ((b = session[s].bundle))
|
||||||
|
{
|
||||||
|
// This session was part of a bundle
|
||||||
|
bundle[b].num_of_links--;
|
||||||
|
LOG(3, s, 0, "MPPP: Dropping member link: %d from bundle %d\n",s,b);
|
||||||
|
if (bundle[b].num_of_links == 0)
|
||||||
|
{
|
||||||
|
bundleclear(b);
|
||||||
|
LOG(3, s, 0, "MPPP: Kill bundle: %d (No remaing member links)\n",b);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Adjust the members array to accomodate the new change
|
||||||
|
uint8_t mem_num = 0;
|
||||||
|
// It should be here num_of_links instead of num_of_links-1 (previous instruction "num_of_links--")
|
||||||
|
if (bundle[b].members[bundle[b].num_of_links] != s)
|
||||||
|
{
|
||||||
|
uint8_t ml;
|
||||||
|
for (ml = 0; ml<bundle[b].num_of_links; ml++)
|
||||||
|
{
|
||||||
|
if (bundle[b].members[ml] == s)
|
||||||
|
{
|
||||||
|
mem_num = ml;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bundle[b].members[mem_num] = bundle[b].members[bundle[b].num_of_links];
|
||||||
|
LOG(3, s, 0, "MPPP: Adjusted member links array\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cluster_send_bundle(b);
|
||||||
|
}
|
||||||
sessionclear(s);
|
sessionclear(s);
|
||||||
cluster_send_session(s);
|
cluster_send_session(s);
|
||||||
}
|
}
|
||||||
|
|
@ -1764,6 +1886,13 @@ static void tunnelclear(tunnelidt t)
|
||||||
tunnel[t].state = TUNNELFREE;
|
tunnel[t].state = TUNNELFREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bundleclear(bundleidt b)
|
||||||
|
{
|
||||||
|
if (!b) return;
|
||||||
|
memset(&bundle[b], 0, sizeof(bundle[b]));
|
||||||
|
bundle[b].state = BUNDLEFREE;
|
||||||
|
}
|
||||||
|
|
||||||
// kill a tunnel now
|
// kill a tunnel now
|
||||||
static void tunnelkill(tunnelidt t, char *reason)
|
static void tunnelkill(tunnelidt t, char *reason)
|
||||||
{
|
{
|
||||||
|
|
@ -2556,6 +2685,11 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
|
||||||
// start LCP
|
// start LCP
|
||||||
sess_local[s].lcp_authtype = config->radius_authprefer;
|
sess_local[s].lcp_authtype = config->radius_authprefer;
|
||||||
sess_local[s].ppp_mru = MRU;
|
sess_local[s].ppp_mru = MRU;
|
||||||
|
|
||||||
|
// Set multilink options before sending initial LCP packet
|
||||||
|
sess_local[s].mp_mrru = 1614;
|
||||||
|
sess_local[s].mp_epdis = config->bind_address ? config->bind_address : my_address;
|
||||||
|
|
||||||
sendlcp(s, t);
|
sendlcp(s, t);
|
||||||
change_state(s, lcp, RequestSent);
|
change_state(s, lcp, RequestSent);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2679,6 +2813,23 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
|
||||||
|
|
||||||
processipin(s, t, p, l);
|
processipin(s, t, p, l);
|
||||||
}
|
}
|
||||||
|
else if (proto == PPPMP)
|
||||||
|
{
|
||||||
|
if (session[s].die)
|
||||||
|
{
|
||||||
|
LOG(4, s, t, "Session %d is closing. Don't process PPP packets\n", s);
|
||||||
|
return; // closing session, PPP not processed
|
||||||
|
}
|
||||||
|
|
||||||
|
session[s].last_packet = time_now;
|
||||||
|
if (session[s].walled_garden && !config->cluster_iam_master)
|
||||||
|
{
|
||||||
|
master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processmpin(s, t, p, l);
|
||||||
|
}
|
||||||
else if (proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0])
|
else if (proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0])
|
||||||
{
|
{
|
||||||
if (session[s].die)
|
if (session[s].die)
|
||||||
|
|
@ -2873,6 +3024,37 @@ static void regular_cleanups(double period)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for timed out sessions
|
||||||
|
if (session[s].timeout)
|
||||||
|
{
|
||||||
|
bundleidt bid = session[s].bundle;
|
||||||
|
if (bid)
|
||||||
|
{
|
||||||
|
clockt curr_time = time_now;
|
||||||
|
if (curr_time - bundle[bid].last_check >= 1)
|
||||||
|
{
|
||||||
|
bundle[bid].online_time += (curr_time-bundle[bid].last_check)*bundle[bid].num_of_links;
|
||||||
|
bundle[bid].last_check = curr_time;
|
||||||
|
if (bundle[bid].online_time >= session[s].timeout)
|
||||||
|
{
|
||||||
|
int ses;
|
||||||
|
for (ses = bundle[bid].num_of_links - 1; ses >= 0; ses--)
|
||||||
|
{
|
||||||
|
sessionshutdown(bundle[bid].members[ses], "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
|
||||||
|
s_actions++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (session[s].timeout <= time_now - session[s].opened)
|
||||||
|
{
|
||||||
|
sessionshutdown(s, "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
|
||||||
|
s_actions++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PPP timeouts
|
// PPP timeouts
|
||||||
if (sess_local[s].lcp.restart <= time_now)
|
if (sess_local[s].lcp.restart <= time_now)
|
||||||
{
|
{
|
||||||
|
|
@ -2999,7 +3181,7 @@ static void regular_cleanups(double period)
|
||||||
{
|
{
|
||||||
uint8_t b[MAXETHER];
|
uint8_t b[MAXETHER];
|
||||||
|
|
||||||
uint8_t *q = makeppp(b, sizeof(b), 0, 0, s, session[s].tunnel, PPPLCP);
|
uint8_t *q = makeppp(b, sizeof(b), 0, 0, s, session[s].tunnel, PPPLCP, 1, 0, 0);
|
||||||
if (!q) continue;
|
if (!q) continue;
|
||||||
|
|
||||||
*q = EchoReq;
|
*q = EchoReq;
|
||||||
|
|
@ -3714,6 +3896,16 @@ static void initdata(int optdebug, char *optconfig)
|
||||||
LOG(0, 0, 0, "Error doing malloc for tunnels: %s\n", strerror(errno));
|
LOG(0, 0, 0, "Error doing malloc for tunnels: %s\n", strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
if (!(bundle = shared_malloc(sizeof(bundlet) * MAXBUNDLE)))
|
||||||
|
{
|
||||||
|
LOG(0, 0, 0, "Error doing malloc for bundles: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!(frag = shared_malloc(sizeof(fragmentationt) * MAXBUNDLE)))
|
||||||
|
{
|
||||||
|
LOG(0, 0, 0, "Error doing malloc for fragmentations: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (!(session = shared_malloc(sizeof(sessiont) * MAXSESSION)))
|
if (!(session = shared_malloc(sizeof(sessiont) * MAXSESSION)))
|
||||||
{
|
{
|
||||||
LOG(0, 0, 0, "Error doing malloc for sessions: %s\n", strerror(errno));
|
LOG(0, 0, 0, "Error doing malloc for sessions: %s\n", strerror(errno));
|
||||||
|
|
@ -3760,6 +3952,7 @@ static void initdata(int optdebug, char *optconfig)
|
||||||
memset(cli_tunnel_actions, 0, sizeof(struct cli_tunnel_actions) * MAXSESSION);
|
memset(cli_tunnel_actions, 0, sizeof(struct cli_tunnel_actions) * MAXSESSION);
|
||||||
|
|
||||||
memset(tunnel, 0, sizeof(tunnelt) * MAXTUNNEL);
|
memset(tunnel, 0, sizeof(tunnelt) * MAXTUNNEL);
|
||||||
|
memset(bundle, 0, sizeof(bundlet) * MAXBUNDLE);
|
||||||
memset(session, 0, sizeof(sessiont) * MAXSESSION);
|
memset(session, 0, sizeof(sessiont) * MAXSESSION);
|
||||||
memset(radius, 0, sizeof(radiust) * MAXRADIUS);
|
memset(radius, 0, sizeof(radiust) * MAXRADIUS);
|
||||||
memset(ip_address_pool, 0, sizeof(ippoolt) * MAXIPPOOL);
|
memset(ip_address_pool, 0, sizeof(ippoolt) * MAXIPPOOL);
|
||||||
|
|
@ -3777,6 +3970,10 @@ static void initdata(int optdebug, char *optconfig)
|
||||||
for (i = 1; i < MAXTUNNEL; i++)
|
for (i = 1; i < MAXTUNNEL; i++)
|
||||||
tunnel[i].state = TUNNELUNDEF; // mark it as not filled in.
|
tunnel[i].state = TUNNELUNDEF; // mark it as not filled in.
|
||||||
|
|
||||||
|
for (i = 1; i < MAXBUNDLE; i++) {
|
||||||
|
bundle[i].state = BUNDLEUNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
if (!*hostname)
|
if (!*hostname)
|
||||||
{
|
{
|
||||||
// Grab my hostname unless it's been specified
|
// Grab my hostname unless it's been specified
|
||||||
|
|
@ -4601,6 +4798,14 @@ int sessionsetup(sessionidt s, tunnelidt t)
|
||||||
// Make sure this is right
|
// Make sure this is right
|
||||||
session[s].tunnel = t;
|
session[s].tunnel = t;
|
||||||
|
|
||||||
|
// Join a bundle if the MRRU option is accepted
|
||||||
|
if (session[s].mrru > 0 && !session[s].bundle)
|
||||||
|
{
|
||||||
|
LOG(3, s, t, "This session can be part of multilink bundle\n");
|
||||||
|
if (join_bundle(s))
|
||||||
|
cluster_send_bundle(session[s].bundle);
|
||||||
|
}
|
||||||
|
|
||||||
// zap old sessions with same IP and/or username
|
// zap old sessions with same IP and/or username
|
||||||
// Don't kill gardened sessions - doing so leads to a DoS
|
// Don't kill gardened sessions - doing so leads to a DoS
|
||||||
// from someone who doesn't need to know the password
|
// from someone who doesn't need to know the password
|
||||||
|
|
@ -4617,8 +4822,21 @@ int sessionsetup(sessionidt s, tunnelidt t)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->allow_duplicate_users) continue;
|
if (config->allow_duplicate_users)
|
||||||
if (session[s].walled_garden || session[i].walled_garden) continue;
|
continue;
|
||||||
|
|
||||||
|
if (session[s].walled_garden || session[i].walled_garden)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allow duplicate sessions for guest account.
|
||||||
|
if (*config->guest_user && !strcasecmp(user, config->guest_user))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allow duplicate sessions for multilink ones of the same bundle.
|
||||||
|
if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Drop the new session in case of duplicate sessionss, not the old one.
|
||||||
if (!strcasecmp(user, session[i].user))
|
if (!strcasecmp(user, session[i].user))
|
||||||
sessionkill(i, "Duplicate session for users");
|
sessionkill(i, "Duplicate session for users");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
103
l2tpns.h
103
l2tpns.h
|
|
@ -1,5 +1,5 @@
|
||||||
// L2TPNS Global Stuff
|
// L2TPNS Global Stuff
|
||||||
// $Id: l2tpns.h,v 1.114 2006-04-23 23:18:32 bodea Exp $
|
// $Id: l2tpns.h,v 1.115 2006-04-27 09:53:50 bodea Exp $
|
||||||
|
|
||||||
#ifndef __L2TPNS_H__
|
#ifndef __L2TPNS_H__
|
||||||
#define __L2TPNS_H__
|
#define __L2TPNS_H__
|
||||||
|
|
@ -14,10 +14,15 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <libcli.h>
|
#include <libcli.h>
|
||||||
|
|
||||||
#define VERSION "2.1.19"
|
#define VERSION "2.2.0"
|
||||||
|
|
||||||
// Limits
|
// Limits
|
||||||
#define MAXTUNNEL 500 // could be up to 65535
|
#define MAXTUNNEL 500 // could be up to 65535
|
||||||
|
#define MAXBUNDLE 300 // could be up to 65535
|
||||||
|
#define MAXBUNDLESES 10 // Maximum number of member links in bundle
|
||||||
|
#define MAXADDRESS 20 // Maximum length for the Endpoint Discrminiator address
|
||||||
|
#define MAXFRAGNUM 1500 // Maximum number of Multilink fragment in a bundle
|
||||||
|
#define MAXFRAGLEN 1000 // Maximum length for Multilink fragment
|
||||||
#define MAXSESSION 60000 // could be up to 65535
|
#define MAXSESSION 60000 // could be up to 65535
|
||||||
#define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session.
|
#define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session.
|
||||||
|
|
||||||
|
|
@ -43,10 +48,16 @@
|
||||||
#define MAXIPPOOL 131072 // max number of ip addresses in pool
|
#define MAXIPPOOL 131072 // max number of ip addresses in pool
|
||||||
#define RINGBUFFER_SIZE 10000 // Number of ringbuffer entries to allocate
|
#define RINGBUFFER_SIZE 10000 // Number of ringbuffer entries to allocate
|
||||||
#define MAX_LOG_LENGTH 512 // Maximum size of log message
|
#define MAX_LOG_LENGTH 512 // Maximum size of log message
|
||||||
#define ECHO_TIMEOUT 60 // Time between last packet sent and LCP ECHO generation
|
#define ECHO_TIMEOUT 10 // Time between last packet sent and LCP ECHO generation
|
||||||
#define IDLE_TIMEOUT 240 // Time between last packet sent and LCP ECHO generation
|
#define IDLE_TIMEOUT 240 // Time between last packet sent and LCP ECHO generation
|
||||||
#define BUSY_WAIT_TIME 3000 // 5 minutes in 1/10th seconds to wait for radius to cleanup on shutdown
|
#define BUSY_WAIT_TIME 3000 // 5 minutes in 1/10th seconds to wait for radius to cleanup on shutdown
|
||||||
|
|
||||||
|
#define MP_BEGIN 0x80 // This value is used when (b)egin bit is set in MP header
|
||||||
|
#define MP_END 0x40 // This value is used when (e)nd bit is set in MP header
|
||||||
|
#define MP_BOTH_BITS 0xC0 // This value is used when both bits (begin and end) are set in MP header
|
||||||
|
|
||||||
|
#define DEFAULT_EPDIS_ADDRESS "L2TPNetServer" // Company name may goes here!
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
#ifndef ETCDIR
|
#ifndef ETCDIR
|
||||||
#define ETCDIR "/etc/l2tpns"
|
#define ETCDIR "/etc/l2tpns"
|
||||||
|
|
@ -186,6 +197,7 @@ enum {
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
typedef uint16_t sessionidt;
|
typedef uint16_t sessionidt;
|
||||||
|
typedef uint16_t bundleidt;
|
||||||
typedef uint16_t tunnelidt;
|
typedef uint16_t tunnelidt;
|
||||||
typedef uint32_t clockt;
|
typedef uint32_t clockt;
|
||||||
typedef uint8_t hasht[16];
|
typedef uint8_t hasht[16];
|
||||||
|
|
@ -231,6 +243,17 @@ typedef struct controls // control message
|
||||||
}
|
}
|
||||||
controlt;
|
controlt;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t length; // Endpoint Discriminator length
|
||||||
|
uint8_t addr_class; // Endpoint Discriminator class
|
||||||
|
uint8_t address[MAXADDRESS]; // Endpoint Discriminator address
|
||||||
|
} epdist;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t length; // Fragment length
|
||||||
|
uint8_t data[MAXFRAGLEN]; // Fragment data
|
||||||
|
} fragmentt;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
sessionidt next; // next session in linked list
|
sessionidt next; // next session in linked list
|
||||||
|
|
@ -273,6 +296,11 @@ typedef struct
|
||||||
char calling[MAXTEL]; // calling number
|
char calling[MAXTEL]; // calling number
|
||||||
uint32_t tx_connect_speed;
|
uint32_t tx_connect_speed;
|
||||||
uint32_t rx_connect_speed;
|
uint32_t rx_connect_speed;
|
||||||
|
clockt timeout; // Session timeout
|
||||||
|
uint32_t mrru; // Multilink Max-Receive-Reconstructed-Unit
|
||||||
|
uint8_t mssf; // Multilink Short Sequence Number Header Format
|
||||||
|
epdist epdis; // Multilink Endpoint Discriminator
|
||||||
|
bundleidt bundle; // Multilink Bundle Identifier
|
||||||
in_addr_t snoop_ip; // Interception destination IP
|
in_addr_t snoop_ip; // Interception destination IP
|
||||||
uint16_t snoop_port; // Interception destination port
|
uint16_t snoop_port; // Interception destination port
|
||||||
uint8_t walled_garden; // is this session gardened?
|
uint8_t walled_garden; // is this session gardened?
|
||||||
|
|
@ -282,6 +310,33 @@ typedef struct
|
||||||
}
|
}
|
||||||
sessiont;
|
sessiont;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int state; // current state (bundlestate enum)
|
||||||
|
uint32_t seq_num_t; // Sequence Number (transmission)
|
||||||
|
uint32_t seq_num_m; // Last received frame sequence number (bearing B bit)
|
||||||
|
uint32_t offset; // Offset between sequence number and array index
|
||||||
|
uint8_t pending_frag; // Indicate that there is pending fragments to reassemble
|
||||||
|
uint8_t num_of_links; // Number of links joint to this bundle
|
||||||
|
uint32_t online_time; // The time this bundle is online
|
||||||
|
clockt last_check; // Last time the timeout is checked
|
||||||
|
uint32_t mrru; // Multilink Max-Receive-Reconstructed-Unit
|
||||||
|
uint8_t mssf; // Multilink Short Sequence Number Header Format
|
||||||
|
epdist epdis; // Multilink Endpoint Discriminator
|
||||||
|
char user[MAXUSER]; // Needed for matching member links
|
||||||
|
sessionidt current_ses; // Current session to use for sending (used in RR load-balancing)
|
||||||
|
sessionidt members[MAXBUNDLESES]; // Array for member links sessions
|
||||||
|
}
|
||||||
|
bundlet;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
fragmentt fragment[MAXFRAGNUM];
|
||||||
|
uint8_t reassembled_frame[MAXETHER]; // The reassembled frame
|
||||||
|
uint16_t re_frame_len; // The reassembled frame length
|
||||||
|
}
|
||||||
|
fragmentationt;
|
||||||
|
|
||||||
#define AUTHPAP 1 // allow PAP
|
#define AUTHPAP 1 // allow PAP
|
||||||
#define AUTHCHAP 2 // allow CHAP
|
#define AUTHCHAP 2 // allow CHAP
|
||||||
|
|
||||||
|
|
@ -311,6 +366,15 @@ typedef struct
|
||||||
// our MRU
|
// our MRU
|
||||||
uint16_t ppp_mru;
|
uint16_t ppp_mru;
|
||||||
|
|
||||||
|
// our MRRU
|
||||||
|
uint16_t mp_mrru;
|
||||||
|
|
||||||
|
// our mssf
|
||||||
|
uint16_t mp_mssf;
|
||||||
|
|
||||||
|
// our Endpoint Discriminator
|
||||||
|
in_addr_t mp_epdis;
|
||||||
|
|
||||||
// DoS prevention
|
// DoS prevention
|
||||||
clockt last_packet_out;
|
clockt last_packet_out;
|
||||||
uint32_t packets_out;
|
uint32_t packets_out;
|
||||||
|
|
@ -407,6 +471,23 @@ enum
|
||||||
TUNNELUNDEF, // Undefined
|
TUNNELUNDEF, // Undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
BUNDLEFREE, // Not in use
|
||||||
|
BUNDLEOPEN, // Active bundle
|
||||||
|
BUNDLEUNDEF, // Undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NULLCLASS = 0, //End Point Discriminator classes
|
||||||
|
LOCALADDR,
|
||||||
|
IPADDR,
|
||||||
|
IEEEMACADDR,
|
||||||
|
PPPMAGIC,
|
||||||
|
PSNDN,
|
||||||
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
RADIUSNULL, // Not in use
|
RADIUSNULL, // Not in use
|
||||||
|
|
@ -561,6 +642,7 @@ typedef struct
|
||||||
int radius_authprefer;
|
int radius_authprefer;
|
||||||
|
|
||||||
int allow_duplicate_users; // allow multiple logins with the same username
|
int allow_duplicate_users; // allow multiple logins with the same username
|
||||||
|
char guest_user[MAXUSER]; // allow multiple logins to guest account username
|
||||||
|
|
||||||
in_addr_t default_dns1, default_dns2;
|
in_addr_t default_dns1, default_dns2;
|
||||||
|
|
||||||
|
|
@ -583,6 +665,7 @@ typedef struct
|
||||||
int lock_pages; // Lock pages into memory.
|
int lock_pages; // Lock pages into memory.
|
||||||
int icmp_rate; // Max number of ICMP unreachable per second to send
|
int icmp_rate; // Max number of ICMP unreachable per second to send
|
||||||
int max_packets; // DoS prevention: per session limit of packets/0.1s
|
int max_packets; // DoS prevention: per session limit of packets/0.1s
|
||||||
|
char epdis_addr[20]; // MP Endpoint Discriminator address
|
||||||
|
|
||||||
in_addr_t cluster_address; // Multicast address of cluster.
|
in_addr_t cluster_address; // Multicast address of cluster.
|
||||||
// Send to this address to have everyone hear.
|
// Send to this address to have everyone hear.
|
||||||
|
|
@ -594,8 +677,10 @@ typedef struct
|
||||||
int cluster_seq_number; // Sequence number of the next heartbeat we'll send out
|
int cluster_seq_number; // Sequence number of the next heartbeat we'll send out
|
||||||
// (or the seq number we're next expecting if we're a slave).
|
// (or the seq number we're next expecting if we're a slave).
|
||||||
int cluster_undefined_sessions; // How many sessions we're yet to receive from the master.
|
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_tunnels; // How many tunnels we're yet to receive from the master.
|
||||||
int cluster_highest_sessionid;
|
int cluster_highest_sessionid;
|
||||||
|
int cluster_highest_bundleid;
|
||||||
int cluster_highest_tunnelid;
|
int cluster_highest_tunnelid;
|
||||||
clockt cluster_last_hb; // Last time we saw a heartbeat from the master.
|
clockt cluster_last_hb; // Last time we saw a heartbeat from the master.
|
||||||
int cluster_last_hb_ver; // Heartbeat version last seen from master
|
int cluster_last_hb_ver; // Heartbeat version last seen from master
|
||||||
|
|
@ -605,13 +690,11 @@ typedef struct
|
||||||
int cluster_hb_interval; // How often to send a heartbeat.
|
int cluster_hb_interval; // How often to send a heartbeat.
|
||||||
int cluster_hb_timeout; // How many missed heartbeats trigger an election.
|
int cluster_hb_timeout; // How many missed heartbeats trigger an election.
|
||||||
uint64_t cluster_table_version; // # state changes processed by cluster
|
uint64_t cluster_table_version; // # state changes processed by cluster
|
||||||
|
|
||||||
struct in6_addr ipv6_prefix; // Our IPv6 network pool.
|
|
||||||
|
|
||||||
|
|
||||||
int cluster_master_min_adv; // Master advertises routes while the number of up to date
|
int cluster_master_min_adv; // Master advertises routes while the number of up to date
|
||||||
// slaves is less than this value.
|
// slaves is less than this value.
|
||||||
|
|
||||||
|
struct in6_addr ipv6_prefix; // Our IPv6 network pool.
|
||||||
|
|
||||||
#ifdef BGP
|
#ifdef BGP
|
||||||
#define BGP_NUM_PEERS 2
|
#define BGP_NUM_PEERS 2
|
||||||
uint16_t as_number;
|
uint16_t as_number;
|
||||||
|
|
@ -727,14 +810,17 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
||||||
void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
||||||
void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
||||||
void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
||||||
|
void processmpin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
||||||
|
void processmpframe(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint8_t extra);
|
||||||
void processipv6in(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
void processipv6in(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
||||||
void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
|
||||||
void sendchap(sessionidt s, tunnelidt t);
|
void sendchap(sessionidt s, tunnelidt t);
|
||||||
uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, sessionidt s, tunnelidt t, uint16_t mtype);
|
uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, sessionidt s, tunnelidt t, uint16_t mtype, uint8_t prio, bundleidt bid, uint8_t mp_bits);
|
||||||
void sendlcp(sessionidt s, tunnelidt t);
|
void sendlcp(sessionidt s, tunnelidt t);
|
||||||
void send_ipin(sessionidt s, uint8_t *buf, int len);
|
void send_ipin(sessionidt s, uint8_t *buf, int len);
|
||||||
void sendccp(sessionidt s, tunnelidt t);
|
void sendccp(sessionidt s, tunnelidt t);
|
||||||
void protoreject(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint16_t proto);
|
void protoreject(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint16_t proto);
|
||||||
|
int join_bundle(sessionidt s);
|
||||||
|
|
||||||
|
|
||||||
// radius.c
|
// radius.c
|
||||||
|
|
@ -802,6 +888,7 @@ void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, uint
|
||||||
|
|
||||||
|
|
||||||
extern tunnelt *tunnel;
|
extern tunnelt *tunnel;
|
||||||
|
extern bundlet *bundle;
|
||||||
extern sessiont *session;
|
extern sessiont *session;
|
||||||
extern sessionlocalt *sess_local;
|
extern sessionlocalt *sess_local;
|
||||||
extern ippoolt *ip_address_pool;
|
extern ippoolt *ip_address_pool;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Summary: A high-speed clustered L2TP LNS
|
Summary: A high-speed clustered L2TP LNS
|
||||||
Name: l2tpns
|
Name: l2tpns
|
||||||
Version: 2.1.19
|
Version: 2.2.0
|
||||||
Release: 1
|
Release: 1
|
||||||
License: GPL
|
License: GPL
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
|
@ -43,5 +43,5 @@ rm -rf %{buildroot}
|
||||||
%attr(644,root,root) /usr/share/man/man[58]/*
|
%attr(644,root,root) /usr/share/man/man[58]/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Tue Apr 25 2006 Brendan O'Dea <bod@optus.net> 2.1.19-1
|
* Thu Apr 27 2006 Brendan O'Dea <bod@optus.net> 2.2.0-1
|
||||||
- 2.1.19 release, see /usr/share/doc/l2tpns-2.1.19/Changes
|
- 2.2.0 release, see /usr/share/doc/l2tpns-2.2.0/Changes
|
||||||
|
|
|
||||||
513
ppp.c
513
ppp.c
|
|
@ -1,6 +1,6 @@
|
||||||
// L2TPNS PPP Stuff
|
// L2TPNS PPP Stuff
|
||||||
|
|
||||||
char const *cvs_id_ppp = "$Id: ppp.c,v 1.99 2006-04-18 06:00:08 bodea Exp $";
|
char const *cvs_id_ppp = "$Id: ppp.c,v 1.100 2006-04-27 09:53:50 bodea Exp $";
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -15,6 +15,8 @@ char const *cvs_id_ppp = "$Id: ppp.c,v 1.99 2006-04-18 06:00:08 bodea Exp $";
|
||||||
#include "cluster.h"
|
#include "cluster.h"
|
||||||
|
|
||||||
extern tunnelt *tunnel;
|
extern tunnelt *tunnel;
|
||||||
|
extern bundlet *bundle;
|
||||||
|
extern fragmentationt *frag;
|
||||||
extern sessiont *session;
|
extern sessiont *session;
|
||||||
extern radiust *radius;
|
extern radiust *radius;
|
||||||
extern int tunfd;
|
extern int tunfd;
|
||||||
|
|
@ -24,6 +26,10 @@ extern time_t time_now;
|
||||||
extern configt *config;
|
extern configt *config;
|
||||||
|
|
||||||
static int add_lcp_auth(uint8_t *b, int size, int authtype);
|
static int add_lcp_auth(uint8_t *b, int size, int authtype);
|
||||||
|
static bundleidt new_bundle(void);
|
||||||
|
static int epdiscmp(epdist, epdist);
|
||||||
|
static void setepdis(epdist *, epdist);
|
||||||
|
static void ipcp_open(sessionidt s, tunnelidt t);
|
||||||
|
|
||||||
// Process PAP messages
|
// Process PAP messages
|
||||||
void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
|
|
@ -90,7 +96,7 @@ void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
// respond now, either no RADIUS available or already authenticated
|
// respond now, either no RADIUS available or already authenticated
|
||||||
uint8_t b[MAXETHER];
|
uint8_t b[MAXETHER];
|
||||||
uint8_t id = p[1];
|
uint8_t id = p[1];
|
||||||
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPPAP);
|
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPPAP, 0, 0, 0);
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
|
|
||||||
if (session[s].ip)
|
if (session[s].ip)
|
||||||
|
|
@ -351,6 +357,18 @@ void lcp_open(sessionidt s, tunnelidt t)
|
||||||
sendchap(s, t);
|
sendchap(s, t);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (session[s].bundle && bundle[session[s].bundle].num_of_links > 1)
|
||||||
|
{
|
||||||
|
sessionidt first_ses = bundle[session[s].bundle].members[0];
|
||||||
|
LOG(3, s, t, "MPPP: Skipping IPCP negotiation for session:%d, first session of bundle is:%d\n", s, first_ses);
|
||||||
|
session[s].ip = session[first_ses].ip;
|
||||||
|
session[s].dns1 = session[first_ses].dns1;
|
||||||
|
session[s].dns2 = session[first_ses].dns2;
|
||||||
|
session[s].timeout = session[first_ses].timeout;
|
||||||
|
ipcp_open(s, t);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// This-Layer-Up
|
// This-Layer-Up
|
||||||
sendipcp(s, t);
|
sendipcp(s, t);
|
||||||
|
|
@ -363,6 +381,7 @@ void lcp_open(sessionidt s, tunnelidt t)
|
||||||
|
|
||||||
change_state(s, ccp, Stopped);
|
change_state(s, ccp, Stopped);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcp_restart(sessionidt s)
|
static void lcp_restart(sessionidt s)
|
||||||
|
|
@ -379,7 +398,7 @@ static uint8_t *ppp_conf_rej(sessionidt s, uint8_t *buf, size_t blen, uint16_t m
|
||||||
{
|
{
|
||||||
if (!*response || **response != ConfigRej)
|
if (!*response || **response != ConfigRej)
|
||||||
{
|
{
|
||||||
queued = *response = makeppp(buf, blen, packet, 2, s, session[s].tunnel, mtype);
|
queued = *response = makeppp(buf, blen, packet, 2, s, session[s].tunnel, mtype, 0, 0, 0);
|
||||||
if (!queued)
|
if (!queued)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -423,7 +442,7 @@ static uint8_t *ppp_conf_nak(sessionidt s, uint8_t *buf, size_t blen, uint16_t m
|
||||||
if (*nak_sent >= config->ppp_max_failure)
|
if (*nak_sent >= config->ppp_max_failure)
|
||||||
return ppp_conf_rej(s, buf, blen, mtype, response, 0, packet, option);
|
return ppp_conf_rej(s, buf, blen, mtype, response, 0, packet, option);
|
||||||
|
|
||||||
queued = *response = makeppp(buf, blen, packet, 2, s, session[s].tunnel, mtype);
|
queued = *response = makeppp(buf, blen, packet, 2, s, session[s].tunnel, mtype, 0, 0, 0);
|
||||||
if (!queued)
|
if (!queued)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -455,7 +474,7 @@ static void ppp_code_rej(sessionidt s, tunnelidt t, uint16_t proto,
|
||||||
l += 4;
|
l += 4;
|
||||||
if (l > mru) l = mru;
|
if (l > mru) l = mru;
|
||||||
|
|
||||||
q = makeppp(buf, size, 0, 0, s, t, proto);
|
q = makeppp(buf, size, 0, 0, s, t, proto, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
*q = CodeRej;
|
*q = CodeRej;
|
||||||
|
|
@ -567,6 +586,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
uint8_t *response = 0;
|
uint8_t *response = 0;
|
||||||
static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero
|
static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero
|
||||||
static uint8_t authproto[5];
|
static uint8_t authproto[5];
|
||||||
|
int changed = 0;
|
||||||
|
|
||||||
while (x > 2)
|
while (x > 2)
|
||||||
{
|
{
|
||||||
|
|
@ -582,7 +602,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
if (mru >= MINMTU)
|
if (mru >= MINMTU)
|
||||||
{
|
{
|
||||||
session[s].mru = mru;
|
session[s].mru = mru;
|
||||||
cluster_send_session(s);
|
changed++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -655,6 +675,64 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
case 8: // Address-And-Control-Field-Compression
|
case 8: // Address-And-Control-Field-Compression
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 17: // Multilink Max-Receive-Reconstructed-Unit
|
||||||
|
{
|
||||||
|
uint16_t mrru = ntohs(*(uint16_t *)(o + 2));
|
||||||
|
session[s].mrru = mrru;
|
||||||
|
changed++;
|
||||||
|
LOG(3, s, t, " Received PPP LCP option MRRU: %d\n",mrru);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 18: // Multilink Short Sequence Number Header Format
|
||||||
|
{
|
||||||
|
session[s].mssf = 1;
|
||||||
|
changed++;
|
||||||
|
LOG(3, s, t, " Received PPP LCP option MSSN format\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 19: // Multilink Endpoint Discriminator
|
||||||
|
{
|
||||||
|
uint8_t epdis_class = o[2];
|
||||||
|
int addr;
|
||||||
|
|
||||||
|
session[s].epdis.addr_class = epdis_class;
|
||||||
|
session[s].epdis.length = length - 3;
|
||||||
|
if (session[s].epdis.length > 20)
|
||||||
|
{
|
||||||
|
LOG(1, s, t, "Error: received EndDis Address Length more than 20: %d\n", session[s].epdis.length);
|
||||||
|
session[s].epdis.length = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (addr = 0; addr < session[s].epdis.length; addr++)
|
||||||
|
session[s].epdis.address[addr] = o[3+addr];
|
||||||
|
|
||||||
|
changed++;
|
||||||
|
|
||||||
|
switch (epdis_class)
|
||||||
|
{
|
||||||
|
case LOCALADDR:
|
||||||
|
LOG(3, s, t, " Received PPP LCP option Multilink EndDis Local Address Class: %d\n",epdis_class);
|
||||||
|
break;
|
||||||
|
case IPADDR:
|
||||||
|
LOG(3, s, t, " Received PPP LCP option Multilink EndDis IP Address Class: %d\n",epdis_class);
|
||||||
|
break;
|
||||||
|
case IEEEMACADDR:
|
||||||
|
LOG(3, s, t, " Received PPP LCP option Multilink EndDis IEEE MAC Address Class: %d\n",epdis_class);
|
||||||
|
break;
|
||||||
|
case PPPMAGIC:
|
||||||
|
LOG(3, s, t, " Received PPP LCP option Multilink EndDis PPP Magic No Class: %d\n",epdis_class);
|
||||||
|
break;
|
||||||
|
case PSNDN:
|
||||||
|
LOG(3, s, t, " Received PPP LCP option Multilink EndDis PSND No Class: %d\n",epdis_class);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG(3, s, t, " Received PPP LCP option Multilink EndDis NULL Class %d\n",epdis_class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default: // Reject any unknown options
|
default: // Reject any unknown options
|
||||||
LOG(3, s, t, " Rejecting unknown PPP LCP option %d\n", type);
|
LOG(3, s, t, " Rejecting unknown PPP LCP option %d\n", type);
|
||||||
q = ppp_conf_rej(s, b, sizeof(b), PPPLCP, &response, q, p, o);
|
q = ppp_conf_rej(s, b, sizeof(b), PPPLCP, &response, q, p, o);
|
||||||
|
|
@ -663,6 +741,9 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
o += length;
|
o += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
cluster_send_session(s);
|
||||||
|
|
||||||
if (response)
|
if (response)
|
||||||
{
|
{
|
||||||
l = q - response; // LCP packet length
|
l = q - response; // LCP packet length
|
||||||
|
|
@ -671,7 +752,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Send packet back as ConfigAck
|
// Send packet back as ConfigAck
|
||||||
response = makeppp(b, sizeof(b), p, l, s, t, PPPLCP);
|
response = makeppp(b, sizeof(b), p, l, s, t, PPPLCP, 0, 0, 0);
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
*response = ConfigAck;
|
*response = ConfigAck;
|
||||||
}
|
}
|
||||||
|
|
@ -679,7 +760,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
switch (session[s].ppp.lcp)
|
switch (session[s].ppp.lcp)
|
||||||
{
|
{
|
||||||
case Closed:
|
case Closed:
|
||||||
response = makeppp(b, sizeof(b), p, 2, s, t, PPPLCP);
|
response = makeppp(b, sizeof(b), p, 2, s, t, PPPLCP, 0, 0, 0);
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
*response = TerminateAck;
|
*response = TerminateAck;
|
||||||
*((uint16_t *) (response + 2)) = htons(l = 4);
|
*((uint16_t *) (response + 2)) = htons(l = 4);
|
||||||
|
|
@ -812,6 +893,50 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
cluster_send_session(s);
|
cluster_send_session(s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 17: // Multilink Max-Receive-Reconstructed-Unit
|
||||||
|
{
|
||||||
|
if (*p == ConfigNak)
|
||||||
|
{
|
||||||
|
sess_local[s].mp_mrru = ntohs(*(uint16_t *)(o + 2));
|
||||||
|
LOG(3, s, t, " Remote requested MRRU of %u\n", sess_local[s].mp_mrru);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sess_local[s].mp_mrru = 0;
|
||||||
|
LOG(3, s, t, " Remote rejected MRRU negotiation\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 18: // Multilink Short Sequence Number Header Format
|
||||||
|
{
|
||||||
|
if (*p == ConfigNak)
|
||||||
|
{
|
||||||
|
sess_local[s].mp_mssf = 0;
|
||||||
|
LOG(3, s, t, " Remote requested Naked mssf\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sess_local[s].mp_mssf = 0;
|
||||||
|
LOG(3, s, t, " Remote rejected mssf\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 19: // Multilink Endpoint Discriminator
|
||||||
|
{
|
||||||
|
if (*p == ConfigNak)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, " Remote should not configNak Endpoint Dis!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sess_local[s].mp_epdis = 0;
|
||||||
|
LOG(3, s, t, " Remote rejected Endpoint Discriminator\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG(2, s, t, "LCP: remote sent %s for type %u?\n", ppp_code(*p), type);
|
LOG(2, s, t, "LCP: remote sent %s for type %u?\n", ppp_code(*p), type);
|
||||||
sessionshutdown(s, "Unable to negotiate LCP.", CDN_ADMIN_DISC, TERM_USER_ERROR);
|
sessionshutdown(s, "Unable to negotiate LCP.", CDN_ADMIN_DISC, TERM_USER_ERROR);
|
||||||
|
|
@ -835,7 +960,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
case Closed:
|
case Closed:
|
||||||
case Stopped:
|
case Stopped:
|
||||||
{
|
{
|
||||||
uint8_t *response = makeppp(b, sizeof(b), p, 2, s, t, PPPLCP);
|
uint8_t *response = makeppp(b, sizeof(b), p, 2, s, t, PPPLCP, 0, 0, 0);
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
*response = TerminateAck;
|
*response = TerminateAck;
|
||||||
*((uint16_t *) (response + 2)) = htons(l = 4);
|
*((uint16_t *) (response + 2)) = htons(l = 4);
|
||||||
|
|
@ -893,7 +1018,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
}
|
}
|
||||||
|
|
||||||
*p = TerminateAck; // send ack
|
*p = TerminateAck; // send ack
|
||||||
q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP);
|
q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
LOG(3, s, t, "LCP: send %s\n", ppp_code(*q));
|
LOG(3, s, t, "LCP: send %s\n", ppp_code(*q));
|
||||||
|
|
@ -929,7 +1054,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
{
|
{
|
||||||
*p = EchoReply; // reply
|
*p = EchoReply; // reply
|
||||||
*(uint32_t *) (p + 4) = htonl(session[s].magic); // our magic number
|
*(uint32_t *) (p + 4) = htonl(session[s].magic); // our magic number
|
||||||
q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP);
|
q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
LOG(4, s, t, "LCP: send %s\n", ppp_code(*q));
|
LOG(4, s, t, "LCP: send %s\n", ppp_code(*q));
|
||||||
|
|
@ -947,6 +1072,93 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int join_bundle(sessionidt s)
|
||||||
|
{
|
||||||
|
// Search for a bundle to join
|
||||||
|
bundleidt i;
|
||||||
|
bundleidt b;
|
||||||
|
for (i = 1; i < MAXBUNDLE; i++)
|
||||||
|
{
|
||||||
|
if (bundle[i].state != BUNDLEFREE)
|
||||||
|
{
|
||||||
|
if (epdiscmp(session[s].epdis,bundle[i].epdis) && !strcmp(session[s].user, bundle[i].user))
|
||||||
|
{
|
||||||
|
session[s].bundle = i;
|
||||||
|
bundle[i].mrru = session[s].mrru;
|
||||||
|
bundle[i].mssf = session[s].mssf;
|
||||||
|
if (session[s].epdis.length > 0)
|
||||||
|
setepdis(&bundle[i].epdis, session[s].epdis);
|
||||||
|
|
||||||
|
strcpy(bundle[i].user, session[s].user);
|
||||||
|
bundle[i].members[bundle[i].num_of_links] = s;
|
||||||
|
bundle[i].num_of_links++;
|
||||||
|
LOG(3, s, session[s].tunnel, "MPPP: Bundling additional line in bundle (%d), lines:%d\n",i,bundle[i].num_of_links);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No previously created bundle was found for this session, so create a new one
|
||||||
|
if (!(b = new_bundle())) return 0;
|
||||||
|
|
||||||
|
session[s].bundle = b;
|
||||||
|
bundle[b].mrru = session[s].mrru;
|
||||||
|
bundle[b].mssf = session[s].mssf;
|
||||||
|
if (session[s].epdis.length > 0)
|
||||||
|
setepdis(&bundle[b].epdis, session[s].epdis);
|
||||||
|
|
||||||
|
strcpy(bundle[b].user, session[s].user);
|
||||||
|
bundle[b].members[0] = s;
|
||||||
|
LOG(3, s, session[s].tunnel, "MPPP: Created a new bundle (%d)\n", b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int epdiscmp(epdist ep1, epdist ep2)
|
||||||
|
{
|
||||||
|
int ad;
|
||||||
|
if (ep1.length != ep2.length)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ep1.addr_class != ep2.addr_class)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (ad = 0; ad < ep1.length; ad++)
|
||||||
|
if (ep1.address[ad] != ep2.address[ad])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setepdis(epdist *ep1, epdist ep2)
|
||||||
|
{
|
||||||
|
int ad;
|
||||||
|
ep1->length = ep2.length;
|
||||||
|
ep1->addr_class = ep2.addr_class;
|
||||||
|
for (ad = 0; ad < ep2.length; ad++)
|
||||||
|
ep1->address[ad] = ep2.address[ad];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bundleidt new_bundle()
|
||||||
|
{
|
||||||
|
bundleidt i;
|
||||||
|
for (i = 1; i < MAXBUNDLE; i++)
|
||||||
|
{
|
||||||
|
if (bundle[i].state == BUNDLEFREE)
|
||||||
|
{
|
||||||
|
LOG(4, 0, 0, "MPPP: Assigning bundle ID %d\n", i);
|
||||||
|
bundle[i].num_of_links = 1;
|
||||||
|
bundle[i].last_check = time_now; // Initialize last_check value
|
||||||
|
bundle[i].state = BUNDLEOPEN;
|
||||||
|
bundle[i].current_ses = -1; // This is to enforce the first session 0 to be used at first
|
||||||
|
if (i > config->cluster_highest_bundleid)
|
||||||
|
config->cluster_highest_bundleid = i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG(0, 0, 0, "MPPP: Can't find a free bundle! There shouldn't be this many in use!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void ipcp_open(sessionidt s, tunnelidt t)
|
static void ipcp_open(sessionidt s, tunnelidt t)
|
||||||
{
|
{
|
||||||
LOG(3, s, t, "IPCP: Opened, session is now active\n");
|
LOG(3, s, t, "IPCP: Opened, session is now active\n");
|
||||||
|
|
@ -1105,7 +1317,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
else if (gotip)
|
else if (gotip)
|
||||||
{
|
{
|
||||||
// Send packet back as ConfigAck
|
// Send packet back as ConfigAck
|
||||||
response = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP);
|
response = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP, 0, 0, 0);
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
*response = ConfigAck;
|
*response = ConfigAck;
|
||||||
}
|
}
|
||||||
|
|
@ -1119,7 +1331,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
switch (session[s].ppp.ipcp)
|
switch (session[s].ppp.ipcp)
|
||||||
{
|
{
|
||||||
case Closed:
|
case Closed:
|
||||||
response = makeppp(b, sizeof(b), p, 2, s, t, PPPIPCP);
|
response = makeppp(b, sizeof(b), p, 2, s, t, PPPIPCP, 0, 0, 0);
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
*response = TerminateAck;
|
*response = TerminateAck;
|
||||||
*((uint16_t *) (response + 2)) = htons(l = 4);
|
*((uint16_t *) (response + 2)) = htons(l = 4);
|
||||||
|
|
@ -1192,7 +1404,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
}
|
}
|
||||||
|
|
||||||
*p = TerminateAck; // send ack
|
*p = TerminateAck; // send ack
|
||||||
q = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP);
|
q = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
LOG(3, s, t, "IPCP: send %s\n", ppp_code(*q));
|
LOG(3, s, t, "IPCP: send %s\n", ppp_code(*q));
|
||||||
|
|
@ -1326,7 +1538,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
else if (gotip)
|
else if (gotip)
|
||||||
{
|
{
|
||||||
// Send packet back as ConfigAck
|
// Send packet back as ConfigAck
|
||||||
response = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP);
|
response = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP, 0, 0, 0);
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
*response = ConfigAck;
|
*response = ConfigAck;
|
||||||
}
|
}
|
||||||
|
|
@ -1340,7 +1552,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
switch (session[s].ppp.ipv6cp)
|
switch (session[s].ppp.ipv6cp)
|
||||||
{
|
{
|
||||||
case Closed:
|
case Closed:
|
||||||
response = makeppp(b, sizeof(b), p, 2, s, t, PPPIPV6CP);
|
response = makeppp(b, sizeof(b), p, 2, s, t, PPPIPV6CP, 0, 0, 0);
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
*response = TerminateAck;
|
*response = TerminateAck;
|
||||||
*((uint16_t *) (response + 2)) = htons(l = 4);
|
*((uint16_t *) (response + 2)) = htons(l = 4);
|
||||||
|
|
@ -1413,7 +1625,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
}
|
}
|
||||||
|
|
||||||
*p = TerminateAck; // send ack
|
*p = TerminateAck; // send ack
|
||||||
q = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP);
|
q = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
LOG(3, s, t, "IPV6CP: send %s\n", ppp_code(*q));
|
LOG(3, s, t, "IPV6CP: send %s\n", ppp_code(*q));
|
||||||
|
|
@ -1456,12 +1668,15 @@ void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
if (session[s].ppp.phase != Network || session[s].ppp.ipcp != Opened)
|
if (session[s].ppp.phase != Network || session[s].ppp.ipcp != Opened)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!session[s].bundle || bundle[session[s].bundle].num_of_links < 2) // FIXME:
|
||||||
|
{
|
||||||
// no spoof (do sessionbyip to handled statically routed subnets)
|
// no spoof (do sessionbyip to handled statically routed subnets)
|
||||||
if (ip != session[s].ip && sessionbyip(htonl(ip)) != s)
|
if (ip != session[s].ip && sessionbyip(htonl(ip)) != s)
|
||||||
{
|
{
|
||||||
LOG(5, s, t, "Dropping packet with spoofed IP %s\n", fmtaddr(htonl(ip), 0));
|
LOG(4, s, t, "Dropping packet with spoofed IP %s\n", fmtaddr(htonl(ip), 0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// run access-list if any
|
// run access-list if any
|
||||||
if (session[s].filter_in && !ip_filter(p, l, session[s].filter_in - 1))
|
if (session[s].filter_in && !ip_filter(p, l, session[s].filter_in - 1))
|
||||||
|
|
@ -1526,6 +1741,167 @@ void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
INC_STAT(tun_tx_bytes, l);
|
INC_STAT(tun_tx_bytes, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process Multilink PPP packet received
|
||||||
|
void processmpin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
|
{
|
||||||
|
bundleidt b = session[s].bundle;
|
||||||
|
uint8_t begin_frame;
|
||||||
|
uint8_t end_frame;
|
||||||
|
uint32_t seq_num;
|
||||||
|
uint32_t offset;
|
||||||
|
|
||||||
|
if (!b)
|
||||||
|
{
|
||||||
|
LOG(3, s, t, "MPPP: Invalid bundle id: 0\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
begin_frame = (*p & 0x80);
|
||||||
|
end_frame = (*p & 0x40);
|
||||||
|
if (session[s].mssf)
|
||||||
|
{
|
||||||
|
// Get 12 bit for seq number
|
||||||
|
uint16_t short_seq_num = ntohs((*(uint16_t *) p) & 0xFF0F);
|
||||||
|
uint16_t short_seq_num2 = short_seq_num >> 4;
|
||||||
|
p += 2;
|
||||||
|
l -= 2;
|
||||||
|
seq_num = short_seq_num2;
|
||||||
|
// After this point the pointer should be advanced 2 bytes
|
||||||
|
LOG(3, s, t, "MPPP: 12 bits, sequence number: %d, short1: %d, short2: %d\n",seq_num, short_seq_num, short_seq_num2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get 24 bit for seq number
|
||||||
|
p++;
|
||||||
|
seq_num = ntohl((*(uint32_t *) p) & 0xFFFFFF00);
|
||||||
|
seq_num = seq_num >> 8;
|
||||||
|
p += 3;
|
||||||
|
l -= 4;
|
||||||
|
// After this point the pointer should be advanced 4 bytes
|
||||||
|
LOG(4, s, t, "MPPP: 24 bits sequence number:%d\n",seq_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seq_num - bundle[b].offset < 0)
|
||||||
|
{
|
||||||
|
bundle[b].offset = 0;
|
||||||
|
bundle[b].pending_frag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = bundle[b].offset;
|
||||||
|
if (begin_frame)
|
||||||
|
{
|
||||||
|
// Check for previous non-assembled frames
|
||||||
|
int error = 0;
|
||||||
|
if (bundle[b].pending_frag)
|
||||||
|
{
|
||||||
|
uint32_t fn = bundle[b].seq_num_m - offset;
|
||||||
|
uint16_t cur_len;
|
||||||
|
bundle[b].pending_frag = 0;
|
||||||
|
// Check for array indexes
|
||||||
|
if (fn < 0 || fn > MAXFRAGNUM)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "ERROR: Index out of range fn:%d, bundle:%d\n",fn,b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seq_num-offset < 0 || seq_num-offset > MAXFRAGNUM)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "ERROR: Index out of range fn(last):%d, bundle:%d\n",fn,b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
cur_len = 4; // This is set to 4 to leave 4 bytes for function processipin
|
||||||
|
for (fn = bundle[b].seq_num_m - offset; fn < seq_num - offset; fn++)
|
||||||
|
{
|
||||||
|
if (!frag[b].fragment[fn].length)
|
||||||
|
{
|
||||||
|
LOG(4, s, t, "MPPP: Found lost fragment while reassembling frame %d in (%d,%d)\n",fn, bundle[b].seq_num_m-offset, seq_num-offset);
|
||||||
|
error = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_len + frag[b].fragment[fn].length > MAXETHER)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "MPPP: ERROR: very long frame after assembling %d\n", frag[b].fragment[fn].length+cur_len);
|
||||||
|
error = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(frag[b].reassembled_frame+cur_len, frag[b].fragment[fn].data, frag[b].fragment[fn].length);
|
||||||
|
cur_len += frag[b].fragment[fn].length;
|
||||||
|
frag[b].fragment[fn].length = 0; // Indicates that this fragment has been consumed
|
||||||
|
// This is usefull for compression
|
||||||
|
memset(frag[b].fragment[fn].data, 0, sizeof(frag[b].fragment[fn].data));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
frag[b].re_frame_len = cur_len;
|
||||||
|
// Process the resassembled frame
|
||||||
|
LOG(4, s, t, "MPPP: Process the reassembled frame, len=%d\n",cur_len);
|
||||||
|
processmpframe(s, t, frag[b].reassembled_frame, frag[b].re_frame_len, 1);
|
||||||
|
// Set reassembled frame length to zero after processing it
|
||||||
|
frag[b].re_frame_len = 0;
|
||||||
|
memset(frag[b].reassembled_frame, 0, sizeof(frag[b].reassembled_frame));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////
|
||||||
|
bundle[b].seq_num_m = seq_num;
|
||||||
|
if (end_frame)
|
||||||
|
{
|
||||||
|
// Both bits are set
|
||||||
|
LOG(4, s, t, "MPPP: Both bits are set (Begin and End).\n");
|
||||||
|
processmpframe(s, t, p, l, 0);
|
||||||
|
// The maximum number of fragments is 1500
|
||||||
|
if (seq_num - bundle[b].offset >= 1400)
|
||||||
|
{
|
||||||
|
bundle[b].offset = seq_num;
|
||||||
|
LOG(4, s, t, "MPPP: Setting offset to: %d\n",bundle[b].offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bundle[b].pending_frag = 1;
|
||||||
|
// End bit is clear
|
||||||
|
LOG(4, s, t, "MPPP: Push to receive buffer\n");
|
||||||
|
// Push to the receive buffer
|
||||||
|
// Array indexes checking
|
||||||
|
if (seq_num-offset < 0 || seq_num-offset >= MAXFRAGNUM)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "ERROR: Index out of range, push to receive buffer(1) seq:%d, offset:%d, bundle:%d\n",seq_num,offset,b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Perform length checking
|
||||||
|
if (l > MAXFRAGLEN)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "MPPP: ERROR: very long fragment length (1)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frag[b].fragment[seq_num - offset].length = l;
|
||||||
|
memcpy(frag[b].fragment[seq_num - offset].data, p, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(4, s, t, "MPPP: Push to receive buffer\n");
|
||||||
|
// Push to the receive buffer
|
||||||
|
// Array indexes checking
|
||||||
|
if (seq_num-offset < 0 || seq_num-offset >= MAXFRAGNUM)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "ERROR: Index out of range, push to receive buffer(2) seq:%d, offset:%d, bundle:%d\n",seq_num,offset,b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Perform length checking
|
||||||
|
if (l > MAXFRAGLEN)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "MPPP: ERROR: very long fragment length (2).\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frag[b].fragment[seq_num - offset].length = l;
|
||||||
|
memcpy(frag[b].fragment[seq_num - offset].data, p, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// process IPv6 packet received
|
// process IPv6 packet received
|
||||||
//
|
//
|
||||||
// This MUST be called with at least 4 byte behind 'p'.
|
// This MUST be called with at least 4 byte behind 'p'.
|
||||||
|
|
@ -1685,7 +2061,7 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
STAT(tunnel_rx_errors);
|
STAT(tunnel_rx_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(3, s, t, "CCP: recv %s\n", ppp_code(*p));
|
LOG(4, s, t, "CCP: recv %s\n", ppp_code(*p));
|
||||||
if (*p == ConfigAck)
|
if (*p == ConfigAck)
|
||||||
{
|
{
|
||||||
switch (session[s].ppp.ccp)
|
switch (session[s].ppp.ccp)
|
||||||
|
|
@ -1718,13 +2094,13 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
else // compression requested--reject
|
else // compression requested--reject
|
||||||
*p = ConfigRej;
|
*p = ConfigRej;
|
||||||
|
|
||||||
q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP);
|
q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
switch (session[s].ppp.ccp)
|
switch (session[s].ppp.ccp)
|
||||||
{
|
{
|
||||||
case Closed:
|
case Closed:
|
||||||
q = makeppp(b, sizeof(b), p, 2, s, t, PPPCCP);
|
q = makeppp(b, sizeof(b), p, 2, s, t, PPPCCP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
*q = TerminateAck;
|
*q = TerminateAck;
|
||||||
*((uint16_t *) (q + 2)) = htons(l = 4);
|
*((uint16_t *) (q + 2)) = htons(l = 4);
|
||||||
|
|
@ -1770,13 +2146,13 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(3, s, t, "CCP: send %s\n", ppp_code(*q));
|
LOG(4, s, t, "CCP: send %s\n", ppp_code(*q));
|
||||||
tunnelsend(b, l + (q - b), t);
|
tunnelsend(b, l + (q - b), t);
|
||||||
}
|
}
|
||||||
else if (*p == TerminateReq)
|
else if (*p == TerminateReq)
|
||||||
{
|
{
|
||||||
*p = TerminateAck;
|
*p = TerminateAck;
|
||||||
q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP);
|
q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
LOG(3, s, t, "CCP: send %s\n", ppp_code(*q));
|
LOG(3, s, t, "CCP: send %s\n", ppp_code(*q));
|
||||||
tunnelsend(b, l + (q - b), t);
|
tunnelsend(b, l + (q - b), t);
|
||||||
|
|
@ -1820,7 +2196,7 @@ void sendchap(sessionidt s, tunnelidt t)
|
||||||
STAT(tunnel_tx_errors);
|
STAT(tunnel_tx_errors);
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
q = makeppp(b, sizeof(b), 0, 0, s, t, PPPCHAP);
|
q = makeppp(b, sizeof(b), 0, 0, s, t, PPPCHAP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
*q = 1; // challenge
|
*q = 1; // challenge
|
||||||
|
|
@ -1834,37 +2210,86 @@ void sendchap(sessionidt s, tunnelidt t)
|
||||||
|
|
||||||
// fill in a L2TP message with a PPP frame,
|
// fill in a L2TP message with a PPP frame,
|
||||||
// returns start of PPP frame
|
// returns start of PPP frame
|
||||||
uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, sessionidt s, tunnelidt t, uint16_t mtype)
|
uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, sessionidt s, tunnelidt t, uint16_t mtype, uint8_t prio, bundleidt bid, uint8_t mp_bits)
|
||||||
{
|
{
|
||||||
if (size < 12) // Need more space than this!!
|
uint16_t hdr = 0x0002; // L2TP with no options
|
||||||
|
uint16_t type = mtype;
|
||||||
|
uint8_t *start = b;
|
||||||
|
|
||||||
|
if (size < 16) // Need more space than this!!
|
||||||
{
|
{
|
||||||
LOG(0, s, t, "makeppp buffer too small for L2TP header (size=%d)\n", size);
|
LOG(0, s, t, "makeppp buffer too small for L2TP header (size=%d)\n", size);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*(uint16_t *) (b + 0) = htons(0x0002); // L2TP with no options
|
if (prio) hdr |= 0x0100; // set priority bit
|
||||||
|
|
||||||
|
*(uint16_t *) (b + 0) = htons(hdr);
|
||||||
*(uint16_t *) (b + 2) = htons(tunnel[t].far); // tunnel
|
*(uint16_t *) (b + 2) = htons(tunnel[t].far); // tunnel
|
||||||
*(uint16_t *) (b + 4) = htons(session[s].far); // session
|
*(uint16_t *) (b + 4) = htons(session[s].far); // session
|
||||||
b += 6;
|
b += 6;
|
||||||
if (mtype == PPPLCP || !(session[s].flags & SESSION_ACFC))
|
|
||||||
|
// Check whether this session is part of multilink
|
||||||
|
if (bid)
|
||||||
|
{
|
||||||
|
if (bundle[bid].num_of_links > 1)
|
||||||
|
type = PPPMP; // Change PPP message type to the PPPMP
|
||||||
|
else
|
||||||
|
bid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == PPPLCP || !(session[s].flags & SESSION_ACFC))
|
||||||
{
|
{
|
||||||
*(uint16_t *) b = htons(0xFF03); // HDLC header
|
*(uint16_t *) b = htons(0xFF03); // HDLC header
|
||||||
b += 2;
|
b += 2;
|
||||||
}
|
}
|
||||||
if (mtype < 0x100 && session[s].flags & SESSION_PFC)
|
|
||||||
*b++ = mtype;
|
if (type < 0x100 && session[s].flags & SESSION_PFC)
|
||||||
|
{
|
||||||
|
*b++ = type;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*(uint16_t *) b = htons(mtype);
|
*(uint16_t *) b = htons(type);
|
||||||
b += 2;
|
b += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l + 12 > size)
|
if (bid)
|
||||||
{
|
{
|
||||||
LOG(2, s, t, "makeppp would overflow buffer (size=%d, header+payload=%d)\n", size, l + 12);
|
// Set the sequence number and (B)egin (E)nd flags
|
||||||
|
if (session[s].mssf)
|
||||||
|
{
|
||||||
|
// Set the multilink bits
|
||||||
|
uint16_t bits_send = mp_bits;
|
||||||
|
*(uint16_t *) b = htons((bundle[bid].seq_num_t & 0xFF0F)|bits_send);
|
||||||
|
b += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(uint32_t *) b = htonl(bundle[bid].seq_num_t);
|
||||||
|
// Set the multilink bits
|
||||||
|
*b = mp_bits;
|
||||||
|
b += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle[bid].seq_num_t++;
|
||||||
|
|
||||||
|
// Add the message type if this fragment has the begin bit set
|
||||||
|
if (mp_bits & MP_BEGIN)
|
||||||
|
{
|
||||||
|
//*b++ = mtype; // The next two lines are instead of this
|
||||||
|
*(uint16_t *) b = htons(mtype); // Message type
|
||||||
|
b += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((b - start) + l > size)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "makeppp would overflow buffer (size=%d, header+payload=%d)\n", size, (b - start) + l);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the payload
|
||||||
if (p && l)
|
if (p && l)
|
||||||
memcpy(b, p, l);
|
memcpy(b, p, l);
|
||||||
|
|
||||||
|
|
@ -1903,10 +2328,10 @@ void sendlcp(sessionidt s, tunnelidt t)
|
||||||
uint8_t b[500], *q, *l;
|
uint8_t b[500], *q, *l;
|
||||||
int authtype = sess_local[s].lcp_authtype;
|
int authtype = sess_local[s].lcp_authtype;
|
||||||
|
|
||||||
if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPLCP)))
|
if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPLCP, 0, 0, 0)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG(3, s, t, "LCP: send ConfigReq%s%s%s\n",
|
LOG(3, s, t, "LCP: send ConfigReq%s%s%s including MP options\n",
|
||||||
authtype ? " (" : "",
|
authtype ? " (" : "",
|
||||||
authtype ? (authtype == AUTHCHAP ? "CHAP" : "PAP") : "",
|
authtype ? (authtype == AUTHCHAP ? "CHAP" : "PAP") : "",
|
||||||
authtype ? ")" : "");
|
authtype ? ")" : "");
|
||||||
|
|
@ -1933,6 +2358,20 @@ void sendlcp(sessionidt s, tunnelidt t)
|
||||||
l += 4;
|
l += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sess_local[s].mp_mrru)
|
||||||
|
{
|
||||||
|
*l++ = 17; *l++ = 4; // Multilink Max-Receive-Reconstructed-Unit (length 4)
|
||||||
|
*(uint16_t *) l = htons(sess_local[s].mp_mrru); l += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sess_local[s].mp_epdis)
|
||||||
|
{
|
||||||
|
*l++ = 19; *l++ = 7; // Multilink Endpoint Discriminator (length 7)
|
||||||
|
*l++ = IPADDR; // Endpoint Discriminator class
|
||||||
|
*(uint32_t *) l = htonl(sess_local[s].mp_epdis);
|
||||||
|
l += 4;
|
||||||
|
}
|
||||||
|
|
||||||
*(uint16_t *)(q + 2) = htons(l - q); // Length
|
*(uint16_t *)(q + 2) = htons(l - q); // Length
|
||||||
|
|
||||||
LOG_HEX(5, "PPPLCP", q, l - q);
|
LOG_HEX(5, "PPPLCP", q, l - q);
|
||||||
|
|
@ -1947,7 +2386,7 @@ void sendccp(sessionidt s, tunnelidt t)
|
||||||
{
|
{
|
||||||
uint8_t b[500], *q;
|
uint8_t b[500], *q;
|
||||||
|
|
||||||
if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPCCP)))
|
if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPCCP, 0, 0, 0)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG(3, s, t, "CCP: send ConfigReq (no compression)\n");
|
LOG(3, s, t, "CCP: send ConfigReq (no compression)\n");
|
||||||
|
|
@ -1974,7 +2413,7 @@ void protoreject(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint16_t pro
|
||||||
l += 6;
|
l += 6;
|
||||||
if (l > mru) l = mru;
|
if (l > mru) l = mru;
|
||||||
|
|
||||||
q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPLCP);
|
q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPLCP, 0, 0, 0);
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
|
|
||||||
*q = ProtocolRej;
|
*q = ProtocolRej;
|
||||||
|
|
|
||||||
19
radius.c
19
radius.c
|
|
@ -1,6 +1,6 @@
|
||||||
// L2TPNS Radius Stuff
|
// L2TPNS Radius Stuff
|
||||||
|
|
||||||
char const *cvs_id_radius = "$Id: radius.c,v 1.49 2006-04-13 11:14:35 bodea Exp $";
|
char const *cvs_id_radius = "$Id: radius.c,v 1.50 2006-04-27 09:53:50 bodea Exp $";
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -537,7 +537,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
|
||||||
if (radius[r].chap)
|
if (radius[r].chap)
|
||||||
{
|
{
|
||||||
// CHAP
|
// CHAP
|
||||||
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPCHAP);
|
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPCHAP, 0, 0, 0);
|
||||||
if (!p) return; // Abort!
|
if (!p) return; // Abort!
|
||||||
|
|
||||||
*p = (r_code == AccessAccept) ? 3 : 4; // ack/nak
|
*p = (r_code == AccessAccept) ? 3 : 4; // ack/nak
|
||||||
|
|
@ -551,7 +551,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// PAP
|
// PAP
|
||||||
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPPAP);
|
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPPAP, 0, 0, 0);
|
||||||
if (!p) return; // Abort!
|
if (!p) return; // Abort!
|
||||||
|
|
||||||
// ack/nak
|
// ack/nak
|
||||||
|
|
@ -593,6 +593,19 @@ void processrad(uint8_t *buf, int len, char socket_index)
|
||||||
LOG(3, s, session[s].tunnel, " Radius reply contains primary DNS address %s\n",
|
LOG(3, s, session[s].tunnel, " Radius reply contains primary DNS address %s\n",
|
||||||
fmtaddr(htonl(session[s].dns1), 0));
|
fmtaddr(htonl(session[s].dns1), 0));
|
||||||
}
|
}
|
||||||
|
else if (*p == 27)
|
||||||
|
{
|
||||||
|
// Session timeout
|
||||||
|
if (p[1] < 6) {
|
||||||
|
LOG(2, s, session[s].tunnel, "Error: Received Session timeout with length %d < 6\n", p[1]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
session[s].timeout = ntohl(*(uint32_t *) (p + 2));
|
||||||
|
LOG(3, s, session[s].tunnel, " Radius reply contains Session timeout %d\n", session[s].timeout);
|
||||||
|
if (!session[s].timeout)
|
||||||
|
sessionshutdown(s, "Session timeout is zero", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
|
||||||
|
}
|
||||||
else if (*p == 136)
|
else if (*p == 136)
|
||||||
{
|
{
|
||||||
// DNS address
|
// DNS address
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue