Merge branch 'upstream'

This commit is contained in:
Benjamin Cama 2011-07-28 17:59:33 +02:00
commit fbd2194031
30 changed files with 5124 additions and 557 deletions

29
Changes
View file

@ -1,16 +1,27 @@
* Fri Dec 1 2006 Brendan O'Dea <bod@optus.net> 2.1.21
- Security: Rhys Kidd identified a vulnerability in the handling of
heartbeat packets. Drop oversize heartbeat packets.
* Thu Jan 20 2011 Brendan O'Dea <bod@optus.net> 2.2.x
- Apply MLPPP patch from Muhammad Tayseer Alquoatli.
- Apply patch from Michael O to avoid sending multiple CDNs.
- Apply patch from Cyril Elkaim to fix an issue with MacOS.
- Apply patch from Geoffrey D. Bennett to fix retry of control packets.
* Thu Aug 3 2006 Brendan O'Dea <bod@optus.net> 2.1.20
- Fix sign problem with reporting of unknown VSAs.
- Allow DNS servers to be specified either using the old or new
vendor-specific Ascend formats.
* Fri Jun 23 2006 Brendan O'Dea <bod@optus.net> 2.1.19
* Mon Dec 18 2006 Brendan O'Dea <bod@optus.net> 2.2.0
- Only poll clifd if successfully bound.
- Add "Practical VPNs" document from Liran Tal as Docs/vpn .
- Add Multilink support from Khaled Al Hamwi.
- Remove non-working setuid option.
- Convert manual.html to Docbook.
- Kludge around problem with Netgear DM602 authentication.
- Add session/idle timeouts (Graham Maltby).
- Use result code AVP to set Acct-Terminate-Cause is disconnect cause
AVP is not present.
- Add radius_bind_{min,max} to simplify firewalling of RADIUS ports.
- Fix sign problem with reporting of unknown RADIUS VSAs.
- Allow DNS servers to be specified either using the old or new
vendor-specific Ascend formats.
- Security [CVE-2006-5873]: Rhys Kidd identified a vulnerability in the
handling of heartbeat packets. Drop oversize heartbeat packets.
- Don't send interim records before session start (Daryl Tester).
- Add "shutdown" and "reload" CLI commands (Daryl Tester).
* Tue Apr 18 2006 Brendan O'Dea <bod@optus.net> 2.1.18
- Don't shutdown on TerminateReq, wait for CDN.

4
Docs/common/config.xml Normal file
View file

@ -0,0 +1,4 @@
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="html.stylesheet" select="'../common/docbook.css'"/>
</xsl:stylesheet>

69
Docs/common/docbook.css Normal file
View file

@ -0,0 +1,69 @@
div.article > div.titlepage {
text-align: center;
}
.abstract {
text-align: justify;
}
.title {
font-family: sans-serif;
font-weight: bolder;
margin-bottom: 0.5em;
}
.sect2, .sect2, .sect3, .sect4 {
margin-left: 2%;
margin-right: 2%;
}
.sect2 .title, .sect2 .title, .sect3 .title, .sect4 .title {
margin-left: 0;
margin-right: 0;
}
.synopsis, .screen, .programlisting {
font-family: monospace;
font-size: 1em;
display: block;
padding: 10px;
border: 1px solid #bbb;
background-color: #eee;
color: #000;
overflow: auto;
border-radius: 2.5px;
-moz-border-radius: 2.5px;
margin: 0.5em 2em;
}
.programlisting em {
color: red;
}
.hanging-indent {
margin-left: 4em;
text-indent: -2em;
}
table {
margin: 0.5em 2em;
border: 1px solid #bbb;
border-collapse: collapse;
}
td {
vertical-align: baseline;
}
thead {
background-color: #eee;
}
td table {
margin: 0;
border: 0;
}
td {
border: 1px solid #bbb;
}

2163
Docs/manual/manual.xml Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
.de Id
.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.18 2006/07/01 12:40:17 bodea Exp $
.TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
.SH NAME
startup\-config \- configuration file for l2tpns
@ -77,17 +77,17 @@ Number of configure requests to send before giving up (default: 10).
Number of Configure-Nak requests to send before sending a
Configure-Reject (default: 5).
.TP
.BR primary_dns , " secondary_dns"
.BR primary_dns ", " secondary_dns
Whenever a PPP connection is established, DNS servers will be sent to the
user, both a primary and a secondary. If either is set to 0.0.0.0, then that
one will not be sent.
.TP
.BR primary_radius , " secondary_radius"
.BR primary_radius ", " secondary_radius
Sets the RADIUS servers used for both authentication and accounting.
If the primary server does not respond, then the secondary RADIUS
server will be tried.
.TP
.BR primary_radius_port , " secondary_radius_port"
.BR primary_radius_port ", " secondary_radius_port
Sets the authentication ports for the primary and secondary RADIUS
servers. The accounting port is one more than the authentication
port. If no ports are given, authentication defaults to 1645, and
@ -118,11 +118,19 @@ A comma separated list of supported RADIUS authentication methods
Port for DAE RADIUS (Packet of Death/Disconnect, Change of Authorization)
requests (default: 3799).
.TP
.BR radius_bind_min ", " radius_bind_max
Define a port range in which to bind sockets used to send and receive
RADIUS packets. Must be at least RADIUS_FDS (64) wide. Simplifies
firewalling of RADIUS ports (default: dynamically assigned).
.TP
.B allow_duplicate_users
Allow multiple logins with the same username. If false (the default),
any prior session with the same username will be dropped when a new
session is established.
.TP
.B guest_account
Allow multiple logins matching this specific username.
.TP
.B bind_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
@ -149,10 +157,6 @@ session requires two buckets (in and out).
If set to a directory, then every 5 minutes the current usage for
every connected use will be dumped to a file in this directory.
.TP
.B setuid
After starting up and binding the interface, change UID to this. This
doesn't work properly.
.TP
.B dump_speed
If set to true, then the current bandwidth utilization will be logged
every second. Even if this is disabled, you can see this information

1086
Docs/vpn/practical-vpns.xml Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
Docs/vpn/vpn-deployment.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
Docs/vpn/vpn-process.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

6
THANKS
View file

@ -12,7 +12,7 @@ Yuri <yuri@actcom.net.il>
Juergen Kammer <j.kammer@eurodata.de>
Simon Talbot <simont@nse.co.uk>
Jonathan McDowell <noodles@earth.li>
Bjørn Augestad <augestad@users.sourceforge.net>
Bjørn Augestad <augestad@users.sourceforge.net>
Roberto Chostakovis <rchostakovis@users.sourceforge.net>
Jordan Hrycaj <jordan@mjh.teddy-net.com>
Vladislav Bjelic <vladislav@gmail.com>
@ -26,4 +26,8 @@ Jon Morby <jon@fido.net>
Paul Martin <pm@zetnet.net>
Jonathan Yarden <jyarden@bluegrass.net>
Patrick Cole <z@amused.net>
Khaled Al Hamwi <kh.alhamwi@gmail.com>
Graham Maltby <gmaltby+l2tpns@iig.com.au>
Rhys Kidd <rhys.kidd@staff.westnet.com.au>
Muhammad Tayseer Alquoatli <idoit.ief@gmail.com>
Cyril Elkaim <cyrelk@users.sourceforge.net>

View file

@ -9,11 +9,11 @@
* lcp:interface-config#2=service-policy output N
*
* throttle=N
* throttle=yes (use throttle_rate from config)
* throttle=yes (use throttle_speed from config)
* throttle=no
*/
char const *cvs_id = "$Id: autothrottle.c,v 1.16 2005/10/11 09:04:53 bodea Exp $";
char const *cvs_id = "$Id: autothrottle.c,v 1.17 2006/05/18 14:40:31 bodea Exp $";
int plugin_api_version = PLUGIN_API_VERSION;
static struct pluginfuncs *f = 0;

50
cli.c
View file

@ -1,8 +1,8 @@
// L2TPNS Command Line Interface
// vim: sw=8 ts=8
char const *cvs_name = "$Name: release_2_1_21 $";
char const *cvs_id_cli = "$Id: cli.c,v 1.71 2005/12/06 09:43:42 bodea Exp $";
char const *cvs_name = "$Name: $";
char const *cvs_id_cli = "$Id: cli.c,v 1.76 2006/12/18 12:08:28 bodea Exp $";
#include <stdio.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
extern tunnelt *tunnel;
extern bundlet *bundle;
extern sessiont *session;
extern radiust *radius;
extern ippoolt *ip_address_pool;
@ -99,6 +100,9 @@ static int cmd_set(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_load_plugin(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_remove_plugin(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_uptime(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_shutdown(struct cli_def *cli, char *command, char **argv, int argc);
static int cmd_reload(struct cli_def *cli, char *command, char **argv, int argc);
static int regular_stuff(struct cli_def *cli);
@ -175,6 +179,8 @@ void init_cli(char *hostname)
#endif
cli_register_command(cli, NULL, "uptime", cmd_uptime, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show uptime and bandwidth utilisation");
cli_register_command(cli, NULL, "shutdown", cmd_shutdown, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Shutdown l2tpns daemon and exit");
cli_register_command(cli, NULL, "reload", cmd_reload, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Reload configuration");
c = cli_register_command(cli, NULL, "write", NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
cli_register_command(cli, c, "memory", cmd_write_memory, PRIVILEGE_PRIVILEGED, MODE_EXEC, "Save the running config to flash");
@ -268,7 +274,7 @@ void init_cli(char *hostname)
}
memset(&addr, 0, sizeof(addr));
clifd = socket(PF_INET, SOCK_STREAM, 6);
clifd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(clifd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
{
int flags;
@ -425,6 +431,18 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
cli_print(cli, "\tUnique SID:\t%u", session[s].unique_id);
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);
if (session[s].session_timeout)
{
clockt opened = session[s].opened;
if (session[s].bundle && bundle[session[s].bundle].num_of_links > 1)
opened = bundle[session[s].bundle].online_time;
cli_print(cli, "\tSess Timeout:\t%u seconds", session[s].session_timeout - (opened ? abs(time_now - opened) : 0));
}
if (session[s].idle_timeout)
cli_print(cli, "\tIdle Timeout:\t%u seconds", session[s].idle_timeout - (session[s].last_data ? abs(time_now - session[s].last_data) : 0));
cli_print(cli, "\tBytes In/Out:\t%u/%u", session[s].cout, session[s].cin);
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);
@ -2016,7 +2034,7 @@ static int cmd_router_bgp_neighbour(struct cli_def *cli, char *command, char **a
int keepalive;
int hold;
if (CLI_HELP_REQUESTED)
if (CLI_HELP_REQUESTED)
{
switch (argc)
{
@ -2126,14 +2144,14 @@ static int cmd_router_bgp_neighbour(struct cli_def *cli, char *command, char **a
config->neighbour[i].keepalive = keepalive;
config->neighbour[i].hold = hold;
return CLI_OK;
return CLI_OK;
}
static int cmd_router_bgp_no_neighbour(struct cli_def *cli, char *command, char **argv, int argc)
{
int i;
if (CLI_HELP_REQUESTED)
if (CLI_HELP_REQUESTED)
return cli_arg_help(cli, argc > 0,
"A.B.C.D", "BGP neighbour address",
"NAME", "BGP neighbour name",
@ -2158,7 +2176,7 @@ static int cmd_router_bgp_no_neighbour(struct cli_def *cli, char *command, char
}
memset(&config->neighbour[i], 0, sizeof(config->neighbour[i]));
return CLI_OK;
return CLI_OK;
}
static int cmd_show_bgp(struct cli_def *cli, char *command, char **argv, int argc)
@ -3064,3 +3082,21 @@ static int cmd_show_access_list(struct cli_def *cli, char *command, char **argv,
return CLI_OK;
}
static int cmd_shutdown(struct cli_def *cli, char *command, char **argv, int argc)
{
if (CLI_HELP_REQUESTED)
return CLI_HELP_NO_ARGS;
kill(getppid(), SIGQUIT);
return CLI_OK;
}
static int cmd_reload(struct cli_def *cli, char *command, char **argv, int argc)
{
if (CLI_HELP_REQUESTED)
return CLI_HELP_NO_ARGS;
kill(getppid(), SIGHUP);
return CLI_OK;
}

169
cluster.c
View file

@ -1,6 +1,6 @@
// L2TPNS Clustering Stuff
char const *cvs_id_cluster = "$Id: cluster.c,v 1.50.2.1 2006/12/02 14:09:14 bodea Exp $";
char const *cvs_id_cluster = "$Id: cluster.c,v 1.55 2009/12/08 14:49:28 bodea Exp $";
#include <stdio.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.
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.
int forked = 0; // Sanity check: CLI must not diddle with heartbeat table
@ -85,6 +86,7 @@ int cluster_init()
int opt;
config->cluster_undefined_sessions = MAXSESSION-1;
config->cluster_undefined_bundles = MAXBUNDLE-1;
config->cluster_undefined_tunnels = MAXTUNNEL-1;
if (!config->cluster_address)
@ -227,7 +229,7 @@ static void cluster_uptodate(void)
if (config->cluster_iam_uptodate)
return;
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels)
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles)
return;
config->cluster_iam_uptodate = 1;
@ -400,7 +402,7 @@ void cluster_send_ping(time_t basetime)
x.ver = 1;
x.addr = config->bind_address;
x.undef = config->cluster_undefined_sessions + config->cluster_undefined_tunnels;
x.undef = config->cluster_undefined_sessions + config->cluster_undefined_tunnels + config->cluster_undefined_bundles;
x.basetime = basetime;
add_type(&p, C_PING, basetime, (uint8_t *) &x, sizeof(x));
@ -520,7 +522,7 @@ void cluster_check_slaves(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;
clockt t = TIME;
static int probed = 0;
@ -614,6 +616,19 @@ void cluster_check_master(void)
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.
// reset the idle timeouts.
@ -639,7 +654,7 @@ void cluster_check_master(void)
}
// Reset idle timeouts..
session[i].last_packet = time_now;
session[i].last_packet = session[i].last_data = time_now;
// Reset die relative to our uptime rather than the old master's
if (session[i].die) session[i].die = TIME;
@ -675,10 +690,11 @@ void cluster_check_master(void)
rebuild_address_pool();
// 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);
config->cluster_undefined_sessions = 0;
config->cluster_undefined_bundles = 0;
config->cluster_undefined_tunnels = 0;
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'
// 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;
@ -705,7 +721,7 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig
if (config->cluster_iam_uptodate)
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;
// 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;
}
// 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
// undefs remaining.
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) {
LOG(2, 0, 0, "Cleared undefined sessions/tunnels. %d sess (high %d), %d tunn (high %d)\n",
config->cluster_undefined_sessions, highsession, config->cluster_undefined_tunnels, hightunnel);
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles) {
LOG(2, 0, 0, "Cleared undefined sessions/bundles/tunnels. %d sess (high %d), %d bund (high %d), %d tunn (high %d)\n",
config->cluster_undefined_sessions, highsession, config->cluster_undefined_bundles, highbundle, config->cluster_undefined_tunnels, hightunnel);
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));
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
uint8_t c[sizeof(tunnelt) * 2]; // Bigger than worst case.
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()
{
int i, count = 0, tcount = 0;
int i, count = 0, tcount = 0, bcount = 0;
uint8_t buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
heartt h;
uint8_t *p = buff;
@ -823,7 +873,9 @@ void cluster_heartbeat()
h.highsession = config->cluster_highest_sessionid;
h.freesession = sessionfree;
h.hightunnel = config->cluster_highest_tunnelid;
h.highbundle = config->cluster_highest_bundleid;
h.size_sess = sizeof(sessiont); // Just in case.
h.size_bund = sizeof(bundlet);
h.size_tunn = sizeof(tunnelt);
h.interval = config->cluster_hb_interval;
h.timeout = config->cluster_hb_timeout;
@ -878,6 +930,21 @@ void cluster_heartbeat()
++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_CBUNDLE, walk_bundle_number);
walk_bundle_number = (1+walk_bundle_number)%(config->cluster_highest_bundleid+1); // +1 avoids divide by zero.
++bcount;
}
//
// Did we do something wrong?
if (p > (buff + sizeof(buff))) { // Did we somehow manage to overun the buffer?
@ -887,9 +954,9 @@ void cluster_heartbeat()
}
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,
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_num_changes = 0;
@ -938,6 +1005,17 @@ int cluster_send_session(int 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!
int cluster_send_tunnel(int tid)
{
@ -1135,7 +1213,9 @@ static int cluster_handle_bytes(uint8_t *data, int size)
session[b->sid].cout_delta += b->cout;
if (b->cin)
session[b->sid].last_packet = time_now; // Reset idle timer!
session[b->sid].last_packet = session[b->sid].last_data = time_now;
else if (b->cout)
session[b->sid].last_data = time_now;
size -= sizeof(*b);
++b;
@ -1175,6 +1255,31 @@ static int cluster_recv_session(int more, uint8_t *p)
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)
{
if (more >= MAXTUNNEL) {
@ -1465,7 +1570,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
// 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)
{
@ -1573,6 +1678,34 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t
p += sizeof(tunnel[more]);
s -= sizeof(tunnel[more]);
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:
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!!
@ -1640,7 +1773,7 @@ int processcluster(uint8_t *data, int size, in_addr_t addr)
case C_FORWARD_DAE: // Forwarded DAE packet. pass off to processdae.
if (!config->cluster_iam_master)
{
LOG(0, 0, 0, "I'm not the master, but I got a C_FORWARD_%s from %s?\n",
LOG(0, 0, 0, "I'm not the master, but I got a C_FORWARD%s from %s?\n",
type == C_FORWARD_DAE ? "_DAE" : "", fmtaddr(addr, 0));
return -1;
@ -1758,11 +1891,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, "Next sequence number expected: %d", config->cluster_seq_number);
cli_print(cli, "%d sessions undefined of %d", config->cluster_undefined_sessions, config->cluster_highest_sessionid);
cli_print(cli, "%d bundles undefined of %d", config->cluster_undefined_bundles, config->cluster_highest_bundleid);
cli_print(cli, "%d tunnels undefined of %d", config->cluster_undefined_tunnels, config->cluster_highest_tunnelid);
} else {
cli_print(cli, "Table version # : %" PRIu64, config->cluster_table_version);
cli_print(cli, "Next heartbeat # : %d", config->cluster_seq_number);
cli_print(cli, "Highest session : %d", config->cluster_highest_sessionid);
cli_print(cli, "Highest bundle : %d", config->cluster_highest_bundleid);
cli_print(cli, "Highest tunnel : %d", config->cluster_highest_tunnelid);
cli_print(cli, "%d changes queued for sending", config->cluster_num_changes);
}

View file

@ -1,5 +1,5 @@
// L2TPNS Clustering Stuff
// $Id: cluster.h,v 1.14 2005/07/31 10:04:10 bodea Exp $
// $Id: cluster.h,v 1.16 2006/12/04 20:54:51 bodea Exp $
#ifndef __CLUSTER_H__
#define __CLUSTER_H__
@ -21,6 +21,8 @@
#define C_GARDEN 14 // Gardened packet
#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_BUNDLE 17 // Bundle structure.
#define C_CBUNDLE 18 // Compressed bundle structure.
#define HB_VERSION 5 // Protocol version number..
#define HB_MAX_SEQ (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!)
@ -43,16 +45,18 @@ typedef struct {
uint32_t highsession; // Id of the highest in-use 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 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 interval; // ping/heartbeat interval
uint32_t timeout; // heartbeat timeout
uint64_t table_version; // # state changes processed by cluster
char reserved[128 - 13*sizeof(uint32_t)]; // Pad out to 128 bytes.
char reserved[128 - 13*sizeof(uint32_t) - sizeof(uint64_t)]; // Pad out to 128 bytes.
} heartt;
typedef struct { /* Used to update byte counters on the */
@ -74,6 +78,7 @@ typedef struct {
int cluster_init(void);
int processcluster(uint8_t *buf, int size, in_addr_t addr);
int cluster_send_session(int sid);
int cluster_send_bundle(int bid);
int cluster_send_tunnel(int tid);
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);

View file

@ -1,6 +1,6 @@
// L2TPNS: constants
char const *cvs_id_constants = "$Id: constants.c,v 1.7 2005/07/31 10:04:10 bodea Exp $";
char const *cvs_id_constants = "$Id: constants.c,v 1.8 2009/12/08 14:49:28 bodea Exp $";
#include <stdio.h>
#include "constants.h"
@ -197,7 +197,8 @@ CONSTANT(radius_state,
"RADIUSSTART", // 3
"RADIUSSTOP", // 4
"RADIUSINTERIM", // 5
"RADIUSWAIT" // 6
"RADIUSWAIT", // 6
"RADIUSJUSTAUTH" // 7
)
CONSTANT(radius_code,

View file

@ -41,6 +41,12 @@ set radius_secret "secret"
# Allow multiple logins for the same username
#set allow_duplicate_users no
# Kill timedout sessions ? (default yes)
#set kill_timedout_sessions no
# Allow multiple logins for specific username
#set guest_account ""
# Write usage accounting files into specified directory
set accounting_dir "/var/run/l2tpns/acct"
@ -59,9 +65,6 @@ set accounting_dir "/var/run/l2tpns/acct"
# Number of buckets to allocate for throttling
#set throttle_buckets 3000
# If set to anything other than 0, setuid when initialised.
#set setuid 0
# If set to true, dump current speed to stderr every second
#set dump_speed no
@ -96,6 +99,9 @@ set accounting_dir "/var/run/l2tpns/acct"
# Minimum number of slaves before master withdraws routes
#set cluster_master_min_adv 1
# IPv6 address prefix
#set ipv6_prefix ::
# Drop/kill sessions
#load plugin "sessionctl"

View file

@ -1,5 +1,5 @@
/* kludge up some limited epoll semantics using select for 2.4 kernels */
/* $Id: fake_epoll.h,v 1.1 2005/06/04 15:42:35 bodea Exp $ */
/* $Id: fake_epoll.h,v 1.2 2007/06/28 07:22:50 bodea Exp $ */
#ifndef __FAKE_EPOLL_H__
#define __FAKE_EPOLL_H__
@ -150,6 +150,9 @@ static int epoll_wait(int epfd __attribute__ ((unused)),
tp = 0;
n = select(_epoll_fds, &r, &w, 0, tp);
if (n < 0)
return n;
if (n > maxevents)
n = maxevents;

4
icmp.c
View file

@ -1,6 +1,6 @@
// 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 <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");
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)
{

573
l2tpns.c

File diff suppressed because it is too large Load diff

121
l2tpns.h
View file

@ -1,5 +1,5 @@
// L2TPNS Global Stuff
// $Id: l2tpns.h,v 1.113.2.3 2006/12/02 14:09:14 bodea Exp $
// $Id: l2tpns.h,v 1.121 2009/12/08 14:49:28 bodea Exp $
#ifndef __L2TPNS_H__
#define __L2TPNS_H__
@ -14,10 +14,13 @@
#include <sys/types.h>
#include <libcli.h>
#define VERSION "2.1.21"
#define VERSION "2.2.0"
// Limits
#define MAXTUNNEL 500 // could be up to 65535
#define MAXBUNDLE 300 // could be up to 65535
#define MAXBUNDLESES 12 // Maximum number of member links in bundle
#define MAXADDRESS 20 // Maximum length for the Endpoint Discrminiator address
#define MAXSESSION 60000 // could be up to 65535
#define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session.
@ -43,10 +46,20 @@
#define MAXIPPOOL 131072 // max number of ip addresses in pool
#define RINGBUFFER_SIZE 10000 // Number of ringbuffer entries to allocate
#define MAX_LOG_LENGTH 512 // Maximum size of log message
#define ECHO_TIMEOUT 60 // Time between last packet sent and LCP ECHO generation
#define IDLE_TIMEOUT 240 // 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 seen and session 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 MINFRAGLEN 64 // Minumum fragment length
#define MAXFRAGLEN 750 // Maximum length for Multilink fragment (MTU / 2 sessions)
#define MAXFRAGNUM 128 // Maximum number of Multilink fragment in a bundle (must be in the form of 2^X)
// it's not expected to have a space for more than 10 unassembled packets = 10 * MAXBUNDLESES
#define MAXFRAGNUM_MASK 127 // Must be equal to MAXFRAGNUM-1
// Constants
#ifndef ETCDIR
#define ETCDIR "/etc/l2tpns"
@ -186,6 +199,7 @@ enum {
// Types
typedef uint16_t sessionidt;
typedef uint16_t bundleidt;
typedef uint16_t tunnelidt;
typedef uint32_t clockt;
typedef uint8_t hasht[16];
@ -231,6 +245,20 @@ typedef struct controls // control message
}
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 {
sessionidt sid; // Fragment originating session
uint8_t flags; // MP frame flags
uint32_t seq; // fragment seq num
uint16_t length; // Fragment length
uint8_t data[MAXFRAGLEN]; // Fragment data
} fragmentt;
typedef struct
{
sessionidt next; // next session in linked list
@ -261,7 +289,10 @@ typedef struct
uint16_t mru; // maximum receive unit
clockt opened; // when started
clockt die; // being closed, when to finally free
uint32_t session_timeout; // Maximum session time in seconds
uint32_t idle_timeout; // Maximum idle time in seconds
time_t last_packet; // Last packet from the user (used for idle timeouts)
time_t last_data; // Last data packet to/from the user (used for idle timeouts)
in_addr_t dns1, dns2; // DNS servers
routet route[MAXROUTE]; // static routes
uint16_t tbf_in; // filter bucket for throttling in from the user.
@ -273,6 +304,11 @@ typedef struct
char calling[MAXTEL]; // calling number
uint32_t tx_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
uint16_t snoop_port; // Interception destination port
uint8_t walled_garden; // is this session gardened?
@ -282,6 +318,36 @@ typedef struct
}
sessiont;
typedef struct
{
int state; // current state (bundlestate enum)
uint32_t seq_num_t; // Sequence Number (transmission)
uint32_t timeout; // Session-Timeout for bundle
uint32_t max_seq; // Max value of sequence number field
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
uint16_t re_frame_begin_index, re_frame_end_index; // reassembled frame begin index, end index respectively
uint16_t start_index, end_index; // start and end sequence numbers available on the fragments array respectively
uint32_t M; // Minumum frame sequence number received over all bundle members
uint32_t start_seq; // Last received frame sequence number (bearing B bit)
}
fragmentationt;
#define AUTHPAP 1 // allow PAP
#define AUTHCHAP 2 // allow CHAP
@ -311,6 +377,15 @@ typedef struct
// our 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
clockt last_packet_out;
uint32_t packets_out;
@ -324,6 +399,9 @@ typedef struct
// last LCP Echo
time_t last_echo;
// Last Multilink frame sequence number received
uint32_t last_seq;
} sessionlocalt;
// session flags
@ -407,6 +485,23 @@ enum
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
{
RADIUSNULL, // Not in use
@ -416,6 +511,7 @@ enum
RADIUSSTOP, // sending stop accounting to RADIUS server
RADIUSINTERIM, // sending interim accounting to RADIUS server
RADIUSWAIT, // waiting timeout before available, in case delayed replies
RADIUSJUSTAUTH, // sending auth to RADIUS server, just authentication, no ip assigning
};
struct Tstats
@ -554,13 +650,16 @@ typedef struct
uint16_t radiusport[MAXRADSERVER]; // radius base ports
uint8_t numradiusservers; // radius server count
uint16_t radius_dae_port; // local port for radius dae
uint16_t radius_dae_port; // port for radius DAE
uint16_t radius_bind_min; // port range for udp sockets used to send/recv radius packets
uint16_t radius_bind_max;
char radius_authtypes_s[32]; // list of valid authentication types (chap, pap) in order of preference
int radius_authtypes;
int radius_authprefer;
int allow_duplicate_users; // allow multiple logins with the same username
int kill_timedout_sessions; // kill authenticated sessions with "session_timeout == 0"
in_addr_t default_dns1, default_dns2;
@ -572,7 +671,6 @@ typedef struct
in_addr_t peer_address;
int send_garp; // Set to true to garp for vip address on startup
int target_uid;
int dump_speed;
char plugins[64][MAXPLUGINS];
char old_plugins[64][MAXPLUGINS];
@ -583,6 +681,7 @@ typedef struct
int lock_pages; // Lock pages into memory.
int icmp_rate; // Max number of ICMP unreachable per second to send
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.
// Send to this address to have everyone hear.
@ -594,8 +693,10 @@ typedef struct
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).
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_highest_sessionid;
int cluster_highest_bundleid;
int cluster_highest_tunnelid;
clockt cluster_last_hb; // Last time we saw a heartbeat from the master.
int cluster_last_hb_ver; // Heartbeat version last seen from master
@ -611,6 +712,8 @@ typedef struct
int cluster_master_min_adv; // Master advertises routes while the number of up to date
// slaves is less than this value.
// Guest change
char guest_user[MAXUSER]; // Guest account username
#ifdef BGP
#define BGP_NUM_PEERS 2
@ -727,14 +830,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 processipv6cp(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 processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
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 send_ipin(sessionidt s, uint8_t *buf, int len);
void sendccp(sessionidt s, tunnelidt t);
void protoreject(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint16_t proto);
int join_bundle(sessionidt s);
// radius.c
@ -802,6 +908,7 @@ void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, uint
extern tunnelt *tunnel;
extern bundlet *bundle;
extern sessiont *session;
extern sessionlocalt *sess_local;
extern ippoolt *ip_address_pool;

View file

@ -1,6 +1,6 @@
Summary: A high-speed clustered L2TP LNS
Name: l2tpns
Version: 2.1.21
Version: 2.2.0
Release: 1
License: GPL
Group: System Environment/Daemons
@ -43,5 +43,5 @@ rm -rf %{buildroot}
%attr(644,root,root) /usr/share/man/man[58]/*
%changelog
* Fri Dec 1 2006 Brendan O'Dea <bod@optus.net> 2.1.21-1
- 2.1.21 release, see /usr/share/doc/l2tpns-2.1.21/Changes
* Mon Dec 18 2006 Brendan O'Dea <bod@optus.net> 2.2.0-1
- 2.2.0 release, see /usr/share/doc/l2tpns-2.2.0/Changes

362
md5.c
View file

@ -15,10 +15,7 @@
* and avoid compile-time configuration.
*/
#ifndef HAVE_OPENSSL
#include <string.h>
#include "md5.h"
/*
@ -27,18 +24,18 @@
* F is optimized compared to its RFC 1321 definition just like in Colin
* Plumb's implementation.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
/*
* The MD5 transformation for all four rounds.
*/
#define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b);
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b);
/*
* SET reads 4 input bytes in little-endian byte order and stores them
@ -49,19 +46,17 @@
* doesn't work.
*/
#if defined(__i386__) || defined(__vax__)
#define SET(n) \
(*(MD5_u32plus *)&ptr[(n) * 4])
#define GET(n) \
SET(n)
# define SET(n) (*(MD5_u32plus *)&ptr[(n) * 4])
# define GET(n) SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = \
(MD5_u32plus)ptr[(n) * 4] | \
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
(ctx->block[(n)])
# define SET(n) \
(ctx->block[(n)] = \
(MD5_u32plus)ptr[(n) * 4] | \
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
# define GET(n) \
(ctx->block[(n)])
#endif
/*
@ -70,205 +65,208 @@
*/
static void *body(MD5_CTX *ctx, void *data, unsigned long size)
{
unsigned char *ptr;
MD5_u32plus a, b, c, d;
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
unsigned char *ptr;
MD5_u32plus a, b, c, d;
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
ptr = data;
ptr = data;
a = ctx->a;
b = ctx->b;
c = ctx->c;
d = ctx->d;
a = ctx->a;
b = ctx->b;
c = ctx->c;
d = ctx->d;
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
/* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ptr += MD5_BLOCK_SZ;
} while (size -= MD5_BLOCK_SZ);
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
return ptr;
return ptr;
}
void MD5_Init(MD5_CTX *ctx)
{
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe;
ctx->d = 0x10325476;
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe;
ctx->d = 0x10325476;
ctx->lo = 0;
ctx->hi = 0;
ctx->lo = 0;
ctx->hi = 0;
}
void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)
{
MD5_u32plus saved_lo;
unsigned long used, free;
MD5_u32plus saved_lo;
unsigned long used, free;
saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
used = saved_lo & 0x3f;
ctx->hi += size >> 29;
if (used) {
free = 64 - used;
used = saved_lo & 0x3f;
if (size < free) {
memcpy(&ctx->buffer[used], data, size);
return;
}
if (used)
{
free = MD5_BLOCK_SZ - used;
memcpy(&ctx->buffer[used], data, free);
data = (unsigned char *)data + free;
size -= free;
body(ctx, ctx->buffer, 64);
if (size < free)
{
memcpy(&ctx->buffer[used], data, size);
return;
}
if (size >= 64) {
data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
memcpy(&ctx->buffer[used], data, free);
data = (unsigned char *)data + free;
size -= free;
body(ctx, ctx->buffer, MD5_BLOCK_SZ);
}
memcpy(ctx->buffer, data, size);
if (size >= MD5_BLOCK_SZ)
{
data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
{
unsigned long used, free;
unsigned long used, free;
used = ctx->lo & 0x3f;
used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
ctx->buffer[used++] = 0x80;
free = 64 - used;
free = MD5_BLOCK_SZ - used;
if (free < 8) {
memset(&ctx->buffer[used], 0, free);
body(ctx, ctx->buffer, 64);
used = 0;
free = 64;
}
if (free < 8)
{
memset(&ctx->buffer[used], 0, free);
body(ctx, ctx->buffer, MD5_BLOCK_SZ);
used = 0;
free = MD5_BLOCK_SZ;
}
memset(&ctx->buffer[used], 0, free - 8);
memset(&ctx->buffer[used], 0, free - 8);
ctx->lo <<= 3;
ctx->buffer[56] = ctx->lo;
ctx->buffer[57] = ctx->lo >> 8;
ctx->buffer[58] = ctx->lo >> 16;
ctx->buffer[59] = ctx->lo >> 24;
ctx->buffer[60] = ctx->hi;
ctx->buffer[61] = ctx->hi >> 8;
ctx->buffer[62] = ctx->hi >> 16;
ctx->buffer[63] = ctx->hi >> 24;
ctx->lo <<= 3;
ctx->buffer[56] = ctx->lo;
ctx->buffer[57] = ctx->lo >> 8;
ctx->buffer[58] = ctx->lo >> 16;
ctx->buffer[59] = ctx->lo >> 24;
ctx->buffer[60] = ctx->hi;
ctx->buffer[61] = ctx->hi >> 8;
ctx->buffer[62] = ctx->hi >> 16;
ctx->buffer[63] = ctx->hi >> 24;
body(ctx, ctx->buffer, 64);
body(ctx, ctx->buffer, MD5_BLOCK_SZ);
result[0] = ctx->a;
result[1] = ctx->a >> 8;
result[2] = ctx->a >> 16;
result[3] = ctx->a >> 24;
result[4] = ctx->b;
result[5] = ctx->b >> 8;
result[6] = ctx->b >> 16;
result[7] = ctx->b >> 24;
result[8] = ctx->c;
result[9] = ctx->c >> 8;
result[10] = ctx->c >> 16;
result[11] = ctx->c >> 24;
result[12] = ctx->d;
result[13] = ctx->d >> 8;
result[14] = ctx->d >> 16;
result[15] = ctx->d >> 24;
result[0] = ctx->a;
result[1] = ctx->a >> 8;
result[2] = ctx->a >> 16;
result[3] = ctx->a >> 24;
result[4] = ctx->b;
result[5] = ctx->b >> 8;
result[6] = ctx->b >> 16;
result[7] = ctx->b >> 24;
result[8] = ctx->c;
result[9] = ctx->c >> 8;
result[10] = ctx->c >> 16;
result[11] = ctx->c >> 24;
result[12] = ctx->d;
result[13] = ctx->d >> 8;
result[14] = ctx->d >> 16;
result[15] = ctx->d >> 24;
memset(ctx, 0, sizeof(*ctx));
memset(ctx, 0, sizeof(*ctx));
}
#endif

19
md5.h
View file

@ -6,23 +6,24 @@
* in the public domain. See md5.c for more information.
*/
#ifdef HAVE_OPENSSL
#include <openssl/md5.h>
#elif !defined(_MD5_H)
#define _MD5_H
#ifndef __MD5_H__
#define __MD5_H__
#define MD5_DIGEST_SZ 16
#define MD5_BLOCK_SZ 64
/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned long MD5_u32plus;
typedef struct {
MD5_u32plus lo, hi;
MD5_u32plus a, b, c, d;
unsigned char buffer[64];
MD5_u32plus block[16];
MD5_u32plus lo, hi;
MD5_u32plus a, b, c, d;
unsigned char buffer[MD5_BLOCK_SZ];
MD5_u32plus block[MD5_DIGEST_SZ];
} MD5_CTX;
extern void MD5_Init(MD5_CTX *ctx);
extern void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size);
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
#endif
#endif /* __MD5_H__ */

View file

@ -8,8 +8,6 @@ enum
{
PLUGIN_PRE_AUTH = 1,
PLUGIN_POST_AUTH,
PLUGIN_PACKET_RX,
PLUGIN_PACKET_TX,
PLUGIN_TIMER,
PLUGIN_NEW_SESSION,
PLUGIN_KILL_SESSION,
@ -62,37 +60,11 @@ struct param_post_auth
int protocol;
};
struct param_packet_rx
{
tunnelt *t;
sessiont *s;
char *buf;
int len;
};
struct param_packet_tx
{
tunnelt *t;
sessiont *s;
char *buf;
int len;
};
struct param_timer
{
time_t time_now;
};
struct param_control
{
int iam_master;
int argc;
char **argv;
// output
int response;
char *additional;
};
struct param_new_session
{
tunnelt *t;
@ -105,6 +77,16 @@ struct param_kill_session
sessiont *s;
};
struct param_control
{
int iam_master;
int argc;
char **argv;
// output
int response;
char *additional;
};
struct param_radius_response
{
tunnelt *t;

665
ppp.c
View file

@ -1,6 +1,6 @@
// L2TPNS PPP Stuff
char const *cvs_id_ppp = "$Id: ppp.c,v 1.99.2.1 2006/05/26 07:33:52 bodea Exp $";
char const *cvs_id_ppp = "$Id: ppp.c,v 1.104 2009/12/08 14:49:28 bodea Exp $";
#include <stdio.h>
#include <string.h>
@ -15,6 +15,8 @@ char const *cvs_id_ppp = "$Id: ppp.c,v 1.99.2.1 2006/05/26 07:33:52 bodea Exp $"
#include "cluster.h"
extern tunnelt *tunnel;
extern bundlet *bundle;
extern fragmentationt *frag;
extern sessiont *session;
extern radiust *radius;
extern int tunfd;
@ -24,6 +26,20 @@ extern time_t time_now;
extern configt *config;
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);
static int first_session_in_bundle(sessionidt s)
{
bundleidt i;
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))
return 0;
return 1;
}
// Process PAP messages
void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
@ -90,7 +106,7 @@ void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
// respond now, either no RADIUS available or already authenticated
uint8_t b[MAXETHER];
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 (session[s].ip)
@ -134,7 +150,10 @@ void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
radius[r].id = p[1];
LOG(3, s, t, "Sending login for %s/%s to RADIUS\n", user, pass);
radiussend(r, RADIUSAUTH);
if ((session[s].mrru) && (!first_session_in_bundle(s)))
radiussend(r, RADIUSJUSTAUTH);
else
radiussend(r, RADIUSAUTH);
}
}
@ -251,7 +270,10 @@ void processchap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
radius[r].chap = 1;
LOG(3, s, t, "CHAP login %s\n", session[s].user);
radiussend(r, RADIUSAUTH);
if ((session[s].mrru) && (!first_session_in_bundle(s)))
radiussend(r, RADIUSJUSTAUTH);
else
radiussend(r, RADIUSAUTH);
}
static void dumplcp(uint8_t *p, int l)
@ -360,16 +382,25 @@ void lcp_open(sessionidt s, tunnelidt t)
}
else
{
// This-Layer-Up
sendipcp(s, t);
change_state(s, ipcp, RequestSent);
// move to passive state for IPv6 (if configured), CCP
if (config->ipv6_prefix.s6_addr[0])
change_state(s, ipv6cp, Stopped);
else
change_state(s, ipv6cp, Closed);
if(session[s].bundle == 0 || bundle[session[s].bundle].num_of_links == 1)
{
// This-Layer-Up
sendipcp(s, t);
change_state(s, ipcp, RequestSent);
// move to passive state for IPv6 (if configured), CCP
if (config->ipv6_prefix.s6_addr[0])
change_state(s, ipv6cp, Stopped);
else
change_state(s, ipv6cp, Closed);
change_state(s, ccp, Stopped);
change_state(s, ccp, Stopped);
}
else
{
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);
ipcp_open(s, t);
}
}
}
@ -387,7 +418,7 @@ static uint8_t *ppp_conf_rej(sessionidt s, uint8_t *buf, size_t blen, uint16_t m
{
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)
return 0;
@ -431,7 +462,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)
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)
return 0;
@ -463,7 +494,7 @@ static void ppp_code_rej(sessionidt s, tunnelidt t, uint16_t proto,
l += 4;
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;
*q = CodeRej;
@ -575,6 +606,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
uint8_t *response = 0;
static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero
static uint8_t authproto[5];
int changed = 0;
while (x > 2)
{
@ -590,7 +622,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
if (mru >= MINMTU)
{
session[s].mru = mru;
cluster_send_session(s);
changed++;
break;
}
@ -663,6 +695,64 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
case 8: // Address-And-Control-Field-Compression
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
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);
@ -671,6 +761,9 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
o += length;
}
if (changed)
cluster_send_session(s);
if (response)
{
l = q - response; // LCP packet length
@ -679,7 +772,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
else
{
// 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;
*response = ConfigAck;
}
@ -687,7 +780,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
switch (session[s].ppp.lcp)
{
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;
*response = TerminateAck;
*((uint16_t *) (response + 2)) = htons(l = 4);
@ -820,6 +913,50 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
cluster_send_session(s);
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:
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);
@ -843,7 +980,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
case Closed:
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;
*response = TerminateAck;
*((uint16_t *) (response + 2)) = htons(l = 4);
@ -901,7 +1038,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
}
*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;
LOG(3, s, t, "LCP: send %s\n", ppp_code(*q));
@ -937,7 +1074,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
{
*p = EchoReply; // reply
*(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;
LOG(4, s, t, "LCP: send %s\n", ppp_code(*q));
@ -955,6 +1092,112 @@ 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))
{
sessionidt first_ses = bundle[i].members[0];
if (bundle[i].mssf != session[s].mssf)
{
// uniformity of sequence number format must be insured
LOG(3, s, session[s].tunnel, "MPPP: unable to bundle session %d in bundle %d cause of different mssf\n", s, i);
return -1;
}
session[s].bundle = i;
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;
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;
// FIXME !!! to enable l2tpns reading mssf frames receiver_max_seq, sender_max_seq must be introduce
// now session[s].mssf flag indecates that the receiver wish to receive frames in mssf, so max_seq (i.e. recv_max_seq) = 1<<24
/*
if (bundle[b].mssf)
bundle[b].max_seq = 1 << 12;
else */
bundle[b].max_seq = 1 << 24;
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;
bundle[b].timeout = session[s].timeout;
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
memset(&frag[i], 0, sizeof(fragmentationt));
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)
{
LOG(3, s, t, "IPCP: Opened, session is now active\n");
@ -1113,7 +1356,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
else if (gotip)
{
// 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;
*response = ConfigAck;
}
@ -1127,7 +1370,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
switch (session[s].ppp.ipcp)
{
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;
*response = TerminateAck;
*((uint16_t *) (response + 2)) = htons(l = 4);
@ -1200,7 +1443,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
}
*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;
LOG(3, s, t, "IPCP: send %s\n", ppp_code(*q));
@ -1334,7 +1577,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
else if (gotip)
{
// 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;
*response = ConfigAck;
}
@ -1348,7 +1591,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
switch (session[s].ppp.ipv6cp)
{
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;
*response = TerminateAck;
*((uint16_t *) (response + 2)) = htons(l = 4);
@ -1421,7 +1664,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
}
*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;
LOG(3, s, t, "IPV6CP: send %s\n", ppp_code(*q));
@ -1433,6 +1676,39 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
}
}
static void update_sessions_in_stat(sessionidt s, uint16_t l)
{
bundleidt b = session[s].bundle;
if (!b)
{
increment_counter(&session[s].cin, &session[s].cin_wrap, l);
session[s].cin_delta += l;
session[s].pin++;
sess_local[s].cin += l;
sess_local[s].pin++;
}
else
{
int i = frag[b].re_frame_begin_index;
int end = frag[b].re_frame_end_index;
for (;;)
{
l = frag[b].fragment[i].length;
s = frag[b].fragment[i].sid;
increment_counter(&session[s].cin, &session[s].cin_wrap, l);
session[s].cin_delta += l;
session[s].pin++;
sess_local[s].cin += l;
sess_local[s].pin++;
if (i == end)
return;
i = (i + 1) & MAXFRAGNUM_MASK;
}
}
}
// process IP packet received
//
// This MUST be called with at least 4 byte behind 'p'.
@ -1464,11 +1740,14 @@ void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
if (session[s].ppp.phase != Network || session[s].ppp.ipcp != Opened)
return;
// no spoof (do sessionbyip to handled statically routed subnets)
if (ip != session[s].ip && sessionbyip(htonl(ip)) != s)
if (!session[s].bundle || bundle[session[s].bundle].num_of_links < 2) // FIXME:
{
LOG(5, s, t, "Dropping packet with spoofed IP %s\n", fmtaddr(htonl(ip), 0));
return;
// no spoof (do sessionbyip to handled statically routed subnets)
if (ip != session[s].ip && sessionbyip(htonl(ip)) != s)
{
LOG(4, s, t, "Dropping packet with spoofed IP %s\n", fmtaddr(htonl(ip), 0));
return;
}
}
// run access-list if any
@ -1488,17 +1767,13 @@ void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
*(uint32_t *) p = htonl(PKTIP);
l += 4;
// Are we throttled and a slave?
if (session[s].tbf_in && !config->cluster_iam_master) {
// Pass it to the master for handling.
master_throttle_packet(session[s].tbf_in, p, l);
return;
}
// Are we throttled and a master??
if (session[s].tbf_in && config->cluster_iam_master) {
// Actually handle the throttled packets.
tbf_queue_packet(session[s].tbf_in, p, l);
if (session[s].tbf_in)
{
// Are we throttling this session?
if (config->cluster_iam_master)
tbf_queue_packet(session[s].tbf_in, p, l);
else
master_throttle_packet(session[s].tbf_in, p, l);
return;
}
@ -1521,12 +1796,7 @@ void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
snoop_send_packet(p, l, session[s].snoop_ip, session[s].snoop_port);
}
increment_counter(&session[s].cin, &session[s].cin_wrap, l);
session[s].cin_delta += l;
session[s].pin++;
sess_local[s].cin += l;
sess_local[s].pin++;
update_sessions_in_stat(s, l);
eth_tx += l;
@ -1534,6 +1804,195 @@ void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t 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;
bundlet * this_bundle = &bundle[b];
uint32_t frag_offset, M_offset;
uint16_t frag_index, M_index;
fragmentationt *this_fragmentation = &frag[b];
uint8_t begin_frame = (*p & MP_BEGIN);
uint8_t end_frame = (*p & MP_END);
uint32_t seq_num;
uint8_t flags = *p;
uint16_t begin_index, end_index;
// Perform length checking
if(l > MAXFRAGLEN)
{
LOG(2, s, t, "MPPP: discarding fragment larger than MAXFRAGLEN\n");
return;
}
if(!b)
{
LOG(2, s, t, "MPPP: Invalid bundle id: 0\n");
return;
}
// FIXME !! session[s].mssf means that the receiver wants to receive frames in mssf not means the receiver will send frames in mssf
/* if(session[s].mssf)
{
// Get 12 bit for seq number
seq_num = ntohs((*(uint16_t *) p) & 0xFF0F);
p += 2;
l -= 2;
// After this point the pointer should be advanced 2 bytes
LOG(3, s, t, "MPPP: 12 bits, sequence number: %d\n",seq_num);
}
else */
{
// Get 24 bit for seq number
seq_num = ntohl((*(uint32_t *) p) & 0xFFFFFF00);
p += 4;
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);
}
// calculate this fragment's offset from the begin seq in the bundle
frag_offset = (seq_num + this_bundle->max_seq - this_fragmentation->start_seq) & (this_bundle->max_seq-1);
// discard this fragment if frag_offset is bigger that the fragmentation buffer size
if (frag_offset >= MAXFRAGNUM)
{
LOG(3, s, t, "MPPP: Index out of range, received more than MAXFRAGNUM fragment (lost frag) seq:%d, begin_seq:%d, bundle:%d, max:%d\n",seq_num, this_fragmentation->start_seq, b, this_bundle->max_seq);
return;
}
// update M
sess_local[s].last_seq = seq_num;
if (seq_num < this_fragmentation->M)
this_fragmentation->M = seq_num;
else
{
uint32_t i, min = sess_local[(this_bundle->members[0])].last_seq;;
for (i = 1; i < this_bundle->num_of_links; i++)
{
uint32_t s_seq = sess_local[(this_bundle->members[i])].last_seq;
if (s_seq < min)
min = s_seq;
}
this_fragmentation->M = min;
}
LOG(4, s, t, "MPPP: Setting M to %d\n", this_fragmentation->M);
//calculate M's offset from the begin seq in the bundle
M_offset = (this_fragmentation->M + this_bundle->max_seq - this_fragmentation->start_seq) & (this_bundle->max_seq-1);
//caculate M's index in the fragment array
M_index = (M_offset + this_fragmentation->start_index) & MAXFRAGNUM_MASK;
//caculate received fragment's index in the fragment array
frag_index = (frag_offset + this_fragmentation->start_index) & MAXFRAGNUM_MASK;
//frame with a single fragment
if (begin_frame && end_frame)
{
// process and reset fragmentation
LOG(4, s, t, "MPPP: Both bits are set (Begin and End).\n");
this_fragmentation->fragment[frag_index].length = l;
this_fragmentation->fragment[frag_index].sid = s;
this_fragmentation->fragment[frag_index].flags = flags;
this_fragmentation->fragment[frag_index].seq = seq_num;
this_fragmentation->re_frame_begin_index = frag_index;
this_fragmentation->re_frame_end_index = frag_index;
processmpframe(s, t, p, l, 0);
this_fragmentation->fragment[frag_index].length = 0;
this_fragmentation->fragment[frag_index].flags = 0;
end_index = frag_index;
}
else
{
// insert the frame in it's place
fragmentt *this_frag = &this_fragmentation->fragment[frag_index];
this_frag->length = l;
this_frag->sid = s;
this_frag->flags = flags;
this_frag->seq = seq_num;
memcpy(this_frag->data, p, l);
// try to assemble the frame that has the received fragment as a member
// get the beginning of this frame
begin_index = end_index = frag_index;
while (this_fragmentation->fragment[begin_index].length)
{
if (this_fragmentation->fragment[begin_index].flags & MP_BEGIN)
break;
begin_index = (begin_index ? (begin_index -1) : (MAXFRAGNUM -1));
}
// return if a lost fragment is found
if (!(this_fragmentation->fragment[begin_index].length))
return; // assembling frame failed
// get the end of his frame
while (this_fragmentation->fragment[end_index].length)
{
if (this_fragmentation->fragment[end_index].flags & MP_END)
break;
end_index = (end_index +1) & MAXFRAGNUM_MASK;
}
// return if a lost fragment is found
if (!(this_fragmentation->fragment[end_index].length))
return; // assembling frame failed
// assemble the packet
//assemble frame, process it, reset fragmentation
uint16_t cur_len = 4; // This is set to 4 to leave 4 bytes for function processipin
uint32_t i;
LOG(4, s, t, "MPPP: processing fragments from %d to %d\n", begin_index, end_index);
// Push to the receive buffer
for (i = begin_index;; i = (i + 1) & MAXFRAGNUM_MASK)
{
this_frag = &this_fragmentation->fragment[i];
if(cur_len + this_frag->length > MAXETHER)
{
LOG(2, s, t, "MPPP: discarding reassembled frames larger than MAXETHER\n");
break;
}
memcpy(this_fragmentation->reassembled_frame+cur_len, this_frag->data, this_frag->length);
LOG(5, s, t, "MPPP: processing frame at %d, with len %d\n", i, this_frag->length);
cur_len += this_frag->length;
if (i == end_index)
{
this_fragmentation->re_frame_len = cur_len;
this_fragmentation->re_frame_begin_index = begin_index;
this_fragmentation->re_frame_end_index = end_index;
// Process the resassembled frame
LOG(5, s, t, "MPPP: Process the reassembled frame, len=%d\n",cur_len);
processmpframe(s, t, this_fragmentation->reassembled_frame, this_fragmentation->re_frame_len, 1);
break;
}
}
// Set reassembled frame length to zero after processing it
this_fragmentation->re_frame_len = 0;
for (i = begin_index;; i = (i + 1) & MAXFRAGNUM_MASK)
{
this_fragmentation->fragment[i].length = 0; // Indicates that this fragment has been consumed
this_fragmentation->fragment[i].flags = 0;
if (i == end_index)
break;
}
}
//discard fragments received before the recently assembled frame
begin_index = this_fragmentation->start_index;
this_fragmentation->start_index = (end_index + 1) & MAXFRAGNUM_MASK;
this_fragmentation->start_seq = (this_fragmentation->fragment[end_index].seq + 1) & (this_bundle->max_seq-1);
//clear length and flags of the discarded fragments
while (begin_index != this_fragmentation->start_index)
{
this_fragmentation->fragment[begin_index].flags = 0;
this_fragmentation->fragment[begin_index].length = 0;
begin_index = (begin_index + 1) & MAXFRAGNUM_MASK;
}
LOG(4, s, t, "MPPP after assembling: M index is =%d, start index is = %d, start seq=%d\n",M_index, this_fragmentation->start_index, this_fragmentation->start_seq);
return;
}
// process IPv6 packet received
//
// This MUST be called with at least 4 byte behind 'p'.
@ -1617,12 +2076,7 @@ void processipv6in(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
snoop_send_packet(p, l, session[s].snoop_ip, session[s].snoop_port);
}
increment_counter(&session[s].cin, &session[s].cin_wrap, l);
session[s].cin_delta += l;
session[s].pin++;
sess_local[s].cin += l;
sess_local[s].pin++;
update_sessions_in_stat(s, l);
eth_tx += l;
@ -1693,7 +2147,7 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
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)
{
switch (session[s].ppp.ccp)
@ -1726,13 +2180,13 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
else // compression requested--reject
*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;
switch (session[s].ppp.ccp)
{
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;
*q = TerminateAck;
*((uint16_t *) (q + 2)) = htons(l = 4);
@ -1778,13 +2232,13 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
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);
}
else if (*p == TerminateReq)
{
*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;
LOG(3, s, t, "CCP: send %s\n", ppp_code(*q));
tunnelsend(b, l + (q - b), t);
@ -1828,7 +2282,7 @@ void sendchap(sessionidt s, tunnelidt t)
STAT(tunnel_tx_errors);
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;
*q = 1; // challenge
@ -1842,37 +2296,86 @@ void sendchap(sessionidt s, tunnelidt t)
// fill in a L2TP message with a 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);
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 + 4) = htons(session[s].far); // session
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
b += 2;
}
if (mtype < 0x100 && session[s].flags & SESSION_PFC)
*b++ = mtype;
if (type < 0x100 && session[s].flags & SESSION_PFC)
{
*b++ = type;
}
else
{
*(uint16_t *) b = htons(mtype);
*(uint16_t *) b = htons(type);
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 & 0x0FFF)|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;
}
// Copy the payload
if (p && l)
memcpy(b, p, l);
@ -1911,10 +2414,10 @@ void sendlcp(sessionidt s, tunnelidt t)
uint8_t b[500], *q, *l;
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;
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 == AUTHCHAP ? "CHAP" : "PAP") : "",
authtype ? ")" : "");
@ -1941,6 +2444,20 @@ void sendlcp(sessionidt s, tunnelidt t)
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
LOG_HEX(5, "PPPLCP", q, l - q);
@ -1955,7 +2472,7 @@ void sendccp(sessionidt s, tunnelidt t)
{
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;
LOG(3, s, t, "CCP: send ConfigReq (no compression)\n");
@ -1982,7 +2499,7 @@ void protoreject(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint16_t pro
l += 6;
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;
*q = ProtocolRej;

184
radius.c
View file

@ -1,6 +1,6 @@
// L2TPNS Radius Stuff
char const *cvs_id_radius = "$Id: radius.c,v 1.49.2.2 2006/08/02 14:17:20 bodea Exp $";
char const *cvs_id_radius = "$Id: radius.c,v 1.56 2009/12/08 14:49:28 bodea Exp $";
#include <time.h>
#include <stdio.h>
@ -45,6 +45,25 @@ static void calc_auth(const void *buf, size_t len, const uint8_t *in, uint8_t *o
void initrad(void)
{
int i;
uint16_t port = 0;
uint16_t min = config->radius_bind_min;
uint16_t max = config->radius_bind_max;
int inc = 1;
struct sockaddr_in addr;
if (min)
{
port = min;
if (!max)
max = ~0 - 1;
}
else if (max) /* no minimum specified, bind from max down */
{
port = max;
min = 1;
inc = -1;
}
LOG(3, 0, 0, "Creating %d sockets for RADIUS queries\n", RADIUS_FDS);
radfds = calloc(sizeof(int), RADIUS_FDS);
for (i = 0; i < RADIUS_FDS; i++)
@ -53,6 +72,27 @@ void initrad(void)
radfds[i] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
flags = fcntl(radfds[i], F_GETFL, 0);
fcntl(radfds[i], F_SETFL, flags | O_NONBLOCK);
if (port)
{
int b;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
do {
addr.sin_port = htons(port);
if ((b = bind(radfds[i], (struct sockaddr *) &addr, sizeof(addr))) < 0)
{
if ((port += inc) < min || port > max)
{
LOG(0, 0, 0, "Can't bind RADIUS socket in range %u-%u\n", min, max);
exit(1);
}
}
} while (b < 0);
}
}
}
@ -137,7 +177,7 @@ void radiussend(uint16_t r, uint8_t state)
return;
}
if (state != RADIUSAUTH && !config->radius_accounting)
if (state != RADIUSAUTH && state != RADIUSJUSTAUTH && !config->radius_accounting)
{
// Radius accounting is turned off
radiusclear(r, s);
@ -157,7 +197,7 @@ void radiussend(uint16_t r, uint8_t state)
{
if (s)
{
if (state == RADIUSAUTH)
if (state == RADIUSAUTH || state == RADIUSJUSTAUTH)
sessionshutdown(s, "RADIUS timeout.", CDN_ADMIN_DISC, TERM_REAUTHENTICATION_FAILURE);
else
{
@ -179,6 +219,7 @@ void radiussend(uint16_t r, uint8_t state)
switch (state)
{
case RADIUSAUTH:
case RADIUSJUSTAUTH:
b[0] = AccessRequest; // access request
break;
case RADIUSSTART:
@ -199,7 +240,7 @@ void radiussend(uint16_t r, uint8_t state)
strcpy((char *) p + 2, session[s].user);
p += p[1];
}
if (state == RADIUSAUTH)
if (state == RADIUSAUTH || state == RADIUSJUSTAUTH)
{
if (radius[r].chap)
{
@ -330,6 +371,7 @@ void radiussend(uint16_t r, uint8_t state)
}
}
}
if (s)
{
*p = 5; // NAS-Port
@ -339,59 +381,80 @@ void radiussend(uint16_t r, uint8_t state)
*p = 6; // Service-Type
p[1] = 6;
*(uint32_t *) (p + 2) = htonl(2); // Framed-User
*(uint32_t *) (p + 2) = htonl((state == RADIUSJUSTAUTH ? 8 : 2)); // Authenticate only or Framed-User respectevily
p += p[1];
*p = 7; // Framed-Protocol
p[1] = 6;
*(uint32_t *) (p + 2) = htonl(1); // PPP
p[1] = htonl((state == RADIUSJUSTAUTH ? 0 : 6));
*(uint32_t *) (p + 2) = htonl((state == RADIUSJUSTAUTH ? 0 : 1)); // PPP
p += p[1];
}
if (s && session[s].ip)
{
*p = 8; // Framed-IP-Address
p[1] = 6;
*(uint32_t *) (p + 2) = htonl(session[s].ip);
p += p[1];
}
if (s && session[s].route[0].ip)
{
int r;
for (r = 0; s && r < MAXROUTE && session[s].route[r].ip; r++)
if (session[s].ip)
{
int width = 32;
if (session[s].route[r].mask)
*p = 8; // Framed-IP-Address
p[1] = 6;
*(uint32_t *) (p + 2) = htonl(session[s].ip);
p += p[1];
}
if (session[s].route[0].ip)
{
int r;
for (r = 0; s && r < MAXROUTE && session[s].route[r].ip; r++)
{
int mask = session[s].route[r].mask;
while (!(mask & 1))
{
width--;
mask >>= 1;
}
int width = 32;
if (session[s].route[r].mask)
{
int mask = session[s].route[r].mask;
while (!(mask & 1))
{
width--;
mask >>= 1;
}
}
*p = 22; // Framed-Route
p[1] = sprintf((char *) p + 2, "%s/%d %s 1",
fmtaddr(htonl(session[s].route[r].ip), 0),
width, fmtaddr(htonl(session[s].ip), 1)) + 2;
p += p[1];
}
}
*p = 22; // Framed-Route
p[1] = sprintf((char *) p + 2, "%s/%d %s 1",
fmtaddr(htonl(session[s].route[r].ip), 0),
width, fmtaddr(htonl(session[s].ip), 1)) + 2;
if (session[s].session_timeout)
{
*p = 27; // Session-Timeout
p[1] = 6;
*(uint32_t *) (p + 2) = htonl(session[s].session_timeout);
p += p[1];
}
if (session[s].idle_timeout)
{
*p = 28; // Idle-Timeout
p[1] = 6;
*(uint32_t *) (p + 2) = htonl(session[s].idle_timeout);
p += p[1];
}
if (*session[s].called)
{
*p = 30; // called
p[1] = strlen(session[s].called) + 2;
strcpy((char *) p + 2, session[s].called);
p += p[1];
}
if (*session[s].calling)
{
*p = 31; // calling
p[1] = strlen(session[s].calling) + 2;
strcpy((char *) p + 2, session[s].calling);
p += p[1];
}
}
if (*session[s].called)
{
*p = 30; // called
p[1] = strlen(session[s].called) + 2;
strcpy((char *) p + 2, session[s].called);
p += p[1];
}
if (*session[s].calling)
{
*p = 31; // calling
p[1] = strlen(session[s].calling) + 2;
strcpy((char *) p + 2, session[s].calling);
p += p[1];
}
// NAS-IP-Address
*p = 4;
p[1] = 6;
@ -400,7 +463,7 @@ void radiussend(uint16_t r, uint8_t state)
// All AVpairs added
*(uint16_t *) (b + 2) = htons(p - b);
if (state != RADIUSAUTH)
if (state != RADIUSAUTH && state != RADIUSJUSTAUTH)
{
// Build auth for accounting packet
calc_auth(b, p - b, zero, b + 4);
@ -413,7 +476,7 @@ void radiussend(uint16_t r, uint8_t state)
// get radius port
uint16_t port = config->radiusport[(radius[r].try - 1) % config->numradiusservers];
// assume RADIUS accounting port is the authentication port +1
addr.sin_port = htons((state == RADIUSAUTH) ? port : port+1);
addr.sin_port = htons((state == RADIUSAUTH || state == RADIUSJUSTAUTH) ? port : port+1);
}
LOG_HEX(5, "RADIUS Send", b, (p - b));
@ -496,7 +559,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
LOG(1, s, session[s].tunnel, " Unexpected RADIUS response\n");
return;
}
if (radius[r].state != RADIUSAUTH && radius[r].state != RADIUSSTART
if (radius[r].state != RADIUSAUTH && radius[r].state != RADIUSJUSTAUTH && radius[r].state != RADIUSSTART
&& radius[r].state != RADIUSSTOP && radius[r].state != RADIUSINTERIM)
{
LOG(1, s, session[s].tunnel, " Unexpected RADIUS response\n");
@ -511,7 +574,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
return; // Do nothing. On timeout, it will try the next radius server.
}
if ((radius[r].state == RADIUSAUTH && r_code != AccessAccept && r_code != AccessReject) ||
if (((radius[r].state == RADIUSAUTH ||radius[r].state == RADIUSJUSTAUTH) && r_code != AccessAccept && r_code != AccessReject) ||
((radius[r].state == RADIUSSTART || radius[r].state == RADIUSSTOP || radius[r].state == RADIUSINTERIM) && r_code != AccountingResponse))
{
LOG(1, s, session[s].tunnel, " Unexpected RADIUS response %s\n", radius_code(r_code));
@ -519,7 +582,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
// care off finishing the radius session if that's really correct.
}
if (radius[r].state == RADIUSAUTH)
if (radius[r].state == RADIUSAUTH || radius[r].state == RADIUSJUSTAUTH)
{
// run post-auth plugin
struct param_post_auth packet = {
@ -537,7 +600,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
if (radius[r].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!
*p = (r_code == AccessAccept) ? 3 : 4; // ack/nak
@ -551,7 +614,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
else
{
// 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!
// ack/nak
@ -715,6 +778,22 @@ void processrad(uint8_t *buf, int len, char socket_index)
ip_filters[f].used++;
}
}
else if (*p == 27)
{
// Session-Timeout
if (p[1] < 6) continue;
session[s].session_timeout = ntohl(*(uint32_t *)(p + 2));
LOG(3, s, session[s].tunnel, " Radius reply contains Session-Timeout = %u\n", session[s].session_timeout);
if(!session[s].session_timeout && config->kill_timedout_sessions)
sessionshutdown(s, "Session timeout is zero", CDN_ADMIN_DISC, 0);
}
else if (*p == 28)
{
// Idle-Timeout
if (p[1] < 6) continue;
session[s].idle_timeout = ntohl(*(uint32_t *)(p + 2));
LOG(3, s, session[s].tunnel, " Radius reply contains Idle-Timeout = %u\n", session[s].idle_timeout);
}
else if (*p == 99)
{
// Framed-IPv6-Route
@ -793,6 +872,7 @@ void radiusretry(uint16_t r)
sendchap(s, t);
break;
case RADIUSAUTH: // sending auth to RADIUS server
case RADIUSJUSTAUTH: // sending auth to RADIUS server
case RADIUSSTART: // sending start accounting to RADIUS server
case RADIUSSTOP: // sending stop accounting to RADIUS server
case RADIUSINTERIM: // sending interim accounting to RADIUS server

11
test/Makefile Normal file
View file

@ -0,0 +1,11 @@
CFLAGS = -g -Wall -W -std=c99 -pedantic
TARGETS = bounce generateload radius
all: $(TARGETS)
clean:
rm -f $(TARGETS)
../md5.o: ../md5.c ../md5.h
$(MAKE) -C .. md5.o
radius: radius.c ../md5.o

View file

@ -68,7 +68,8 @@ int main(int argc, char *argv[])
while (1)
{
struct sockaddr_in addr;
int alen = sizeof(addr), l;
socklen_t alen = sizeof(addr);
int l;
unsigned int iseq;
l = recvfrom(s, packet, 65535, 0, (void *) &addr, &alen);
@ -87,7 +88,7 @@ int main(int argc, char *argv[])
free(packet);
}
void sigalarm(int junk)
void sigalarm(int unusedg __attribute__ ((unused)))
{
printf("Recv: %10llu %0.1fMbits/s (%lu pps) (%5ld dropped)\n", recv_count, (bytes / 1024.0 / 1024.0 * 8), pps, dropped);
pps = bytes = 0;

View file

@ -1,3 +1,9 @@
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#define __USE_XOPEN_EXTENDED
#define __USE_MISC
#include <arpa/inet.h>
#include <time.h>
#include <errno.h>
@ -6,11 +12,8 @@
#include <netdb.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <unistd.h>
@ -179,10 +182,10 @@ typedef struct
} control_message;
typedef struct {
unsigned long long send_count , recv_count ;
unsigned long long spkt , rpkt ;
unsigned int dropped;
unsigned long sbytes , rbytes ;
long long send_count, recv_count;
long long spkt, rpkt ;
int dropped;
long sbytes, rbytes ;
int quitit;
struct sessiont
{
@ -210,7 +213,7 @@ void dump_control_message(control_message *c);
u32 avp_get_32(control_message *c, int id);
u16 avp_get_16(control_message *c, int id);
char *avp_get_s(control_message *c, int id);
void reader_thread(int udpfd);
void reader_thread(void);
void skip_zlb();
void cm_free(control_message *m);
controlt *ppp_new(u16 session, int protocol);
@ -234,7 +237,7 @@ void print_report();
int ns = 0, nr = 0;
int udpfd;
int t = 0;
struct sockaddr_in gatewayaddr = {0};
struct sockaddr_in gatewayaddr;
int numsessions = NUM_SESSIONS;
int packet_length = PACKET_LENGTH;
int target_pps = TARGET_PPS;
@ -251,7 +254,7 @@ char *suffix = "@optusnet.com.au";
int main(int argc, char *argv[])
{
int s;
char *packet;
unsigned char *packet;
ss = (sharedt*) mmap(NULL, sizeof(*ss), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
@ -377,6 +380,7 @@ int main(int argc, char *argv[])
printf("Bound to port %d\n", htons(addr.sin_port));
}/*}}}*/
memset(&gatewayaddr, 0, sizeof(gatewayaddr));
gatewayaddr.sin_family = AF_INET;
gatewayaddr.sin_port = htons(1701);
inet_aton(gwaddr, &gatewayaddr.sin_addr);
@ -400,7 +404,8 @@ int main(int argc, char *argv[])
// Receive reply/*{{{*/
{
struct sockaddr_in addr;
int alen = sizeof(addr), l;
int l;
socklen_t alen = sizeof(addr);
l = recvfrom(udpfd, packet, 4096, 0, (void *) &addr, &alen);
if (l < 0)
@ -409,7 +414,7 @@ int main(int argc, char *argv[])
return -1;
}
printf("Received ");
r = parsecontrol(packet, l);
r = parsecontrol((char *) packet, l);
if (!r->first)
{
printf("Invalid packet.. no first avp\n");
@ -446,7 +451,7 @@ int main(int argc, char *argv[])
printf("All session create requests sent...\n");/*}}}*/
if ( fork() == 0) {
reader_thread(udpfd);
reader_thread();
exit(0);
}
@ -529,7 +534,7 @@ int main(int argc, char *argv[])
*(u16 *)(c->buf + 4) = htons(ss->sessions[i].remote_session); // Session ID
iph->saddr = ss->sessions[i].addr;
iph->check = 0;
iph->check = ntohs(checksum((char *)iph, sizeof(struct iphdr)));
iph->check = ntohs(checksum((unsigned char *)iph, sizeof(struct iphdr)));
*((unsigned int *) data) = seq++;
ppp_send(c);
@ -546,7 +551,8 @@ int main(int argc, char *argv[])
nanosleep(&req, NULL);
}
if (max_packets && ss->send_count >= max_packets) ss->quitit++;
if (max_packets && ss->send_count >= max_packets)
ss->quitit++;
}
}
@ -602,22 +608,24 @@ void clean_shutdown()/*{{{*/
}
}/*}}}*/
void sigint(int signal)
void sigint(int unused __attribute__ ((unused)))
{
ss->quitit++;
}
void sigalarm(int junk)
void sigalarm(int unused __attribute__ ((unused)))
{
static unsigned long long last_rpkts[AVG_SIZE], last_spkts[AVG_SIZE];
static int last = 0, avg_count = 0;
register unsigned int avg_s = 0, avg_r = 0, i;
unsigned int avg_s = 0, avg_r = 0;
int i;
float loss;
last_rpkts[last] = ss->rpkt;
last_spkts[last] = ss->spkt;
last = (last + 1) % AVG_SIZE;
if (avg_count < AVG_SIZE) avg_count++;
if (avg_count < AVG_SIZE)
avg_count++;
for (i = 0; i < avg_count; i++)
{
@ -867,7 +875,7 @@ void cm_free(control_message *m)
// }}}
void reader_thread(int updfd)/*{{{*/
void reader_thread()/*{{{*/
{
unsigned char *packet;
unsigned int seq = 0;
@ -877,7 +885,7 @@ void reader_thread(int updfd)/*{{{*/
while (!ss->quitit)
{
struct sockaddr_in addr;
int alen = sizeof(addr);
socklen_t alen = sizeof(addr);
control_message *m;
int l;
int s;
@ -906,7 +914,7 @@ void reader_thread(int updfd)/*{{{*/
{
// Control Packet
printf("Reader Received ");
m = parsecontrol(packet, l);
m = parsecontrol((char *) packet, l);
printf("\n");
s = m->session;
@ -975,7 +983,7 @@ void reader_thread(int updfd)/*{{{*/
if (protocol != PPPIP)
{
printf("Received ");
dump_ppp_packet(packet + 6, l - 6);
dump_ppp_packet((char *) (packet + 6), l - 6);
}
if (protocol == PPPLCP)
@ -1073,13 +1081,13 @@ void reader_thread(int updfd)/*{{{*/
if (iph->protocol == 17)
{
int iseq;
unsigned int iseq;
ss->recv_count++;
ss->rpkt++;
iseq = *((unsigned int *) data);
if (seq != iseq) {
if (seq != iseq)
ss->dropped += (iseq - seq) ;
}
seq = iseq + 1; // Next sequence number to expect.
}
}
@ -1095,7 +1103,7 @@ void reader_thread(int updfd)/*{{{*/
void skip_zlb() /*{{{*/
{
struct sockaddr_in addr;
int alen = sizeof(addr);
socklen_t alen = sizeof(addr);
char buf[1024];
int l;
l = recvfrom(udpfd, buf, 1024, MSG_PEEK, (void *) &addr, &alen);