- Use openssl MD5, fix DAE vector (Alex Kiernan).
-* Wed Jun 29 2005 Brendan O'Dea <bod@c47.org> 2.1.2
-- Don't resend IPCP while still in progress.
-- Ignore duplicate ACKs for IPCP.
-- Clear RADIUSIPCP for walled garden sessions on ACK.
+* Sun Jul 31 2005 Brendan O'Dea <bod@> 2.1.2
- Clear cluster_master on election so that slaves will accept a new master.
- Provide more comments/defaults in etc/startup-config.default.
- Add DAE support (PoD/CoA) from Vladislav Bjelic.
+- Clean up new warnings from gcc 4.0.
+- Replace flags used for LCP/IPCP with state machine.
+- Use openssl MD5, fix DAE vector (Alex Kiernan).
* Tue Jun 14 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.1
- Add missing newline to backtrace macro.
used if the LAC requests authentication.
</LI>
+<LI><B>ppp_restart_time</B> (int)<BR>
+<B>ppp_max_configure</B> (int)<BR>
+<B>ppp_max_failure</B> (int)<BR>
+PPP counters and timers values, as described in §4.1 of
+<a href="ftp://ftp.rfc-editor.org/in-notes/rfc1661.txt">RFC1661</a>.
+</LI>
+
<LI><B>primary_dns</B> (ip address)
<LI><B>secondary_dns</B> (ip address)<BR>
Whenever a PPP connection is established, DNS servers will be sent to the
.de Id
.ds Dt \\$4 \\$5
..
-.Id $Id: startup-config.5,v 1.11 2005-06-28 14:48:31 bodea Exp $
+.Id $Id: startup-config.5,v 1.12 2005-07-31 10:04:14 bodea Exp $
.TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
.SH NAME
startup\-config \- configuration file for l2tpns
authentication will fail. Only actually be used if the LAC requests
authentication.
.TP
+.B ppp_restart_time
+Restart timer for PPP protocol negotiation in seconds (default: 3).
+.TP
+.B ppp_max_configure
+Number of configure requests to send before giving up (default: 10).
+.TP
+.B ppp_max_failure
+Number of Configure-Nak requests to send before sending a
+Configure-Reject (default: 5).
+.TP
.BR primary_dns , " secondary_dns"
Whenever a PPP connection is established, DNS servers will be sent to the
user, both a primary and a secondary. If either is set to 0.0.0.0, then that
LDLIBS =
INSTALL = install -c -D -o root -g root
-l2tpns.LIBS = -lm -lcli -ldl
+l2tpns.LIBS = -lcrypto -lm -lcli -ldl
OBJS = arp.o cli.o cluster.o constants.o control.o icmp.o l2tpns.o \
- ll.o md5.o ppp.o radius.o tbf.o util.o
+ ll.o ppp.o radius.o tbf.o util.o
PROGRAMS = l2tpns nsctl
PLUGINS = autosnoop.so autothrottle.so garden.so sessionctl.so \
## Dependencies: (autogenerated) ##
arp.o: arp.c l2tpns.h
-cli.o: cli.c l2tpns.h util.h cluster.h tbf.h ll.h bgp.h
+cli.o: cli.c l2tpns.h constants.h util.h cluster.h tbf.h ll.h bgp.h
cluster.o: cluster.c l2tpns.h cluster.h util.h tbf.h bgp.h
constants.o: constants.c constants.h
control.o: control.c l2tpns.h control.h
icmp.o: icmp.c l2tpns.h
-l2tpns.o: l2tpns.c md5.h l2tpns.h cluster.h plugin.h ll.h constants.h \
- control.h util.h tbf.h bgp.h
+l2tpns.o: l2tpns.c l2tpns.h cluster.h plugin.h ll.h constants.h control.h \
+ util.h tbf.h bgp.h fake_epoll.h
ll.o: ll.c ll.h
-md5.o: md5.c md5.h
ppp.o: ppp.c l2tpns.h constants.h plugin.h util.h tbf.h cluster.h
-radius.o: radius.c md5.h constants.h l2tpns.h plugin.h util.h
+radius.o: radius.c constants.h l2tpns.h plugin.h util.h cluster.h
tbf.o: tbf.c l2tpns.h util.h tbf.h
util.o: util.c l2tpns.h bgp.h
-bgp.o: bgp.c l2tpns.h bgp.h util.h
+bgp.o: bgp.c l2tpns.h bgp.h util.h fake_epoll.h
autosnoop.so: autosnoop.c l2tpns.h plugin.h
autothrottle.so: autothrottle.c l2tpns.h plugin.h
garden.so: garden.c l2tpns.h plugin.h control.h
Roberto Chostakovis <rchostakovis@users.sourceforge.net>
Jordan Hrycaj <jordan@mjh.teddy-net.com>
Vladislav Bjelic <vladislav@gmail.com>
+Alex Kiernan <alex.kiernan@gmail.com>
// L2TPNS: arp
-char const *cvs_id_arp = "$Id: arp.c,v 1.6 2005-01-07 07:14:14 bodea Exp $";
+char const *cvs_id_arp = "$Id: arp.c,v 1.7 2005-07-31 10:04:09 bodea Exp $";
#include <string.h>
#include <unistd.h>
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
- strncpy(sll.sll_addr, mac, sizeof(sll.sll_addr) - 1);
+ memcpy(sll.sll_addr, mac, sizeof(sll.sll_addr) - 1);
sll.sll_halen = ETH_ALEN;
sll.sll_ifindex = ifr_idx;
* nor RFC2385 (which requires a kernel patch on 2.4 kernels).
*/
-char const *cvs_id_bgp = "$Id: bgp.c,v 1.10 2005-06-04 15:42:35 bodea Exp $";
+char const *cvs_id_bgp = "$Id: bgp.c,v 1.11 2005-07-31 10:04:09 bodea Exp $";
#include <stdlib.h>
#include <unistd.h>
static int bgp_handle_connect(struct bgp_peer *peer)
{
int err = 0;
- int len = sizeof(int);
+ socklen_t len = sizeof(int);
getsockopt(peer->sock, SOL_SOCKET, SO_ERROR, &err, &len);
if (err)
{
// vim: sw=8 ts=8
char const *cvs_name = "$Name: $";
-char const *cvs_id_cli = "$Id: cli.c,v 1.63 2005-06-28 14:48:17 bodea Exp $";
+char const *cvs_id_cli = "$Id: cli.c,v 1.64 2005-07-31 10:04:09 bodea Exp $";
#include <stdio.h>
#include <stdarg.h>
#include <libcli.h>
#include "l2tpns.h"
+#include "constants.h"
#include "util.h"
#include "cluster.h"
#include "tbf.h"
{
int require_auth = 1;
struct sockaddr_in addr;
- int l = sizeof(addr);
+ socklen_t l = sizeof(addr);
if (fork_and_close()) return;
- if (getpeername(sockfd, (struct sockaddr *)&addr, &l) == 0)
+ if (getpeername(sockfd, (struct sockaddr *) &addr, &l) == 0)
{
require_auth = addr.sin_addr.s_addr != inet_addr("127.0.0.1");
LOG(require_auth ? 3 : 4, 0, 0, "Accepted connection to CLI from %s\n",
cli_print(cli, "\tCalling Num:\t%s", session[s].calling);
cli_print(cli, "\tCalled Num:\t%s", session[s].called);
cli_print(cli, "\tTunnel ID:\t%d", session[s].tunnel);
+ cli_print(cli, "\tPPP Phase:\t%s", ppp_phase(session[s].ppp.phase));
+ switch (session[s].ppp.phase)
+ {
+ case Establish:
+ cli_print(cli, "\tLCP state:\t%s", ppp_state(session[s].ppp.lcp));
+ break;
+
+ case Authenticate:
+ case Network:
+ cli_print(cli, "\t IPCP state:\t%s", ppp_state(session[s].ppp.ipcp));
+ cli_print(cli, "\t IPV6CP state:\t%s", ppp_state(session[s].ppp.ipv6cp));
+ cli_print(cli, "\t CCP state:\t%s", ppp_state(session[s].ppp.ccp));
+ }
cli_print(cli, "\tIP address:\t%s", fmtaddr(htonl(session[s].ip), 0));
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);
(session[i].snoop_ip && session[i].snoop_port) ? "Y" : "N",
(session[i].throttle_in || session[i].throttle_out) ? "Y" : "N",
(session[i].walled_garden) ? "Y" : "N",
- (session[i].flags & SF_IPV6CP_ACKED) ? "Y" : "N",
+ (session[i].ppp.ipv6cp == Opened) ? "Y" : "N",
abs(time_now - (unsigned long)session[i].opened),
(unsigned long)session[i].cout,
(unsigned long)session[i].cin,
cli_print(cli, " %s", cvs_id_icmp);
cli_print(cli, " %s", cvs_id_l2tpns);
cli_print(cli, " %s", cvs_id_ll);
- cli_print(cli, " %s", cvs_id_md5);
cli_print(cli, " %s", cvs_id_ppp);
cli_print(cli, " %s", cvs_id_radius);
cli_print(cli, " %s", cvs_id_tbf);
// L2TPNS Clustering Stuff
-char const *cvs_id_cluster = "$Id: cluster.c,v 1.44 2005-06-28 14:48:19 bodea Exp $";
+char const *cvs_id_cluster = "$Id: cluster.c,v 1.45 2005-07-31 10:04:09 bodea Exp $";
#include <stdio.h>
#include <stdlib.h>
static struct {
int seq;
int size;
- char data[MAX_HEART_SIZE];
+ uint8_t data[MAX_HEART_SIZE];
} past_hearts[HB_HISTORY_SIZE]; // Ring buffer of heartbeats that we've recently sent out. Needed so
// we can re-transmit if needed.
// Maintains the format. Assumes that the caller
// has passed in a big enough buffer!
//
-static void add_type(char **p, int type, int more, char *data, int size)
+static void add_type(uint8_t **p, int type, int more, uint8_t *data, int size)
{
*((uint32_t *) (*p)) = type;
*p += sizeof(uint32_t);
// Send a unicast UDP packet to a peer with 'data' as the
// contents.
//
-static int peer_send_data(in_addr_t peer, char *data, int size)
+static int peer_send_data(in_addr_t peer, uint8_t *data, int size)
{
struct sockaddr_in addr = {0};
//
// Send a structured message to a peer with a single element of type 'type'.
//
-static int peer_send_message(in_addr_t peer, int type, int more, char *data, int size)
+static int peer_send_message(in_addr_t peer, int type, int more, uint8_t *data, int size)
{
- char buf[65536]; // Vast overkill.
- char *p = buf;
+ uint8_t buf[65536]; // Vast overkill.
+ uint8_t *p = buf;
LOG(4, 0, 0, "Sending message to peer (type %d, more %d, size %d)\n", type, more, size);
add_type(&p, type, more, data, size);
}
// send a packet to the master
-static int _forward_packet(char *data, int size, in_addr_t addr, int port, int type)
+static int _forward_packet(uint8_t *data, int size, in_addr_t addr, int port, int type)
{
- char buf[65536]; // Vast overkill.
- char *p = buf;
+ uint8_t buf[65536]; // Vast overkill.
+ uint8_t *p = buf;
if (!config->cluster_master_address) // No election has been held yet. Just skip it.
return -1;
LOG(4, 0, 0, "Forwarding packet from %s to master (size %d)\n", fmtaddr(addr, 0), size);
STAT(c_forwarded);
- add_type(&p, type, addr, (char *) &port, sizeof(port)); // ick. should be uint16_t
+ add_type(&p, type, addr, (uint8_t *) &port, sizeof(port)); // ick. should be uint16_t
memcpy(p, data, size);
p += size;
// The master just processes the payload as if it had
// received it off the tun device.
//
-int master_forward_packet(char *data, int size, in_addr_t addr, int port)
+int master_forward_packet(uint8_t *data, int size, in_addr_t addr, int port)
{
return _forward_packet(data, size, addr, port, C_FORWARD);
}
// Forward a DAE RADIUS packet to the master.
-int master_forward_dae_packet(char *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)
{
return _forward_packet(data, size, addr, port, C_FORWARD_DAE);
}
// token bucket queue, and lets normal processing take care
// of it.
//
-int master_throttle_packet(int tbfid, char *data, int size)
+int master_throttle_packet(int tbfid, uint8_t *data, int size)
{
- char buf[65536]; // Vast overkill.
- char *p = buf;
+ uint8_t buf[65536]; // Vast overkill.
+ uint8_t *p = buf;
if (!config->cluster_master_address) // No election has been held yet. Just skip it.
return -1;
//
// (Note that this must be called with the tun header
// as the start of the data).
-int master_garden_packet(sessionidt s, char *data, int size)
+int master_garden_packet(sessionidt s, uint8_t *data, int size)
{
- char buf[65536]; // Vast overkill.
- char *p = buf;
+ uint8_t buf[65536]; // Vast overkill.
+ uint8_t *p = buf;
if (!config->cluster_master_address) // No election has been held yet. Just skip it.
return -1;
// Send a chunk of data as a heartbeat..
// We save it in the history buffer as we do so.
//
-static void send_heartbeat(int seq, char *data, int size)
+static void send_heartbeat(int seq, uint8_t *data, int size)
{
int i;
//
void cluster_send_ping(time_t basetime)
{
- char buff[100 + sizeof(pingt)];
- char *p = buff;
+ uint8_t buff[100 + sizeof(pingt)];
+ uint8_t *p = buff;
pingt x;
if (config->cluster_iam_master && basetime) // We're heartbeating so no need to ping.
x.undef = config->cluster_undefined_sessions + config->cluster_undefined_tunnels;
x.basetime = basetime;
- add_type(&p, C_PING, basetime, (char *) &x, sizeof(x));
+ add_type(&p, C_PING, basetime, (uint8_t *) &x, sizeof(x));
cluster_send_data(buff, (p-buff) );
}
// Forward the data to the master.
LOG(4, 0, 0, "Sending byte counters to master (%d elements)\n", c);
- peer_send_message(config->cluster_master_address, C_BYTES, c, (char *) &b, sizeof(b[0]) * c);
+ peer_send_message(config->cluster_master_address, C_BYTES, c, (uint8_t *) &b, sizeof(b[0]) * c);
return;
}
cluster_uptodate();
}
-static int hb_add_type(char **p, int type, int id)
+static int hb_add_type(uint8_t **p, int type, int id)
{
switch (type) {
case C_CSESSION: { // Compressed C_SESSION.
// Did we compress the full structure, and is the size actually
// reduced??
if ( (d - orig) == sizeof(sessiont) && size < sizeof(sessiont) ) {
- add_type(p, C_CSESSION, id, (char *) c, size);
+ add_type(p, C_CSESSION, id, c, size);
break;
}
// Failed to compress : Fall through.
}
- case C_SESSION: add_type(p, C_SESSION, id,
- (char *) &session[id], sizeof(sessiont));
+ case C_SESSION:
+ add_type(p, C_SESSION, id, (uint8_t *) &session[id], sizeof(sessiont));
break;
case C_CTUNNEL: { // Compressed C_TUNNEL
}
// Failed to compress : Fall through.
}
- case C_TUNNEL: add_type(p, C_TUNNEL, id,
- (char *) &tunnel[id], sizeof(tunnelt));
+ case C_TUNNEL:
+ add_type(p, C_TUNNEL, id, (uint8_t *) &tunnel[id], sizeof(tunnelt));
break;
default:
LOG(0, 0, 0, "Found an invalid type in heart queue! (%d)\n", type);
void cluster_heartbeat()
{
int i, count = 0, tcount = 0;
- char buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
+ uint8_t buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
heartt h;
- char *p = buff;
+ uint8_t *p = buff;
if (!config->cluster_iam_master) // Only the master does this.
return;
h.timeout = config->cluster_hb_timeout;
h.table_version = config->cluster_table_version;
- add_type(&p, C_HEARTBEAT, HB_VERSION, (char *) &h, sizeof(h));
+ add_type(&p, C_HEARTBEAT, HB_VERSION, (uint8_t *) &h, sizeof(h));
for (i = 0; i < config->cluster_num_changes; ++i) {
hb_add_type(&p, cluster_changes[i].type, cluster_changes[i].id);
// Note that we don't mark the session as dirty; We rely on
// the slow table walk to propogate this back out to the slaves.
//
-static int cluster_handle_bytes(char *data, int size)
+static int cluster_handle_bytes(uint8_t *data, int size)
{
bytest *b;
uint32_t tx_connect_speed;
uint32_t rx_connect_speed;
uint32_t flags;
+#define SF_IPCP_ACKED 1 // Has this session seen an IPCP Ack?
+#define SF_LCP_ACKED 2 // LCP negotiated
+#define SF_CCP_ACKED 4 // CCP negotiated
in_addr_t snoop_ip;
uint16_t snoop_port;
uint16_t sid;
new.far = old->far;
new.tunnel = old->tunnel;
new.l2tp_flags = old->l2tp_flags;
- new.flags = old->flags;
new.ip = old->ip;
new.ip_pool_index = old->ip_pool_index;
new.unique_id = old->unique_id;
for (i = 0; i < MAXROUTE; i++)
memcpy(&new.route[i], &old->route[i], sizeof(new.route[i]));
+ if (new.opened)
+ {
+ new.ppp.phase = Establish;
+ if (old->flags & (SF_IPCP_ACKED|SF_LCP_ACKED))
+ {
+ new.ppp.phase = Network;
+ new.ppp.lcp = Opened;
+ new.ppp.ipcp = (old->flags & SF_IPCP_ACKED) ? Opened : Starting;
+ new.ppp.ccp = (old->flags & SF_CCP_ACKED) ? Opened : Stopped;
+ }
+
+ // no PPPv6 in old session
+ new.ppp.ipv6cp = Stopped;
+ }
+
return (uint8_t *) &new;
}
// We got a packet on the cluster port!
// Handle pings, lastseens, and heartbeats!
//
-int processcluster(char *data, int size, in_addr_t addr)
+int processcluster(uint8_t *data, int size, in_addr_t addr)
{
int type, more;
- char *p = data;
+ uint8_t *p = data;
int s = size;
if (addr == my_address)
{
int count;
int orig_dsize = dsize;
- char *src = *src_p;
+ uint8_t *src = *src_p;
while (ssize >0 && dsize > 0) { // While there's more to decompress, and there's room in the decompress buffer...
count = *src++; --ssize; // get the count byte from the source.
// L2TPNS Clustering Stuff
-// $Id: cluster.h,v 1.13 2005-06-28 14:48:19 bodea Exp $
+// $Id: cluster.h,v 1.14 2005-07-31 10:04:10 bodea Exp $
#ifndef __CLUSTER_H__
#define __CLUSTER_H__
} pingt;
int cluster_init(void);
-int processcluster(char *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_tunnel(int tid);
-int master_forward_packet(char *data, int size, in_addr_t addr, int port);
-int master_forward_dae_packet(char *data, int size, in_addr_t addr, int port);
-int master_throttle_packet(int tid, char *data, int size);
-int master_garden_packet(sessionidt s, char *data, int size);
+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_throttle_packet(int tid, uint8_t *data, int size);
+int master_garden_packet(sessionidt s, uint8_t *data, int size);
void master_update_counts(void);
void cluster_send_ping(time_t basetime);
void cluster_heartbeat(void);
// L2TPNS: constants
-char const *cvs_id_constants = "$Id: constants.c,v 1.6 2005-06-28 14:48:20 bodea Exp $";
+char const *cvs_id_constants = "$Id: constants.c,v 1.7 2005-07-31 10:04:10 bodea Exp $";
#include <stdio.h>
#include "constants.h"
return n; \
}
-CONSTANT(lcp_type,
+CONSTANT(l2tp_code,
0, // 0
- "Maximum-Receive-Unit", // 1
- "Async-Control-Map", // 2
- "Authentication-Protocol", // 3
- "Quality-Protocol", // 4
- "Magic-Number", // 5
- 0, // 6
- "Protocol-Field-Compression", // 7
- "Address-and-Control-Field-Compression" // 8
+ "SCCRQ", // 1
+ "SCCRP", // 2
+ "SCCCN", // 3
+ "StopCCN", // 4
+ 0, // 5
+ "HELLO", // 6
+ "OCRQ", // 7
+ "OCRP", // 8
+ "OCCN", // 9
+ "ICRQ", // 10
+ "ICRP", // 11
+ "ICCN", // 12
+ 0, // 13
+ "CDN", // 14
+ "WEN", // 15
+ "SLI" // 16
)
-CONSTANT(avp_name,
+CONSTANT(l2tp_avp_name,
"Message Type", // 0
"Result Code", // 1
"Protocol Version", // 2
"Sequencing Required" // 39
)
-CONSTANT(stopccn_result_code,
+CONSTANT(l2tp_stopccn_result_code,
0, // 0
"General request to clear control connection", // 1
"General error--Error Code indicates the problem", // 2
"Finite State Machine error" // 7
)
-CONSTANT(cdn_result_code,
+CONSTANT(l2tp_cdn_result_code,
0, // 0
"Call disconnected due to loss of carrier", // 1
"Call disconnected for the reason indicated in"
" detected" // 11
)
-CONSTANT(error_code,
+CONSTANT(l2tp_error_code,
"No general error", // 0
"No control connection exists yet for this LAC-LNS"
" pair", // 1
" an unknown AVP with the M-bit set" // 8
)
-CONSTANT(auth_type,
+CONSTANT(ppp_phase,
+ "Dead", // 0
+ "Establish", // 1
+ "Authenticate", // 2
+ "Network", // 3
+ "Terminate", // 4
+)
+
+CONSTANT(ppp_state,
+ "Initial", // 0
+ "Starting", // 1
+ "Closed", // 2
+ "Stopped", // 3
+ "Closing", // 4
+ "Stopping", // 5
+ "Request-Sent", // 6
+ "Ack-Received", // 7
+ "Ack-Sent", // 8
+ "Opened" // 9
+)
+
+CONSTANT(ppp_auth_type,
0, // 0
"Textual username/password exchange", // 1
"PPP CHAP", // 2
"Microsoft CHAP Version 1 (MSCHAPv1)" // 5
)
-CONSTANT(ppp_lcp_type,
+CONSTANT(ppp_code,
0, // 0
"ConfigReq", // 1
"ConfigAck", // 2
"IdentRequest" // 12
)
+CONSTANT(ppp_lcp_option,
+ 0, // 0
+ "Maximum-Receive-Unit", // 1
+ "Async-Control-Map", // 2
+ "Authentication-Protocol", // 3
+ "Quality-Protocol", // 4
+ "Magic-Number", // 5
+ 0, // 6
+ "Protocol-Field-Compression", // 7
+ "Address-and-Control-Field-Compression" // 8
+)
+
CONSTANT(radius_state,
"RADIUSNULL", // 0
"RADIUSCHAP", // 1
"RADIUSAUTH", // 2
- "RADIUSIPCP", // 3
- "RADIUSSTART", // 4
- "RADIUSSTOP", // 5
- "RADIUSINTERIM", // 6
- "RADIUSWAIT" // 7
+ "RADIUSSTART", // 3
+ "RADIUSSTOP", // 4
+ "RADIUSINTERIM", // 5
+ "RADIUSWAIT" // 6
)
CONSTANT(radius_code,
"CoA-ACK", // 44
"CoA-NAK" // 45
)
-
-CONSTANT(l2tp_message_type,
- 0, // 0
- "SCCRQ", // 1
- "SCCRP", // 2
- "SCCCN", // 3
- "StopCCN", // 4
- 0, // 5
- "HELLO", // 6
- "OCRQ", // 7
- "OCRP", // 8
- "OCCN", // 9
- "ICRQ", // 10
- "ICRP", // 11
- "ICCN", // 12
- 0, // 13
- "CDN", // 14
- "WEN", // 15
- "SLI" // 16
-)
#ifndef __CONSTANTS_H__
#define __CONSTANTS_H__
-char const *lcp_type(int type);
-char const *avp_name(int avp);
-char const *stopccn_result_code(int code);
-char const *cdn_result_code(int code);
-char const *error_code(int code);
-char const *auth_type(int type);
-char const *ppp_lcp_type(int type);
+char const *l2tp_code(int type);
+char const *l2tp_avp_name(int avp);
+char const *l2tp_stopccn_result_code(int code);
+char const *l2tp_cdn_result_code(int code);
+char const *l2tp_error_code(int code);
+char const *ppp_phase(int code);
+char const *ppp_state(int code);
+char const *ppp_auth_type(int type);
+char const *ppp_code(int type);
+char const *ppp_lcp_option(int type);
char const *radius_state(int state);
char const *radius_code(int code);
-char const *l2tp_message_type(int type);
#endif /* __CONSTANTS_H__ */
// L2TPNS: control
-char const *cvs_id_control = "$Id: control.c,v 1.4 2004-12-16 08:49:53 bodea Exp $";
+char const *cvs_id_control = "$Id: control.c,v 1.5 2005-07-31 10:04:10 bodea Exp $";
#include <string.h>
#include "l2tpns.h"
#include "control.h"
-int pack_control(char *data, int len, uint8_t type, int argc, char *argv[])
+int pack_control(uint8_t *data, int len, uint8_t type, int argc, char *argv[])
{
struct nsctl_packet pkt;
struct nsctl_args arg;
return sz;
}
-int unpack_control(struct nsctl *control, char *data, int len)
+int unpack_control(struct nsctl *control, uint8_t *data, int len)
{
struct nsctl_packet pkt;
char *p = pkt.argv;
char *argv[0xff];
};
-int pack_control(char *data, int len, uint8_t type, int argc, char *argv[]);
-int unpack_control(struct nsctl *packet, char *data, int len);
+int pack_control(uint8_t *data, int len, uint8_t type, int argc, char *argv[]);
+int unpack_control(struct nsctl *packet, uint8_t *data, int len);
void dump_control(struct nsctl *control, FILE *stream);
#endif /* __CONTROL_H__ */
// L2TPNS: icmp
-char const *cvs_id_icmp = "$Id: icmp.c,v 1.8 2005-06-04 15:42:06 bodea Exp $";
+char const *cvs_id_icmp = "$Id: icmp.c,v 1.9 2005-07-31 10:04:10 bodea Exp $";
#include <arpa/inet.h>
#include <netdb.h>
#include "l2tpns.h"
-static uint16_t _checksum(unsigned char *addr, int count);
+static uint16_t _checksum(uint8_t *addr, int count);
struct ipv6_pseudo_hdr {
struct in6_addr src;
uint32_t nexthdr : 8;
};
-void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, char *packet, int packet_len)
+void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, uint8_t *packet, int packet_len)
{
char buf[128] = {0};
struct iphdr *iph;
icmp->type = ICMP_DEST_UNREACH;
icmp->code = ICMP_HOST_UNREACH;
- icmp->checksum = _checksum((char *) icmp, sizeof(struct icmphdr) + packet_len);
+ icmp->checksum = _checksum((uint8_t *) icmp, sizeof(struct icmphdr) + packet_len);
- iph->check = _checksum((char *) iph, sizeof(struct iphdr));
+ iph->check = _checksum((uint8_t *) iph, sizeof(struct iphdr));
- sendto(icmp_socket, (char *)buf, len, 0, (struct sockaddr *)&whereto, sizeof(struct sockaddr));
+ sendto(icmp_socket, buf, len, 0, (struct sockaddr *)&whereto, sizeof(struct sockaddr));
close(icmp_socket);
}
-static uint16_t _checksum(unsigned char *addr, int count)
+static uint16_t _checksum(uint8_t *addr, int count)
{
register long sum = 0;
// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
// vim: sw=8 ts=8
-char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.114 2005-07-04 05:49:46 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.115 2005-07-31 10:04:10 bodea Exp $";
#include <arpa/inet.h>
#include <assert.h>
#include <unistd.h>
#include <sched.h>
#include <sys/sysinfo.h>
+#include <openssl/md5.h>
#include <libcli.h>
-#include "md5.h"
#include "l2tpns.h"
#include "cluster.h"
#include "plugin.h"
CONFIG("pid_file", pid_file, STRING),
CONFIG("random_device", random_device, STRING),
CONFIG("l2tp_secret", l2tpsecret, STRING),
+ CONFIG("ppp_restart_time", ppp_restart_time, INT),
+ CONFIG("ppp_max_configure", ppp_max_configure, INT),
+ CONFIG("ppp_max_failure", ppp_max_failure, INT),
CONFIG("primary_dns", default_dns1, IPv4),
CONFIG("secondary_dns", default_dns2, IPv4),
CONFIG("primary_radius", radiusserver[0], IPv4),
static void sigalrm_handler(int sig);
static void shutdown_handler(int sig);
static void sigchild_handler(int sig);
-static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_length, char **challenge_response);
+static void build_chap_response(uint8_t *challenge, uint8_t id, uint16_t challenge_length, uint8_t **challenge_response);
static void update_config(void);
static void read_config_file(void);
static void initplugins(void);
va_end(ap);
}
-void _log_hex(int level, const char *title, const char *data, int maxsize)
+void _log_hex(int level, const char *title, const uint8_t *data, int maxsize)
{
int i, j;
- const uint8_t *d = (const uint8_t *) data;
+ const uint8_t *d = data;
if (config->debug < level) return;
tunidx = ifr.ifr_ifindex;
// Only setup IPv6 on the tun device if we have a configured prefix
- if (config->ipv6_prefix.s6_addr[0] > 0) {
+ if (config->ipv6_prefix.s6_addr[0]) {
ifr6fd = socket(PF_INET6, SOCK_DGRAM, 0);
// Link local address is FE80::1
CSTAT(sessionbyipv6);
if (!memcmp(&config->ipv6_prefix, &ip, 8) ||
- (ip.s6_addr[0] == 0xFE && ip.s6_addr[1] == 0x80 &&
- (ip.s6_addr16[1] == ip.s6_addr16[2] == ip.s6_addr16[3] == 0))) {
+ (ip.s6_addr[0] == 0xFE &&
+ ip.s6_addr[1] == 0x80 &&
+ ip.s6_addr16[1] == 0 &&
+ ip.s6_addr16[2] == 0 &&
+ ip.s6_addr16[3] == 0)) {
s = lookup_ipmap(*(in_addr_t *) &ip.s6_addr[8]);
} else {
s = lookup_ipv6map(ip);
// process outgoing (to tunnel) IP
//
-static void processipout(uint8_t * buf, int len)
+static void processipout(uint8_t *buf, int len)
{
sessionidt s;
sessiont *sp;
tunnelidt t;
in_addr_t ip;
- char *data = buf; // Keep a copy of the originals.
+ uint8_t *data = buf; // Keep a copy of the originals.
int size = len;
uint8_t b[MAXETHER + 20];
in_addr_t ip;
struct in6_addr ip6;
- char *data = buf; // Keep a copy of the originals.
+ uint8_t *data = buf; // Keep a copy of the originals.
int size = len;
uint8_t b[MAXETHER + 20];
}
// add a binary AVP
-static void controlb(controlt * c, uint16_t avp, char *val, unsigned int len, uint8_t m)
+static void controlb(controlt * c, uint16_t avp, uint8_t *val, unsigned int len, uint8_t m)
{
uint16_t l = ((m ? 0x8000 : 0) + len + 6);
*(uint16_t *) (c->buf + c->length + 0) = htons(l);
if (session[s].ip && !walled_garden && !session[s].die)
{
// RADIUS Stop message
- uint16_t r = sess_local[s].radius;
- if (!r)
- r = radiusnew(s);
-
+ uint16_t r = radiusnew(s);
if (r)
{
// stop, if not already trying
free_ip_address(s);
// unroute IPv6, if setup
- if (session[s].flags & SF_IPV6_ROUTED)
+ if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen)
route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
}
controlt *c = controlnew(14); // sending CDN
if (error)
{
- char buf[4];
+ uint8_t buf[4];
*(uint16_t *) buf = htons(result);
*(uint16_t *) (buf+2) = htons(error);
controlb(c, 1, buf, 4, 1);
if (session[s].filter_in) ip_filters[session[s].filter_in - 1].used--;
if (session[s].filter_out) ip_filters[session[s].filter_out - 1].used--;
+ // clear PPP state
+ memset(&session[s].ppp, 0, sizeof(session[s].ppp));
+ sess_local[s].lcp.restart = 0;
+ sess_local[s].ipcp.restart = 0;
+ sess_local[s].ipv6cp.restart = 0;
+ sess_local[s].ccp.restart = 0;
+
cluster_send_session(s);
}
void sendipcp(tunnelidt t, sessionidt s)
{
uint8_t buf[MAXCONTROL];
- uint16_t r = sess_local[s].radius;
uint8_t *q;
CSTAT(sendipcp);
- if (!r)
- r = radiusnew(s);
-
- if (!r)
- {
- sessionshutdown(s, "No free RADIUS sessions for IPCP", 3, 0);
- return;
- }
-
- if (radius[r].state != RADIUSIPCP)
- {
- radius[r].state = RADIUSIPCP;
- radius[r].try = 0;
- }
-
- radius[r].retry = backoff(radius[r].try++);
- if (radius[r].try > 10)
+ if (!session[s].unique_id)
{
- radiusclear(r, s); // Clear radius session.
- sessionshutdown(s, "No reply to IPCP.", 3, 0);
- return;
+ if (!++last_id) ++last_id; // skip zero
+ session[s].unique_id = last_id;
}
q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPCP);
if (!q) return;
*q = ConfigReq;
- q[1] = r >> RADIUS_SHIFT; // ID, dont care, we only send one type of request
- *(uint16_t *) (q + 2) = htons(10);
- q[4] = 3;
- q[5] = 6;
+ q[1] = session[s].unique_id & 0xf; // ID, dont care, we only send one type of request
+ *(uint16_t *) (q + 2) = htons(10); // packet length
+ q[4] = 3; // ip address option
+ q[5] = 6; // option length
*(in_addr_t *) (q + 6) = config->peer_address ? config->peer_address :
config->bind_address ? config->bind_address :
my_address; // send my IP
tunnelsend(buf, 10 + (q - buf), t); // send it
- session[s].flags &= ~SF_IPCP_ACKED; // Clear flag.
-
- // If we have an IPv6 prefix length configured, assume we should
- // try to negotiate an IPv6 session as well. Unless we've had a
- // (N)ACK for IPV6CP.
- if (config->ipv6_prefix.s6_addr[0] > 0 &&
- !(session[s].flags & SF_IPV6CP_ACKED) &&
- !(session[s].flags & SF_IPV6_NACKED))
- {
- q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPV6CP);
- if (!q) return;
-
- *q = ConfigReq;
- q[1] = r >> RADIUS_SHIFT; // ID, don't care, we
- // only send one type
- // of request
- *(uint16_t *) (q + 2) = htons(14);
- q[4] = 1;
- q[5] = 10;
- *(uint32_t *) (q + 6) = 0; // We'll be prefix::1
- *(uint32_t *) (q + 10) = 0;
- q[13] = 1;
-
- tunnelsend(buf, 14 + (q - buf), t); // send it
- }
+}
+
+void sendipv6cp(tunnelidt t, sessionidt s)
+{
+ uint8_t buf[MAXCONTROL];
+ uint8_t *q;
+
+ CSTAT(sendipv6cp);
+
+ q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPV6CP);
+ if (!q) return;
+
+ *q = ConfigReq;
+ q[1] = session[s].unique_id & 0xf; // ID, don't care, we
+ // only send one type
+ // of request
+ *(uint16_t *) (q + 2) = htons(14);
+ q[4] = 1; // interface identifier option
+ q[5] = 10; // option length
+ *(uint32_t *) (q + 6) = 0; // We'll be prefix::1
+ *(uint32_t *) (q + 10) = 0;
+ q[13] = 1;
+
+ tunnelsend(buf, 14 + (q - buf), t); // send it
}
static void sessionclear(sessionidt s)
controlt *c = controlnew(4); // sending StopCCN
if (error)
{
- char buf[64];
+ uint8_t buf[64];
int l = 4;
*(uint16_t *) buf = htons(result);
*(uint16_t *) (buf+2) = htons(error);
}
// read and process packet on tunnel (UDP)
-void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
+void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
{
- char *chapresponse = NULL;
+ uint8_t *chapresponse = NULL;
uint16_t l = len, t = 0, s = 0, ns = 0, nr = 0;
uint8_t *p = buf + 2;
n = orig_len;
}
- LOG(4, s, t, " AVP %d (%s) len %d%s%s\n", mtype, avp_name(mtype), n,
+ LOG(4, s, t, " AVP %d (%s) len %d%s%s\n", mtype, l2tp_avp_name(mtype), n,
flags & 0x40 ? ", hidden" : "", flags & 0x80 ? ", mandatory" : "");
switch (mtype)
case 0: // message type
message = ntohs(*(uint16_t *) b);
mandatory = flags & 0x80;
- LOG(4, s, t, " Message type = %d (%s)\n", *b, l2tp_message_type(message));
+ LOG(4, s, t, " Message type = %d (%s)\n", *b, l2tp_code(message));
break;
case 1: // result code
{
const char* resdesc = "(unknown)";
if (message == 4)
{ /* StopCCN */
- resdesc = stopccn_result_code(rescode);
+ resdesc = l2tp_stopccn_result_code(rescode);
}
else if (message == 14)
{ /* CDN */
- resdesc = cdn_result_code(rescode);
+ resdesc = l2tp_cdn_result_code(rescode);
}
LOG(4, s, t, " Result Code %d: %s\n", rescode, resdesc);
if (n >= 4)
{
uint16_t errcode = ntohs(*(uint16_t *)(b + 2));
- LOG(4, s, t, " Error Code %d: %s\n", errcode, error_code(errcode));
+ LOG(4, s, t, " Error Code %d: %s\n", errcode, l2tp_error_code(errcode));
}
if (n > 4)
LOG(4, s, t, " Error String: %.*s\n", n-4, b+4);
case 29: // Proxy Authentication Type
{
uint16_t atype = ntohs(*(uint16_t *)b);
- LOG(4, s, t, " Proxy Auth Type %d (%s)\n", atype, auth_type(atype));
+ LOG(4, s, t, " Proxy Auth Type %d (%s)\n", atype, ppp_auth_type(atype));
if (atype == 2)
authtype = AUTHCHAP;
else if (atype == 3)
case 10: // ICRQ
if (sessionfree && main_quit != QUIT_SHUTDOWN)
{
- uint16_t r;
+ controlt *c = controlnew(11); // ICRP
s = sessionfree;
sessionfree = session[s].next;
if (s > config->cluster_highest_sessionid)
config->cluster_highest_sessionid = s;
- // make a RADIUS session
- if ((r = radiusnew(s)))
- {
- controlt *c = controlnew(11); // sending ICRP
- session[s].opened = time_now;
- session[s].tunnel = t;
- session[s].far = asession;
- session[s].last_packet = time_now;
- LOG(3, s, t, "New session (%d/%d)\n", tunnel[t].far, session[s].far);
- control16(c, 14, s, 1); // assigned session
- controladd(c, t, asession); // send the reply
-
- strncpy(radius[r].calling, calling, sizeof(radius[r].calling) - 1);
- strncpy(session[s].called, called, sizeof(session[s].called) - 1);
- strncpy(session[s].calling, calling, sizeof(session[s].calling) - 1);
- STAT(session_created);
- break;
- }
+ session[s].opened = time_now;
+ session[s].tunnel = t;
+ session[s].far = asession;
+ session[s].last_packet = time_now;
+ LOG(3, s, t, "New session (%d/%d)\n", tunnel[t].far, session[s].far);
+ control16(c, 14, s, 1); // assigned session
+ controladd(c, t, asession); // send the reply
+ strncpy(session[s].called, called, sizeof(session[s].called) - 1);
+ strncpy(session[s].calling, calling, sizeof(session[s].calling) - 1);
- LOG(1, s, t, "No free RADIUS sessions for ICRQ\n");
- sessionclear(s);
- }
- else
- {
- STAT(session_overflow);
- LOG(1, 0, t, "No free sessions\n");
+ session[s].ppp.phase = Establish;
+ session[s].ppp.lcp = Starting;
+
+ STAT(session_created);
+ break;
}
{
controlt *c = controlnew(14); // CDN
- if (main_quit == QUIT_SHUTDOWN)
- control16(c, 1, 2, 7); // try another
- else
+ if (!sessionfree)
+ {
+ STAT(session_overflow);
+ LOG(1, 0, t, "No free sessions\n");
control16(c, 1, 4, 0); // temporary lack of resources
+ }
+ else
+ control16(c, 1, 2, 7); // shutting down, try another
controladd(c, t, asession); // send the message
}
session[s].l2tp_flags = aflags; // set flags received
LOG(3, s, t, "Magic %X Flags %X\n", amagic, aflags);
controlnull(t); // ack
+
// proxy authentication type is not supported
if (!(config->radius_authtypes & authtype))
authtype = config->radius_authprefer;
// start LCP
sendlcp(t, s, authtype);
+ sess_local[s].lcp.restart = time_now + config->ppp_restart_time;
+ sess_local[s].lcp.conf_sent = 1;
+ sess_local[s].lcp.nak_sent = 0;
+ sess_local[s].lcp_authtype = authtype;
+ session[s].ppp.lcp = RequestSent;
+
break;
case 14: // CDN
controlnull(t); // ack
}
else if (prot == PPPIPV6CP)
{
- if (config->ipv6_prefix.s6_addr[0] > 0)
- {
- session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
- processipv6cp(t, s, p, l);
- }
- else
- {
- LOG(1, s, t, "IPv6 not configured; ignoring IPv6CP\n");
- }
+ session[s].last_packet = time_now;
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ processipv6cp(t, s, p, l);
}
else if (prot == PPPCCP)
{
}
else if (prot == PPPIPV6)
{
- if (!config->ipv6_prefix.s6_addr[0] > 0)
+ if (!config->ipv6_prefix.s6_addr[0])
{
LOG(1, s, t, "IPv6 not configured; yet received IPv6 packet. Ignoring.\n");
return;
if (*(uint16_t *) (buf + 2) == htons(PKTIP)) // IPv4
processipout(buf, len);
else if (*(uint16_t *) (buf + 2) == htons(PKTIPV6) // IPV6
- && config->ipv6_prefix.s6_addr[0] > 0)
+ && config->ipv6_prefix.s6_addr[0])
processipv6out(buf, len);
// Else discard.
continue;
}
- if (session[s].ip && !(session[s].flags & SF_IPCP_ACKED)
- && !(sess_local[s].radius && radius[sess_local[s].radius].state == RADIUSIPCP))
+ // PPP timeouts
+ if (sess_local[s].lcp.restart >= time_now)
{
- // IPCP has not completed yet. Resend
- LOG(3, s, session[s].tunnel, "No ACK for initial IPCP ConfigReq... resending\n");
- sendipcp(session[s].tunnel, s);
- s_actions++;
+ int next_state = session[s].ppp.lcp;
+ switch (session[s].ppp.lcp)
+ {
+ case RequestSent:
+ case AckReceived:
+ next_state = RequestSent;
+
+ case AckSent:
+ if (sess_local[s].lcp.conf_sent < config->ppp_max_configure)
+ {
+ LOG(3, s, session[s].tunnel, "No ACK for LCP ConfigReq... resending\n");
+ sess_local[s].lcp.restart = time_now + config->ppp_restart_time;
+ sess_local[s].lcp.conf_sent++;
+ sendlcp(t, s, sess_local[s].lcp_authtype);
+ change_state(s, lcp, next_state);
+ }
+ else
+ {
+ sessionshutdown(s, "No response to LCP ConfigReq.", 3, 0);
+ STAT(session_timeout);
+ }
+
+ s_actions++;
+ }
+
+ if (session[s].die)
+ continue;
+ }
+
+ if (sess_local[s].ipcp.restart >= time_now)
+ {
+ int next_state = session[s].ppp.ipcp;
+ switch (session[s].ppp.ipcp)
+ {
+ case RequestSent:
+ case AckReceived:
+ next_state = RequestSent;
+
+ case AckSent:
+ if (sess_local[s].ipcp.conf_sent < config->ppp_max_configure)
+ {
+ LOG(3, s, session[s].tunnel, "No ACK for IPCP ConfigReq... resending\n");
+ sess_local[s].ipcp.restart = time_now + config->ppp_restart_time;
+ sess_local[s].ipcp.conf_sent++;
+ sendipcp(t, s);
+ change_state(s, ipcp, next_state);
+ }
+ else
+ {
+ sessionshutdown(s, "No response to IPCP ConfigReq.", 3, 0);
+ STAT(session_timeout);
+ }
+
+ s_actions++;
+ }
+
+ if (session[s].die)
+ continue;
+ }
+
+ if (sess_local[s].ipv6cp.restart >= time_now)
+ {
+ int next_state = session[s].ppp.ipv6cp;
+ switch (session[s].ppp.ipv6cp)
+ {
+ case RequestSent:
+ case AckReceived:
+ next_state = RequestSent;
+
+ case AckSent:
+ if (sess_local[s].ipv6cp.conf_sent < config->ppp_max_configure)
+ {
+ LOG(3, s, session[s].tunnel, "No ACK for IPV6CP ConfigReq... resending\n");
+ sess_local[s].ipv6cp.restart = time_now + config->ppp_restart_time;
+ sess_local[s].ipv6cp.conf_sent++;
+ sendipv6cp(t, s);
+ change_state(s, ipv6cp, next_state);
+ }
+ else
+ {
+ LOG(3, s, session[s].tunnel, "No ACK for IPV6CP ConfigReq\n");
+ change_state(s, ipv6cp, Stopped);
+ }
+
+ s_actions++;
+ }
+ }
+
+ if (sess_local[s].ccp.restart >= time_now)
+ {
+ int next_state = session[s].ppp.ccp;
+ switch (session[s].ppp.ccp)
+ {
+ case RequestSent:
+ case AckReceived:
+ next_state = RequestSent;
+
+ case AckSent:
+ if (sess_local[s].ccp.conf_sent < config->ppp_max_configure)
+ {
+ LOG(3, s, session[s].tunnel, "No ACK for CCP ConfigReq... resending\n");
+ sess_local[s].ccp.restart = time_now + config->ppp_restart_time;
+ sess_local[s].ccp.conf_sent++;
+ sendccp(t, s);
+ change_state(s, ccp, next_state);
+ }
+ else
+ {
+ LOG(3, s, session[s].tunnel, "No ACK for CCP ConfigReq\n");
+ change_state(s, ccp, Stopped);
+ }
+
+ s_actions++;
+ }
}
// Drop sessions who have not responded within IDLE_TIMEOUT seconds
}
// No data in ECHO_TIMEOUT seconds, send LCP ECHO
- if (session[s].user[0] && (time_now - session[s].last_packet >= ECHO_TIMEOUT))
+ if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= ECHO_TIMEOUT))
{
uint8_t b[MAXCONTROL] = {0};
if (n)
{
struct sockaddr_in addr;
- int alen, c, s;
+ socklen_t alen;
+ int c, s;
int udp_ready = 0;
int tun_ready = 0;
int cluster_ready = 0;
config->num_tbfs = MAXTBFS;
config->rl_rate = 28; // 28kbps
config->cluster_master_min_adv = 1;
+ config->ppp_restart_time = 3;
+ config->ppp_max_configure = 10;
+ config->ppp_max_failure = 5;
strcpy(config->random_device, RANDOMDEVICE);
log_stream = stderr;
LOG(1, 0, 0, "IP address pool is %d addresses\n", ip_pool_size - 1);
}
-void snoop_send_packet(char *packet, uint16_t size, in_addr_t destination, uint16_t port)
+void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, uint16_t port)
{
struct sockaddr_in snoop_addr = {0};
if (!destination || !port || snoopfd <= 0 || size <= 0 || !packet)
;
}
-static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_length, char **challenge_response)
+static void build_chap_response(uint8_t *challenge, uint8_t id, uint16_t challenge_length, uint8_t **challenge_response)
{
MD5_CTX ctx;
*challenge_response = NULL;
LOG(4, 0, 0, " Building challenge response for CHAP request\n");
- *challenge_response = (char *)calloc(17, 1);
+ *challenge_response = calloc(17, 1);
- MD5Init(&ctx);
- MD5Update(&ctx, &id, 1);
- MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
- MD5Update(&ctx, challenge, challenge_length);
- MD5Final(*challenge_response, &ctx);
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, &id, 1);
+ MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
+ MD5_Update(&ctx, challenge, challenge_length);
+ MD5_Final(*challenge_response, &ctx);
return;
}
cache_ipmap(session[s].ip, s);
}
- if (!session[s].unique_id)
- {
- // did this session just finish radius?
- LOG(3, s, t, "Sending initial IPCP to client\n");
- sendipcp(t, s);
- session[s].unique_id = ++last_id;
- }
+ sess_local[s].lcp_authtype = 0; // RADIUS authentication complete
+ lcp_open(t, s); // transition to Network phase and send initial IPCP
// Run the plugin's against this new session.
{
}
// check v6 routing
- if (new->flags & SF_IPV6_ROUTED && !(session[s].flags & SF_IPV6_ROUTED))
+ if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
route6set(s, new->ipv6route, new->ipv6prefixlen, 1);
// check filters
run_plugin_done(p);
}
-static void processcontrol(uint8_t * buf, int len, struct sockaddr_in *addr, int alen)
+static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen)
{
struct nsctl request;
struct nsctl response;
uint16_t m = htons(type);
// Compute initial pad
- MD5Init(&ctx);
- MD5Update(&ctx, (unsigned char *) &m, 2);
- MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
- MD5Update(&ctx, vector, vec_len);
- MD5Final(digest, &ctx);
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, (unsigned char *) &m, 2);
+ MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
+ MD5_Update(&ctx, vector, vec_len);
+ MD5_Final(digest, &ctx);
// pointer to last decoded 16 octets
last = value;
// calculate a new pad based on the last decoded block
if (d >= sizeof(digest))
{
- MD5Init(&ctx);
- MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
- MD5Update(&ctx, last, sizeof(digest));
- MD5Final(digest, &ctx);
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
+ MD5_Update(&ctx, last, sizeof(digest));
+ MD5_Final(digest, &ctx);
d = 0;
last = value;
// L2TPNS Global Stuff
-// $Id: l2tpns.h,v 1.80 2005-06-28 14:48:27 bodea Exp $
+// $Id: l2tpns.h,v 1.81 2005-07-31 10:04:10 bodea Exp $
#ifndef __L2TPNS_H__
#define __L2TPNS_H__
#define CONFIGFILE FLASHDIR "/startup-config" // Configuration file
#define CLIUSERS FLASHDIR "/users" // CLI Users file
#define IPPOOLFILE FLASHDIR "/ip_pool" // Address pool configuration
-#define ACCT_TIME 3000 // 5 minute accounting interval
-#define ACCT_SHUT_TIME 600 // 1 minute for counters of shutdown sessions
-#define L2TPPORT 1701 // L2TP port
-#define RADPORT 1645 // old radius port...
-#define DAEPORT 3799 // DAE port
-#define PKTARP 0x0806 // ARP packet type
-#define PKTIP 0x0800 // IPv4 packet type
-#define PKTIPV6 0x86DD // IPv6 packet type
+#define ACCT_TIME 3000 // 5 minute accounting interval
+#define ACCT_SHUT_TIME 600 // 1 minute for counters of shutdown sessions
+#define L2TPPORT 1701 // L2TP port
+#define RADPORT 1645 // old radius port...
+#define DAEPORT 3799 // DAE port
+#define PKTARP 0x0806 // ARP packet type
+#define PKTIP 0x0800 // IPv4 packet type
+#define PKTIPV6 0x86DD // IPv6 packet type
#define PPPPAP 0xC023
#define PPPCHAP 0xC223
#define PPPLCP 0xC021
CoANAK
};
+// PPP phases
+enum {
+ Dead,
+ Establish,
+ Authenticate,
+ Network,
+ Terminate
+};
+
+// PPP states
+enum {
+ Initial,
+ Starting,
+ Closed,
+ Stopped,
+ Closing,
+ Stopping,
+ RequestSent,
+ AckReceived,
+ AckSent,
+ Opened
+};
+
+// reset state machine counters
+#define initialise_restart_count(_s, _fsm) \
+ sess_local[_s]._fsm.conf_sent = sess_local[_s]._fsm.nak_sent
+
+// stop timer on change to state where timer does not run
+#define change_state(_s, _fsm, _new) ({ \
+ if (_new != session[_s].ppp._fsm) \
+ { \
+ switch (_new) \
+ { \
+ case Initial: \
+ case Starting: \
+ case Closed: \
+ case Stopped: \
+ case Opened: \
+ sess_local[_s]._fsm.restart = 0; \
+ initialise_restart_count(_s, _fsm); \
+ } \
+ session[_s].ppp._fsm = _new; \
+ cluster_send_session(_s); \
+ } \
+})
+
// Types
typedef uint16_t sessionidt;
typedef uint16_t tunnelidt;
sessionidt far; // far end session ID
tunnelidt tunnel; // near end tunnel ID
uint8_t l2tp_flags; // various bit flags from the ICCN on the l2tp tunnel.
- uint8_t flags; // Various session flags.
+ struct {
+ uint8_t phase; // PPP phase
+ uint8_t lcp:4; // LCP state
+ uint8_t ipcp:4; // IPCP state
+ uint8_t ipv6cp:4; // IPV6CP state
+ uint8_t ccp:4; // CCP state
+ uint8_t pad; // unused
+ } ppp;
in_addr_t ip; // IP of session set by RADIUS response (host byte order).
int ip_pool_index; // index to IP pool
uint32_t unique_id; // unique session id
uint16_t tbf_in; // filter bucket for throttling in from the user.
uint16_t tbf_out; // filter bucket for throttling out to the user.
int random_vector_length;
- char random_vector[MAXTEL];
+ uint8_t random_vector[MAXTEL];
char user[MAXUSER]; // user (needed in seesion for radius stop messages)
char called[MAXTEL]; // called number
char calling[MAXTEL]; // calling number
uint8_t walled_garden; // is this session gardened?
uint8_t ipv6prefixlen; // IPv6 route prefix length
struct in6_addr ipv6route; // Static IPv6 route
- char reserved[16]; // Space to expand structure without changing HB_VERSION
+ char reserved[11]; // Space to expand structure without changing HB_VERSION
}
sessiont;
-#define SF_IPCP_ACKED 1 // Has this session seen an IPCP Ack?
-#define SF_LCP_ACKED 2 // LCP negotiated
-#define SF_CCP_ACKED 4 // CCP negotiated
-#define SF_IPV6CP_ACKED 8 // IPv6 negotiated
-#define SF_IPV6_NACKED 16 // IPv6 rejected
-#define SF_IPV6_ROUTED 32 // advertised v6 route
-
#define AUTHPAP 1 // allow PAP
#define AUTHCHAP 2 // allow CHAP
uint32_t cin;
uint32_t cout;
+ // PPP restart timer/counters
+ struct {
+ time_t restart;
+ int conf_sent;
+ int nak_sent;
+ } lcp, ipcp, ipv6cp, ccp;
+
+ // authentication to use
+ int lcp_authtype;
+
// DoS prevention
clockt last_packet_out;
uint32_t packets_out;
}
tunnelt;
-// 180 bytes per radius session
+// 160 bytes per radius session
typedef struct // outstanding RADIUS requests
{
sessionidt session; // which session this applies to
hasht auth; // request authenticator
clockt retry; // when to try next
- char calling[MAXTEL]; // calling number
char pass[129]; // password
uint8_t id; // ID for PPP response
uint8_t try; // which try we are on
RADIUSNULL, // Not in use
RADIUSCHAP, // sending CHAP down PPP
RADIUSAUTH, // sending auth to RADIUS server
- RADIUSIPCP, // sending IPCP to end user
RADIUSSTART, // sending start accounting to RADIUS server
RADIUSSTOP, // sending stop accounting to RADIUS server
RADIUSINTERIM, // sending interim accounting to RADIUS server
uint32_t call_sessionbyuser;
uint32_t call_sendarp;
uint32_t call_sendipcp;
+ uint32_t call_sendipv6cp;
uint32_t call_processipv6cp;
uint32_t call_tunnelsend;
uint32_t call_sessionkill;
char random_device[256]; // random device path, defaults to RANDOMDEVICE
+ int ppp_restart_time; // timeout for PPP restart
+ int ppp_max_configure; // max lcp configure requests to send
+ int ppp_max_failure; // max lcp configure naks to send
+
char radiussecret[64];
int radius_accounting;
int radius_interim;
// ppp.c
void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
void processchap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
+void lcp_open(tunnelidt t, sessionidt s);
void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
void processipcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, tunnelidt t, sessionidt s, uint16_t mtype);
void sendlcp(tunnelidt t, sessionidt s, int authtype);
void send_ipin(sessionidt s, uint8_t *buf, int len);
+void sendccp(tunnelidt t, sessionidt s);
// radius.c
void send_garp(in_addr_t ip);
void tunnelsend(uint8_t *buf, uint16_t l, tunnelidt t);
void sendipcp(tunnelidt t, sessionidt s);
+void sendipv6cp(tunnelidt t, sessionidt s);
void processudp(uint8_t *buf, int len, struct sockaddr_in *addr);
-void snoop_send_packet(char *packet, uint16_t size, in_addr_t destination, uint16_t port);
+void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, uint16_t port);
int find_filter(char const *name, size_t len);
int ip_filter(uint8_t *buf, int len, uint8_t filter);
int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc);
#define LOG_HEX(D, t, d, s) ({ if (D <= config->debug) _log_hex(D, t, d, s); })
void _log(int level, sessionidt s, tunnelidt t, const char *format, ...) __attribute__((format (printf, 4, 5)));
-void _log_hex(int level, const char *title, const char *data, int maxsize);
+void _log_hex(int level, const char *title, const uint8_t *data, int maxsize);
int sessionsetup(tunnelidt t, sessionidt s);
int run_plugins(int plugin_type, void *data);
// icmp.c
-void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, char *packet, int packet_len);
+void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, uint8_t *packet, int packet_len);
extern tunnelt *tunnel;
URL: http://sourceforge.net/projects/l2tpns
BuildRoot: %{_tmppath}/%{name}-%{version}-root
Prereq: /sbin/chkconfig
-BuildRequires: libcli >= 1.8.5
-Requires: libcli >= 1.8.5
+BuildRequires: libcli >= 1.8.5, openssl-devel
+Requires: libcli >= 1.8.5, openssl
%description
l2tpns is a layer 2 tunneling protocol network server (LNS). It
%attr(644,root,root) /usr/share/man/man[58]/*
%changelog
-* Wed Jun 29 2005 Brendan O'Dea <bod@c47.org> 2.1.2-1
+* Sun Jul 31 2005 Brendan O'Dea <bod@> 2.1.2-1
- 2.1.2 release, see /usr/share/doc/l2tpns-2.1.2/Changes
+++ /dev/null
-/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- */
-
-char const *cvs_id_md5 = "$Id: md5.c,v 1.3 2004-08-13 00:02:50 fred_nerk Exp $";
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-#include <string.h>
-#include "md5.h"
-
-/* Constants for MD5Transform routine.
- */
-
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-static void MD5Transform PROTO_LIST((UINT4[4], unsigned char[64]));
-static void Encode PROTO_LIST((unsigned char *, UINT4 *, unsigned int));
-static void Decode PROTO_LIST((UINT4 *, unsigned char *, unsigned int));
-
-static unsigned char PADDING[64] = {
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions.
- */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits.
- */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context.
- */
-void MD5Init(MD5_CTX *context)
-{
- context->count[0] = context->count[1] = 0;
- // Load magic initialization constants.
- context->state[0] = 0x67452301;
- context->state[1] = 0xefcdab89;
- context->state[2] = 0x98badcfe;
- context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest
- operation, processing another message block, and updating the
- context.
- */
-void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
-
-{
- unsigned int i,
- index,
- partLen;
-
- /* Compute number of bytes mod 64 */
- index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
-
- /* Update number of bits */
- if ((context->count[0] += ((UINT4) inputLen << 3)) < ((UINT4) inputLen << 3))
- context->count[1]++;
- context->count[1] += ((UINT4) inputLen >> 29);
-
- partLen = 64 - index;
-
- /* Transform as many times as possible.
- */
- if (inputLen >= partLen)
- {
- memcpy(&context->buffer[index], input, partLen);
- MD5Transform(context->state, context->buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64)
- MD5Transform(context->state, &input[i]);
-
- index = 0;
- }
- else
- i = 0;
-
- /* Buffer remaining input */
- memcpy(&context->buffer[index], &input[i], inputLen - i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
- the message digest and zeroizing the context.
- */
-void MD5Final(unsigned char digest[16], MD5_CTX *context)
-{
- unsigned char bits[8];
- unsigned int index, padLen;
-
- /* Save number of bits */
- Encode(bits, context->count, 8);
-
- /* Pad out to 56 mod 64.
- */
- index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
- padLen = (index < 56) ? (56 - index) : (120 - index);
- MD5Update(context, PADDING, padLen);
-
- /* Append length (before padding) */
- MD5Update(context, bits, 8);
-
- /* Store state in digest */
- Encode(digest, context->state, 16);
-
- /* Zeroize sensitive information.
- */
- memset(context, 0, sizeof(*context));
-}
-
-/* MD5 basic transformation. Transforms state based on block.
- */
-static void MD5Transform(UINT4 state[4], unsigned char block[64])
-{
- UINT4 a = state[0],
- b = state[1],
- c = state[2],
- d = state[3],
- x[16];
-
- Decode(x, block, 64);
-
- /* Round 1 */
- FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
- FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
- FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
- FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
- FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
- FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
- FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
- FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
- FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
- FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
- FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
- FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
- FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
- FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
- FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
- FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
- GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
- GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
- GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
- GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
- GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
- GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
- GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
- GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
- GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
- GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
- GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
-
- GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
- GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
- GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
- GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
- GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
- /* Round 3 */
- HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
- HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
- HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
- HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
- HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
- HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
- HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
- HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
- HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
- HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
- HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
- HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
- HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
- HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
- HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
- HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
-
- /* Round 4 */
- II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
- II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
- II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
- II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
- II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
- II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
- II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
- II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
- II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
- II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
- II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
- II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
- II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
- II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
- II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
- II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
-
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
-
- // Zeroize sensitive information.
- memset(x, 0, sizeof(x));
-}
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
- a multiple of 4.
- */
-static void Encode(unsigned char *output, UINT4 *input, unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4)
- {
- output[j] = (unsigned char) (input[i] & 0xff);
- output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
- output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
- output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
- }
-}
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
- a multiple of 4.
- */
-static void Decode(UINT4 *output, unsigned char *input, unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) | (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
-}
-
+++ /dev/null
-/* RSAREF types and constants
- */
-
-#ifndef __MD5_H__
-#define __MD5_H__
-
-/* PROTOTYPES should be set to one if and only if the compiler supports
- function argument prototyping.
-The following makes PROTOTYPES default to 0 if it has not already
-
- been defined with C compiler flags.
- */
-#ifndef PROTOTYPES
-#define PROTOTYPES 0
-#endif
-
-/* POINTER defines a generic pointer type */
-typedef unsigned char *POINTER;
-
-/* UINT2 defines a two byte word */
-typedef unsigned short int UINT2;
-
-/* UINT4 defines a four byte word */
-typedef unsigned long int UINT4;
-
-/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
-If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
- returns an empty list.
- */
-#if PROTOTYPES
-#define PROTO_LIST(list) list
-#else
-#define PROTO_LIST(list) ()
-#endif
-
-
-/* MD5.H - header file for MD5C.C
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-/* MD5 context. */
-typedef struct {
- UINT4 state[4]; /* state (ABCD) */
- UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
-} MD5_CTX;
-
-void MD5Init PROTO_LIST ((MD5_CTX *));
-void MD5Update PROTO_LIST
- ((MD5_CTX *, unsigned char *, unsigned int));
-void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
-
-#endif /* __MD5_H__ */
socklen_t len = sizeof(peer);
struct hostent *h = gethostbyname(host);
int fd;
- char buf[NSCTL_MAX_PKT_SZ];
+ uint8_t buf[NSCTL_MAX_PKT_SZ];
int sz;
char *err;
struct pluginfuncs
{
void (*log)(int level, sessionidt s, tunnelidt t, const char *format, ...);
- void (*log_hex)(int level, const char *title, const char *data, int maxsize);
+ void (*log_hex)(int level, const char *title, const uint8_t *data, int maxsize);
char *(*fmtaddr)(in_addr_t addr, int n);
sessionidt (*get_session_by_username)(char *username);
sessiont *(*get_session_by_id)(sessionidt s);
// L2TPNS PPP Stuff
-char const *cvs_id_ppp = "$Id: ppp.c,v 1.64 2005-06-24 08:34:53 bodea Exp $";
+char const *cvs_id_ppp = "$Id: ppp.c,v 1.65 2005-07-31 10:04:10 bodea Exp $";
#include <stdio.h>
#include <string.h>
extern time_t time_now;
extern configt *config;
-static void initccp(tunnelidt t, sessionidt s);
-static uint8_t *add_lcp_auth(uint8_t *b, int size, int authtype);
+static int add_lcp_auth(uint8_t *b, int size, int authtype);
// Process PAP messages
void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
char user[MAXUSER];
char pass[MAXPASS];
uint16_t hl;
+ uint16_t r;
CSTAT(processpap);
return;
}
+ if (session[s].ppp.phase != Authenticate)
+ {
+ LOG(2, s, t, "PAP ignored in %s phase\n", ppp_phase(session[s].ppp.phase));
+ return;
+ }
+
{
uint8_t *b = p;
b += 4;
}
LOG(3, s, t, "PAP login %s/%s\n", user, pass);
}
- if (session[s].ip || !sess_local[s].radius)
+
+ r = radiusnew(s);
+ if (session[s].ip || !r)
{
// respond now, either no RADIUS available or already authenticated
uint8_t b[MAXCONTROL];
p[1] = id;
*(uint16_t *) (p + 2) = htons(5); // length
p[4] = 0; // no message
+ tunnelsend(b, 5 + (p - b), t); // send it
+
if (session[s].ip)
{
LOG(3, s, t, "Already an IP allocated: %s (%d)\n",
fmtaddr(htonl(session[s].ip), 0), session[s].ip_pool_index);
-
- session[s].flags &= ~SF_IPCP_ACKED;
}
else
{
- LOG(1, s, t, "No radius session available to authenticate session...\n");
+ LOG(1, s, t, "No RADIUS session available to authenticate session...\n");
+ sessionshutdown(s, "No free RADIUS sessions.", 4, 0);
}
- LOG(3, s, t, "Fallback response to PAP (%s)\n", (session[s].ip) ? "ACK" : "NAK");
- tunnelsend(b, 5 + (p - b), t); // send it
- sessionshutdown(s, "PAP authentication failed.", 3, 0);
}
else
{
- // set up RADIUS request
- uint16_t r = sess_local[s].radius;
-
// Run PRE_AUTH plugins
struct param_pre_auth packet = { &tunnel[t], &session[s], strdup(user), strdup(pass), PPPPAP, 1 };
run_plugins(PLUGIN_PRE_AUTH, &packet);
sessionshutdown(s, "CHAP length mismatch.", 3, 0);
return;
}
+
+ if (session[s].ppp.phase != Authenticate)
+ {
+ LOG(2, s, t, "CHAP ignored in %s phase\n", ppp_phase(session[s].ppp.phase));
+ return;
+ }
+
if (p[1] != radius[r].id)
{
LOG(1, s, t, "Wrong CHAP response ID %d (should be %d) (%d)\n", p[1], radius[r].id, r);
uint8_t *o = (p + 4);
LOG_HEX(5, "PPP LCP Packet", p, l);
- LOG(4, 0, 0, "PPP LCP Packet type %d (%s len %d)\n", *p, ppp_lcp_type((int)*p), ntohs( ((uint16_t *) p)[1]) );
+ LOG(4, 0, 0, "PPP LCP Packet type %d (%s len %d)\n", *p, ppp_code((int)*p), ntohs( ((uint16_t *) p)[1]) );
LOG(4, 0, 0, "Length: %d\n", l);
if (*p != ConfigReq && *p != ConfigRej && *p != ConfigAck)
return;
{
case 1: // Maximum-Receive-Unit
if (length == 4)
- LOG(4, 0, 0, " %s %d\n", lcp_type(type), ntohs(*(uint16_t *)(o + 2)));
+ LOG(4, 0, 0, " %s %d\n", ppp_lcp_option(type), ntohs(*(uint16_t *)(o + 2)));
else
- LOG(4, 0, 0, " %s odd length %d\n", lcp_type(type), length);
+ LOG(4, 0, 0, " %s odd length %d\n", ppp_lcp_option(type), length);
break;
case 2: // Async-Control-Character-Map
if (length == 6)
{
uint32_t asyncmap = ntohl(*(uint32_t *)(o + 2));
- LOG(4, 0, 0, " %s %x\n", lcp_type(type), asyncmap);
+ LOG(4, 0, 0, " %s %x\n", ppp_lcp_option(type), asyncmap);
}
else
- LOG(4, 0, 0, " %s odd length %d\n", lcp_type(type), length);
+ LOG(4, 0, 0, " %s odd length %d\n", ppp_lcp_option(type), length);
break;
case 3: // Authentication-Protocol
if (length == 4)
{
int proto = ntohs(*(uint16_t *)(o + 2));
- LOG(4, 0, 0, " %s 0x%x (%s)\n", lcp_type(type), proto,
+ LOG(4, 0, 0, " %s 0x%x (%s)\n", ppp_lcp_option(type), proto,
proto == PPPPAP ? "PAP" : "UNSUPPORTED");
}
else if (length == 5)
{
int proto = ntohs(*(uint16_t *)(o + 2));
int algo = *(uint8_t *)(o + 4);
- LOG(4, 0, 0, " %s 0x%x 0x%x (%s)\n", lcp_type(type), proto, algo,
+ LOG(4, 0, 0, " %s 0x%x 0x%x (%s)\n", ppp_lcp_option(type), proto, algo,
(proto == PPPCHAP && algo == 5) ? "CHAP MD5" : "UNSUPPORTED");
}
else
- LOG(4, 0, 0, " %s odd length %d\n", lcp_type(type), length);
+ LOG(4, 0, 0, " %s odd length %d\n", ppp_lcp_option(type), length);
break;
case 4: // Quality-Protocol
{
uint32_t qp = ntohl(*(uint32_t *)(o + 2));
- LOG(4, 0, 0, " %s %x\n", lcp_type(type), qp);
+ LOG(4, 0, 0, " %s %x\n", ppp_lcp_option(type), qp);
}
break;
case 5: // Magic-Number
if (length == 6)
{
uint32_t magicno = ntohl(*(uint32_t *)(o + 2));
- LOG(4, 0, 0, " %s %x\n", lcp_type(type), magicno);
+ LOG(4, 0, 0, " %s %x\n", ppp_lcp_option(type), magicno);
}
else
- LOG(4, 0, 0, " %s odd length %d\n", lcp_type(type), length);
+ LOG(4, 0, 0, " %s odd length %d\n", ppp_lcp_option(type), length);
break;
case 7: // Protocol-Field-Compression
case 8: // Address-And-Control-Field-Compression
- LOG(4, 0, 0, " %s\n", lcp_type(type));
+ LOG(4, 0, 0, " %s\n", ppp_lcp_option(type));
break;
default:
LOG(2, 0, 0, " Unknown PPP LCP Option type %d\n", type);
}
}
+void lcp_open(tunnelidt t, sessionidt s)
+{
+ // transition to Authentication or Network phase:
+ session[s].ppp.phase = sess_local[s].lcp_authtype ? Authenticate : Network;
+
+ // LCP now Opened
+ change_state(s, lcp, Opened);
+
+ if (session[s].ppp.phase == Authenticate)
+ {
+ if (sess_local[s].lcp_authtype == AUTHCHAP)
+ sendchap(t, s);
+ }
+ else
+ {
+ // This-Layer-Up
+ sendipcp(t, s);
+ change_state(s, ipcp, RequestSent);
+ // move to passive state for IPv6 (if configured), CCP
+ if (config->ipv6_prefix.s6_addr[0])
+ change_state(s, ipv6cp, Stopped);
+ else
+ change_state(s, ipv6cp, Closed);
+
+ change_state(s, ccp, Stopped);
+ }
+}
+
+static void lcp_restart(sessionidt s)
+{
+ session[s].ppp.phase = Establish;
+ // This-Layer-Down
+ change_state(s, ipcp, Dead);
+ change_state(s, ipv6cp, Dead);
+ change_state(s, ccp, Dead);
+}
+
+static uint8_t *ppp_rej(sessionidt s, uint8_t *buf, size_t blen, uint16_t mtype,
+ uint8_t **response, uint8_t *queued, uint8_t *packet, uint8_t *option)
+{
+ if (!*response || **response != ConfigRej)
+ {
+ queued = *response = makeppp(buf, blen, packet, 2, session[s].tunnel, s, mtype);
+ if (!queued)
+ return 0;
+
+ *queued = ConfigRej;
+ queued += 4;
+ }
+
+ if ((queued - buf + option[1]) > blen)
+ {
+ LOG(2, s, session[s].tunnel, "PPP overflow for ConfigRej (proto %u, option %u).\n", mtype, *option);
+ return 0;
+ }
+
+ memcpy(queued, option, option[1]);
+ return queued + option[1];
+}
+
+static uint8_t *ppp_nak(sessionidt s, uint8_t *buf, size_t blen, uint16_t mtype,
+ uint8_t **response, uint8_t *queued, uint8_t *packet, uint8_t *option,
+ uint8_t *value, size_t vlen)
+{
+ int *nak_sent;
+ switch (mtype)
+ {
+ case PPPLCP: nak_sent = &sess_local[s].lcp.nak_sent; break;
+ case PPPIPCP: nak_sent = &sess_local[s].ipcp.nak_sent; break;
+ case PPPIPV6CP: nak_sent = &sess_local[s].ipv6cp.nak_sent; break;
+ default: return 0; // ?
+ }
+
+ if (*response && **response != ConfigNak)
+ {
+ if (*nak_sent < config->ppp_max_failure) // reject queued
+ return queued;
+
+ return ppp_rej(s, buf, blen, mtype, response, 0, packet, option);
+ }
+
+ if (!*response)
+ {
+ if (*nak_sent >= config->ppp_max_failure)
+ return ppp_rej(s, buf, blen, mtype, response, 0, packet, option);
+
+ queued = *response = makeppp(buf, blen, packet, 2, session[s].tunnel, s, mtype);
+ if (!queued)
+ return 0;
+
+ *nak_sent++;
+ *queued = ConfigNak;
+ queued += 4;
+ }
+
+ if ((queued - buf + vlen + 2) > blen)
+ {
+ LOG(2, s, session[s].tunnel, "PPP overflow for ConfigNak (proto %u, option %u).\n", mtype, *option);
+ return 0;
+ }
+
+ *queued++ = *option;
+ *queued++ = vlen + 2;
+ memcpy(queued, value, vlen);
+ return queued + vlen;
+}
+
// Process LCP messages
void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
{
}
l = hl;
+ if (session[s].die) // going down...
+ return;
+
if (*p == ConfigAck)
{
int x = l - 4;
uint8_t *o = (p + 4);
+ int authtype = 0;
LOG(3, s, t, "LCP: ConfigAck (%d bytes)...\n", l);
if (config->debug > 3) dumplcp(p, l);
case 3: // Authentication-Protocol
{
int proto = ntohs(*(uint16_t *)(o + 2));
- if (proto == PPPCHAP && *(o + 4) == 5)
- sendchap(t, s);
+ if (proto == PPPPAP)
+ authtype = AUTHPAP;
+ else if (proto == PPPCHAP && *(o + 4) == 5)
+ authtype = AUTHCHAP;
}
break;
o += length;
}
- session[s].flags |= SF_LCP_ACKED;
+ if (!session[s].ip && authtype)
+ sess_local[s].lcp_authtype = authtype;
+
+ switch (session[s].ppp.lcp)
+ {
+ case RequestSent:
+ initialise_restart_count(s, lcp);
+ change_state(s, lcp, AckReceived);
+ break;
+
+ case AckReceived:
+ case Opened:
+ LOG(3, s, t, "LCP: ConfigAck in state %s? Sending ConfigReq\n", ppp_state(session[s].ppp.lcp));
+ if (session[s].ppp.lcp == Opened)
+ lcp_restart(s);
+
+ sendlcp(s, t, sess_local[s].lcp_authtype);
+ change_state(s, lcp, RequestSent);
+ break;
+
+ case AckSent:
+ lcp_open(t, s);
+ break;
+
+ default:
+ LOG(3, s, t, "LCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.lcp));
+ }
}
else if (*p == ConfigReq)
{
int x = l - 4;
uint8_t *o = (p + 4);
uint8_t *response = 0;
+ static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero
+ static uint8_t authproto[5];
LOG(3, s, t, "LCP: ConfigReq (%d bytes)...\n", l);
if (config->debug > 3) dumplcp(p, l);
if (!ntohl(*(uint32_t *)(o + 2))) // all bits zero is OK
break;
- if (response && *response != ConfigNak) // rej already queued
- break;
-
LOG(2, s, t, " Remote requesting asyncmap. Rejecting.\n");
- if (!response)
- {
- q = response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
- if (!q) break;
- *q = ConfigNak;
- q += 4;
- }
-
- if ((q - b + 11) > sizeof(b))
- {
- LOG(2, s, t, "LCP overflow for asyncmap ConfigNak.\n");
- break;
- }
-
- *q++ = type;
- *q++ = 6;
- memset(q, 0, 4); // asyncmap 0
- q += 4;
+ q = ppp_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, asyncmap, sizeof(asyncmap));
break;
case 3: // Authentication-Protocol
{
int proto = ntohs(*(uint16_t *)(o + 2));
char proto_name[] = "0x0000";
- uint8_t *a;
+ int alen;
if (proto == PPPPAP)
{
if (config->radius_authtypes & AUTHPAP)
+ {
+ sess_local[s].lcp_authtype = AUTHPAP;
break;
+ }
strcpy(proto_name, "PAP");
}
{
if (config->radius_authtypes & AUTHCHAP
&& *(o + 4) == 5) // MD5
+ {
+ sess_local[s].lcp_authtype = AUTHCHAP;
break;
+ }
strcpy(proto_name, "CHAP");
}
else
sprintf(proto_name, "%#4.4x", proto);
- if (response && *response != ConfigNak) // rej already queued
- break;
-
LOG(2, s, t, " Remote requesting %s authentication. Rejecting.\n", proto_name);
- if (!response)
- {
- q = response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
- if (!q) break;
- *q = ConfigNak;
- q += 4;
- }
-
- a = add_lcp_auth(q, sizeof(b) - (q - b), config->radius_authprefer);
- if (!a)
- {
- LOG(2, s, t, "LCP overflow for %s ConfigNak.\n", proto_name);
- break;
- }
-
- q = a;
+ alen = add_lcp_auth(authproto, sizeof(authproto), config->radius_authprefer);
+ if (alen < 2) break; // paranoia
- if (config->radius_authtypes != config->radius_authprefer)
+ q = ppp_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, authproto + 2, alen - 2);
+ if (q && *response == ConfigNak &&
+ config->radius_authtypes != config->radius_authprefer)
{
- a = add_lcp_auth(q, sizeof(b) - (q - b), config->radius_authtypes & ~config->radius_authprefer);
- if (!a)
- {
- LOG(2, s, t, "LCP overflow for %s ConfigNak.\n", proto_name);
- break;
- }
-
- q = a;
+ // alternate type
+ alen = add_lcp_auth(authproto, sizeof(authproto), config->radius_authtypes & ~config->radius_authprefer);
+ if (alen < 2) break;
+ q = ppp_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, authproto + 2, alen - 2);
}
break;
default: // Reject any unknown options
LOG(2, s, t, " Rejecting PPP LCP Option type %d\n", type);
- if (!response || *response != ConfigRej) // drop nak in favour of rej
- {
- q = response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
- if (!q) break;
- *q = ConfigRej;
- q += 4;
- }
-
- if ((q - b + length) > sizeof(b))
- {
- LOG(2, s, t, "LCP overflow for ConfigRej (type=%d).\n", type);
- break;
- }
-
- memcpy(q, o, length);
- q += length;
+ q = ppp_rej(s, b, sizeof(b), PPPLCP, &response, q, p, o);
}
x -= length;
o += length;
*response = ConfigAck;
}
- LOG(3, s, t, "Sending %s\n", ppp_lcp_type(*response));
- tunnelsend(b, l + response - b, t);
+ switch (session[s].ppp.lcp)
+ {
+ case Closed:
+ response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
+ if (!response) return;
+ *response = TerminateAck;
+ *((uint16_t *) (response + 2)) = htons(l = 4);
+ break;
+
+ case Stopped:
+ initialise_restart_count(s, lcp);
+ sendlcp(s, t, sess_local[s].lcp_authtype);
+ if (*response == ConfigAck)
+ change_state(s, lcp, AckSent);
+ else
+ change_state(s, lcp, RequestSent);
+
+ break;
+
+ case RequestSent:
+ if (*response == ConfigAck)
+ change_state(s, lcp, AckSent);
+
+ break;
+
+ case AckReceived:
+ if (*response == ConfigAck)
+ lcp_open(t, s);
+
+ break;
+
+ case Opened:
+ lcp_restart(s);
+ sendlcp(s, t, sess_local[s].lcp_authtype);
+ /* fallthrough */
+
+ case AckSent:
+ if (*response == ConfigAck)
+ change_state(s, lcp, AckSent);
+ else
+ change_state(s, lcp, RequestSent);
- if (!(session[s].flags & SF_LCP_ACKED))
- sendlcp(t, s, config->radius_authprefer);
+ break;
+
+ default:
+ LOG(3, s, t, "LCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.lcp));
+ return;
+ }
+
+ LOG(3, s, t, "LCP: Sending %s\n", ppp_code(*response));
+ tunnelsend(b, l + (response - b), t);
}
else if (*p == ConfigNak)
{
return;
}
- if (authtype == -1)
- authtype = config->radius_authprefer;
+ if (authtype > 0)
+ sess_local[s].lcp_authtype = authtype;
+
+ switch (session[s].ppp.lcp)
+ {
+ case Closed:
+ case Stopped:
+ {
+ uint8_t *response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
+ if (!response) return;
+ *response = TerminateAck;
+ *((uint16_t *) (response + 2)) = htons(l = 4);
+ tunnelsend(b, l + (response - b), t);
+ }
+ break;
+
+ case RequestSent:
+ case AckSent:
+ initialise_restart_count(s, lcp);
+ sendlcp(s, t, sess_local[s].lcp_authtype);
+ break;
+
+ case AckReceived:
+ LOG(3, s, t, "LCP: ConfigNak in state %s? Sending ConfigReq\n", ppp_state(session[s].ppp.lcp));
+ sendlcp(s, t, sess_local[s].lcp_authtype);
+ break;
+
+ case Opened:
+ lcp_restart(s);
+ sendlcp(s, t, sess_local[s].lcp_authtype);
+ break;
- sendlcp(t, s, authtype);
+ default:
+ LOG(3, s, t, "LCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.lcp));
+ return;
+ }
}
else if (*p == TerminateReq)
{
if (*(uint16_t *) (p+4) == htons(PPPIPV6CP))
{
LOG(3, s, t, "IPv6 rejected\n");
- session[s].flags |= SF_IPV6_NACKED;
+ change_state(s, ipv6cp, Closed);
}
else
{
{
// Ignore it, last_packet time is set earlier than this.
}
- else if (*p == IdentRequest)
+ else
{
+ int code = *p;
+ int mru = session[s].mru;
+ if (!mru)
+ mru = DEFAULT_MRU;
+
+ if (l > mru) l = mru;
+
*p = CodeRej;
- if (l > MAXCONTROL)
- {
- LOG(1, s, t, "Truncated Ident Packet (length=%d) to 1400 bytes\n", l);
- l = 1400;
- }
q = makeppp(b, sizeof(b), p, l, t, s, PPPLCP);
if (!q) return;
- LOG_HEX(5, "LCPIdentRej", q, l + 4);
- tunnelsend(b, 12 + 4 + l, t);
- }
- else
- {
- LOG(1, s, t, "Unexpected LCP code %d\n", *p);
- STAT(tunnel_rx_errors);
+
+ LOG(3, s, t, "Unexpected LCP code %s\n", ppp_code(code));
+ tunnelsend(b, l + (q - b), t);
}
}
-// find a PPP option, returns point to option, or 0 if not found
-static uint8_t *findppp(uint8_t *b, uint8_t mtype)
+static void ipcp_open(tunnelidt t, sessionidt s)
{
- uint16_t l = ntohs(*(uint16_t *) (b + 2));
- if (l < 4)
- return 0;
- b += 4;
- l -= 4;
- while (l)
+ LOG(3, s, t, "IPCP Acked, session is now active\n");
+
+ change_state(s, ipcp, Opened);
+
+ if (!session[s].walled_garden)
{
- if (l < b[1] || !b[1])
- return 0; // faulty
- if (*b == mtype)
- return b;
- l -= b[1];
- b += b[1];
+ uint16_t r = radiusnew(s);
+ if (r)
+ radiussend(r, RADIUSSTART); // send radius start
+ }
+
+ // start IPv6 if configured and still in passive state
+ if (session[s].ppp.ipv6cp == Stopped)
+ {
+ sendipv6cp(t, s);
+ change_state(s, ipv6cp, RequestSent);
}
- return 0;
}
// Process IPCP messages
void processipcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
{
+ uint8_t b[MAXCONTROL];
+ uint8_t *q = 0;
uint16_t hl;
CSTAT(processipcp);
}
l = hl;
+ if (session[s].ppp.phase < Network)
+ {
+ LOG(2, s, t, "IPCP %s ignored in %s phase\n", ppp_code(*p), ppp_phase(session[s].ppp.phase));
+ return;
+ }
+
if (*p == ConfigAck)
{
- uint16_t r = sess_local[s].radius;
+ switch (session[s].ppp.ipcp)
+ {
+ case RequestSent:
+ initialise_restart_count(s, ipcp);
+ change_state(s, ipcp, AckReceived);
+ break;
- // ignore duplicate ACKs
- if (session[s].flags & SF_IPCP_ACKED)
- return;
+ case AckReceived:
+ case Opened:
+ LOG(3, s, t, "IPCP: ConfigAck in state %s? Sending ConfigReq\n", ppp_state(session[s].ppp.ipcp));
+ sendipcp(s, t);
+ change_state(s, ipcp, RequestSent);
+ break;
- // happy with our IPCP
- session[s].flags |= SF_IPCP_ACKED;
+ case AckSent:
+ ipcp_open(t, s);
+ break;
- LOG(3, s, t, "IPCP Acked, session is now active\n");
+ default:
+ LOG(3, s, t, "IPCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipcp));
+ }
+ }
+ else if (*p == ConfigReq)
+ {
+ uint8_t *response = 0;
+ uint8_t *o = p + 4;
+ int length = l - 4;
+ int gotip = 0;
+ in_addr_t addr;
- // clear LCP_ACKED/CCP_ACKED flag for possible fast renegotiation for routers
- session[s].flags &= ~(SF_LCP_ACKED|SF_CCP_ACKED);
+ LOG(4, s, t, "IPCP ConfigReq received\n");
- if (r && session[s].walled_garden)
+ while (length > 2)
{
- radiusclear(r, s);
- return;
- }
+ switch (*o)
+ {
+ case 3: // ip address
+ gotip++; // seen address
+ if (o[1] != 6 || o[1] > length) return;
- if (!r)
- r = radiusnew(s);
+ addr = htonl(session[s].ip);
+ if (memcmp(o + 2, &addr, (sizeof addr)))
+ {
+ q = ppp_nak(s, b, sizeof(b), PPPIPCP, &response, q, p, o, (uint8_t *) &addr, sizeof(addr));
+ if (!q || *response == ConfigRej)
+ {
+ sessionshutdown(s, "Can't negotiate IPCP.", 3, 0);
+ return;
+ }
+ }
- if (r)
- radiussend(r, RADIUSSTART); // send radius start, having got IPCP at last
+ break;
- return;
- }
- if (*p != ConfigReq)
- {
- LOG(1, s, t, "Unexpected IPCP code %d\n", *p);
- STAT(tunnel_rx_errors);
- return ;
- }
- LOG(4, s, t, "IPCP ConfigReq received\n");
+ case 129: // primary DNS
+ if (o[1] != 6 || o[1] > length) return;
- if (!session[s].ip)
- {
- LOG(3, s, t, "Waiting on radius reply\n");
- return; // have to wait on RADIUS reply
- }
- // form a config reply quoting the IP in the session
- {
- uint8_t b[MAXCONTROL];
- uint8_t *i, *q;
+ addr = htonl(session[s].dns1);
+ if (memcmp(o + 2, &addr, (sizeof addr)))
+ {
+ q = ppp_nak(s, b, sizeof(b), PPPIPCP, &response, q, p, o, (uint8_t *) &addr, sizeof(addr));
+ if (!q) return;
+ }
- q = p + 4;
- i = p + l;
- while (q < i && q[1])
- {
- if (*q != 0x81 && *q != 0x83 && *q != 3)
break;
- q += q[1];
- }
- if (q < i)
- {
- // reject
- uint16_t n = 4;
- i = p + l;
- if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP)))
- return;
-
- *q = ConfigRej;
- p += 4;
- while (p < i && p[1])
- {
- if (*p != 0x81 && *p != 0x83 && *p != 3)
+
+ case 131: // secondary DNS
+ if (o[1] != 6 || o[1] > length) return;
+
+ addr = htonl(session[s].dns1);
+ if (memcmp(o + 2, &addr, sizeof(addr)))
{
- LOG(2, s, t, "IPCP reject %d\n", *p);
- memcpy(q + n, p, p[1]);
- n += p[1];
+ q = ppp_nak(s, b, sizeof(b), PPPIPCP, &response, q, p, o, (uint8_t *) &addr, sizeof(addr));
+ if (!q) return;
}
- p += p[1];
+
+ break;
+
+ default:
+ LOG(2, s, t, " Rejecting PPP IPCP Option type %d\n", *o);
+ q = ppp_rej(s, b, sizeof(b), PPPIPCP, &response, q, p, o);
+ if (!q) return;
}
- *(uint16_t *) (q + 2) = htons(n);
- LOG(4, s, t, "Sending ConfigRej\n");
- tunnelsend(b, n + (q - b), t); // send it
+
+ length -= o[1];
+ o += o[1];
+ }
+
+ if (response)
+ {
+ l = q - response; // IPCP packet length
+ *((uint16_t *) (response + 2)) = htons(l); // update header
+ }
+ else if (gotip)
+ {
+ // Send packet back as ConfigAck
+ response = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP);
+ if (!response) return;
+ *response = ConfigAck;
}
else
{
- LOG(4, s, t, "Sending ConfigAck\n");
- *p = ConfigAck;
- if ((i = findppp(p, 0x81))) // Primary DNS address
- {
- if (*(uint32_t *) (i + 2) != htonl(session[s].dns1))
- {
- *(uint32_t *) (i + 2) = htonl(session[s].dns1);
- *p = ConfigNak;
- LOG(5, s, t, " DNS1 = %s\n",
- fmtaddr(htonl(session[s].dns1), 0));
- }
- }
- if ((i = findppp(p, 0x83))) // Secondary DNS address (TBA, is it)
- {
- if (*(uint32_t *) (i + 2) != htonl(session[s].dns2))
- {
- *(uint32_t *) (i + 2) = htonl(session[s].dns2);
- *p = ConfigNak;
- LOG(5, s, t, " DNS2 = %s\n",
- fmtaddr(htonl(session[s].dns2), 0));
- }
- }
- i = findppp(p, 3); // IP address
- if (!i || i[1] != 6)
- {
- LOG(1, s, t, "No IP in IPCP request\n");
- STAT(tunnel_rx_errors);
- return ;
- }
- if (*(uint32_t *) (i + 2) != htonl(session[s].ip))
- {
- *(uint32_t *) (i + 2) = htonl(session[s].ip);
- *p = ConfigNak;
- LOG(4, s, t, " No, a ConfigNak, client is requesting IP - sending %s\n",
- fmtaddr(htonl(session[s].ip), 0));
- }
- if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP)))
- return;
+ LOG(1, s, t, "No IP in IPCP request\n");
+ STAT(tunnel_rx_errors);
+ return;
+ }
+
+ switch (session[s].ppp.ipcp)
+ {
+ case Closed:
+ response = makeppp(b, sizeof(b), p, 2, t, s, PPPIPCP);
+ if (!response) return;
+ *response = TerminateAck;
+ *((uint16_t *) (response + 2)) = htons(l = 4);
+ break;
+
+ case Stopped:
+ initialise_restart_count(s, ipcp);
+ sendipcp(s, t);
+ if (*response == ConfigAck)
+ change_state(s, ipcp, AckSent);
+ else
+ change_state(s, ipcp, RequestSent);
+
+ break;
- tunnelsend(b, l + (q - b), t); // send it
+ case RequestSent:
+ if (*response == ConfigAck)
+ change_state(s, ipcp, AckSent);
+
+ break;
+
+ case AckReceived:
+ if (*response == ConfigAck)
+ ipcp_open(t, s);
+
+ break;
+
+ case Opened:
+ initialise_restart_count(s, ipcp);
+ sendipcp(s, t);
+ /* fallthrough */
+
+ case AckSent:
+ if (*response == ConfigAck)
+ change_state(s, ipcp, AckSent);
+ else
+ change_state(s, ipcp, RequestSent);
+
+ break;
+
+ default:
+ LOG(3, s, t, "IPCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipcp));
+ return;
}
+
+ LOG(3, s, t, "IPCP: Sending %s\n", ppp_code(*response));
+ tunnelsend(b, l + (response - b), t);
+ }
+ else if (*p == TerminateReq)
+ {
+ LOG(3, s, t, "IPCP: Received TerminateReq. Sending TerminateAck\n");
+ *p = TerminateAck;
+ q = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP);
+ if (!q) return;
+ tunnelsend(b, l + (q - b), t);
+ change_state(s, ipcp, Stopped);
}
+ else
+ {
+ int code = *p;
+ int mru = session[s].mru;
+ if (!mru)
+ mru = DEFAULT_MRU;
+
+ if (l > mru) l = mru;
+
+ *p = CodeRej;
+ q = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP);
+ if (!q) return;
+
+ LOG(3, s, t, "Unexpected IPCP code %s\n", ppp_code(code));
+ tunnelsend(b, l + (q - b), t);
+ }
+}
+
+static void ipv6cp_open(tunnelidt t, sessionidt s)
+{
+ LOG(3, s, t, "IPV6CP Acked\n");
+
+ change_state(s, ipv6cp, Opened);
+ if (session[s].ipv6prefixlen)
+ route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 1);
+
+ // Send an initial RA (TODO: Should we send these regularly?)
+ send_ipv6_ra(t, s, NULL);
}
// Process IPV6CP messages
void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
{
+ uint8_t b[MAXCONTROL];
+ uint8_t *q = 0;
+ uint16_t hl;
CSTAT(processipv6cp);
STAT(tunnel_rx_errors);
return ;
}
- if (*p == ConfigAck)
- {
- // happy with our IPV6CP
- session[s].flags |= SF_IPV6CP_ACKED;
- LOG(3, s, t, "IPV6CP Acked, IPv6 is now active\n");
- // Add a routed block if configured.
- if (session[s].ipv6prefixlen)
- {
- route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 1);
- session[s].flags |= SF_IPV6_ROUTED;
- }
-
- // Send an initial RA (TODO: Should we send these regularly?)
- send_ipv6_ra(t, s, NULL);
- return;
- }
- if (*p != ConfigReq)
+ if ((hl = ntohs(*(uint16_t *) (p + 2))) > l)
{
- LOG(1, s, t, "Unexpected IPV6CP code %d\n", *p);
+ LOG(1, s, t, "Length mismatch IPV6CP %u/%u\n", hl, l);
STAT(tunnel_rx_errors);
+ return ;
+ }
+ l = hl;
+
+ if (session[s].ppp.phase < Network)
+ {
+ LOG(2, s, t, "IPV6CP %s ignored in %s phase\n", ppp_code(*p), ppp_phase(session[s].ppp.phase));
return;
}
- LOG(4, s, t, "IPV6CP ConfigReq received\n");
- if (ntohs(*(uint16_t *) (p + 2)) > l)
+ if (!config->ipv6_prefix.s6_addr[0])
{
- LOG(1, s, t, "Length mismatch IPV6CP %d/%d\n", ntohs(*(uint16_t *) (p + 2)), l);
- STAT(tunnel_rx_errors);
- return ;
+ LOG(2, s, t, "IPV6CP %s rejected (not configured)\n", ppp_code(*p));
+ *p = ProtocolRej;
+ q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP);
+ if (!q) return;
+ tunnelsend(b, l + (q - b), t);
+ return;
}
+
if (!session[s].ip)
{
- LOG(3, s, t, "Waiting on radius reply\n");
- return; // have to wait on RADIUS reply
+ LOG(3, s, t, "IPV6CP: no IPv4 address (IPCP in state %s)\n", ppp_state(session[s].ppp.ipcp));
+ return; // need IPCP to complete...
}
- // form a config reply quoting the IP in the session
- {
- uint8_t b[MAXCONTROL];
- uint8_t *i,
- *q;
- l = ntohs(*(uint16_t *) (p + 2)); // We must use length from IPV6CP len field
- q = p + 4;
- i = p + l;
- while (q < i && q[1])
+ if (*p == ConfigAck)
+ {
+ switch (session[s].ppp.ipv6cp)
{
- if (*q != 1)
- break;
- q += q[1];
+ case RequestSent:
+ initialise_restart_count(s, ipv6cp);
+ change_state(s, ipv6cp, AckReceived);
+ break;
+
+ case AckReceived:
+ case Opened:
+ LOG(3, s, t, "IPV6CP: ConfigAck in state %s? Sending ConfigReq\n", ppp_state(session[s].ppp.ipv6cp));
+ sendipv6cp(s, t);
+ change_state(s, ipv6cp, RequestSent);
+ break;
+
+ case AckSent:
+ ipv6cp_open(t, s);
+ break;
+
+ default:
+ LOG(3, s, t, "IPV6CP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipv6cp));
}
- if (q < i)
+ }
+ else if (*p == ConfigReq)
+ {
+ uint8_t *response = 0;
+ uint8_t *o = p + 4;
+ int length = l - 4;
+ int gotip = 0;
+ uint8_t ident[8];
+
+ LOG(4, s, t, "IPV6CP ConfigReq received\n");
+
+ while (length > 2)
{
- // reject
- uint16_t n = 4;
- i = p + l;
- if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP)))
- {
- LOG(2, s, t, "Failed to send IPV6CP ConfigRej\n");
- return;
- }
- *q = ConfigRej;
- p += 4;
- while (p < i && p[1])
+ switch (*o)
{
- if (*p != 1)
+ case 1: // interface identifier
+ gotip++; // seen address
+ if (o[1] != 10 || o[1] > length) return;
+
+ *(uint32_t *) ident = htonl(session[s].ip);
+ *(uint32_t *) (ident + 4) = 0;
+
+ if (memcmp(o + 2, ident, sizeof(ident)))
{
- LOG(2, s, t, "IPV6CP reject %d\n", *p);
- memcpy(q + n, p, p[1]);
- n += p[1];
+ q = ppp_nak(s, b, sizeof(b), PPPIPV6CP, &response, q, p, o, ident, sizeof(ident));
+ if (!q) return;
}
- p += p[1];
+
+ break;
+
+ default:
+ LOG(2, s, t, " Rejecting PPP IPV6CP Option type %d\n", *o);
+ q = ppp_rej(s, b, sizeof(b), PPPIPV6CP, &response, q, p, o);
+ if (!q) return;
}
- *(uint16_t *) (q + 2) = htons(n);
- LOG(4, s, t, "Sending ConfigRej\n");
- tunnelsend(b, n + (q - b), t); // send it
+
+ length -= o[1];
+ o += o[1];
+ }
+
+ if (response)
+ {
+ l = q - response; // IPV6CP packet length
+ *((uint16_t *) (response + 2)) = htons(l); // update header
+ }
+ else if (gotip)
+ {
+ // Send packet back as ConfigAck
+ response = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP);
+ if (!response) return;
+ *response = ConfigAck;
}
else
{
- LOG(4, s, t, "Sending ConfigAck\n");
- *p = ConfigAck;
- i = findppp(p, 1); // IP address
- if (!i || i[1] != 10)
- {
- LOG(1, s, t, "No IP in IPV6CP request\n");
- STAT(tunnel_rx_errors);
- return ;
- }
- if ((*(uint32_t *) (i + 2) != htonl(session[s].ip)) ||
- (*(uint32_t *) (i + 6) != 0))
- {
- *(uint32_t *) (i + 2) = htonl(session[s].ip);
- *(uint32_t *) (i + 6) = 0;
- *p = ConfigNak;
- LOG(4, s, t,
- " No, a ConfigNak, client is "
- "requesting IP - sending %s\n",
- fmtaddr(htonl(session[s].ip), 0));
- }
- if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP)))
- {
- LOG(2, s, t, " Failed to send IPV6CP packet.\n");
- return;
- }
- tunnelsend(b, l + (q - b), t); // send it
+ LOG(1, s, t, "No interface identifier in IPV6CP request\n");
+ STAT(tunnel_rx_errors);
+ return;
+ }
+
+ switch (session[s].ppp.ipv6cp)
+ {
+ case Closed:
+ response = makeppp(b, sizeof(b), p, 2, t, s, PPPIPV6CP);
+ if (!response) return;
+ *response = TerminateAck;
+ *((uint16_t *) (response + 2)) = htons(l = 4);
+ break;
+
+ case Stopped:
+ initialise_restart_count(s, ipv6cp);
+ sendipv6cp(s, t);
+ if (*response == ConfigAck)
+ change_state(s, ipv6cp, AckSent);
+ else
+ change_state(s, ipv6cp, RequestSent);
+
+ break;
+
+ case RequestSent:
+ if (*response == ConfigAck)
+ change_state(s, ipv6cp, AckSent);
+
+ break;
+
+ case AckReceived:
+ if (*response == ConfigAck)
+ ipv6cp_open(t, s);
+
+ break;
+
+ case Opened:
+ initialise_restart_count(s, ipv6cp);
+ sendipv6cp(s, t);
+ /* fallthrough */
+
+ case AckSent:
+ if (*response == ConfigAck)
+ change_state(s, ipv6cp, AckSent);
+ else
+ change_state(s, ipv6cp, RequestSent);
+
+ break;
+
+ default:
+ LOG(3, s, t, "IPV6CP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipv6cp));
+ return;
}
+
+ LOG(3, s, t, "IPV6CP: Sending %s\n", ppp_code(*response));
+ tunnelsend(b, l + (response - b), t);
+ }
+ else if (*p == TerminateReq)
+ {
+ LOG(3, s, t, "IPV6CP: Received TerminateReq. Sending TerminateAck\n");
+ *p = TerminateAck;
+ q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP);
+ if (!q) return;
+ tunnelsend(b, l + (q - b), t);
+ change_state(s, ipv6cp, Stopped);
+ }
+ else
+ {
+ int code = *p;
+ int mru = session[s].mru;
+ if (!mru)
+ mru = DEFAULT_MRU;
+
+ if (l > mru) l = mru;
+
+ *p = CodeRej;
+ q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP);
+ if (!q) return;
+
+ LOG(3, s, t, "Unexpected IPV6CP code %s\n", ppp_code(code));
+ tunnelsend(b, l + (q - b), t);
}
}
return ;
}
+ if (session[s].ppp.phase != Network || session[s].ppp.ipcp != Opened)
+ return;
+
// no spoof (do sessionbyip to handled statically routed subnets)
if (ip != session[s].ip && sessionbyip(htonl(ip)) != s)
{
return ;
}
+ if (session[s].ppp.phase != Network || session[s].ppp.ipv6cp != Opened)
+ return;
+
// no spoof
if (ipv4 != session[s].ip && memcmp(&config->ipv6_prefix, &ip, 8) && sessionbyipv6(ip) != s)
{
CSTAT(processccp);
LOG_HEX(5, "CCP", p, l);
- switch (l > 1 ? *p : 0)
+
+ if (session[s].ppp.phase < Network)
{
- case ConfigAck:
- session[s].flags |= SF_CCP_ACKED;
+ LOG(2, s, t, "CCP %s ignored in %s phase\n", ppp_code(*p), ppp_phase(session[s].ppp.phase));
return;
+ }
- case ConfigReq:
- if (l < 6) // accept no compression
+ if (l < 1)
+ {
+ LOG(1, s, t, "Short CCP packet\n");
+ STAT(tunnel_rx_errors);
+ }
+
+ if (*p == ConfigAck)
+ {
+ switch (session[s].ppp.ccp)
{
- *p = ConfigAck;
+ case RequestSent:
+ initialise_restart_count(s, ccp);
+ change_state(s, ccp, AckReceived);
+ break;
+
+ case AckReceived:
+ case Opened:
+ LOG(3, s, t, "CCP: ConfigAck in state %s? Sending ConfigReq\n", ppp_state(session[s].ppp.ccp));
+ sendccp(s, t);
+ change_state(s, ccp, RequestSent);
break;
+
+ case AckSent:
+ LOG(3, s, t, "CCP Acked\n");
+ change_state(s, ccp, Opened);
+ break;
+
+ default:
+ LOG(3, s, t, "CCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ccp));
}
+ }
+ else if (*p == ConfigReq)
+ {
+ if (l < 6) // accept no compression
+ *p = ConfigAck;
+ else // compression requested--reject
+ *p = ConfigRej;
- // compression requested--reject
- *p = ConfigRej;
+ q = makeppp(b, sizeof(b), p, l, t, s, PPPCCP);
+ if (!q) return;
- // send CCP request for no compression for our end if not negotiated
- if (!(session[s].flags & SF_CCP_ACKED))
- initccp(t, s);
+ switch (session[s].ppp.ccp)
+ {
+ case Closed:
+ q = makeppp(b, sizeof(b), p, 2, t, s, PPPCCP);
+ if (!q) return;
+ *q = TerminateAck;
+ *((uint16_t *) (q + 2)) = htons(l = 4);
+ break;
- break;
+ case Stopped:
+ initialise_restart_count(s, ccp);
+ sendccp(s, t);
+ if (*q == ConfigAck)
+ change_state(s, ccp, AckSent);
+ else
+ change_state(s, ccp, RequestSent);
- case TerminateReq:
- *p = TerminateAck;
- break;
+ break;
- default:
- if (l > 1)
- LOG(1, s, t, "Unexpected CCP request code %d\n", *p);
- else
- LOG(1, s, t, "Short CCP packet\n");
+ case RequestSent:
+ if (*q == ConfigAck)
+ change_state(s, ccp, AckSent);
- STAT(tunnel_rx_errors);
- return;
+ break;
+
+ case AckReceived:
+ if (*q == ConfigAck)
+ change_state(s, ccp, Opened);
+
+ break;
+
+ case Opened:
+ initialise_restart_count(s, ccp);
+ sendccp(s, t);
+ /* fallthrough */
+
+ case AckSent:
+ if (*q == ConfigAck)
+ change_state(s, ccp, AckSent);
+ else
+ change_state(s, ccp, RequestSent);
+
+ break;
+
+ default:
+ LOG(3, s, t, "CCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ccp));
+ return;
+ }
+
+ LOG(3, s, t, "CCP: Sending %s\n", ppp_code(*q));
+ tunnelsend(b, l + (q - b), t);
}
+ else if (*p == TerminateReq)
+ {
+ LOG(3, s, t, "CCP: Received TerminateReq. Sending TerminateAck\n");
+ *p = TerminateAck;
+ q = makeppp(b, sizeof(b), p, l, t, s, PPPCCP);
+ if (!q) return;
+ tunnelsend(b, l + (q - b), t);
+ change_state(s, ccp, Stopped);
+ }
+ else
+ {
+ int code = *p;
+ int mru = session[s].mru;
+ if (!mru)
+ mru = DEFAULT_MRU;
- if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPCCP)))
- return;
+ if (l > mru) l = mru;
+
+ *p = CodeRej;
+ q = makeppp(b, sizeof(b), p, l, t, s, PPPCCP);
+ if (!q) return;
- tunnelsend(b, l + (q - b), t); // send it
+ LOG(3, s, t, "Unexpected CCP code %s\n", ppp_code(code));
+ tunnelsend(b, l + (q - b), t);
+ }
}
// send a CHAP challenge
q[1] = radius[r].id; // ID
q[4] = 16; // value size (size of challenge)
memcpy(q + 5, radius[r].auth, 16); // challenge
- strcpy(q + 21, hostname); // our name
+ strcpy((char *) q + 21, hostname); // our name
*(uint16_t *) (q + 2) = htons(strlen(hostname) + 21); // length
tunnelsend(b, strlen(hostname) + 21 + (q - b), t); // send it
}
return b;
}
-static uint8_t *add_lcp_auth(uint8_t *b, int size, int authtype)
+static int add_lcp_auth(uint8_t *b, int size, int authtype)
{
+ int len = 0;
if ((authtype == AUTHCHAP && size < 5) || size < 4)
return 0;
*b++ = 3; // Authentication-Protocol
if (authtype == AUTHCHAP)
{
- *b++ = 5; // length
+ len = *b++ = 5; // length
*(uint16_t *) b = htons(PPPCHAP); b += 2;
*b++ = 5; // MD5
}
else if (authtype == AUTHPAP)
{
- *b++ = 4; // length
+ len = *b++ = 4; // length
*(uint16_t *) b = htons(PPPPAP); b += 2;
}
else
LOG(0, 0, 0, "add_lcp_auth called with unsupported auth type %d\n", authtype);
}
- return b;
+ return len;
}
// Send initial LCP ConfigReq for MRU, authentication type and magic no
void sendlcp(tunnelidt t, sessionidt s, int authtype)
{
- char b[500], *q, *l;
+ uint8_t b[500], *q, *l;
if (!(q = makeppp(b, sizeof(b), NULL, 0, t, s, PPPLCP)))
return;
- LOG(4, s, t, "Sending LCP ConfigReq for %s\n",
- authtype == AUTHCHAP ? "CHAP" : "PAP");
+ LOG(4, s, t, "Sending LCP ConfigReq%s%s\n",
+ authtype ? " for " : "",
+ authtype ? (authtype == AUTHCHAP ? "CHAP" : "PAP") : "");
if (!session[s].mru)
session[s].mru = DEFAULT_MRU;
*l++ = 1; *l++ = 4; // Maximum-Receive-Unit (length 4)
*(uint16_t *) l = htons(session[s].mru); l += 2;
- l = add_lcp_auth(l, sizeof(b) - (l - b), authtype);
+ if (authtype)
+ l += add_lcp_auth(l, sizeof(b) - (l - b), authtype);
*l++ = 5; *l++ = 6; // Magic-Number (length 6)
*(uint32_t *) l = htonl(session[s].magic);
}
// Send CCP request for no compression
-static void initccp(tunnelidt t, sessionidt s)
+void sendccp(tunnelidt t, sessionidt s)
{
- char b[500], *q;
+ uint8_t b[500], *q;
if (!(q = makeppp(b, sizeof(b), NULL, 0, t, s, PPPCCP)))
return;
// L2TPNS Radius Stuff
-char const *cvs_id_radius = "$Id: radius.c,v 1.36 2005-06-30 14:31:26 bodea Exp $";
+char const *cvs_id_radius = "$Id: radius.c,v 1.37 2005-07-31 10:04:10 bodea Exp $";
#include <time.h>
#include <stdio.h>
#include <ctype.h>
#include <netinet/in.h>
#include <errno.h>
-#include "md5.h"
+#include <openssl/md5.h>
#include "constants.h"
#include "l2tpns.h"
#include "plugin.h"
{
*p = 1; // user name
p[1] = strlen(session[s].user) + 2;
- strcpy(p + 2, session[s].user);
+ strcpy((char *) p + 2, session[s].user);
p += p[1];
}
if (state == RADIUSAUTH)
while (p < pl)
{
MD5_CTX ctx;
- MD5Init(&ctx);
- MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, config->radiussecret, strlen(config->radiussecret));
if (p)
- MD5Update(&ctx, pass + p - 16, 16);
+ MD5_Update(&ctx, pass + p - 16, 16);
else
- MD5Update(&ctx, radius[r].auth, 16);
- MD5Final(hash, &ctx);
+ MD5_Update(&ctx, radius[r].auth, 16);
+ MD5_Final(hash, &ctx);
do
{
pass[p] ^= hash[p & 15];
{
*p = 44; // session ID
p[1] = 18;
- sprintf(p + 2, "%08X%08X", session[s].unique_id, session[s].opened);
+ sprintf((char *) p + 2, "%08X%08X", session[s].unique_id, session[s].opened);
p += p[1];
if (state == RADIUSSTART)
{ // start
*p = 26; // vendor-specific
*(uint32_t *) (p + 2) = htonl(9); // Cisco
p[6] = 1; // Cisco-AVPair
- p[7] = 2 + sprintf(p + 8, "intercept=%s:%d",
+ p[7] = 2 + sprintf((char *) p + 8, "intercept=%s:%d",
fmtaddr(session[s].snoop_ip, 0), session[s].snoop_port);
p[1] = p[7] + 6;
{
*p = 30; // called
p[1] = strlen(session[s].called) + 2;
- strcpy(p + 2, session[s].called);
- p += p[1];
- }
- if (*radius[r].calling)
- {
- *p = 31; // calling
- p[1] = strlen(radius[r].calling) + 2;
- strcpy(p + 2, radius[r].calling);
+ strcpy((char *) p + 2, session[s].called);
p += p[1];
}
else if (*session[s].calling)
{
*p = 31; // calling
p[1] = strlen(session[s].calling) + 2;
- strcpy(p + 2, session[s].calling);
+ strcpy((char *) p + 2, session[s].calling);
p += p[1];
}
// NAS-IP-Address
if (state != RADIUSAUTH)
{
// Build auth for accounting packet
- char z[16] = {0};
- char hash[16] = {0};
+ uint8_t z[16] = {0};
+ uint8_t hash[16] = {0};
MD5_CTX ctx;
- MD5Init(&ctx);
- MD5Update(&ctx, b, 4);
- MD5Update(&ctx, z, 16);
- MD5Update(&ctx, b + 20, (p - b) - 20);
- MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
- MD5Final(hash, &ctx);
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, b, 4);
+ MD5_Update(&ctx, z, 16);
+ MD5_Update(&ctx, b + 20, (p - b) - 20);
+ MD5_Update(&ctx, config->radiussecret, strlen(config->radiussecret));
+ MD5_Final(hash, &ctx);
memcpy(b + 4, hash, 16);
memcpy(radius[r].auth, hash, 16);
}
static void handle_avpair(sessionidt s, uint8_t *avp, int len)
{
- char *key = avp;
- char *value = memchr(avp, '=', len);
- char tmp[2048] = "";
+ uint8_t *key = avp;
+ uint8_t *value = memchr(avp, '=', len);
+ uint8_t tmp[2048] = "";
if (value)
{
// Run hooks
{
- struct param_radius_response p = { &tunnel[session[s].tunnel], &session[s], key, value };
+ struct param_radius_response p = { &tunnel[session[s].tunnel], &session[s], (char *) key, (char *) value };
run_plugins(PLUGIN_RADIUS_RESPONSE, &p);
}
}
return;
}
t = session[s].tunnel;
- MD5Init(&ctx);
- MD5Update(&ctx, buf, 4);
- MD5Update(&ctx, radius[r].auth, 16);
- MD5Update(&ctx, buf + 20, len - 20);
- MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
- MD5Final(hash, &ctx);
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, buf, 4);
+ MD5_Update(&ctx, radius[r].auth, 16);
+ MD5_Update(&ctx, buf + 20, len - 20);
+ MD5_Update(&ctx, config->radiussecret, strlen(config->radiussecret));
+ MD5_Final(hash, &ctx);
do {
if (memcmp(hash, buf + 4, 16))
{
else if (*p == 11)
{
// Filter-Id
- char *filter = p + 2;
+ char *filter = (char *) p + 2;
int l = p[1] - 2;
char *suffix;
int f;
int prefixlen;
uint8_t *n = p + 2;
uint8_t *e = p + p[1];
- uint8_t *m = strchr(n, '/');
+ uint8_t *m = memchr(n, '/', e - p);
*m++ = 0;
- inet_pton(AF_INET6, n, &r6);
+ inet_pton(AF_INET6, (char *) n, &r6);
prefixlen = 0;
while (m < e && isdigit(*m)) {
if (!session[s].dns1 && config->default_dns1)
{
- session[s].dns1 = htonl(config->default_dns1);
+ session[s].dns1 = ntohl(config->default_dns1);
LOG(3, s, t, " Sending dns1 = %s\n", fmtaddr(config->default_dns1, 0));
}
if (!session[s].dns2 && config->default_dns2)
{
- session[s].dns2 = htonl(config->default_dns2);
+ session[s].dns2 = ntohl(config->default_dns2);
LOG(3, s, t, " Sending dns2 = %s\n", fmtaddr(config->default_dns2, 0));
}
case RADIUSCHAP: // sending CHAP down PPP
sendchap(t, s);
break;
- case RADIUSIPCP:
- sendipcp(t, s); // send IPCP
- break;
case RADIUSAUTH: // sending auth to RADIUS server
- radiussend(r, RADIUSAUTH);
- break;
case RADIUSSTART: // sending start accounting to RADIUS server
- radiussend(r, RADIUSSTART);
- break;
case RADIUSSTOP: // sending stop accounting to RADIUS server
- radiussend(r, RADIUSSTOP);
- break;
case RADIUSINTERIM: // sending interim accounting to RADIUS server
- radiussend(r, RADIUSINTERIM);
+ radiussend(r, radius[r].state);
break;
default:
case RADIUSNULL: // Not in use
i = strlen(config->radiussecret);
if (i > 16) i = 16;
- MD5Init(&ctx);
- MD5Update(&ctx, buf, len);
- MD5Update(&ctx, buf, config->radiussecret, i);
- MD5Final(hash, &ctx);
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, buf, len);
+ MD5_Update(&ctx, config->radiussecret, i);
+ MD5_Final(hash, &ctx);
if (memcmp(hash, vector, 16) != 0)
{
LOG(1, 0, 0, "Incorrect vector in DAE request (wrong secret in radius config?)\n");
}
len = p - packet;
- i = find_filter(packet, len);
+ i = find_filter((char *) packet, len);
if (i < 0 || !*ip_filters[i].name)
{
error = 404;
i = strlen(config->radiussecret);
if (i > 16) i = 16;
- MD5Init(&ctx);
- MD5Update(&ctx, buf, len);
- MD5Update(&ctx, config->radiussecret, i);
- MD5Final(hash, &ctx);
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, buf, len);
+ MD5_Update(&ctx, config->radiussecret, i);
+ MD5_Final(hash, &ctx);
memcpy(buf + 4, hash, 16);
LOG(3, 0, 0, "Sending DAE %s, id=%d\n", radius_code(r_code), r_id);
// L2TPNS: token bucket filters
-char const *cvs_id_tbf = "$Id: tbf.c,v 1.12 2005-05-02 09:55:04 bodea Exp $";
+char const *cvs_id_tbf = "$Id: tbf.c,v 1.13 2005-07-31 10:04:10 bodea Exp $";
#include <string.h>
#include "l2tpns.h"
// If we can send it right away, we do. Else we
// try and queue it to send later. Else we drop it.
//
-int tbf_queue_packet(int tbf_id, char * data, int size)
+int tbf_queue_packet(int tbf_id, uint8_t *data, int size)
{
int i;
- tbft * f;
+ tbft *f;
if (!filter_list)
return -1;
uint32_t p_delayed; // Total packets not sent immediately.
int sizes[TBF_MAX_QUEUE];
- char packets[TBF_MAX_QUEUE][TBF_MAX_SIZE];
+ uint8_t packets[TBF_MAX_QUEUE][TBF_MAX_SIZE];
} tbft;
void init_tbf(int num_tbfs);
int tbf_run_timer(void);
-int tbf_queue_packet(int tbf_id, char * data, int size);
+int tbf_queue_packet(int tbf_id, uint8_t * data, int size);
int new_tbf(int sid, int max_credit, int rate, void (*f)(sessionidt, uint8_t *, int));
int free_tbf(int tid);
void fsck_tbfs(void);
#include <fcntl.h>
#include <sys/select.h>
#include <signal.h>
-#include "../md5.h"
+#include <openssl/md5.h>
extern char *optarg;
extern int optind;
for (int j = 0; j < pw_len; j += 16)
{
MD5_CTX ctx;
- MD5Init(&ctx);
- MD5Update(&ctx, secret, strlen(secret));
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, secret, strlen(secret));
if (j)
- MD5Update(&ctx, pass + j - 16, 16);
+ MD5_Update(&ctx, pass + j - 16, 16);
else
/* authenticator */
- MD5Update(&ctx, u->request + 4, 16);
+ MD5_Update(&ctx, u->request + 4, 16);
- char digest[16];
- MD5Final(digest, &ctx);
+ uint8_t digest[16];
+ MD5_Final(digest, &ctx);
for (int k = 0; k < 16; k++)
pass[j + k] ^= digest[k];