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 * Thu Jan 20 2011 Brendan O'Dea <bod@optus.net> 2.2.x
- Security: Rhys Kidd identified a vulnerability in the handling of - Apply MLPPP patch from Muhammad Tayseer Alquoatli.
heartbeat packets. Drop oversize heartbeat packets. - 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 * Mon Dec 18 2006 Brendan O'Dea <bod@optus.net> 2.2.0
- Fix sign problem with reporting of unknown VSAs. - Only poll clifd if successfully bound.
- Allow DNS servers to be specified either using the old or new - Add "Practical VPNs" document from Liran Tal as Docs/vpn .
vendor-specific Ascend formats. - Add Multilink support from Khaled Al Hamwi.
- Remove non-working setuid option.
* Fri Jun 23 2006 Brendan O'Dea <bod@optus.net> 2.1.19 - Convert manual.html to Docbook.
- Kludge around problem with Netgear DM602 authentication. - 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 - Use result code AVP to set Acct-Terminate-Cause is disconnect cause
AVP is not present. 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 * Tue Apr 18 2006 Brendan O'Dea <bod@optus.net> 2.1.18
- Don't shutdown on TerminateReq, wait for CDN. - Don't shutdown on TerminateReq, wait for CDN.

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 .de Id
.ds Dt \\$4 \\$5 .ds Dt \\$4 \\$5
.. ..
.Id $Id: startup-config.5,v 1.15 2005/09/16 05:04:31 bodea Exp $ .Id $Id: startup-config.5,v 1.18 2006/07/01 12:40:17 bodea Exp $
.TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions" .TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
.SH NAME .SH NAME
startup\-config \- configuration file for l2tpns startup\-config \- configuration file for l2tpns
@ -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 Number of Configure-Nak requests to send before sending a
Configure-Reject (default: 5). Configure-Reject (default: 5).
.TP .TP
.BR primary_dns , " secondary_dns" .BR primary_dns ", " secondary_dns
Whenever a PPP connection is established, DNS servers will be sent to the 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 user, both a primary and a secondary. If either is set to 0.0.0.0, then that
one will not be sent. one will not be sent.
.TP .TP
.BR primary_radius , " secondary_radius" .BR primary_radius ", " secondary_radius
Sets the RADIUS servers used for both authentication and accounting. Sets the RADIUS servers used for both authentication and accounting.
If the primary server does not respond, then the secondary RADIUS If the primary server does not respond, then the secondary RADIUS
server will be tried. server will be tried.
.TP .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 Sets the authentication ports for the primary and secondary RADIUS
servers. The accounting port is one more than the authentication servers. The accounting port is one more than the authentication
port. If no ports are given, authentication defaults to 1645, and 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) Port for DAE RADIUS (Packet of Death/Disconnect, Change of Authorization)
requests (default: 3799). requests (default: 3799).
.TP .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 .B allow_duplicate_users
Allow multiple logins with the same username. If false (the default), Allow multiple logins with the same username. If false (the default),
any prior session with the same username will be dropped when a new any prior session with the same username will be dropped when a new
session is established. session is established.
.TP .TP
.B guest_account
Allow multiple logins matching this specific username.
.TP
.B bind_address .B bind_address
When the tun interface is created, it is assigned the address When the tun interface is created, it is assigned the address
specified here. If no address is given, 1.1.1.1 is used. Packets specified here. If no address is given, 1.1.1.1 is used. Packets
@ -149,10 +157,6 @@ session requires two buckets (in and out).
If set to a directory, then every 5 minutes the current usage for 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. every connected use will be dumped to a file in this directory.
.TP .TP
.B setuid
After starting up and binding the interface, change UID to this. This
doesn't work properly.
.TP
.B dump_speed .B dump_speed
If set to true, then the current bandwidth utilization will be logged If set to true, then the current bandwidth utilization will be logged
every second. Even if this is disabled, you can see this information 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> Juergen Kammer <j.kammer@eurodata.de>
Simon Talbot <simont@nse.co.uk> Simon Talbot <simont@nse.co.uk>
Jonathan McDowell <noodles@earth.li> 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> Roberto Chostakovis <rchostakovis@users.sourceforge.net>
Jordan Hrycaj <jordan@mjh.teddy-net.com> Jordan Hrycaj <jordan@mjh.teddy-net.com>
Vladislav Bjelic <vladislav@gmail.com> Vladislav Bjelic <vladislav@gmail.com>
@ -26,4 +26,8 @@ Jon Morby <jon@fido.net>
Paul Martin <pm@zetnet.net> Paul Martin <pm@zetnet.net>
Jonathan Yarden <jyarden@bluegrass.net> Jonathan Yarden <jyarden@bluegrass.net>
Patrick Cole <z@amused.net> Patrick Cole <z@amused.net>
Khaled Al Hamwi <kh.alhamwi@gmail.com>
Graham Maltby <gmaltby+l2tpns@iig.com.au>
Rhys Kidd <rhys.kidd@staff.westnet.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 * lcp:interface-config#2=service-policy output N
* *
* throttle=N * throttle=N
* throttle=yes (use throttle_rate from config) * throttle=yes (use throttle_speed from config)
* throttle=no * 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; int plugin_api_version = PLUGIN_API_VERSION;
static struct pluginfuncs *f = 0; static struct pluginfuncs *f = 0;

50
cli.c
View file

@ -1,8 +1,8 @@
// L2TPNS Command Line Interface // L2TPNS Command Line Interface
// vim: sw=8 ts=8 // vim: sw=8 ts=8
char const *cvs_name = "$Name: release_2_1_21 $"; char const *cvs_name = "$Name: $";
char const *cvs_id_cli = "$Id: cli.c,v 1.71 2005/12/06 09:43:42 bodea Exp $"; char const *cvs_id_cli = "$Id: cli.c,v 1.76 2006/12/18 12:08:28 bodea Exp $";
#include <stdio.h> #include <stdio.h>
#include <stddef.h> #include <stddef.h>
@ -36,6 +36,7 @@ char const *cvs_id_cli = "$Id: cli.c,v 1.71 2005/12/06 09:43:42 bodea Exp $";
#endif #endif
extern tunnelt *tunnel; extern tunnelt *tunnel;
extern bundlet *bundle;
extern sessiont *session; extern sessiont *session;
extern radiust *radius; extern radiust *radius;
extern ippoolt *ip_address_pool; extern ippoolt *ip_address_pool;
@ -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_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_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_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); static int regular_stuff(struct cli_def *cli);
@ -175,6 +179,8 @@ void init_cli(char *hostname)
#endif #endif
cli_register_command(cli, NULL, "uptime", cmd_uptime, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show uptime and bandwidth utilisation"); 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); 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"); 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)); 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)); setsockopt(clifd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
{ {
int flags; 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, "\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, "\tOpened:\t\t%u seconds", session[s].opened ? abs(time_now - session[s].opened) : 0);
cli_print(cli, "\tIdle time:\t%u seconds", session[s].last_packet ? abs(time_now - session[s].last_packet) : 0); cli_print(cli, "\tIdle time:\t%u seconds", session[s].last_packet ? abs(time_now - session[s].last_packet) : 0);
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, "\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, "\tPkts In/Out:\t%u/%u", session[s].pout, session[s].pin);
cli_print(cli, "\tMRU:\t\t%d", session[s].mru); cli_print(cli, "\tMRU:\t\t%d", session[s].mru);
@ -2016,7 +2034,7 @@ static int cmd_router_bgp_neighbour(struct cli_def *cli, char *command, char **a
int keepalive; int keepalive;
int hold; int hold;
if (CLI_HELP_REQUESTED) if (CLI_HELP_REQUESTED)
{ {
switch (argc) 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].keepalive = keepalive;
config->neighbour[i].hold = hold; 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) static int cmd_router_bgp_no_neighbour(struct cli_def *cli, char *command, char **argv, int argc)
{ {
int i; int i;
if (CLI_HELP_REQUESTED) if (CLI_HELP_REQUESTED)
return cli_arg_help(cli, argc > 0, return cli_arg_help(cli, argc > 0,
"A.B.C.D", "BGP neighbour address", "A.B.C.D", "BGP neighbour address",
"NAME", "BGP neighbour name", "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])); 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) 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; 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 // 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 <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -42,6 +42,7 @@ extern int cluster_sockfd; // The filedescriptor for the cluster communications
in_addr_t my_address = 0; // The network address of my ethernet port. in_addr_t my_address = 0; // The network address of my ethernet port.
static int walk_session_number = 0; // The next session to send when doing the slow table walk. static int walk_session_number = 0; // The next session to send when doing the slow table walk.
static int walk_bundle_number = 0; // The next bundle to send when doing the slow table walk.
static int walk_tunnel_number = 0; // The next tunnel to send when doing the slow table walk. static int walk_tunnel_number = 0; // The next tunnel to send when doing the slow table walk.
int forked = 0; // Sanity check: CLI must not diddle with heartbeat table int forked = 0; // Sanity check: CLI must not diddle with heartbeat table
@ -85,6 +86,7 @@ int cluster_init()
int opt; int opt;
config->cluster_undefined_sessions = MAXSESSION-1; config->cluster_undefined_sessions = MAXSESSION-1;
config->cluster_undefined_bundles = MAXBUNDLE-1;
config->cluster_undefined_tunnels = MAXTUNNEL-1; config->cluster_undefined_tunnels = MAXTUNNEL-1;
if (!config->cluster_address) if (!config->cluster_address)
@ -227,7 +229,7 @@ static void cluster_uptodate(void)
if (config->cluster_iam_uptodate) if (config->cluster_iam_uptodate)
return; return;
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels) if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles)
return; return;
config->cluster_iam_uptodate = 1; config->cluster_iam_uptodate = 1;
@ -400,7 +402,7 @@ void cluster_send_ping(time_t basetime)
x.ver = 1; x.ver = 1;
x.addr = config->bind_address; 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; x.basetime = basetime;
add_type(&p, C_PING, basetime, (uint8_t *) &x, sizeof(x)); 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) void cluster_check_master(void)
{ {
int i, count, tcount, high_unique_id = 0; int i, count, tcount, bcount, high_unique_id = 0;
int last_free = 0; int last_free = 0;
clockt t = TIME; clockt t = TIME;
static int probed = 0; static int probed = 0;
@ -614,6 +616,19 @@ void cluster_check_master(void)
config->cluster_highest_tunnelid = i; config->cluster_highest_tunnelid = i;
} }
//
// Go through and mark all the bundles as defined.
// Count the highest used bundle number as well.
//
config->cluster_highest_bundleid = 0;
for (i = 0, bcount = 0; i < MAXBUNDLE; ++i) {
if (bundle[i].state == BUNDLEUNDEF)
bundle[i].state = BUNDLEFREE;
if (bundle[i].state != BUNDLEFREE && i > config->cluster_highest_bundleid)
config->cluster_highest_bundleid = i;
}
// //
// Go through and mark all the sessions as being defined. // Go through and mark all the sessions as being defined.
// reset the idle timeouts. // reset the idle timeouts.
@ -639,7 +654,7 @@ void cluster_check_master(void)
} }
// Reset idle timeouts.. // 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 // Reset die relative to our uptime rather than the old master's
if (session[i].die) session[i].die = TIME; if (session[i].die) session[i].die = TIME;
@ -675,10 +690,11 @@ void cluster_check_master(void)
rebuild_address_pool(); rebuild_address_pool();
// If we're not the very first master, this is a big issue! // If we're not the very first master, this is a big issue!
if(count>0) if (count > 0)
LOG(0, 0, 0, "Warning: Fixed %d uninitialized sessions in becoming master!\n", count); LOG(0, 0, 0, "Warning: Fixed %d uninitialized sessions in becoming master!\n", count);
config->cluster_undefined_sessions = 0; config->cluster_undefined_sessions = 0;
config->cluster_undefined_bundles = 0;
config->cluster_undefined_tunnels = 0; config->cluster_undefined_tunnels = 0;
config->cluster_iam_uptodate = 1; // assume all peers are up-to-date config->cluster_iam_uptodate = 1; // assume all peers are up-to-date
@ -696,7 +712,7 @@ void cluster_check_master(void)
// we fix it up here, and we ensure that the 'first free session' // we fix it up here, and we ensure that the 'first free session'
// pointer is valid. // pointer is valid.
// //
static void cluster_check_sessions(int highsession, int freesession_ptr, int hightunnel) static void cluster_check_sessions(int highsession, int freesession_ptr, int highbundle, int hightunnel)
{ {
int i; int i;
@ -705,7 +721,7 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig
if (config->cluster_iam_uptodate) if (config->cluster_iam_uptodate)
return; return;
if (highsession > config->cluster_undefined_sessions && hightunnel > config->cluster_undefined_tunnels) if (highsession > config->cluster_undefined_sessions && highbundle > config->cluster_undefined_bundles && hightunnel > config->cluster_undefined_tunnels)
return; return;
// Clear out defined sessions, counting the number of // Clear out defined sessions, counting the number of
@ -721,6 +737,19 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig
++config->cluster_undefined_sessions; ++config->cluster_undefined_sessions;
} }
// Clear out defined bundles, counting the number of
// undefs remaining.
config->cluster_undefined_bundles = 0;
for (i = 1 ; i < MAXBUNDLE; ++i) {
if (i > highbundle) {
if (bundle[i].state == BUNDLEUNDEF) bundle[i].state = BUNDLEFREE; // Defined.
continue;
}
if (bundle[i].state == BUNDLEUNDEF)
++config->cluster_undefined_bundles;
}
// Clear out defined tunnels, counting the number of // Clear out defined tunnels, counting the number of
// undefs remaining. // undefs remaining.
config->cluster_undefined_tunnels = 0; config->cluster_undefined_tunnels = 0;
@ -735,9 +764,9 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig
} }
if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels) { if (config->cluster_undefined_sessions || config->cluster_undefined_tunnels || config->cluster_undefined_bundles) {
LOG(2, 0, 0, "Cleared undefined sessions/tunnels. %d sess (high %d), %d tunn (high %d)\n", LOG(2, 0, 0, "Cleared undefined sessions/bundles/tunnels. %d sess (high %d), %d bund (high %d), %d tunn (high %d)\n",
config->cluster_undefined_sessions, highsession, config->cluster_undefined_tunnels, hightunnel); config->cluster_undefined_sessions, highsession, config->cluster_undefined_bundles, highbundle, config->cluster_undefined_tunnels, hightunnel);
return; return;
} }
@ -770,6 +799,27 @@ static int hb_add_type(uint8_t **p, int type, int id)
add_type(p, C_SESSION, id, (uint8_t *) &session[id], sizeof(sessiont)); add_type(p, C_SESSION, id, (uint8_t *) &session[id], sizeof(sessiont));
break; break;
case C_CBUNDLE: { // Compressed C_BUNDLE
uint8_t c[sizeof(bundlet) * 2]; // Bigger than worst case.
uint8_t *d = (uint8_t *) &bundle[id];
uint8_t *orig = d;
int size;
size = rle_compress( &d, sizeof(bundlet), c, sizeof(c) );
// Did we compress the full structure, and is the size actually
// reduced??
if ( (d - orig) == sizeof(bundlet) && size < sizeof(bundlet) ) {
add_type(p, C_CBUNDLE, id, c, size);
break;
}
// Failed to compress : Fall through.
}
case C_BUNDLE:
add_type(p, C_BUNDLE, id, (uint8_t *) &bundle[id], sizeof(bundlet));
break;
case C_CTUNNEL: { // Compressed C_TUNNEL case C_CTUNNEL: { // Compressed C_TUNNEL
uint8_t c[sizeof(tunnelt) * 2]; // Bigger than worst case. uint8_t c[sizeof(tunnelt) * 2]; // Bigger than worst case.
uint8_t *d = (uint8_t *) &tunnel[id]; uint8_t *d = (uint8_t *) &tunnel[id];
@ -802,7 +852,7 @@ static int hb_add_type(uint8_t **p, int type, int id)
// //
void cluster_heartbeat() void cluster_heartbeat()
{ {
int i, count = 0, tcount = 0; int i, count = 0, tcount = 0, bcount = 0;
uint8_t buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ]; uint8_t buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
heartt h; heartt h;
uint8_t *p = buff; uint8_t *p = buff;
@ -823,7 +873,9 @@ void cluster_heartbeat()
h.highsession = config->cluster_highest_sessionid; h.highsession = config->cluster_highest_sessionid;
h.freesession = sessionfree; h.freesession = sessionfree;
h.hightunnel = config->cluster_highest_tunnelid; h.hightunnel = config->cluster_highest_tunnelid;
h.highbundle = config->cluster_highest_bundleid;
h.size_sess = sizeof(sessiont); // Just in case. h.size_sess = sizeof(sessiont); // Just in case.
h.size_bund = sizeof(bundlet);
h.size_tunn = sizeof(tunnelt); h.size_tunn = sizeof(tunnelt);
h.interval = config->cluster_hb_interval; h.interval = config->cluster_hb_interval;
h.timeout = config->cluster_hb_timeout; h.timeout = config->cluster_hb_timeout;
@ -878,6 +930,21 @@ void cluster_heartbeat()
++tcount; ++tcount;
} }
//
// Fill out the packet with bundles from the bundle table...
while ( (p + sizeof(uint32_t) * 2 + sizeof(bundlet) ) < (buff + MAX_HEART_SIZE) ) {
if (!walk_bundle_number) // bundle #0 isn't valid.
++walk_bundle_number;
if (bcount >= config->cluster_highest_bundleid)
break;
hb_add_type(&p, C_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? // Did we do something wrong?
if (p > (buff + sizeof(buff))) { // Did we somehow manage to overun the buffer? if (p > (buff + sizeof(buff))) { // Did we somehow manage to overun the buffer?
@ -887,9 +954,9 @@ void cluster_heartbeat()
} }
LOG(3, 0, 0, "Sending v%d heartbeat #%d, change #%" PRIu64 " with %d changes " LOG(3, 0, 0, "Sending v%d heartbeat #%d, change #%" PRIu64 " with %d changes "
"(%d x-sess, %d x-tunnels, %d highsess, %d hightun, size %d)\n", "(%d x-sess, %d x-bundles, %d x-tunnels, %d highsess, %d highbund, %d hightun, size %d)\n",
HB_VERSION, h.seq, h.table_version, config->cluster_num_changes, HB_VERSION, h.seq, h.table_version, config->cluster_num_changes,
count, tcount, config->cluster_highest_sessionid, count, bcount, tcount, config->cluster_highest_sessionid, config->cluster_highest_bundleid,
config->cluster_highest_tunnelid, (int) (p - buff)); config->cluster_highest_tunnelid, (int) (p - buff));
config->cluster_num_changes = 0; config->cluster_num_changes = 0;
@ -938,6 +1005,17 @@ int cluster_send_session(int sid)
return type_changed(C_CSESSION, sid); return type_changed(C_CSESSION, sid);
} }
// A particular bundle has been changed!
int cluster_send_bundle(int bid)
{
if (!config->cluster_iam_master) {
LOG(0, 0, bid, "I'm not a master, but I just tried to change a bundle!\n");
return -1;
}
return type_changed(C_CBUNDLE, bid);
}
// A particular tunnel has been changed! // A particular tunnel has been changed!
int cluster_send_tunnel(int tid) int cluster_send_tunnel(int tid)
{ {
@ -1135,7 +1213,9 @@ static int cluster_handle_bytes(uint8_t *data, int size)
session[b->sid].cout_delta += b->cout; session[b->sid].cout_delta += b->cout;
if (b->cin) 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); size -= sizeof(*b);
++b; ++b;
@ -1175,6 +1255,31 @@ static int cluster_recv_session(int more, uint8_t *p)
return 0; return 0;
} }
static int cluster_recv_bundle(int more, uint8_t *p)
{
if (more >= MAXBUNDLE) {
LOG(0, 0, 0, "DANGER: Received a bundle id > MAXBUNDLE!\n");
return -1;
}
if (bundle[more].state == BUNDLEUNDEF) {
if (config->cluster_iam_uptodate) { // Sanity.
LOG(0, 0, 0, "I thought I was uptodate but I just found an undefined bundle!\n");
} else {
--config->cluster_undefined_bundles;
}
}
memcpy(&bundle[more], p, sizeof(bundle[more]) );
LOG(5, 0, more, "Received bundle update\n");
if (!config->cluster_iam_uptodate)
cluster_uptodate(); // Check to see if we're up to date.
return 0;
}
static int cluster_recv_tunnel(int more, uint8_t *p) static int cluster_recv_tunnel(int more, uint8_t *p)
{ {
if (more >= MAXTUNNEL) { if (more >= MAXTUNNEL) {
@ -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 // Check that we don't have too many undefined sessions, and
// that the free session pointer is correct. // that the free session pointer is correct.
cluster_check_sessions(h->highsession, h->freesession, h->hightunnel); cluster_check_sessions(h->highsession, h->freesession, h->highbundle, h->hightunnel);
if (h->interval != config->cluster_hb_interval) if (h->interval != config->cluster_hb_interval)
{ {
@ -1573,6 +1678,34 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t
p += sizeof(tunnel[more]); p += sizeof(tunnel[more]);
s -= sizeof(tunnel[more]); s -= sizeof(tunnel[more]);
break; break;
case C_CBUNDLE: { // Compressed bundle structure.
uint8_t c[ sizeof(bundlet) + 2];
int size;
uint8_t *orig_p = p;
size = rle_decompress((uint8_t **) &p, s, c, sizeof(c));
s -= (p - orig_p);
if (size != sizeof(bundlet) ) { // Ouch! Very very bad!
LOG(0, 0, 0, "DANGER: Received a CBUNDLE that didn't decompress correctly!\n");
// Now what? Should exit! No-longer up to date!
break;
}
cluster_recv_bundle(more, c);
break;
}
case C_BUNDLE:
if ( s < sizeof(bundle[more]))
goto shortpacket;
cluster_recv_bundle(more, p);
p += sizeof(bundle[more]);
s -= sizeof(bundle[more]);
break;
default: default:
LOG(0, 0, 0, "DANGER: I received a heartbeat element where I didn't understand the type! (%d)\n", type); LOG(0, 0, 0, "DANGER: I received a heartbeat element where I didn't understand the type! (%d)\n", type);
return -1; // can't process any more of the packet!! return -1; // can't process any more of the packet!!
@ -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. case C_FORWARD_DAE: // Forwarded DAE packet. pass off to processdae.
if (!config->cluster_iam_master) 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)); type == C_FORWARD_DAE ? "_DAE" : "", fmtaddr(addr, 0));
return -1; 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, "Table version # : %" PRIu64, config->cluster_table_version);
cli_print(cli, "Next sequence number expected: %d", config->cluster_seq_number); cli_print(cli, "Next sequence number expected: %d", config->cluster_seq_number);
cli_print(cli, "%d sessions undefined of %d", config->cluster_undefined_sessions, config->cluster_highest_sessionid); cli_print(cli, "%d sessions undefined of %d", config->cluster_undefined_sessions, config->cluster_highest_sessionid);
cli_print(cli, "%d bundles undefined of %d", config->cluster_undefined_bundles, config->cluster_highest_bundleid);
cli_print(cli, "%d tunnels undefined of %d", config->cluster_undefined_tunnels, config->cluster_highest_tunnelid); cli_print(cli, "%d tunnels undefined of %d", config->cluster_undefined_tunnels, config->cluster_highest_tunnelid);
} else { } else {
cli_print(cli, "Table version # : %" PRIu64, config->cluster_table_version); cli_print(cli, "Table version # : %" PRIu64, config->cluster_table_version);
cli_print(cli, "Next heartbeat # : %d", config->cluster_seq_number); cli_print(cli, "Next heartbeat # : %d", config->cluster_seq_number);
cli_print(cli, "Highest session : %d", config->cluster_highest_sessionid); cli_print(cli, "Highest session : %d", config->cluster_highest_sessionid);
cli_print(cli, "Highest bundle : %d", config->cluster_highest_bundleid);
cli_print(cli, "Highest tunnel : %d", config->cluster_highest_tunnelid); cli_print(cli, "Highest tunnel : %d", config->cluster_highest_tunnelid);
cli_print(cli, "%d changes queued for sending", config->cluster_num_changes); cli_print(cli, "%d changes queued for sending", config->cluster_num_changes);
} }

View file

@ -1,5 +1,5 @@
// L2TPNS Clustering Stuff // L2TPNS Clustering Stuff
// $Id: cluster.h,v 1.14 2005/07/31 10:04:10 bodea Exp $ // $Id: cluster.h,v 1.16 2006/12/04 20:54:51 bodea Exp $
#ifndef __CLUSTER_H__ #ifndef __CLUSTER_H__
#define __CLUSTER_H__ #define __CLUSTER_H__
@ -21,6 +21,8 @@
#define C_GARDEN 14 // Gardened packet #define C_GARDEN 14 // Gardened packet
#define C_MASTER 15 // Tell a slave the address of the master. #define C_MASTER 15 // Tell a slave the address of the master.
#define C_FORWARD_DAE 16 // A DAE packet for the master to handle #define C_FORWARD_DAE 16 // A DAE packet for the master to handle
#define C_BUNDLE 17 // Bundle structure.
#define C_CBUNDLE 18 // Compressed bundle structure.
#define HB_VERSION 5 // Protocol version number.. #define HB_VERSION 5 // Protocol version number..
#define HB_MAX_SEQ (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!) #define HB_MAX_SEQ (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!)
@ -43,16 +45,18 @@ typedef struct {
uint32_t highsession; // Id of the highest in-use session. uint32_t highsession; // Id of the highest in-use session.
uint32_t freesession; // Id of the first free session. uint32_t freesession; // Id of the first free session.
uint32_t highbundle; // Id of the highest used bundle.
uint32_t hightunnel; // Id of the highest used tunnel. uint32_t hightunnel; // Id of the highest used tunnel.
uint32_t size_sess; // Size of the session structure. uint32_t size_sess; // Size of the session structure.
uint32_t size_bund; // size of the bundle structure.
uint32_t size_tunn; // size of the tunnel structure. uint32_t size_tunn; // size of the tunnel structure.
uint32_t interval; // ping/heartbeat interval uint32_t interval; // ping/heartbeat interval
uint32_t timeout; // heartbeat timeout uint32_t timeout; // heartbeat timeout
uint64_t table_version; // # state changes processed by cluster 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; } heartt;
typedef struct { /* Used to update byte counters on the */ typedef struct { /* Used to update byte counters on the */
@ -74,6 +78,7 @@ typedef struct {
int cluster_init(void); int cluster_init(void);
int processcluster(uint8_t *buf, int size, in_addr_t addr); int processcluster(uint8_t *buf, int size, in_addr_t addr);
int cluster_send_session(int sid); int cluster_send_session(int sid);
int cluster_send_bundle(int bid);
int cluster_send_tunnel(int tid); int cluster_send_tunnel(int tid);
int master_forward_packet(uint8_t *data, int size, in_addr_t addr, int port); int master_forward_packet(uint8_t *data, int size, in_addr_t addr, int port);
int master_forward_dae_packet(uint8_t *data, int size, in_addr_t addr, int port); int master_forward_dae_packet(uint8_t *data, int size, in_addr_t addr, int port);

View file

@ -1,6 +1,6 @@
// L2TPNS: constants // 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 <stdio.h>
#include "constants.h" #include "constants.h"
@ -197,7 +197,8 @@ CONSTANT(radius_state,
"RADIUSSTART", // 3 "RADIUSSTART", // 3
"RADIUSSTOP", // 4 "RADIUSSTOP", // 4
"RADIUSINTERIM", // 5 "RADIUSINTERIM", // 5
"RADIUSWAIT" // 6 "RADIUSWAIT", // 6
"RADIUSJUSTAUTH" // 7
) )
CONSTANT(radius_code, CONSTANT(radius_code,

View file

@ -41,6 +41,12 @@ set radius_secret "secret"
# Allow multiple logins for the same username # Allow multiple logins for the same username
#set allow_duplicate_users no #set allow_duplicate_users no
# 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 # Write usage accounting files into specified directory
set accounting_dir "/var/run/l2tpns/acct" 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 # Number of buckets to allocate for throttling
#set throttle_buckets 3000 #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 # If set to true, dump current speed to stderr every second
#set dump_speed no #set dump_speed no
@ -96,6 +99,9 @@ set accounting_dir "/var/run/l2tpns/acct"
# Minimum number of slaves before master withdraws routes # Minimum number of slaves before master withdraws routes
#set cluster_master_min_adv 1 #set cluster_master_min_adv 1
# IPv6 address prefix
#set ipv6_prefix ::
# Drop/kill sessions # Drop/kill sessions
#load plugin "sessionctl" #load plugin "sessionctl"

View file

@ -1,5 +1,5 @@
/* kludge up some limited epoll semantics using select for 2.4 kernels */ /* 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__ #ifndef __FAKE_EPOLL_H__
#define __FAKE_EPOLL_H__ #define __FAKE_EPOLL_H__
@ -150,6 +150,9 @@ static int epoll_wait(int epfd __attribute__ ((unused)),
tp = 0; tp = 0;
n = select(_epoll_fds, &r, &w, 0, tp); n = select(_epoll_fds, &r, &w, 0, tp);
if (n < 0)
return n;
if (n > maxevents) if (n > maxevents)
n = maxevents; n = maxevents;

4
icmp.c
View file

@ -1,6 +1,6 @@
// L2TPNS: icmp // L2TPNS: icmp
char const *cvs_id_icmp = "$Id: icmp.c,v 1.10 2005/08/10 11:25:56 bodea Exp $"; char const *cvs_id_icmp = "$Id: icmp.c,v 1.11 2006/04/27 09:53:49 bodea Exp $";
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
@ -114,7 +114,7 @@ void send_ipv6_ra(sessionidt s, tunnelidt t, struct in6_addr *ip)
LOG(3, s, t, "Sending IPv6 RA\n"); LOG(3, s, t, "Sending IPv6 RA\n");
memset(b, 0, sizeof(b)); memset(b, 0, sizeof(b));
o = makeppp(b, sizeof(b), 0, 0, s, t, PPPIPV6); o = makeppp(b, sizeof(b), 0, 0, s, t, PPPIPV6, 0, 0, 0);
if (!o) if (!o)
{ {

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 // 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__ #ifndef __L2TPNS_H__
#define __L2TPNS_H__ #define __L2TPNS_H__
@ -14,10 +14,13 @@
#include <sys/types.h> #include <sys/types.h>
#include <libcli.h> #include <libcli.h>
#define VERSION "2.1.21" #define VERSION "2.2.0"
// Limits // Limits
#define MAXTUNNEL 500 // could be up to 65535 #define MAXTUNNEL 500 // could be up to 65535
#define MAXBUNDLE 300 // could be up to 65535
#define MAXBUNDLESES 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 MAXSESSION 60000 // could be up to 65535
#define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session. #define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session.
@ -43,10 +46,20 @@
#define MAXIPPOOL 131072 // max number of ip addresses in pool #define MAXIPPOOL 131072 // max number of ip addresses in pool
#define RINGBUFFER_SIZE 10000 // Number of ringbuffer entries to allocate #define RINGBUFFER_SIZE 10000 // Number of ringbuffer entries to allocate
#define MAX_LOG_LENGTH 512 // Maximum size of log message #define MAX_LOG_LENGTH 512 // Maximum size of log message
#define ECHO_TIMEOUT 60 // Time between last packet sent and LCP ECHO generation #define ECHO_TIMEOUT 10 // Time between last packet sent and LCP ECHO generation
#define IDLE_TIMEOUT 240 // Time between last packet sent and LCP ECHO generation #define IDLE_TIMEOUT 240 // Time between last packet seen and session shutdown
#define BUSY_WAIT_TIME 3000 // 5 minutes in 1/10th seconds to wait for radius to cleanup on shutdown #define BUSY_WAIT_TIME 3000 // 5 minutes in 1/10th seconds to wait for radius to cleanup on shutdown
#define MP_BEGIN 0x80 // This value is used when (b)egin bit is set in MP header
#define MP_END 0x40 // This value is used when (e)nd bit is set in MP header
#define MP_BOTH_BITS 0xC0 // This value is used when both bits (begin and end) are set in MP header
#define 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 // Constants
#ifndef ETCDIR #ifndef ETCDIR
#define ETCDIR "/etc/l2tpns" #define ETCDIR "/etc/l2tpns"
@ -186,6 +199,7 @@ enum {
// Types // Types
typedef uint16_t sessionidt; typedef uint16_t sessionidt;
typedef uint16_t bundleidt;
typedef uint16_t tunnelidt; typedef uint16_t tunnelidt;
typedef uint32_t clockt; typedef uint32_t clockt;
typedef uint8_t hasht[16]; typedef uint8_t hasht[16];
@ -231,6 +245,20 @@ typedef struct controls // control message
} }
controlt; controlt;
typedef struct {
uint8_t length; // Endpoint Discriminator length
uint8_t addr_class; // Endpoint Discriminator class
uint8_t address[MAXADDRESS]; // Endpoint Discriminator address
} epdist;
typedef struct {
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 typedef struct
{ {
sessionidt next; // next session in linked list sessionidt next; // next session in linked list
@ -261,7 +289,10 @@ typedef struct
uint16_t mru; // maximum receive unit uint16_t mru; // maximum receive unit
clockt opened; // when started clockt opened; // when started
clockt die; // being closed, when to finally free 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_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 in_addr_t dns1, dns2; // DNS servers
routet route[MAXROUTE]; // static routes routet route[MAXROUTE]; // static routes
uint16_t tbf_in; // filter bucket for throttling in from the user. uint16_t tbf_in; // filter bucket for throttling in from the user.
@ -273,6 +304,11 @@ typedef struct
char calling[MAXTEL]; // calling number char calling[MAXTEL]; // calling number
uint32_t tx_connect_speed; uint32_t tx_connect_speed;
uint32_t rx_connect_speed; uint32_t rx_connect_speed;
clockt timeout; // Session timeout
uint32_t mrru; // Multilink Max-Receive-Reconstructed-Unit
uint8_t mssf; // Multilink Short Sequence Number Header Format
epdist epdis; // Multilink Endpoint Discriminator
bundleidt bundle; // Multilink Bundle Identifier
in_addr_t snoop_ip; // Interception destination IP in_addr_t snoop_ip; // Interception destination IP
uint16_t snoop_port; // Interception destination port uint16_t snoop_port; // Interception destination port
uint8_t walled_garden; // is this session gardened? uint8_t walled_garden; // is this session gardened?
@ -282,6 +318,36 @@ typedef struct
} }
sessiont; 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 AUTHPAP 1 // allow PAP
#define AUTHCHAP 2 // allow CHAP #define AUTHCHAP 2 // allow CHAP
@ -311,6 +377,15 @@ typedef struct
// our MRU // our MRU
uint16_t ppp_mru; uint16_t ppp_mru;
// our MRRU
uint16_t mp_mrru;
// our mssf
uint16_t mp_mssf;
// our Endpoint Discriminator
in_addr_t mp_epdis;
// DoS prevention // DoS prevention
clockt last_packet_out; clockt last_packet_out;
uint32_t packets_out; uint32_t packets_out;
@ -324,6 +399,9 @@ typedef struct
// last LCP Echo // last LCP Echo
time_t last_echo; time_t last_echo;
// Last Multilink frame sequence number received
uint32_t last_seq;
} sessionlocalt; } sessionlocalt;
// session flags // session flags
@ -407,6 +485,23 @@ enum
TUNNELUNDEF, // Undefined TUNNELUNDEF, // Undefined
}; };
enum
{
BUNDLEFREE, // Not in use
BUNDLEOPEN, // Active bundle
BUNDLEUNDEF, // Undefined
};
enum
{
NULLCLASS = 0, //End Point Discriminator classes
LOCALADDR,
IPADDR,
IEEEMACADDR,
PPPMAGIC,
PSNDN,
};
enum enum
{ {
RADIUSNULL, // Not in use RADIUSNULL, // Not in use
@ -416,6 +511,7 @@ enum
RADIUSSTOP, // sending stop accounting to RADIUS server RADIUSSTOP, // sending stop accounting to RADIUS server
RADIUSINTERIM, // sending interim accounting to RADIUS server RADIUSINTERIM, // sending interim accounting to RADIUS server
RADIUSWAIT, // waiting timeout before available, in case delayed replies RADIUSWAIT, // waiting timeout before available, in case delayed replies
RADIUSJUSTAUTH, // sending auth to RADIUS server, just authentication, no ip assigning
}; };
struct Tstats struct Tstats
@ -554,13 +650,16 @@ typedef struct
uint16_t radiusport[MAXRADSERVER]; // radius base ports uint16_t radiusport[MAXRADSERVER]; // radius base ports
uint8_t numradiusservers; // radius server count 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 char radius_authtypes_s[32]; // list of valid authentication types (chap, pap) in order of preference
int radius_authtypes; int radius_authtypes;
int radius_authprefer; int radius_authprefer;
int allow_duplicate_users; // allow multiple logins with the same username int allow_duplicate_users; // allow multiple logins with the same username
int kill_timedout_sessions; // kill authenticated sessions with "session_timeout == 0"
in_addr_t default_dns1, default_dns2; in_addr_t default_dns1, default_dns2;
@ -572,7 +671,6 @@ typedef struct
in_addr_t peer_address; in_addr_t peer_address;
int send_garp; // Set to true to garp for vip address on startup int send_garp; // Set to true to garp for vip address on startup
int target_uid;
int dump_speed; int dump_speed;
char plugins[64][MAXPLUGINS]; char plugins[64][MAXPLUGINS];
char old_plugins[64][MAXPLUGINS]; char old_plugins[64][MAXPLUGINS];
@ -583,6 +681,7 @@ typedef struct
int lock_pages; // Lock pages into memory. int lock_pages; // Lock pages into memory.
int icmp_rate; // Max number of ICMP unreachable per second to send int icmp_rate; // Max number of ICMP unreachable per second to send
int max_packets; // DoS prevention: per session limit of packets/0.1s int max_packets; // DoS prevention: per session limit of packets/0.1s
char epdis_addr[20]; // MP Endpoint Discriminator address
in_addr_t cluster_address; // Multicast address of cluster. in_addr_t cluster_address; // Multicast address of cluster.
// Send to this address to have everyone hear. // Send to this address to have everyone hear.
@ -594,8 +693,10 @@ typedef struct
int cluster_seq_number; // Sequence number of the next heartbeat we'll send out int cluster_seq_number; // Sequence number of the next heartbeat we'll send out
// (or the seq number we're next expecting if we're a slave). // (or the seq number we're next expecting if we're a slave).
int cluster_undefined_sessions; // How many sessions we're yet to receive from the master. int cluster_undefined_sessions; // How many sessions we're yet to receive from the master.
int cluster_undefined_bundles; // How many bundles we're yet to receive from the master.
int cluster_undefined_tunnels; // How many tunnels we're yet to receive from the master. int cluster_undefined_tunnels; // How many tunnels we're yet to receive from the master.
int cluster_highest_sessionid; int cluster_highest_sessionid;
int cluster_highest_bundleid;
int cluster_highest_tunnelid; int cluster_highest_tunnelid;
clockt cluster_last_hb; // Last time we saw a heartbeat from the master. clockt cluster_last_hb; // Last time we saw a heartbeat from the master.
int cluster_last_hb_ver; // Heartbeat version last seen from master int cluster_last_hb_ver; // Heartbeat version last seen from master
@ -611,6 +712,8 @@ typedef struct
int cluster_master_min_adv; // Master advertises routes while the number of up to date int cluster_master_min_adv; // Master advertises routes while the number of up to date
// slaves is less than this value. // slaves is less than this value.
// Guest change
char guest_user[MAXUSER]; // Guest account username
#ifdef BGP #ifdef BGP
#define BGP_NUM_PEERS 2 #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 processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
void processmpin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
void processmpframe(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint8_t extra);
void processipv6in(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); void processipv6in(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
void sendchap(sessionidt s, tunnelidt t); void sendchap(sessionidt s, tunnelidt t);
uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, sessionidt s, tunnelidt t, uint16_t mtype); uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, sessionidt s, tunnelidt t, uint16_t mtype, uint8_t prio, bundleidt bid, uint8_t mp_bits);
void sendlcp(sessionidt s, tunnelidt t); void sendlcp(sessionidt s, tunnelidt t);
void send_ipin(sessionidt s, uint8_t *buf, int len); void send_ipin(sessionidt s, uint8_t *buf, int len);
void sendccp(sessionidt s, tunnelidt t); void sendccp(sessionidt s, tunnelidt t);
void protoreject(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint16_t proto); void protoreject(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint16_t proto);
int join_bundle(sessionidt s);
// radius.c // radius.c
@ -802,6 +908,7 @@ void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, uint
extern tunnelt *tunnel; extern tunnelt *tunnel;
extern bundlet *bundle;
extern sessiont *session; extern sessiont *session;
extern sessionlocalt *sess_local; extern sessionlocalt *sess_local;
extern ippoolt *ip_address_pool; extern ippoolt *ip_address_pool;

View file

@ -1,6 +1,6 @@
Summary: A high-speed clustered L2TP LNS Summary: A high-speed clustered L2TP LNS
Name: l2tpns Name: l2tpns
Version: 2.1.21 Version: 2.2.0
Release: 1 Release: 1
License: GPL License: GPL
Group: System Environment/Daemons Group: System Environment/Daemons
@ -43,5 +43,5 @@ rm -rf %{buildroot}
%attr(644,root,root) /usr/share/man/man[58]/* %attr(644,root,root) /usr/share/man/man[58]/*
%changelog %changelog
* Fri Dec 1 2006 Brendan O'Dea <bod@optus.net> 2.1.21-1 * Mon Dec 18 2006 Brendan O'Dea <bod@optus.net> 2.2.0-1
- 2.1.21 release, see /usr/share/doc/l2tpns-2.1.21/Changes - 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. * and avoid compile-time configuration.
*/ */
#ifndef HAVE_OPENSSL
#include <string.h> #include <string.h>
#include "md5.h" #include "md5.h"
/* /*
@ -27,18 +24,18 @@
* F is optimized compared to its RFC 1321 definition just like in Colin * F is optimized compared to its RFC 1321 definition just like in Colin
* Plumb's implementation. * Plumb's implementation.
*/ */
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z) ((x) ^ (y) ^ (z)) #define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | ~(z))) #define I(x, y, z) ((y) ^ ((x) | ~(z)))
/* /*
* The MD5 transformation for all four rounds. * The MD5 transformation for all four rounds.
*/ */
#define STEP(f, a, b, c, d, x, t, s) \ #define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \ (a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b); (a) += (b);
/* /*
* SET reads 4 input bytes in little-endian byte order and stores them * SET reads 4 input bytes in little-endian byte order and stores them
@ -49,19 +46,17 @@
* doesn't work. * doesn't work.
*/ */
#if defined(__i386__) || defined(__vax__) #if defined(__i386__) || defined(__vax__)
#define SET(n) \ # define SET(n) (*(MD5_u32plus *)&ptr[(n) * 4])
(*(MD5_u32plus *)&ptr[(n) * 4]) # define GET(n) SET(n)
#define GET(n) \
SET(n)
#else #else
#define SET(n) \ # define SET(n) \
(ctx->block[(n)] = \ (ctx->block[(n)] = \
(MD5_u32plus)ptr[(n) * 4] | \ (MD5_u32plus)ptr[(n) * 4] | \
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define GET(n) \ # define GET(n) \
(ctx->block[(n)]) (ctx->block[(n)])
#endif #endif
/* /*
@ -70,205 +65,208 @@
*/ */
static void *body(MD5_CTX *ctx, void *data, unsigned long size) static void *body(MD5_CTX *ctx, void *data, unsigned long size)
{ {
unsigned char *ptr; unsigned char *ptr;
MD5_u32plus a, b, c, d; MD5_u32plus a, b, c, d;
MD5_u32plus saved_a, saved_b, saved_c, saved_d; MD5_u32plus saved_a, saved_b, saved_c, saved_d;
ptr = data; ptr = data;
a = ctx->a; a = ctx->a;
b = ctx->b; b = ctx->b;
c = ctx->c; c = ctx->c;
d = ctx->d; d = ctx->d;
do { do {
saved_a = a; saved_a = a;
saved_b = b; saved_b = b;
saved_c = c; saved_c = c;
saved_d = d; saved_d = d;
/* Round 1 */ /* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17) STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */ /* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9) STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */ /* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11) STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23) STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11) STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23) STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11) STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23) STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11) STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23) STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */ /* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
a += saved_a; a += saved_a;
b += saved_b; b += saved_b;
c += saved_c; c += saved_c;
d += saved_d; d += saved_d;
ptr += 64; ptr += MD5_BLOCK_SZ;
} while (size -= 64); } while (size -= MD5_BLOCK_SZ);
ctx->a = a; ctx->a = a;
ctx->b = b; ctx->b = b;
ctx->c = c; ctx->c = c;
ctx->d = d; ctx->d = d;
return ptr; return ptr;
} }
void MD5_Init(MD5_CTX *ctx) void MD5_Init(MD5_CTX *ctx)
{ {
ctx->a = 0x67452301; ctx->a = 0x67452301;
ctx->b = 0xefcdab89; ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe; ctx->c = 0x98badcfe;
ctx->d = 0x10325476; ctx->d = 0x10325476;
ctx->lo = 0; ctx->lo = 0;
ctx->hi = 0; ctx->hi = 0;
} }
void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size) void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)
{ {
MD5_u32plus saved_lo; MD5_u32plus saved_lo;
unsigned long used, free; unsigned long used, free;
saved_lo = ctx->lo; saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++; ctx->hi++;
ctx->hi += size >> 29;
used = saved_lo & 0x3f; ctx->hi += size >> 29;
if (used) { used = saved_lo & 0x3f;
free = 64 - used;
if (size < free) { if (used)
memcpy(&ctx->buffer[used], data, size); {
return; free = MD5_BLOCK_SZ - used;
}
memcpy(&ctx->buffer[used], data, free); if (size < free)
data = (unsigned char *)data + free; {
size -= free; memcpy(&ctx->buffer[used], data, size);
body(ctx, ctx->buffer, 64); return;
} }
if (size >= 64) { memcpy(&ctx->buffer[used], data, free);
data = body(ctx, data, size & ~(unsigned long)0x3f); data = (unsigned char *)data + free;
size &= 0x3f; 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) 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) { if (free < 8)
memset(&ctx->buffer[used], 0, free); {
body(ctx, ctx->buffer, 64); memset(&ctx->buffer[used], 0, free);
used = 0; body(ctx, ctx->buffer, MD5_BLOCK_SZ);
free = 64; used = 0;
} free = MD5_BLOCK_SZ;
}
memset(&ctx->buffer[used], 0, free - 8); memset(&ctx->buffer[used], 0, free - 8);
ctx->lo <<= 3; ctx->lo <<= 3;
ctx->buffer[56] = ctx->lo; ctx->buffer[56] = ctx->lo;
ctx->buffer[57] = ctx->lo >> 8; ctx->buffer[57] = ctx->lo >> 8;
ctx->buffer[58] = ctx->lo >> 16; ctx->buffer[58] = ctx->lo >> 16;
ctx->buffer[59] = ctx->lo >> 24; ctx->buffer[59] = ctx->lo >> 24;
ctx->buffer[60] = ctx->hi; ctx->buffer[60] = ctx->hi;
ctx->buffer[61] = ctx->hi >> 8; ctx->buffer[61] = ctx->hi >> 8;
ctx->buffer[62] = ctx->hi >> 16; ctx->buffer[62] = ctx->hi >> 16;
ctx->buffer[63] = ctx->hi >> 24; ctx->buffer[63] = ctx->hi >> 24;
body(ctx, ctx->buffer, 64); body(ctx, ctx->buffer, MD5_BLOCK_SZ);
result[0] = ctx->a; result[0] = ctx->a;
result[1] = ctx->a >> 8; result[1] = ctx->a >> 8;
result[2] = ctx->a >> 16; result[2] = ctx->a >> 16;
result[3] = ctx->a >> 24; result[3] = ctx->a >> 24;
result[4] = ctx->b; result[4] = ctx->b;
result[5] = ctx->b >> 8; result[5] = ctx->b >> 8;
result[6] = ctx->b >> 16; result[6] = ctx->b >> 16;
result[7] = ctx->b >> 24; result[7] = ctx->b >> 24;
result[8] = ctx->c; result[8] = ctx->c;
result[9] = ctx->c >> 8; result[9] = ctx->c >> 8;
result[10] = ctx->c >> 16; result[10] = ctx->c >> 16;
result[11] = ctx->c >> 24; result[11] = ctx->c >> 24;
result[12] = ctx->d; result[12] = ctx->d;
result[13] = ctx->d >> 8; result[13] = ctx->d >> 8;
result[14] = ctx->d >> 16; result[14] = ctx->d >> 16;
result[15] = ctx->d >> 24; 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. * in the public domain. See md5.c for more information.
*/ */
#ifdef HAVE_OPENSSL #ifndef __MD5_H__
#include <openssl/md5.h> #define __MD5_H__
#elif !defined(_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 */ /* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned long MD5_u32plus; typedef unsigned long MD5_u32plus;
typedef struct { typedef struct {
MD5_u32plus lo, hi; MD5_u32plus lo, hi;
MD5_u32plus a, b, c, d; MD5_u32plus a, b, c, d;
unsigned char buffer[64]; unsigned char buffer[MD5_BLOCK_SZ];
MD5_u32plus block[16]; MD5_u32plus block[MD5_DIGEST_SZ];
} MD5_CTX; } MD5_CTX;
extern void MD5_Init(MD5_CTX *ctx); extern void MD5_Init(MD5_CTX *ctx);
extern void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size); extern void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size);
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx); 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_PRE_AUTH = 1,
PLUGIN_POST_AUTH, PLUGIN_POST_AUTH,
PLUGIN_PACKET_RX,
PLUGIN_PACKET_TX,
PLUGIN_TIMER, PLUGIN_TIMER,
PLUGIN_NEW_SESSION, PLUGIN_NEW_SESSION,
PLUGIN_KILL_SESSION, PLUGIN_KILL_SESSION,
@ -62,37 +60,11 @@ struct param_post_auth
int protocol; 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 struct param_timer
{ {
time_t time_now; time_t time_now;
}; };
struct param_control
{
int iam_master;
int argc;
char **argv;
// output
int response;
char *additional;
};
struct param_new_session struct param_new_session
{ {
tunnelt *t; tunnelt *t;
@ -105,6 +77,16 @@ struct param_kill_session
sessiont *s; sessiont *s;
}; };
struct param_control
{
int iam_master;
int argc;
char **argv;
// output
int response;
char *additional;
};
struct param_radius_response struct param_radius_response
{ {
tunnelt *t; tunnelt *t;

665
ppp.c
View file

@ -1,6 +1,6 @@
// L2TPNS PPP Stuff // L2TPNS PPP Stuff
char const *cvs_id_ppp = "$Id: ppp.c,v 1.99.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 <stdio.h>
#include <string.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" #include "cluster.h"
extern tunnelt *tunnel; extern tunnelt *tunnel;
extern bundlet *bundle;
extern fragmentationt *frag;
extern sessiont *session; extern sessiont *session;
extern radiust *radius; extern radiust *radius;
extern int tunfd; extern int tunfd;
@ -24,6 +26,20 @@ extern time_t time_now;
extern configt *config; extern configt *config;
static int add_lcp_auth(uint8_t *b, int size, int authtype); static int add_lcp_auth(uint8_t *b, int size, int authtype);
static bundleidt new_bundle(void);
static int epdiscmp(epdist, epdist);
static void setepdis(epdist *, epdist);
static void ipcp_open(sessionidt s, tunnelidt t);
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 // Process PAP messages
void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
@ -90,7 +106,7 @@ void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
// respond now, either no RADIUS available or already authenticated // respond now, either no RADIUS available or already authenticated
uint8_t b[MAXETHER]; uint8_t b[MAXETHER];
uint8_t id = p[1]; uint8_t id = p[1];
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPPAP); uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPPAP, 0, 0, 0);
if (!p) return; if (!p) return;
if (session[s].ip) if (session[s].ip)
@ -134,7 +150,10 @@ void processpap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
radius[r].id = p[1]; radius[r].id = p[1];
LOG(3, s, t, "Sending login for %s/%s to RADIUS\n", user, pass); 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; radius[r].chap = 1;
LOG(3, s, t, "CHAP login %s\n", session[s].user); 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) static void dumplcp(uint8_t *p, int l)
@ -360,16 +382,25 @@ void lcp_open(sessionidt s, tunnelidt t)
} }
else else
{ {
// This-Layer-Up if(session[s].bundle == 0 || bundle[session[s].bundle].num_of_links == 1)
sendipcp(s, t); {
change_state(s, ipcp, RequestSent); // This-Layer-Up
// move to passive state for IPv6 (if configured), CCP sendipcp(s, t);
if (config->ipv6_prefix.s6_addr[0]) change_state(s, ipcp, RequestSent);
change_state(s, ipv6cp, Stopped); // move to passive state for IPv6 (if configured), CCP
else if (config->ipv6_prefix.s6_addr[0])
change_state(s, ipv6cp, Closed); 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) if (!*response || **response != ConfigRej)
{ {
queued = *response = makeppp(buf, blen, packet, 2, s, session[s].tunnel, mtype); queued = *response = makeppp(buf, blen, packet, 2, s, session[s].tunnel, mtype, 0, 0, 0);
if (!queued) if (!queued)
return 0; return 0;
@ -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) if (*nak_sent >= config->ppp_max_failure)
return ppp_conf_rej(s, buf, blen, mtype, response, 0, packet, option); return ppp_conf_rej(s, buf, blen, mtype, response, 0, packet, option);
queued = *response = makeppp(buf, blen, packet, 2, s, session[s].tunnel, mtype); queued = *response = makeppp(buf, blen, packet, 2, s, session[s].tunnel, mtype, 0, 0, 0);
if (!queued) if (!queued)
return 0; return 0;
@ -463,7 +494,7 @@ static void ppp_code_rej(sessionidt s, tunnelidt t, uint16_t proto,
l += 4; l += 4;
if (l > mru) l = mru; if (l > mru) l = mru;
q = makeppp(buf, size, 0, 0, s, t, proto); q = makeppp(buf, size, 0, 0, s, t, proto, 0, 0, 0);
if (!q) return; if (!q) return;
*q = CodeRej; *q = CodeRej;
@ -575,6 +606,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
uint8_t *response = 0; uint8_t *response = 0;
static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero
static uint8_t authproto[5]; static uint8_t authproto[5];
int changed = 0;
while (x > 2) while (x > 2)
{ {
@ -590,7 +622,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
if (mru >= MINMTU) if (mru >= MINMTU)
{ {
session[s].mru = mru; session[s].mru = mru;
cluster_send_session(s); changed++;
break; break;
} }
@ -663,6 +695,64 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
case 8: // Address-And-Control-Field-Compression case 8: // Address-And-Control-Field-Compression
break; break;
case 17: // Multilink Max-Receive-Reconstructed-Unit
{
uint16_t mrru = ntohs(*(uint16_t *)(o + 2));
session[s].mrru = mrru;
changed++;
LOG(3, s, t, " Received PPP LCP option MRRU: %d\n",mrru);
}
break;
case 18: // Multilink Short Sequence Number Header Format
{
session[s].mssf = 1;
changed++;
LOG(3, s, t, " Received PPP LCP option MSSN format\n");
}
break;
case 19: // Multilink Endpoint Discriminator
{
uint8_t epdis_class = o[2];
int addr;
session[s].epdis.addr_class = epdis_class;
session[s].epdis.length = length - 3;
if (session[s].epdis.length > 20)
{
LOG(1, s, t, "Error: received EndDis Address Length more than 20: %d\n", session[s].epdis.length);
session[s].epdis.length = 20;
}
for (addr = 0; addr < session[s].epdis.length; addr++)
session[s].epdis.address[addr] = o[3+addr];
changed++;
switch (epdis_class)
{
case LOCALADDR:
LOG(3, s, t, " Received PPP LCP option Multilink EndDis Local Address Class: %d\n",epdis_class);
break;
case IPADDR:
LOG(3, s, t, " Received PPP LCP option Multilink EndDis IP Address Class: %d\n",epdis_class);
break;
case IEEEMACADDR:
LOG(3, s, t, " Received PPP LCP option Multilink EndDis IEEE MAC Address Class: %d\n",epdis_class);
break;
case PPPMAGIC:
LOG(3, s, t, " Received PPP LCP option Multilink EndDis PPP Magic No Class: %d\n",epdis_class);
break;
case PSNDN:
LOG(3, s, t, " Received PPP LCP option Multilink EndDis PSND No Class: %d\n",epdis_class);
break;
default:
LOG(3, s, t, " Received PPP LCP option Multilink EndDis NULL Class %d\n",epdis_class);
}
}
break;
default: // Reject any unknown options default: // Reject any unknown options
LOG(3, s, t, " Rejecting unknown PPP LCP option %d\n", type); LOG(3, s, t, " Rejecting unknown PPP LCP option %d\n", type);
q = ppp_conf_rej(s, b, sizeof(b), PPPLCP, &response, q, p, o); q = ppp_conf_rej(s, b, sizeof(b), PPPLCP, &response, q, p, o);
@ -671,6 +761,9 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
o += length; o += length;
} }
if (changed)
cluster_send_session(s);
if (response) if (response)
{ {
l = q - response; // LCP packet length l = q - response; // LCP packet length
@ -679,7 +772,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
else else
{ {
// Send packet back as ConfigAck // Send packet back as ConfigAck
response = makeppp(b, sizeof(b), p, l, s, t, PPPLCP); response = makeppp(b, sizeof(b), p, l, s, t, PPPLCP, 0, 0, 0);
if (!response) return; if (!response) return;
*response = ConfigAck; *response = ConfigAck;
} }
@ -687,7 +780,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
switch (session[s].ppp.lcp) switch (session[s].ppp.lcp)
{ {
case Closed: case Closed:
response = makeppp(b, sizeof(b), p, 2, s, t, PPPLCP); response = makeppp(b, sizeof(b), p, 2, s, t, PPPLCP, 0, 0, 0);
if (!response) return; if (!response) return;
*response = TerminateAck; *response = TerminateAck;
*((uint16_t *) (response + 2)) = htons(l = 4); *((uint16_t *) (response + 2)) = htons(l = 4);
@ -820,6 +913,50 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
cluster_send_session(s); cluster_send_session(s);
break; break;
case 17: // Multilink Max-Receive-Reconstructed-Unit
{
if (*p == ConfigNak)
{
sess_local[s].mp_mrru = ntohs(*(uint16_t *)(o + 2));
LOG(3, s, t, " Remote requested MRRU of %u\n", sess_local[s].mp_mrru);
}
else
{
sess_local[s].mp_mrru = 0;
LOG(3, s, t, " Remote rejected MRRU negotiation\n");
}
}
break;
case 18: // Multilink Short Sequence Number Header Format
{
if (*p == ConfigNak)
{
sess_local[s].mp_mssf = 0;
LOG(3, s, t, " Remote requested Naked mssf\n");
}
else
{
sess_local[s].mp_mssf = 0;
LOG(3, s, t, " Remote rejected mssf\n");
}
}
break;
case 19: // Multilink Endpoint Discriminator
{
if (*p == ConfigNak)
{
LOG(2, s, t, " Remote should not configNak Endpoint Dis!\n");
}
else
{
sess_local[s].mp_epdis = 0;
LOG(3, s, t, " Remote rejected Endpoint Discriminator\n");
}
}
break;
default: default:
LOG(2, s, t, "LCP: remote sent %s for type %u?\n", ppp_code(*p), type); LOG(2, s, t, "LCP: remote sent %s for type %u?\n", ppp_code(*p), type);
sessionshutdown(s, "Unable to negotiate LCP.", CDN_ADMIN_DISC, TERM_USER_ERROR); sessionshutdown(s, "Unable to negotiate LCP.", CDN_ADMIN_DISC, TERM_USER_ERROR);
@ -843,7 +980,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
case Closed: case Closed:
case Stopped: case Stopped:
{ {
uint8_t *response = makeppp(b, sizeof(b), p, 2, s, t, PPPLCP); uint8_t *response = makeppp(b, sizeof(b), p, 2, s, t, PPPLCP, 0, 0, 0);
if (!response) return; if (!response) return;
*response = TerminateAck; *response = TerminateAck;
*((uint16_t *) (response + 2)) = htons(l = 4); *((uint16_t *) (response + 2)) = htons(l = 4);
@ -901,7 +1038,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
} }
*p = TerminateAck; // send ack *p = TerminateAck; // send ack
q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP); q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP, 0, 0, 0);
if (!q) return; if (!q) return;
LOG(3, s, t, "LCP: send %s\n", ppp_code(*q)); LOG(3, s, t, "LCP: send %s\n", ppp_code(*q));
@ -937,7 +1074,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
{ {
*p = EchoReply; // reply *p = EchoReply; // reply
*(uint32_t *) (p + 4) = htonl(session[s].magic); // our magic number *(uint32_t *) (p + 4) = htonl(session[s].magic); // our magic number
q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP); q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP, 0, 0, 0);
if (!q) return; if (!q) return;
LOG(4, s, t, "LCP: send %s\n", ppp_code(*q)); LOG(4, s, t, "LCP: send %s\n", ppp_code(*q));
@ -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) static void ipcp_open(sessionidt s, tunnelidt t)
{ {
LOG(3, s, t, "IPCP: Opened, session is now active\n"); LOG(3, s, t, "IPCP: Opened, session is now active\n");
@ -1113,7 +1356,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
else if (gotip) else if (gotip)
{ {
// Send packet back as ConfigAck // Send packet back as ConfigAck
response = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP); response = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP, 0, 0, 0);
if (!response) return; if (!response) return;
*response = ConfigAck; *response = ConfigAck;
} }
@ -1127,7 +1370,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
switch (session[s].ppp.ipcp) switch (session[s].ppp.ipcp)
{ {
case Closed: case Closed:
response = makeppp(b, sizeof(b), p, 2, s, t, PPPIPCP); response = makeppp(b, sizeof(b), p, 2, s, t, PPPIPCP, 0, 0, 0);
if (!response) return; if (!response) return;
*response = TerminateAck; *response = TerminateAck;
*((uint16_t *) (response + 2)) = htons(l = 4); *((uint16_t *) (response + 2)) = htons(l = 4);
@ -1200,7 +1443,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
} }
*p = TerminateAck; // send ack *p = TerminateAck; // send ack
q = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP); q = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP, 0, 0, 0);
if (!q) return; if (!q) return;
LOG(3, s, t, "IPCP: send %s\n", ppp_code(*q)); LOG(3, s, t, "IPCP: send %s\n", ppp_code(*q));
@ -1334,7 +1577,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
else if (gotip) else if (gotip)
{ {
// Send packet back as ConfigAck // Send packet back as ConfigAck
response = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP); response = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP, 0, 0, 0);
if (!response) return; if (!response) return;
*response = ConfigAck; *response = ConfigAck;
} }
@ -1348,7 +1591,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
switch (session[s].ppp.ipv6cp) switch (session[s].ppp.ipv6cp)
{ {
case Closed: case Closed:
response = makeppp(b, sizeof(b), p, 2, s, t, PPPIPV6CP); response = makeppp(b, sizeof(b), p, 2, s, t, PPPIPV6CP, 0, 0, 0);
if (!response) return; if (!response) return;
*response = TerminateAck; *response = TerminateAck;
*((uint16_t *) (response + 2)) = htons(l = 4); *((uint16_t *) (response + 2)) = htons(l = 4);
@ -1421,7 +1664,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
} }
*p = TerminateAck; // send ack *p = TerminateAck; // send ack
q = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP); q = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP, 0, 0, 0);
if (!q) return; if (!q) return;
LOG(3, s, t, "IPV6CP: send %s\n", ppp_code(*q)); LOG(3, s, t, "IPV6CP: send %s\n", ppp_code(*q));
@ -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 // process IP packet received
// //
// This MUST be called with at least 4 byte behind 'p'. // 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) if (session[s].ppp.phase != Network || session[s].ppp.ipcp != Opened)
return; return;
// no spoof (do sessionbyip to handled statically routed subnets) if (!session[s].bundle || bundle[session[s].bundle].num_of_links < 2) // FIXME:
if (ip != session[s].ip && sessionbyip(htonl(ip)) != s)
{ {
LOG(5, s, t, "Dropping packet with spoofed IP %s\n", fmtaddr(htonl(ip), 0)); // no spoof (do sessionbyip to handled statically routed subnets)
return; 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 // 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); *(uint32_t *) p = htonl(PKTIP);
l += 4; l += 4;
// Are we throttled and a slave? if (session[s].tbf_in)
if (session[s].tbf_in && !config->cluster_iam_master) { {
// Pass it to the master for handling. // Are we throttling this session?
master_throttle_packet(session[s].tbf_in, p, l); if (config->cluster_iam_master)
return; tbf_queue_packet(session[s].tbf_in, p, l);
} else
master_throttle_packet(session[s].tbf_in, p, l);
// 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);
return; 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); snoop_send_packet(p, l, session[s].snoop_ip, session[s].snoop_port);
} }
increment_counter(&session[s].cin, &session[s].cin_wrap, l); update_sessions_in_stat(s, l);
session[s].cin_delta += l;
session[s].pin++;
sess_local[s].cin += l;
sess_local[s].pin++;
eth_tx += 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); 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 // process IPv6 packet received
// //
// This MUST be called with at least 4 byte behind 'p'. // This MUST be called with at least 4 byte behind 'p'.
@ -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); snoop_send_packet(p, l, session[s].snoop_ip, session[s].snoop_port);
} }
increment_counter(&session[s].cin, &session[s].cin_wrap, l); update_sessions_in_stat(s, l);
session[s].cin_delta += l;
session[s].pin++;
sess_local[s].cin += l;
sess_local[s].pin++;
eth_tx += l; eth_tx += l;
@ -1693,7 +2147,7 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
STAT(tunnel_rx_errors); STAT(tunnel_rx_errors);
} }
LOG(3, s, t, "CCP: recv %s\n", ppp_code(*p)); LOG(4, s, t, "CCP: recv %s\n", ppp_code(*p));
if (*p == ConfigAck) if (*p == ConfigAck)
{ {
switch (session[s].ppp.ccp) switch (session[s].ppp.ccp)
@ -1726,13 +2180,13 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
else // compression requested--reject else // compression requested--reject
*p = ConfigRej; *p = ConfigRej;
q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP); q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP, 0, 0, 0);
if (!q) return; if (!q) return;
switch (session[s].ppp.ccp) switch (session[s].ppp.ccp)
{ {
case Closed: case Closed:
q = makeppp(b, sizeof(b), p, 2, s, t, PPPCCP); q = makeppp(b, sizeof(b), p, 2, s, t, PPPCCP, 0, 0, 0);
if (!q) return; if (!q) return;
*q = TerminateAck; *q = TerminateAck;
*((uint16_t *) (q + 2)) = htons(l = 4); *((uint16_t *) (q + 2)) = htons(l = 4);
@ -1778,13 +2232,13 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
return; return;
} }
LOG(3, s, t, "CCP: send %s\n", ppp_code(*q)); LOG(4, s, t, "CCP: send %s\n", ppp_code(*q));
tunnelsend(b, l + (q - b), t); tunnelsend(b, l + (q - b), t);
} }
else if (*p == TerminateReq) else if (*p == TerminateReq)
{ {
*p = TerminateAck; *p = TerminateAck;
q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP); q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP, 0, 0, 0);
if (!q) return; if (!q) return;
LOG(3, s, t, "CCP: send %s\n", ppp_code(*q)); LOG(3, s, t, "CCP: send %s\n", ppp_code(*q));
tunnelsend(b, l + (q - b), t); tunnelsend(b, l + (q - b), t);
@ -1828,7 +2282,7 @@ void sendchap(sessionidt s, tunnelidt t)
STAT(tunnel_tx_errors); STAT(tunnel_tx_errors);
return ; return ;
} }
q = makeppp(b, sizeof(b), 0, 0, s, t, PPPCHAP); q = makeppp(b, sizeof(b), 0, 0, s, t, PPPCHAP, 0, 0, 0);
if (!q) return; if (!q) return;
*q = 1; // challenge *q = 1; // challenge
@ -1842,37 +2296,86 @@ void sendchap(sessionidt s, tunnelidt t)
// fill in a L2TP message with a PPP frame, // fill in a L2TP message with a PPP frame,
// returns start of PPP frame // returns start of PPP frame
uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, sessionidt s, tunnelidt t, uint16_t mtype) uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, sessionidt s, tunnelidt t, uint16_t mtype, uint8_t prio, bundleidt bid, uint8_t mp_bits)
{ {
if (size < 12) // Need more space than this!! uint16_t hdr = 0x0002; // L2TP with no options
uint16_t type = mtype;
uint8_t *start = b;
if (size < 16) // Need more space than this!!
{ {
LOG(0, s, t, "makeppp buffer too small for L2TP header (size=%d)\n", size); LOG(0, s, t, "makeppp buffer too small for L2TP header (size=%d)\n", size);
return NULL; return NULL;
} }
*(uint16_t *) (b + 0) = htons(0x0002); // L2TP with no options if (prio) hdr |= 0x0100; // set priority bit
*(uint16_t *) (b + 0) = htons(hdr);
*(uint16_t *) (b + 2) = htons(tunnel[t].far); // tunnel *(uint16_t *) (b + 2) = htons(tunnel[t].far); // tunnel
*(uint16_t *) (b + 4) = htons(session[s].far); // session *(uint16_t *) (b + 4) = htons(session[s].far); // session
b += 6; b += 6;
if (mtype == PPPLCP || !(session[s].flags & SESSION_ACFC))
// Check whether this session is part of multilink
if (bid)
{
if (bundle[bid].num_of_links > 1)
type = PPPMP; // Change PPP message type to the PPPMP
else
bid = 0;
}
if (type == PPPLCP || !(session[s].flags & SESSION_ACFC))
{ {
*(uint16_t *) b = htons(0xFF03); // HDLC header *(uint16_t *) b = htons(0xFF03); // HDLC header
b += 2; b += 2;
} }
if (mtype < 0x100 && session[s].flags & SESSION_PFC)
*b++ = mtype; if (type < 0x100 && session[s].flags & SESSION_PFC)
{
*b++ = type;
}
else else
{ {
*(uint16_t *) b = htons(mtype); *(uint16_t *) b = htons(type);
b += 2; b += 2;
} }
if (l + 12 > size) if (bid)
{ {
LOG(2, s, t, "makeppp would overflow buffer (size=%d, header+payload=%d)\n", size, l + 12); // Set the sequence number and (B)egin (E)nd flags
if (session[s].mssf)
{
// Set the multilink bits
uint16_t bits_send = mp_bits;
*(uint16_t *) b = htons((bundle[bid].seq_num_t & 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; return NULL;
} }
// Copy the payload
if (p && l) if (p && l)
memcpy(b, p, l); memcpy(b, p, l);
@ -1911,10 +2414,10 @@ void sendlcp(sessionidt s, tunnelidt t)
uint8_t b[500], *q, *l; uint8_t b[500], *q, *l;
int authtype = sess_local[s].lcp_authtype; int authtype = sess_local[s].lcp_authtype;
if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPLCP))) if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPLCP, 0, 0, 0)))
return; return;
LOG(3, s, t, "LCP: send ConfigReq%s%s%s\n", LOG(3, s, t, "LCP: send ConfigReq%s%s%s including MP options\n",
authtype ? " (" : "", authtype ? " (" : "",
authtype ? (authtype == AUTHCHAP ? "CHAP" : "PAP") : "", authtype ? (authtype == AUTHCHAP ? "CHAP" : "PAP") : "",
authtype ? ")" : ""); authtype ? ")" : "");
@ -1941,6 +2444,20 @@ void sendlcp(sessionidt s, tunnelidt t)
l += 4; l += 4;
} }
if (sess_local[s].mp_mrru)
{
*l++ = 17; *l++ = 4; // Multilink Max-Receive-Reconstructed-Unit (length 4)
*(uint16_t *) l = htons(sess_local[s].mp_mrru); l += 2;
}
if (sess_local[s].mp_epdis)
{
*l++ = 19; *l++ = 7; // Multilink Endpoint Discriminator (length 7)
*l++ = IPADDR; // Endpoint Discriminator class
*(uint32_t *) l = htonl(sess_local[s].mp_epdis);
l += 4;
}
*(uint16_t *)(q + 2) = htons(l - q); // Length *(uint16_t *)(q + 2) = htons(l - q); // Length
LOG_HEX(5, "PPPLCP", q, l - q); LOG_HEX(5, "PPPLCP", q, l - q);
@ -1955,7 +2472,7 @@ void sendccp(sessionidt s, tunnelidt t)
{ {
uint8_t b[500], *q; uint8_t b[500], *q;
if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPCCP))) if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPCCP, 0, 0, 0)))
return; return;
LOG(3, s, t, "CCP: send ConfigReq (no compression)\n"); LOG(3, s, t, "CCP: send ConfigReq (no compression)\n");
@ -1982,7 +2499,7 @@ void protoreject(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint16_t pro
l += 6; l += 6;
if (l > mru) l = mru; if (l > mru) l = mru;
q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPLCP); q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPLCP, 0, 0, 0);
if (!q) return; if (!q) return;
*q = ProtocolRej; *q = ProtocolRej;

184
radius.c
View file

@ -1,6 +1,6 @@
// L2TPNS Radius Stuff // 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 <time.h>
#include <stdio.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) void initrad(void)
{ {
int i; 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); LOG(3, 0, 0, "Creating %d sockets for RADIUS queries\n", RADIUS_FDS);
radfds = calloc(sizeof(int), RADIUS_FDS); radfds = calloc(sizeof(int), RADIUS_FDS);
for (i = 0; i < RADIUS_FDS; i++) for (i = 0; i < RADIUS_FDS; i++)
@ -53,6 +72,27 @@ void initrad(void)
radfds[i] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); radfds[i] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
flags = fcntl(radfds[i], F_GETFL, 0); flags = fcntl(radfds[i], F_GETFL, 0);
fcntl(radfds[i], F_SETFL, flags | O_NONBLOCK); 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; return;
} }
if (state != RADIUSAUTH && !config->radius_accounting) if (state != RADIUSAUTH && state != RADIUSJUSTAUTH && !config->radius_accounting)
{ {
// Radius accounting is turned off // Radius accounting is turned off
radiusclear(r, s); radiusclear(r, s);
@ -157,7 +197,7 @@ void radiussend(uint16_t r, uint8_t state)
{ {
if (s) if (s)
{ {
if (state == RADIUSAUTH) if (state == RADIUSAUTH || state == RADIUSJUSTAUTH)
sessionshutdown(s, "RADIUS timeout.", CDN_ADMIN_DISC, TERM_REAUTHENTICATION_FAILURE); sessionshutdown(s, "RADIUS timeout.", CDN_ADMIN_DISC, TERM_REAUTHENTICATION_FAILURE);
else else
{ {
@ -179,6 +219,7 @@ void radiussend(uint16_t r, uint8_t state)
switch (state) switch (state)
{ {
case RADIUSAUTH: case RADIUSAUTH:
case RADIUSJUSTAUTH:
b[0] = AccessRequest; // access request b[0] = AccessRequest; // access request
break; break;
case RADIUSSTART: case RADIUSSTART:
@ -199,7 +240,7 @@ void radiussend(uint16_t r, uint8_t state)
strcpy((char *) p + 2, session[s].user); strcpy((char *) p + 2, session[s].user);
p += p[1]; p += p[1];
} }
if (state == RADIUSAUTH) if (state == RADIUSAUTH || state == RADIUSJUSTAUTH)
{ {
if (radius[r].chap) if (radius[r].chap)
{ {
@ -330,6 +371,7 @@ void radiussend(uint16_t r, uint8_t state)
} }
} }
} }
if (s) if (s)
{ {
*p = 5; // NAS-Port *p = 5; // NAS-Port
@ -339,59 +381,80 @@ void radiussend(uint16_t r, uint8_t state)
*p = 6; // Service-Type *p = 6; // Service-Type
p[1] = 6; 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 += p[1];
*p = 7; // Framed-Protocol *p = 7; // Framed-Protocol
p[1] = 6; p[1] = htonl((state == RADIUSJUSTAUTH ? 0 : 6));
*(uint32_t *) (p + 2) = htonl(1); // PPP *(uint32_t *) (p + 2) = htonl((state == RADIUSJUSTAUTH ? 0 : 1)); // PPP
p += p[1]; p += p[1];
}
if (s && session[s].ip) if (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++)
{ {
int width = 32; *p = 8; // Framed-IP-Address
if (session[s].route[r].mask) 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; int width = 32;
while (!(mask & 1)) if (session[s].route[r].mask)
{ {
width--; int mask = session[s].route[r].mask;
mask >>= 1; 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 if (session[s].session_timeout)
p[1] = sprintf((char *) p + 2, "%s/%d %s 1", {
fmtaddr(htonl(session[s].route[r].ip), 0), *p = 27; // Session-Timeout
width, fmtaddr(htonl(session[s].ip), 1)) + 2; 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]; 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 // NAS-IP-Address
*p = 4; *p = 4;
p[1] = 6; p[1] = 6;
@ -400,7 +463,7 @@ void radiussend(uint16_t r, uint8_t state)
// All AVpairs added // All AVpairs added
*(uint16_t *) (b + 2) = htons(p - b); *(uint16_t *) (b + 2) = htons(p - b);
if (state != RADIUSAUTH) if (state != RADIUSAUTH && state != RADIUSJUSTAUTH)
{ {
// Build auth for accounting packet // Build auth for accounting packet
calc_auth(b, p - b, zero, b + 4); calc_auth(b, p - b, zero, b + 4);
@ -413,7 +476,7 @@ void radiussend(uint16_t r, uint8_t state)
// get radius port // get radius port
uint16_t port = config->radiusport[(radius[r].try - 1) % config->numradiusservers]; uint16_t port = config->radiusport[(radius[r].try - 1) % config->numradiusservers];
// assume RADIUS accounting port is the authentication port +1 // 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)); 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"); LOG(1, s, session[s].tunnel, " Unexpected RADIUS response\n");
return; 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) && radius[r].state != RADIUSSTOP && radius[r].state != RADIUSINTERIM)
{ {
LOG(1, s, session[s].tunnel, " Unexpected RADIUS response\n"); 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. 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)) ((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)); 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. // 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 // run post-auth plugin
struct param_post_auth packet = { struct param_post_auth packet = {
@ -537,7 +600,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
if (radius[r].chap) if (radius[r].chap)
{ {
// CHAP // CHAP
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPCHAP); uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPCHAP, 0, 0, 0);
if (!p) return; // Abort! if (!p) return; // Abort!
*p = (r_code == AccessAccept) ? 3 : 4; // ack/nak *p = (r_code == AccessAccept) ? 3 : 4; // ack/nak
@ -551,7 +614,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
else else
{ {
// PAP // PAP
uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPPAP); uint8_t *p = makeppp(b, sizeof(b), 0, 0, s, t, PPPPAP, 0, 0, 0);
if (!p) return; // Abort! if (!p) return; // Abort!
// ack/nak // ack/nak
@ -715,6 +778,22 @@ void processrad(uint8_t *buf, int len, char socket_index)
ip_filters[f].used++; 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) else if (*p == 99)
{ {
// Framed-IPv6-Route // Framed-IPv6-Route
@ -793,6 +872,7 @@ void radiusretry(uint16_t r)
sendchap(s, t); sendchap(s, t);
break; break;
case RADIUSAUTH: // sending auth to RADIUS server case RADIUSAUTH: // sending auth to RADIUS server
case RADIUSJUSTAUTH: // sending auth to RADIUS server
case RADIUSSTART: // sending start accounting to RADIUS server case RADIUSSTART: // sending start accounting to RADIUS server
case RADIUSSTOP: // sending stop accounting to RADIUS server case RADIUSSTOP: // sending stop accounting to RADIUS server
case RADIUSINTERIM: // sending interim 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) while (1)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
int alen = sizeof(addr), l; socklen_t alen = sizeof(addr);
int l;
unsigned int iseq; unsigned int iseq;
l = recvfrom(s, packet, 65535, 0, (void *) &addr, &alen); l = recvfrom(s, packet, 65535, 0, (void *) &addr, &alen);
@ -87,7 +88,7 @@ int main(int argc, char *argv[])
free(packet); 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); printf("Recv: %10llu %0.1fMbits/s (%lu pps) (%5ld dropped)\n", recv_count, (bytes / 1024.0 / 1024.0 * 8), pps, dropped);
pps = bytes = 0; 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 <arpa/inet.h>
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
@ -6,11 +12,8 @@
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <unistd.h> #include <unistd.h>
@ -179,10 +182,10 @@ typedef struct
} control_message; } control_message;
typedef struct { typedef struct {
unsigned long long send_count , recv_count ; long long send_count, recv_count;
unsigned long long spkt , rpkt ; long long spkt, rpkt ;
unsigned int dropped; int dropped;
unsigned long sbytes , rbytes ; long sbytes, rbytes ;
int quitit; int quitit;
struct sessiont struct sessiont
{ {
@ -210,7 +213,7 @@ void dump_control_message(control_message *c);
u32 avp_get_32(control_message *c, int id); u32 avp_get_32(control_message *c, int id);
u16 avp_get_16(control_message *c, int id); u16 avp_get_16(control_message *c, int id);
char *avp_get_s(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 skip_zlb();
void cm_free(control_message *m); void cm_free(control_message *m);
controlt *ppp_new(u16 session, int protocol); controlt *ppp_new(u16 session, int protocol);
@ -234,7 +237,7 @@ void print_report();
int ns = 0, nr = 0; int ns = 0, nr = 0;
int udpfd; int udpfd;
int t = 0; int t = 0;
struct sockaddr_in gatewayaddr = {0}; struct sockaddr_in gatewayaddr;
int numsessions = NUM_SESSIONS; int numsessions = NUM_SESSIONS;
int packet_length = PACKET_LENGTH; int packet_length = PACKET_LENGTH;
int target_pps = TARGET_PPS; int target_pps = TARGET_PPS;
@ -251,7 +254,7 @@ char *suffix = "@optusnet.com.au";
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int s; int s;
char *packet; unsigned char *packet;
ss = (sharedt*) mmap(NULL, sizeof(*ss), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0); 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)); printf("Bound to port %d\n", htons(addr.sin_port));
}/*}}}*/ }/*}}}*/
memset(&gatewayaddr, 0, sizeof(gatewayaddr));
gatewayaddr.sin_family = AF_INET; gatewayaddr.sin_family = AF_INET;
gatewayaddr.sin_port = htons(1701); gatewayaddr.sin_port = htons(1701);
inet_aton(gwaddr, &gatewayaddr.sin_addr); inet_aton(gwaddr, &gatewayaddr.sin_addr);
@ -400,7 +404,8 @@ int main(int argc, char *argv[])
// Receive reply/*{{{*/ // Receive reply/*{{{*/
{ {
struct sockaddr_in addr; 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); l = recvfrom(udpfd, packet, 4096, 0, (void *) &addr, &alen);
if (l < 0) if (l < 0)
@ -409,7 +414,7 @@ int main(int argc, char *argv[])
return -1; return -1;
} }
printf("Received "); printf("Received ");
r = parsecontrol(packet, l); r = parsecontrol((char *) packet, l);
if (!r->first) if (!r->first)
{ {
printf("Invalid packet.. no first avp\n"); printf("Invalid packet.. no first avp\n");
@ -446,7 +451,7 @@ int main(int argc, char *argv[])
printf("All session create requests sent...\n");/*}}}*/ printf("All session create requests sent...\n");/*}}}*/
if ( fork() == 0) { if ( fork() == 0) {
reader_thread(udpfd); reader_thread();
exit(0); exit(0);
} }
@ -529,7 +534,7 @@ int main(int argc, char *argv[])
*(u16 *)(c->buf + 4) = htons(ss->sessions[i].remote_session); // Session ID *(u16 *)(c->buf + 4) = htons(ss->sessions[i].remote_session); // Session ID
iph->saddr = ss->sessions[i].addr; iph->saddr = ss->sessions[i].addr;
iph->check = 0; 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++; *((unsigned int *) data) = seq++;
ppp_send(c); ppp_send(c);
@ -546,7 +551,8 @@ int main(int argc, char *argv[])
nanosleep(&req, NULL); 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++; 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 unsigned long long last_rpkts[AVG_SIZE], last_spkts[AVG_SIZE];
static int last = 0, avg_count = 0; 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; float loss;
last_rpkts[last] = ss->rpkt; last_rpkts[last] = ss->rpkt;
last_spkts[last] = ss->spkt; last_spkts[last] = ss->spkt;
last = (last + 1) % AVG_SIZE; 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++) 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 char *packet;
unsigned int seq = 0; unsigned int seq = 0;
@ -877,7 +885,7 @@ void reader_thread(int updfd)/*{{{*/
while (!ss->quitit) while (!ss->quitit)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
int alen = sizeof(addr); socklen_t alen = sizeof(addr);
control_message *m; control_message *m;
int l; int l;
int s; int s;
@ -906,7 +914,7 @@ void reader_thread(int updfd)/*{{{*/
{ {
// Control Packet // Control Packet
printf("Reader Received "); printf("Reader Received ");
m = parsecontrol(packet, l); m = parsecontrol((char *) packet, l);
printf("\n"); printf("\n");
s = m->session; s = m->session;
@ -975,7 +983,7 @@ void reader_thread(int updfd)/*{{{*/
if (protocol != PPPIP) if (protocol != PPPIP)
{ {
printf("Received "); printf("Received ");
dump_ppp_packet(packet + 6, l - 6); dump_ppp_packet((char *) (packet + 6), l - 6);
} }
if (protocol == PPPLCP) if (protocol == PPPLCP)
@ -1073,13 +1081,13 @@ void reader_thread(int updfd)/*{{{*/
if (iph->protocol == 17) if (iph->protocol == 17)
{ {
int iseq; unsigned int iseq;
ss->recv_count++; ss->recv_count++;
ss->rpkt++; ss->rpkt++;
iseq = *((unsigned int *) data); iseq = *((unsigned int *) data);
if (seq != iseq) { if (seq != iseq)
ss->dropped += (iseq - seq) ; ss->dropped += (iseq - seq) ;
}
seq = iseq + 1; // Next sequence number to expect. seq = iseq + 1; // Next sequence number to expect.
} }
} }
@ -1095,7 +1103,7 @@ void reader_thread(int updfd)/*{{{*/
void skip_zlb() /*{{{*/ void skip_zlb() /*{{{*/
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
int alen = sizeof(addr); socklen_t alen = sizeof(addr);
char buf[1024]; char buf[1024];
int l; int l;
l = recvfrom(udpfd, buf, 1024, MSG_PEEK, (void *) &addr, &alen); l = recvfrom(udpfd, buf, 1024, MSG_PEEK, (void *) &addr, &alen);