From: Brendan O'Dea Date: Sun, 31 Jul 2005 10:04:09 +0000 (+0000) Subject: - Replace flags used for LCP/IPCP with state machine. X-Git-Tag: 2.2.1-2fdn3.1~19^2^2~1^2~143 X-Git-Url: http://git.sameswireless.fr/l2tpns.git/commitdiff_plain/aabf1d3fe915334f5ffab9b8e1076917add14358?ds=sidebyside - Replace flags used for LCP/IPCP with state machine. - Use openssl MD5, fix DAE vector (Alex Kiernan). --- diff --git a/Changes b/Changes index 452407b..e579e70 100644 --- a/Changes +++ b/Changes @@ -1,10 +1,10 @@ -* Wed Jun 29 2005 Brendan O'Dea 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 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 2.1.1 - Add missing newline to backtrace macro. diff --git a/Docs/manual.html b/Docs/manual.html index 2458391..1fe4694 100644 --- a/Docs/manual.html +++ b/Docs/manual.html @@ -185,6 +185,13 @@ the same as the LAC, or authentication will fail. Only actually be used if the LAC requests authentication. +
  • ppp_restart_time (int)
    +ppp_max_configure (int)
    +ppp_max_failure (int)
    +PPP counters and timers values, as described in §4.1 of +RFC1661. +
  • +
  • primary_dns (ip address)
  • secondary_dns (ip address)
    Whenever a PPP connection is established, DNS servers will be sent to the diff --git a/Docs/startup-config.5 b/Docs/startup-config.5 index 7170dbe..c403de1 100644 --- a/Docs/startup-config.5 +++ b/Docs/startup-config.5 @@ -2,7 +2,7 @@ .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 @@ -63,6 +63,16 @@ for authenticating tunnel request. Must be the same as the LAC, or 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 diff --git a/Makefile b/Makefile index 156ff39..de2755f 100644 --- a/Makefile +++ b/Makefile @@ -23,10 +23,10 @@ LDFLAGS = 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 \ @@ -109,20 +109,19 @@ install: all ## 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 diff --git a/THANKS b/THANKS index 07d9619..3262976 100644 --- a/THANKS +++ b/THANKS @@ -16,3 +16,4 @@ Bj Roberto Chostakovis Jordan Hrycaj Vladislav Bjelic +Alex Kiernan diff --git a/arp.c b/arp.c index 1c2faa1..5fad15d 100644 --- a/arp.c +++ b/arp.c @@ -1,6 +1,6 @@ // 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 #include @@ -55,7 +55,7 @@ void sendarp(int ifr_idx, const unsigned char* mac, in_addr_t ip) 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; diff --git a/bgp.c b/bgp.c index 96e2868..bfb8de9 100644 --- a/bgp.c +++ b/bgp.c @@ -10,7 +10,7 @@ * 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 #include @@ -767,7 +767,7 @@ static int bgp_connect(struct bgp_peer *peer) 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) { diff --git a/cli.c b/cli.c index d0f9a8a..e017ff5 100644 --- a/cli.c +++ b/cli.c @@ -2,7 +2,7 @@ // 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 #include @@ -25,6 +25,7 @@ char const *cvs_id_cli = "$Id: cli.c,v 1.63 2005-06-28 14:48:17 bodea Exp $"; #include #include "l2tpns.h" +#include "constants.h" #include "util.h" #include "cluster.h" #include "tbf.h" @@ -289,10 +290,10 @@ void cli_do(int sockfd) { 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", @@ -407,6 +408,19 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int 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); @@ -507,7 +521,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int (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, @@ -816,7 +830,6 @@ static int cmd_show_version(struct cli_def *cli, char *command, char **argv, int 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); diff --git a/cluster.c b/cluster.c index ad41e46..2370eaf 100644 --- a/cluster.c +++ b/cluster.c @@ -1,6 +1,6 @@ // 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 #include @@ -56,7 +56,7 @@ static struct { 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. @@ -178,7 +178,7 @@ static int cluster_send_data(void *data, int datalen) // 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); @@ -231,7 +231,7 @@ static void cluster_uptodate(void) // 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}; @@ -259,10 +259,10 @@ static int peer_send_data(in_addr_t peer, char *data, int size) // // 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); @@ -271,10 +271,10 @@ static int peer_send_message(in_addr_t peer, int type, int more, char *data, int } // 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; @@ -282,7 +282,7 @@ static int _forward_packet(char *data, int size, in_addr_t addr, int port, int t 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; @@ -295,13 +295,13 @@ static int _forward_packet(char *data, int size, in_addr_t addr, int port, int t // 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); } @@ -313,10 +313,10 @@ int master_forward_dae_packet(char *data, int size, in_addr_t addr, int port) // 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; @@ -338,10 +338,10 @@ int master_throttle_packet(int tbfid, char *data, int size) // // (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; @@ -358,7 +358,7 @@ int master_garden_packet(sessionidt s, char *data, int size) // 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; @@ -380,8 +380,8 @@ static void send_heartbeat(int seq, char *data, int size) // 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. @@ -394,7 +394,7 @@ void cluster_send_ping(time_t basetime) 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) ); } @@ -456,7 +456,7 @@ void master_update_counts(void) // 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; } @@ -738,7 +738,7 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig 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. @@ -752,13 +752,13 @@ static int hb_add_type(char **p, int type, int id) // 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 @@ -777,8 +777,8 @@ static int hb_add_type(char **p, int type, int id) } // 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); @@ -794,9 +794,9 @@ static int hb_add_type(char **p, int type, int id) 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; @@ -820,7 +820,7 @@ void cluster_heartbeat() 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); @@ -1099,7 +1099,7 @@ static int cluster_set_master(in_addr_t peer, in_addr_t master) // 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; @@ -1238,6 +1238,9 @@ struct oldsession { 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; @@ -1257,7 +1260,6 @@ static uint8_t *convert_session(struct oldsession *old) 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; @@ -1297,6 +1299,21 @@ static uint8_t *convert_session(struct oldsession *old) 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; } @@ -1572,10 +1589,10 @@ shortpacket: // 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) @@ -1814,7 +1831,7 @@ static int rle_decompress(uint8_t **src_p, int ssize, uint8_t *dst, int dsize) { 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. diff --git a/cluster.h b/cluster.h index 931c007..4fe7ad0 100644 --- a/cluster.h +++ b/cluster.h @@ -1,5 +1,5 @@ // 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__ @@ -72,13 +72,13 @@ typedef struct { } 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); diff --git a/constants.c b/constants.c index f9e3fa1..48e7d59 100644 --- a/constants.c +++ b/constants.c @@ -1,6 +1,6 @@ // 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 #include "constants.h" @@ -19,19 +19,27 @@ char const *cvs_id_constants = "$Id: constants.c,v 1.6 2005-06-28 14:48:20 bodea 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 @@ -74,7 +82,7 @@ CONSTANT(avp_name, "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 @@ -87,7 +95,7 @@ CONSTANT(stopccn_result_code, "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" @@ -107,7 +115,7 @@ CONSTANT(cdn_result_code, " detected" // 11 ) -CONSTANT(error_code, +CONSTANT(l2tp_error_code, "No general error", // 0 "No control connection exists yet for this LAC-LNS" " pair", // 1 @@ -124,7 +132,28 @@ CONSTANT(error_code, " 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 @@ -133,7 +162,7 @@ CONSTANT(auth_type, "Microsoft CHAP Version 1 (MSCHAPv1)" // 5 ) -CONSTANT(ppp_lcp_type, +CONSTANT(ppp_code, 0, // 0 "ConfigReq", // 1 "ConfigAck", // 2 @@ -149,15 +178,26 @@ CONSTANT(ppp_lcp_type, "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, @@ -185,23 +225,3 @@ 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 -) diff --git a/constants.h b/constants.h index a27ce79..a9693c3 100644 --- a/constants.h +++ b/constants.h @@ -1,15 +1,17 @@ #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__ */ diff --git a/control.c b/control.c index bd65de5..805a90b 100644 --- a/control.c +++ b/control.c @@ -1,12 +1,12 @@ // 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 #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; @@ -62,7 +62,7 @@ int pack_control(char *data, int len, uint8_t type, int argc, char *argv[]) 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; diff --git a/control.h b/control.h index ee7ed7d..e1f7d54 100644 --- a/control.h +++ b/control.h @@ -47,8 +47,8 @@ struct nsctl { 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__ */ diff --git a/icmp.c b/icmp.c index da04c38..93d00c1 100644 --- a/icmp.c +++ b/icmp.c @@ -1,6 +1,6 @@ // 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 #include @@ -18,7 +18,7 @@ char const *cvs_id_icmp = "$Id: icmp.c,v 1.8 2005-06-04 15:42:06 bodea Exp $"; #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; @@ -28,7 +28,7 @@ struct ipv6_pseudo_hdr { 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; @@ -72,15 +72,15 @@ void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, char 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; diff --git a/l2tpns.c b/l2tpns.c index a729992..8204503 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,7 +4,7 @@ // 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 #include @@ -38,9 +38,9 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.114 2005-07-04 05:49:46 bodea Exp #include #include #include +#include #include -#include "md5.h" #include "l2tpns.h" #include "cluster.h" #include "plugin.h" @@ -105,6 +105,9 @@ config_descriptt config_values[] = { 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), @@ -182,7 +185,7 @@ static void sighup_handler(int sig); 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); @@ -258,10 +261,10 @@ void _log(int level, sessionidt s, tunnelidt t, const char *format, ...) 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; @@ -551,7 +554,7 @@ static void inittun(void) 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 @@ -702,8 +705,11 @@ sessionidt sessionbyipv6(struct in6_addr ip) 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); @@ -973,14 +979,14 @@ int tun_write(uint8_t * data, int size) // 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]; @@ -1126,7 +1132,7 @@ static void processipv6out(uint8_t * buf, int len) 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]; @@ -1313,7 +1319,7 @@ static void controls(controlt * c, uint16_t avp, char *val, uint8_t m) } // 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); @@ -1493,10 +1499,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) 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 @@ -1534,7 +1537,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) 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); } @@ -1546,7 +1549,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) 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); @@ -1565,78 +1568,66 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) 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) @@ -1742,7 +1733,7 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha 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); @@ -1767,9 +1758,9 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha } // 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; @@ -2061,7 +2052,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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) @@ -2069,7 +2060,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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 { @@ -2077,18 +2068,18 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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); @@ -2222,7 +2213,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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) @@ -2351,7 +2342,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) case 10: // ICRQ if (sessionfree && main_quit != QUIT_SHUTDOWN) { - uint16_t r; + controlt *c = controlnew(11); // ICRP s = sessionfree; sessionfree = session[s].next; @@ -2360,41 +2351,34 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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 } @@ -2408,12 +2392,19 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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 @@ -2507,16 +2498,9 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) } 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) { @@ -2543,7 +2527,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) } 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; @@ -2592,7 +2576,7 @@ static void processtun(uint8_t * buf, int len) 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. @@ -2734,13 +2718,123 @@ static void regular_cleanups(double period) 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 @@ -2753,7 +2847,7 @@ static void regular_cleanups(double period) } // 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}; @@ -3084,7 +3178,8 @@ static void mainloop(void) 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; @@ -3391,6 +3486,9 @@ static void initdata(int optdebug, char *optconfig) 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; @@ -3758,7 +3856,7 @@ static void initippool() 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) @@ -4055,7 +4153,7 @@ 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) { MD5_CTX ctx; *challenge_response = NULL; @@ -4068,13 +4166,13 @@ static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_ 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; } @@ -4384,13 +4482,8 @@ int sessionsetup(tunnelidt t, sessionidt s) 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. { @@ -4499,7 +4592,7 @@ int load_session(sessionidt s, sessiont *new) } // 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 @@ -4716,7 +4809,7 @@ static void plugins_done() 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; @@ -5040,11 +5133,11 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec 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; @@ -5054,10 +5147,10 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec // 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; diff --git a/l2tpns.h b/l2tpns.h index a8e2d9a..2bf86bf 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -1,5 +1,5 @@ // 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__ @@ -72,14 +72,14 @@ #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 @@ -121,6 +121,52 @@ enum { 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; @@ -174,7 +220,14 @@ typedef struct 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 @@ -198,7 +251,7 @@ typedef struct 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 @@ -209,17 +262,10 @@ typedef struct 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 @@ -233,6 +279,16 @@ typedef struct 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; @@ -271,13 +327,12 @@ typedef struct } 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 @@ -328,7 +383,6 @@ enum 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 @@ -391,6 +445,7 @@ struct Tstats 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; @@ -457,6 +512,10 @@ typedef struct 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; @@ -601,6 +660,7 @@ void sendarp(int ifr_idx, const unsigned char* mac, in_addr_t ip); // 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); @@ -611,6 +671,7 @@ void sendchap(tunnelidt t, sessionidt s); 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 @@ -638,8 +699,9 @@ void filter_session(sessionidt s, int filter_in, int filter_out); 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); @@ -652,7 +714,7 @@ int cmd_show_hist_open(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); @@ -670,7 +732,7 @@ int cli_arg_help(struct cli_def *cli, int cr_ok, char *entry, ...); // 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; diff --git a/l2tpns.spec b/l2tpns.spec index 6b760a1..c3d63ca 100644 --- a/l2tpns.spec +++ b/l2tpns.spec @@ -8,8 +8,8 @@ Source: http://optusnet.dl.sourceforge.net/sourceforge/l2tpns/l2tpns-%{version}. 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 @@ -43,5 +43,5 @@ rm -rf %{buildroot} %attr(644,root,root) /usr/share/man/man[58]/* %changelog -* Wed Jun 29 2005 Brendan O'Dea 2.1.2-1 +* Sun Jul 31 2005 Brendan O'Dea 2.1.2-1 - 2.1.2 release, see /usr/share/doc/l2tpns-2.1.2/Changes diff --git a/md5.c b/md5.c deleted file mode 100644 index 59c87be..0000000 --- a/md5.c +++ /dev/null @@ -1,296 +0,0 @@ -/* 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 -#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); -} - diff --git a/md5.h b/md5.h deleted file mode 100644 index 5685fdb..0000000 --- a/md5.h +++ /dev/null @@ -1,74 +0,0 @@ -/* 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__ */ diff --git a/nsctl.c b/nsctl.c index 057edfa..59ad0c6 100644 --- a/nsctl.c +++ b/nsctl.c @@ -141,7 +141,7 @@ static struct nsctl *request(char *host, int port, int type, int argc, char *arg 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; diff --git a/plugin.h b/plugin.h index 6619ad3..faf3a5e 100644 --- a/plugin.h +++ b/plugin.h @@ -28,7 +28,7 @@ enum 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); diff --git a/ppp.c b/ppp.c index 0d3b168..a604755 100644 --- a/ppp.c +++ b/ppp.c @@ -1,6 +1,6 @@ // 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 #include @@ -23,8 +23,7 @@ extern uint32_t eth_tx; 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) @@ -32,6 +31,7 @@ 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); @@ -61,6 +61,12 @@ void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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; @@ -78,7 +84,9 @@ void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) } 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]; @@ -93,26 +101,21 @@ void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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); @@ -177,6 +180,13 @@ void processchap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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); @@ -243,7 +253,7 @@ static void dumplcp(uint8_t *p, int l) 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; @@ -268,54 +278,54 @@ static void dumplcp(uint8_t *p, int l) { 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); @@ -326,6 +336,113 @@ static void dumplcp(uint8_t *p, int l) } } +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) { @@ -352,10 +469,14 @@ 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); @@ -371,8 +492,10 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t 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; @@ -381,13 +504,41 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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); @@ -408,40 +559,23 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t 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"); } @@ -449,45 +583,29 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) { 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; @@ -505,22 +623,7 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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; @@ -539,11 +642,57 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) *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) { @@ -608,10 +757,42 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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) { @@ -631,7 +812,7 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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 { @@ -653,49 +834,50 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) { // 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); @@ -716,135 +898,217 @@ void processipcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) } 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); @@ -855,112 +1119,195 @@ void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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); } } @@ -985,6 +1332,9 @@ void processipin(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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) { @@ -1070,6 +1420,9 @@ void processipv6in(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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) { @@ -1190,46 +1543,131 @@ void processccp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l) 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 @@ -1270,7 +1708,7 @@ void sendchap(tunnelidt t, sessionidt s) 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 } @@ -1319,21 +1757,22 @@ uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, tunnelidt t, sessionid 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 @@ -1341,19 +1780,20 @@ static uint8_t *add_lcp_auth(uint8_t *b, int size, int authtype) 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; @@ -1367,7 +1807,8 @@ void sendlcp(tunnelidt t, sessionidt s, int authtype) *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); @@ -1380,9 +1821,9 @@ void sendlcp(tunnelidt t, sessionidt s, int authtype) } // 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; diff --git a/radius.c b/radius.c index 690380f..b31c6f0 100644 --- a/radius.c +++ b/radius.c @@ -1,6 +1,6 @@ // 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 #include @@ -13,7 +13,7 @@ char const *cvs_id_radius = "$Id: radius.c,v 1.36 2005-06-30 14:31:26 bodea Exp #include #include #include -#include "md5.h" +#include #include "constants.h" #include "l2tpns.h" #include "plugin.h" @@ -182,7 +182,7 @@ void radiussend(uint16_t r, uint8_t state) { *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) @@ -212,13 +212,13 @@ void radiussend(uint16_t r, uint8_t state) 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]; @@ -244,7 +244,7 @@ void radiussend(uint16_t r, uint8_t state) { *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 @@ -299,7 +299,7 @@ void radiussend(uint16_t r, uint8_t state) *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; @@ -325,21 +325,14 @@ void radiussend(uint16_t r, uint8_t state) { *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 @@ -353,15 +346,15 @@ void radiussend(uint16_t r, uint8_t state) 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); } @@ -381,9 +374,9 @@ void radiussend(uint16_t r, uint8_t state) 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) { @@ -415,7 +408,7 @@ static void handle_avpair(sessionidt s, uint8_t *avp, int len) // 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); } } @@ -463,12 +456,12 @@ void processrad(uint8_t *buf, int len, char socket_index) 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)) { @@ -617,7 +610,7 @@ void processrad(uint8_t *buf, int len, char socket_index) else if (*p == 11) { // Filter-Id - char *filter = p + 2; + char *filter = (char *) p + 2; int l = p[1] - 2; char *suffix; int f; @@ -680,10 +673,10 @@ void processrad(uint8_t *buf, int len, char socket_index) 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)) { @@ -710,12 +703,12 @@ void processrad(uint8_t *buf, int len, char socket_index) 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)); } @@ -750,20 +743,11 @@ void radiusretry(uint16_t r) 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 @@ -832,10 +816,10 @@ void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen) 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"); @@ -903,7 +887,7 @@ void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen) } len = p - packet; - i = find_filter(packet, len); + i = find_filter((char *) packet, len); if (i < 0 || !*ip_filters[i].name) { error = 404; @@ -1063,10 +1047,10 @@ void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen) 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); diff --git a/tbf.c b/tbf.c index 091e52d..9b4993d 100644 --- a/tbf.c +++ b/tbf.c @@ -1,6 +1,6 @@ // 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 #include "l2tpns.h" @@ -159,10 +159,10 @@ void fsck_tbfs(void) // 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; diff --git a/tbf.h b/tbf.h index 5c85c39..925e4f7 100644 --- a/tbf.h +++ b/tbf.h @@ -30,12 +30,12 @@ typedef struct { 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); diff --git a/test/radius.c b/test/radius.c index cc42db5..d0a8dc4 100644 --- a/test/radius.c +++ b/test/radius.c @@ -19,7 +19,7 @@ #include #include #include -#include "../md5.h" +#include extern char *optarg; extern int optind; @@ -394,16 +394,16 @@ int main(int argc, char *argv[]) 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];