add Multilink support from Khaled Al Hamwi

This commit is contained in:
Brendan O'Dea 2006-04-27 09:53:49 +00:00
parent 57a847d9a3
commit 5faf075c8d
13 changed files with 1021 additions and 97 deletions

View file

@ -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.

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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);
} }

View file

@ -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);

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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;

View file

@ -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
View file

@ -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;

View file

@ -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