finish incorporating ipv6 patches
This commit is contained in:
parent
1c209703a3
commit
08360e49b4
9 changed files with 724 additions and 18 deletions
4
Changes
4
Changes
|
|
@ -1,5 +1,5 @@
|
||||||
* Thu Jan 13 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0
|
* Tue Jan 25 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0
|
||||||
- Add IPv6 support from Jonathan McDowell (work in progress).
|
- Add IPv6 support from Jonathan McDowell.
|
||||||
- Add CHAP support from Jordan Hrycaj (work in progress).
|
- Add CHAP support from Jordan Hrycaj (work in progress).
|
||||||
- Sanity check that cluster_send_session is not called from a child
|
- Sanity check that cluster_send_session is not called from a child
|
||||||
process.
|
process.
|
||||||
|
|
|
||||||
12
cli.c
12
cli.c
|
|
@ -2,7 +2,7 @@
|
||||||
// vim: sw=8 ts=8
|
// vim: sw=8 ts=8
|
||||||
|
|
||||||
char const *cvs_name = "$Name: $";
|
char const *cvs_name = "$Name: $";
|
||||||
char const *cvs_id_cli = "$Id: cli.c,v 1.51 2005-01-13 08:26:25 bodea Exp $";
|
char const *cvs_id_cli = "$Id: cli.c,v 1.52 2005-01-25 04:19:05 bodea Exp $";
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
@ -478,7 +478,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show Summary
|
// Show Summary
|
||||||
cli_print(cli, "%5s %4s %-32s %-15s %s %s %s %10s %10s %10s %4s %-15s %s",
|
cli_print(cli, "%5s %4s %-32s %-15s %s %s %s %s %10s %10s %10s %4s %-15s %s",
|
||||||
"SID",
|
"SID",
|
||||||
"TID",
|
"TID",
|
||||||
"Username",
|
"Username",
|
||||||
|
|
@ -486,6 +486,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
|
||||||
"I",
|
"I",
|
||||||
"T",
|
"T",
|
||||||
"G",
|
"G",
|
||||||
|
"6",
|
||||||
"opened",
|
"opened",
|
||||||
"downloaded",
|
"downloaded",
|
||||||
"uploaded",
|
"uploaded",
|
||||||
|
|
@ -496,7 +497,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
|
||||||
for (i = 1; i < MAXSESSION; i++)
|
for (i = 1; i < MAXSESSION; i++)
|
||||||
{
|
{
|
||||||
if (!session[i].opened) continue;
|
if (!session[i].opened) continue;
|
||||||
cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %10u %10lu %10lu %4u %-15s %s",
|
cli_print(cli, "%5d %4d %-32s %-15s %s %s %s %s %10u %10lu %10lu %4u %-15s %s",
|
||||||
i,
|
i,
|
||||||
session[i].tunnel,
|
session[i].tunnel,
|
||||||
session[i].user[0] ? session[i].user : "*",
|
session[i].user[0] ? session[i].user : "*",
|
||||||
|
|
@ -504,6 +505,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].snoop_ip && session[i].snoop_port) ? "Y" : "N",
|
||||||
(session[i].throttle_in || session[i].throttle_out) ? "Y" : "N",
|
(session[i].throttle_in || session[i].throttle_out) ? "Y" : "N",
|
||||||
(session[i].walled_garden) ? "Y" : "N",
|
(session[i].walled_garden) ? "Y" : "N",
|
||||||
|
(session[i].flags & SF_IPV6CP_ACKED) ? "Y" : "N",
|
||||||
abs(time_now - (unsigned long)session[i].opened),
|
abs(time_now - (unsigned long)session[i].opened),
|
||||||
(unsigned long)session[i].total_cout,
|
(unsigned long)session[i].total_cout,
|
||||||
(unsigned long)session[i].total_cin,
|
(unsigned long)session[i].total_cin,
|
||||||
|
|
@ -700,18 +702,22 @@ static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, in
|
||||||
cli_print(cli, "-----------------------------------------");
|
cli_print(cli, "-----------------------------------------");
|
||||||
cli_print(cli, "%-30s%u", "call_processtun", GET_STAT(call_processtun));
|
cli_print(cli, "%-30s%u", "call_processtun", GET_STAT(call_processtun));
|
||||||
cli_print(cli, "%-30s%u", "call_processipout", GET_STAT(call_processipout));
|
cli_print(cli, "%-30s%u", "call_processipout", GET_STAT(call_processipout));
|
||||||
|
cli_print(cli, "%-30s%u", "call_processipv6out", GET_STAT(call_processipv6out));
|
||||||
cli_print(cli, "%-30s%u", "call_processudp", GET_STAT(call_processudp));
|
cli_print(cli, "%-30s%u", "call_processudp", GET_STAT(call_processudp));
|
||||||
cli_print(cli, "%-30s%u", "call_processpap", GET_STAT(call_processpap));
|
cli_print(cli, "%-30s%u", "call_processpap", GET_STAT(call_processpap));
|
||||||
cli_print(cli, "%-30s%u", "call_processchap", GET_STAT(call_processchap));
|
cli_print(cli, "%-30s%u", "call_processchap", GET_STAT(call_processchap));
|
||||||
cli_print(cli, "%-30s%u", "call_processlcp", GET_STAT(call_processlcp));
|
cli_print(cli, "%-30s%u", "call_processlcp", GET_STAT(call_processlcp));
|
||||||
cli_print(cli, "%-30s%u", "call_processipcp", GET_STAT(call_processipcp));
|
cli_print(cli, "%-30s%u", "call_processipcp", GET_STAT(call_processipcp));
|
||||||
|
cli_print(cli, "%-30s%u", "call_processipv6cp", GET_STAT(call_processipv6cp));
|
||||||
cli_print(cli, "%-30s%u", "call_processipin", GET_STAT(call_processipin));
|
cli_print(cli, "%-30s%u", "call_processipin", GET_STAT(call_processipin));
|
||||||
|
cli_print(cli, "%-30s%u", "call_processipv6in", GET_STAT(call_processipv6in));
|
||||||
cli_print(cli, "%-30s%u", "call_processccp", GET_STAT(call_processccp));
|
cli_print(cli, "%-30s%u", "call_processccp", GET_STAT(call_processccp));
|
||||||
cli_print(cli, "%-30s%u", "call_processrad", GET_STAT(call_processrad));
|
cli_print(cli, "%-30s%u", "call_processrad", GET_STAT(call_processrad));
|
||||||
cli_print(cli, "%-30s%u", "call_sendarp", GET_STAT(call_sendarp));
|
cli_print(cli, "%-30s%u", "call_sendarp", GET_STAT(call_sendarp));
|
||||||
cli_print(cli, "%-30s%u", "call_sendipcp", GET_STAT(call_sendipcp));
|
cli_print(cli, "%-30s%u", "call_sendipcp", GET_STAT(call_sendipcp));
|
||||||
cli_print(cli, "%-30s%u", "call_sendchap", GET_STAT(call_sendchap));
|
cli_print(cli, "%-30s%u", "call_sendchap", GET_STAT(call_sendchap));
|
||||||
cli_print(cli, "%-30s%u", "call_sessionbyip", GET_STAT(call_sessionbyip));
|
cli_print(cli, "%-30s%u", "call_sessionbyip", GET_STAT(call_sessionbyip));
|
||||||
|
cli_print(cli, "%-30s%u", "call_sessionbyipv6", GET_STAT(call_sessionbyipv6));
|
||||||
cli_print(cli, "%-30s%u", "call_sessionbyuser", GET_STAT(call_sessionbyuser));
|
cli_print(cli, "%-30s%u", "call_sessionbyuser", GET_STAT(call_sessionbyuser));
|
||||||
cli_print(cli, "%-30s%u", "call_tunnelsend", GET_STAT(call_tunnelsend));
|
cli_print(cli, "%-30s%u", "call_tunnelsend", GET_STAT(call_tunnelsend));
|
||||||
cli_print(cli, "%-30s%u", "call_tunnelkill", GET_STAT(call_tunnelkill));
|
cli_print(cli, "%-30s%u", "call_tunnelkill", GET_STAT(call_tunnelkill));
|
||||||
|
|
|
||||||
85
icmp.c
85
icmp.c
|
|
@ -1,6 +1,6 @@
|
||||||
// L2TPNS: icmp
|
// L2TPNS: icmp
|
||||||
|
|
||||||
char const *cvs_id_icmp = "$Id: icmp.c,v 1.6 2004-12-16 08:49:53 bodea Exp $";
|
char const *cvs_id_icmp = "$Id: icmp.c,v 1.7 2005-01-25 04:19:05 bodea Exp $";
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
@ -8,6 +8,7 @@ char const *cvs_id_icmp = "$Id: icmp.c,v 1.6 2004-12-16 08:49:53 bodea Exp $";
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/icmp.h>
|
#include <linux/icmp.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -19,6 +20,14 @@ char const *cvs_id_icmp = "$Id: icmp.c,v 1.6 2004-12-16 08:49:53 bodea Exp $";
|
||||||
|
|
||||||
static uint16_t _checksum(unsigned char *addr, int count);
|
static uint16_t _checksum(unsigned char *addr, int count);
|
||||||
|
|
||||||
|
struct ipv6_pseudo_hdr {
|
||||||
|
struct in6_addr src;
|
||||||
|
struct in6_addr dest;
|
||||||
|
uint32_t ulp_length;
|
||||||
|
uint32_t zero : 24;
|
||||||
|
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, char *packet, int packet_len)
|
||||||
{
|
{
|
||||||
char buf[128] = {0};
|
char buf[128] = {0};
|
||||||
|
|
@ -89,3 +98,77 @@ static uint16_t _checksum(unsigned char *addr, int count)
|
||||||
|
|
||||||
return htons((uint16_t) sum);
|
return htons((uint16_t) sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void send_ipv6_ra(tunnelidt t, sessionidt s, struct in6_addr *ip)
|
||||||
|
{
|
||||||
|
struct nd_opt_prefix_info *pinfo;
|
||||||
|
struct ipv6_pseudo_hdr *phdr;
|
||||||
|
uint8_t b[MAXETHER + 20];
|
||||||
|
uint8_t c[MAXETHER + 20];
|
||||||
|
int l;
|
||||||
|
uint8_t *o;
|
||||||
|
|
||||||
|
LOG(3, s, t, "Sending IPv6 RA\n");
|
||||||
|
|
||||||
|
memset(b, 0, sizeof(b));
|
||||||
|
o = makeppp(b, sizeof(b), 0, 0, t, s, PPPIPV6);
|
||||||
|
|
||||||
|
if (!o)
|
||||||
|
{
|
||||||
|
LOG(3, s, t, "failed to send IPv6 RA\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*o = 0x60; // IPv6
|
||||||
|
*(o+1) = 0;
|
||||||
|
*(o+5) = 48; // Length of payload (not header)
|
||||||
|
*(o+6) = 58; // icmp6 is next
|
||||||
|
*(o+7) = 255; // Hop limit
|
||||||
|
memset(o+8, 0, 16); // source = FE80::1
|
||||||
|
*(o+8) = 0xFE;
|
||||||
|
*(o+9) = 0x80;
|
||||||
|
*(o+23) = 1;
|
||||||
|
if (ip != NULL)
|
||||||
|
memcpy(o+24, ip, 16); // dest = ip
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FF02::1 - all hosts
|
||||||
|
*(o+24) = 0xFF;
|
||||||
|
*(o+25) = 2;
|
||||||
|
*(o+39) = 1;
|
||||||
|
}
|
||||||
|
*(o+40) = 134; // RA message
|
||||||
|
*(o+41) = 0; // Code
|
||||||
|
*(o+42) = *(o+43) = 0; // Checksum
|
||||||
|
*(o+44) = 64; // Hop count
|
||||||
|
*(o+45) = 0; // Flags
|
||||||
|
*(o+46) = *(o+47) = 255; // Lifetime
|
||||||
|
*(uint32_t *)(o+48) = 0; // Reachable time
|
||||||
|
*(uint32_t *)(o+52) = 0; // Retrans timer
|
||||||
|
pinfo = (struct nd_opt_prefix_info *)(o+56);
|
||||||
|
pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
|
||||||
|
pinfo->nd_opt_pi_len = 4;
|
||||||
|
pinfo->nd_opt_pi_prefix_len = 64; // prefix length
|
||||||
|
pinfo->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK;
|
||||||
|
pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
|
||||||
|
pinfo->nd_opt_pi_valid_time = htonl(2592000);
|
||||||
|
pinfo->nd_opt_pi_preferred_time = htonl(604800);
|
||||||
|
pinfo->nd_opt_pi_reserved2 = 0;
|
||||||
|
pinfo->nd_opt_pi_prefix = config->ipv6_prefix;
|
||||||
|
l = sizeof(*pinfo) + 56;
|
||||||
|
|
||||||
|
memset(c, 0, sizeof(c));
|
||||||
|
phdr = (struct ipv6_pseudo_hdr *) c;
|
||||||
|
memcpy(&phdr->src, o+8, 16);
|
||||||
|
memcpy(&phdr->dest, o+24, 16);
|
||||||
|
phdr->ulp_length = htonl(l - 40);
|
||||||
|
phdr->nexthdr = IPPROTO_ICMPV6;
|
||||||
|
|
||||||
|
memcpy(c + sizeof(*phdr), o + 40, l - 40);
|
||||||
|
|
||||||
|
// Checksum is over the icmp6 payload plus the pseudo header
|
||||||
|
*(uint16_t *)(o+42) = _checksum(c, l - 40 + sizeof(*phdr));
|
||||||
|
|
||||||
|
tunnelsend(b, l + (o-b), t); // send it...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
||||||
359
l2tpns.c
359
l2tpns.c
|
|
@ -4,7 +4,7 @@
|
||||||
// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
|
// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
|
||||||
// vim: sw=8 ts=8
|
// vim: sw=8 ts=8
|
||||||
|
|
||||||
char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.79 2005-01-13 08:42:52 bodea Exp $";
|
char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.80 2005-01-25 04:19:05 bodea Exp $";
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
@ -19,6 +19,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.79 2005-01-13 08:42:52 bodea Exp
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -62,9 +63,11 @@ int clifd = -1; // Socket listening for CLI connections.
|
||||||
int snoopfd = -1; // UDP file handle for sending out intercept data
|
int snoopfd = -1; // UDP file handle for sending out intercept data
|
||||||
int *radfds = NULL; // RADIUS requests file handles
|
int *radfds = NULL; // RADIUS requests file handles
|
||||||
int ifrfd = -1; // File descriptor for routing, etc
|
int ifrfd = -1; // File descriptor for routing, etc
|
||||||
|
int ifr6fd = -1; // File descriptor for IPv6 routing, etc
|
||||||
static int rand_fd = -1; // Random data source
|
static int rand_fd = -1; // Random data source
|
||||||
time_t basetime = 0; // base clock
|
time_t basetime = 0; // base clock
|
||||||
char hostname[1000] = ""; // us.
|
char hostname[1000] = ""; // us.
|
||||||
|
static int tunidx; // ifr_ifindex of tun device
|
||||||
static uint32_t sessionid = 0; // session id for radius accounting
|
static uint32_t sessionid = 0; // session id for radius accounting
|
||||||
static int syslog_log = 0; // are we logging to syslog
|
static int syslog_log = 0; // are we logging to syslog
|
||||||
static FILE *log_stream = NULL; // file handle for direct logging (i.e. direct into file, not via syslog).
|
static FILE *log_stream = NULL; // file handle for direct logging (i.e. direct into file, not via syslog).
|
||||||
|
|
@ -75,6 +78,10 @@ struct cli_session_actions *cli_session_actions = NULL; // Pending session chang
|
||||||
struct cli_tunnel_actions *cli_tunnel_actions = NULL; // Pending tunnel changes required by CLI
|
struct cli_tunnel_actions *cli_tunnel_actions = NULL; // Pending tunnel changes required by CLI
|
||||||
|
|
||||||
static void *ip_hash[256]; // Mapping from IP address to session structures.
|
static void *ip_hash[256]; // Mapping from IP address to session structures.
|
||||||
|
struct ipv6radix {
|
||||||
|
int sess;
|
||||||
|
struct ipv6radix *branch;
|
||||||
|
} ipv6_hash[256]; // Mapping from IPv6 address to session structures.
|
||||||
|
|
||||||
// Traffic counters.
|
// Traffic counters.
|
||||||
static uint32_t udp_rx = 0, udp_rx_pkt = 0, udp_tx = 0;
|
static uint32_t udp_rx = 0, udp_rx_pkt = 0, udp_tx = 0;
|
||||||
|
|
@ -125,6 +132,7 @@ config_descriptt config_values[] = {
|
||||||
CONFIG("cluster_interface", cluster_interface, STRING),
|
CONFIG("cluster_interface", cluster_interface, STRING),
|
||||||
CONFIG("cluster_hb_interval", cluster_hb_interval, INT),
|
CONFIG("cluster_hb_interval", cluster_hb_interval, INT),
|
||||||
CONFIG("cluster_hb_timeout", cluster_hb_timeout, INT),
|
CONFIG("cluster_hb_timeout", cluster_hb_timeout, INT),
|
||||||
|
CONFIG("ipv6_prefix", ipv6_prefix, IPv6),
|
||||||
{ NULL, 0, 0, 0 },
|
{ NULL, 0, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -163,6 +171,7 @@ struct Tringbuffer *ringbuffer = NULL;
|
||||||
|
|
||||||
static void cache_ipmap(in_addr_t ip, int s);
|
static void cache_ipmap(in_addr_t ip, int s);
|
||||||
static void uncache_ipmap(in_addr_t ip);
|
static void uncache_ipmap(in_addr_t ip);
|
||||||
|
static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s);
|
||||||
static void free_ip_address(sessionidt s);
|
static void free_ip_address(sessionidt s);
|
||||||
static void dump_acct_info(int all);
|
static void dump_acct_info(int all);
|
||||||
static void sighup_handler(int sig);
|
static void sighup_handler(int sig);
|
||||||
|
|
@ -421,11 +430,61 @@ static void routeset(sessionidt s, in_addr_t ip, in_addr_t mask, in_addr_t gw, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void route6set(sessionidt s, struct in6_addr ip, int prefixlen, int add)
|
||||||
|
{
|
||||||
|
struct in6_rtmsg rt;
|
||||||
|
char ipv6addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
if (ifr6fd < 0)
|
||||||
|
{
|
||||||
|
LOG(0, 0, 0, "Asked to set IPv6 route, but IPv6 not setup.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&rt, 0, sizeof(rt));
|
||||||
|
|
||||||
|
memcpy(&rt.rtmsg_dst, &ip, sizeof(struct in6_addr));
|
||||||
|
rt.rtmsg_dst_len = prefixlen;
|
||||||
|
rt.rtmsg_metric = 1;
|
||||||
|
rt.rtmsg_flags = RTF_UP;
|
||||||
|
rt.rtmsg_ifindex = tunidx;
|
||||||
|
|
||||||
|
LOG(1, 0, 0, "Route %s %s/%d\n",
|
||||||
|
add ? "add" : "del",
|
||||||
|
inet_ntop(AF_INET6, &ip, ipv6addr, INET6_ADDRSTRLEN),
|
||||||
|
prefixlen);
|
||||||
|
|
||||||
|
if (ioctl(ifr6fd, add ? SIOCADDRT : SIOCDELRT, (void *) &rt) < 0)
|
||||||
|
LOG(0, 0, 0, "route6set() error in ioctl: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
// FIXME: need to add BGP routing (RFC2858)
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
if (!add) // Are we deleting a route?
|
||||||
|
s = 0; // Caching the session as '0' is the same as uncaching.
|
||||||
|
|
||||||
|
cache_ipv6map(ip, prefixlen, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// defined in linux/ipv6.h, but tricky to include from user-space
|
||||||
|
// TODO: move routing to use netlink rather than ioctl
|
||||||
|
struct in6_ifreq {
|
||||||
|
struct in6_addr ifr6_addr;
|
||||||
|
__u32 ifr6_prefixlen;
|
||||||
|
unsigned int ifr6_ifindex;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set up TUN interface
|
// Set up TUN interface
|
||||||
static void inittun(void)
|
static void inittun(void)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
struct in6_ifreq ifr6;
|
||||||
struct sockaddr_in sin = {0};
|
struct sockaddr_in sin = {0};
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
ifr.ifr_flags = IFF_TUN;
|
ifr.ifr_flags = IFF_TUN;
|
||||||
|
|
@ -471,6 +530,42 @@ static void inittun(void)
|
||||||
LOG(0, 0, 0, "Error setting tun flags: %s\n", strerror(errno));
|
LOG(0, 0, 0, "Error setting tun flags: %s\n", strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
if (ioctl(ifrfd, SIOCGIFINDEX, (void *) &ifr) < 0)
|
||||||
|
{
|
||||||
|
LOG(0, 0, 0, "Error getting tun ifindex: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
ifr6fd = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
// Link local address is FE80::1
|
||||||
|
memset(&ifr6.ifr6_addr, 0, sizeof(ifr6.ifr6_addr));
|
||||||
|
ifr6.ifr6_addr.s6_addr[0] = 0xFE;
|
||||||
|
ifr6.ifr6_addr.s6_addr[1] = 0x80;
|
||||||
|
ifr6.ifr6_addr.s6_addr[15] = 1;
|
||||||
|
ifr6.ifr6_prefixlen = 64;
|
||||||
|
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
|
||||||
|
if (ioctl(ifr6fd, SIOCSIFADDR, (void *) &ifr6) < 0)
|
||||||
|
{
|
||||||
|
LOG(0, 0, 0, "Error setting tun IPv6 link local address:"
|
||||||
|
" %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global address is prefix::1
|
||||||
|
memset(&ifr6.ifr6_addr, 0, sizeof(ifr6.ifr6_addr));
|
||||||
|
ifr6.ifr6_addr = config->ipv6_prefix;
|
||||||
|
ifr6.ifr6_addr.s6_addr[15] = 1;
|
||||||
|
ifr6.ifr6_prefixlen = 64;
|
||||||
|
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
|
||||||
|
if (ioctl(ifr6fd, SIOCSIFADDR, (void *) &ifr6) < 0)
|
||||||
|
{
|
||||||
|
LOG(0, 0, 0, "Error setting tun IPv6 global address: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up UDP port
|
// set up UDP port
|
||||||
|
|
@ -537,6 +632,32 @@ static int lookup_ipmap(in_addr_t ip)
|
||||||
return (int) (intptr_t) d[(size_t) *a];
|
return (int) (intptr_t) d[(size_t) *a];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lookup_ipv6map(struct in6_addr ip)
|
||||||
|
{
|
||||||
|
struct ipv6radix *curnode;
|
||||||
|
int i;
|
||||||
|
int s;
|
||||||
|
char ipv6addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
curnode = &ipv6_hash[ip.s6_addr[0]];
|
||||||
|
i = 1;
|
||||||
|
s = curnode->sess;
|
||||||
|
|
||||||
|
while (s == 0 && i < 15 && curnode->branch != NULL)
|
||||||
|
{
|
||||||
|
curnode = &curnode->branch[ip.s6_addr[i]];
|
||||||
|
s = curnode->sess;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(4, s, session[s].tunnel, "Looking up address %s and got %d\n",
|
||||||
|
inet_ntop(AF_INET6, &ip, ipv6addr,
|
||||||
|
INET6_ADDRSTRLEN),
|
||||||
|
s);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
sessionidt sessionbyip(in_addr_t ip)
|
sessionidt sessionbyip(in_addr_t ip)
|
||||||
{
|
{
|
||||||
int s = lookup_ipmap(ip);
|
int s = lookup_ipmap(ip);
|
||||||
|
|
@ -548,6 +669,25 @@ sessionidt sessionbyip(in_addr_t ip)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionidt sessionbyipv6(struct in6_addr ip)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
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))) {
|
||||||
|
s = lookup_ipmap(*(in_addr_t *) &ip.s6_addr[8]);
|
||||||
|
} else {
|
||||||
|
s = lookup_ipv6map(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s > 0 && s < MAXSESSION && session[s].tunnel)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Take an IP address in HOST byte order and
|
// Take an IP address in HOST byte order and
|
||||||
// add it to the sessionid by IP cache.
|
// add it to the sessionid by IP cache.
|
||||||
|
|
@ -587,6 +727,42 @@ static void uncache_ipmap(in_addr_t ip)
|
||||||
cache_ipmap(ip, 0); // Assign it to the NULL session.
|
cache_ipmap(ip, 0); // Assign it to the NULL session.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int bytes;
|
||||||
|
struct ipv6radix *curnode;
|
||||||
|
char ipv6addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
curnode = &ipv6_hash[ip.s6_addr[0]];
|
||||||
|
|
||||||
|
bytes = prefixlen >> 3;
|
||||||
|
i = 1;
|
||||||
|
while (i < bytes) {
|
||||||
|
if (curnode->branch == NULL)
|
||||||
|
{
|
||||||
|
if (!(curnode->branch = calloc(256,
|
||||||
|
sizeof (struct ipv6radix))))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
curnode = &curnode->branch[ip.s6_addr[i]];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
curnode->sess = s;
|
||||||
|
|
||||||
|
if (s > 0)
|
||||||
|
LOG(4, s, session[s].tunnel, "Caching ip address %s/%d\n",
|
||||||
|
inet_ntop(AF_INET6, &ip, ipv6addr,
|
||||||
|
INET6_ADDRSTRLEN),
|
||||||
|
prefixlen);
|
||||||
|
else if (s == 0)
|
||||||
|
LOG(4, 0, 0, "Un-caching ip address %s/%d\n",
|
||||||
|
inet_ntop(AF_INET6, &ip, ipv6addr,
|
||||||
|
INET6_ADDRSTRLEN),
|
||||||
|
prefixlen);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// CLI list to dump current ipcache.
|
// CLI list to dump current ipcache.
|
||||||
//
|
//
|
||||||
|
|
@ -908,6 +1084,115 @@ static void processipout(uint8_t * buf, int len)
|
||||||
sess_local[s].cout += len; // To send to master..
|
sess_local[s].cout += len; // To send to master..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process outgoing (to tunnel) IPv6
|
||||||
|
//
|
||||||
|
void processipv6out(uint8_t * buf, int len)
|
||||||
|
{
|
||||||
|
sessionidt s;
|
||||||
|
sessiont *sp;
|
||||||
|
tunnelidt t;
|
||||||
|
in_addr_t ip;
|
||||||
|
struct in6_addr ip6;
|
||||||
|
|
||||||
|
char *data = buf; // Keep a copy of the originals.
|
||||||
|
int size = len;
|
||||||
|
|
||||||
|
uint8_t b[MAXETHER + 20];
|
||||||
|
|
||||||
|
CSTAT(processipv6out);
|
||||||
|
|
||||||
|
if (len < MIN_IP_SIZE)
|
||||||
|
{
|
||||||
|
LOG(1, 0, 0, "Short IPv6, %d bytes\n", len);
|
||||||
|
STAT(tunnel_tx_errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (len >= MAXETHER)
|
||||||
|
{
|
||||||
|
LOG(1, 0, 0, "Oversize IPv6 packet %d bytes\n", len);
|
||||||
|
STAT(tunnel_tx_errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the tun header
|
||||||
|
buf += 4;
|
||||||
|
len -= 4;
|
||||||
|
|
||||||
|
// Got an IP header now
|
||||||
|
if (*(uint8_t *)(buf) >> 4 != 6)
|
||||||
|
{
|
||||||
|
LOG(1, 0, 0, "IP: Don't understand anything except IPv6\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip6 = *(struct in6_addr *)(buf+24);
|
||||||
|
s = sessionbyipv6(ip6);
|
||||||
|
|
||||||
|
if (s == 0)
|
||||||
|
{
|
||||||
|
ip = *(uint32_t *)(buf + 32);
|
||||||
|
s = sessionbyip(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s == 0)
|
||||||
|
{
|
||||||
|
// Is this a packet for a session that doesn't exist?
|
||||||
|
static int rate = 0; // Number of ICMP packets we've sent this second.
|
||||||
|
static int last = 0; // Last time we reset the ICMP packet counter 'rate'.
|
||||||
|
|
||||||
|
if (last != time_now)
|
||||||
|
{
|
||||||
|
last = time_now;
|
||||||
|
rate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second.
|
||||||
|
{
|
||||||
|
// FIXME: Should send icmp6 host unreachable
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t = session[s].tunnel;
|
||||||
|
sp = &session[s];
|
||||||
|
|
||||||
|
// FIXME: add DoS prevention/filters?
|
||||||
|
|
||||||
|
if (sp->tbf_out)
|
||||||
|
{
|
||||||
|
// Are we throttling this session?
|
||||||
|
if (config->cluster_iam_master)
|
||||||
|
tbf_queue_packet(sp->tbf_out, data, size);
|
||||||
|
else
|
||||||
|
master_throttle_packet(sp->tbf_out, data, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (sp->walled_garden && !config->cluster_iam_master)
|
||||||
|
{
|
||||||
|
// We are walled-gardening this
|
||||||
|
master_garden_packet(s, data, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(5, s, t, "Ethernet -> Tunnel (%d bytes)\n", len);
|
||||||
|
|
||||||
|
// Add on L2TP header
|
||||||
|
{
|
||||||
|
uint8_t *p = makeppp(b, sizeof(b), buf, len, t, s, PPPIPV6);
|
||||||
|
if (!p) return;
|
||||||
|
tunnelsend(b, len + (p-b), t); // send it...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snooping this session, send it to intercept box
|
||||||
|
if (sp->snoop_ip && sp->snoop_port)
|
||||||
|
snoop_send_packet(buf, len, sp->snoop_ip, sp->snoop_port);
|
||||||
|
|
||||||
|
sp->cout += len; // byte count
|
||||||
|
sp->total_cout += len; // byte count
|
||||||
|
sp->pout++;
|
||||||
|
udp_tx += len;
|
||||||
|
sess_local[s].cout += len; // To send to master..
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Helper routine for the TBF filters.
|
// Helper routine for the TBF filters.
|
||||||
// Used to send queued data in to the user!
|
// Used to send queued data in to the user!
|
||||||
|
|
@ -1215,6 +1500,10 @@ void sessionshutdown(sessionidt s, char *reason)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
free_ip_address(s);
|
free_ip_address(s);
|
||||||
|
|
||||||
|
// unroute IPv6, if setup
|
||||||
|
if (session[s].flags & SF_IPV6_ROUTED)
|
||||||
|
route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session[s].throttle_in || session[s].throttle_out) // Unthrottle if throttled.
|
if (session[s].throttle_in || session[s].throttle_out) // Unthrottle if throttled.
|
||||||
|
|
@ -1276,6 +1565,30 @@ void sendipcp(tunnelidt t, sessionidt s)
|
||||||
|
|
||||||
tunnelsend(buf, 10 + (q - buf), t); // send it
|
tunnelsend(buf, 10 + (q - buf), t); // send it
|
||||||
session[s].flags &= ~SF_IPCP_ACKED; // Clear flag.
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// kill a session now
|
// kill a session now
|
||||||
|
|
@ -2037,6 +2350,19 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
|
||||||
if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
|
if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
|
||||||
processipcp(t, s, p, l);
|
processipcp(t, s, p, l);
|
||||||
}
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (prot == PPPCCP)
|
else if (prot == PPPCCP)
|
||||||
{
|
{
|
||||||
session[s].last_packet = time_now;
|
session[s].last_packet = time_now;
|
||||||
|
|
@ -2060,6 +2386,28 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
|
||||||
|
|
||||||
processipin(t, s, p, l);
|
processipin(t, s, p, l);
|
||||||
}
|
}
|
||||||
|
else if (prot == PPPIPV6)
|
||||||
|
{
|
||||||
|
if (!config->ipv6_prefix.s6_addr[0] > 0)
|
||||||
|
{
|
||||||
|
LOG(1, s, t, "IPv6 not configured; yet received IPv6 packet. Ignoring.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (session[s].die)
|
||||||
|
{
|
||||||
|
LOG(4, s, t, "Session %d is closing. Don't process PPP packets\n", s);
|
||||||
|
return; // closing session, PPP not processed
|
||||||
|
}
|
||||||
|
|
||||||
|
session[s].last_packet = time_now;
|
||||||
|
if (session[s].walled_garden && !config->cluster_iam_master)
|
||||||
|
{
|
||||||
|
master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processipv6in(t, s, p, l);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
STAT(tunnel_rx_errors);
|
STAT(tunnel_rx_errors);
|
||||||
|
|
@ -2088,6 +2436,10 @@ static void processtun(uint8_t * buf, int len)
|
||||||
|
|
||||||
if (*(uint16_t *) (buf + 2) == htons(PKTIP)) // IPv4
|
if (*(uint16_t *) (buf + 2) == htons(PKTIP)) // IPv4
|
||||||
processipout(buf, len);
|
processipout(buf, len);
|
||||||
|
else if (*(uint16_t *) (buf + 2) == htons(PKTIPV6) // IPV6
|
||||||
|
&& config->ipv6_prefix.s6_addr[0] > 0)
|
||||||
|
processipv6out(buf, len);
|
||||||
|
|
||||||
// Else discard.
|
// Else discard.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3897,6 +4249,7 @@ int sessionsetup(tunnelidt t, sessionidt s)
|
||||||
// convered by a Framed-Route. Anything else is part
|
// convered by a Framed-Route. Anything else is part
|
||||||
// of the IP address pool and is already routed, it
|
// of the IP address pool and is already routed, it
|
||||||
// just needs to be added to the IP cache.
|
// just needs to be added to the IP cache.
|
||||||
|
// IPv6 route setup is done in ppp.c, when IPV6CP is acked.
|
||||||
if (session[s].ip_pool_index == -1) // static ip
|
if (session[s].ip_pool_index == -1) // static ip
|
||||||
{
|
{
|
||||||
if (!routed) routeset(s, session[s].ip, 0, 0, 1);
|
if (!routed) routeset(s, session[s].ip, 0, 0, 1);
|
||||||
|
|
@ -4019,6 +4372,10 @@ int load_session(sessionidt s, sessiont *new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check v6 routing
|
||||||
|
if (new->flags & SF_IPV6_ROUTED && !(session[s].flags & SF_IPV6_ROUTED))
|
||||||
|
route6set(s, new->ipv6route, new->ipv6prefixlen, 1);
|
||||||
|
|
||||||
// check filters
|
// check filters
|
||||||
if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0]))
|
if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0]))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
18
l2tpns.h
18
l2tpns.h
|
|
@ -1,5 +1,5 @@
|
||||||
// L2TPNS Global Stuff
|
// L2TPNS Global Stuff
|
||||||
// $Id: l2tpns.h,v 1.53 2005-01-13 07:57:39 bodea Exp $
|
// $Id: l2tpns.h,v 1.54 2005-01-25 04:19:05 bodea Exp $
|
||||||
|
|
||||||
#ifndef __L2TPNS_H__
|
#ifndef __L2TPNS_H__
|
||||||
#define __L2TPNS_H__
|
#define __L2TPNS_H__
|
||||||
|
|
@ -213,7 +213,9 @@ typedef struct
|
||||||
uint16_t sid; // near end session id.
|
uint16_t sid; // near end session id.
|
||||||
uint8_t filter_in; // input filter index (to ip_filters[N-1]; 0 if none)
|
uint8_t filter_in; // input filter index (to ip_filters[N-1]; 0 if none)
|
||||||
uint8_t filter_out; // output filter index
|
uint8_t filter_out; // output filter index
|
||||||
char reserved[18]; // Space to expand structure without changing HB_VERSION
|
struct in6_addr ipv6route; // Static IPv6 route
|
||||||
|
uint8_t ipv6prefixlen; // IPv6 route prefix length
|
||||||
|
char reserved[1]; // Space to expand structure without changing HB_VERSION
|
||||||
}
|
}
|
||||||
sessiont;
|
sessiont;
|
||||||
|
|
||||||
|
|
@ -222,6 +224,7 @@ sessiont;
|
||||||
#define SF_CCP_ACKED 4 // CCP negotiated
|
#define SF_CCP_ACKED 4 // CCP negotiated
|
||||||
#define SF_IPV6CP_ACKED 8 // IPv6 negotiated
|
#define SF_IPV6CP_ACKED 8 // IPv6 negotiated
|
||||||
#define SF_IPV6_NACKED 16 // IPv6 rejected
|
#define SF_IPV6_NACKED 16 // IPv6 rejected
|
||||||
|
#define SF_IPV6_ROUTED 32 // advertised v6 route
|
||||||
|
|
||||||
#define AUTHPAP 1 // allow PAP
|
#define AUTHPAP 1 // allow PAP
|
||||||
#define AUTHCHAP 2 // allow CHAP
|
#define AUTHCHAP 2 // allow CHAP
|
||||||
|
|
@ -377,11 +380,14 @@ struct Tstats
|
||||||
#ifdef STATISTICS
|
#ifdef STATISTICS
|
||||||
uint32_t call_processtun;
|
uint32_t call_processtun;
|
||||||
uint32_t call_processipout;
|
uint32_t call_processipout;
|
||||||
|
uint32_t call_processipv6out;
|
||||||
uint32_t call_processudp;
|
uint32_t call_processudp;
|
||||||
uint32_t call_sessionbyip;
|
uint32_t call_sessionbyip;
|
||||||
|
uint32_t call_sessionbyipv6;
|
||||||
uint32_t call_sessionbyuser;
|
uint32_t call_sessionbyuser;
|
||||||
uint32_t call_sendarp;
|
uint32_t call_sendarp;
|
||||||
uint32_t call_sendipcp;
|
uint32_t call_sendipcp;
|
||||||
|
uint32_t call_processipv6cp;
|
||||||
uint32_t call_tunnelsend;
|
uint32_t call_tunnelsend;
|
||||||
uint32_t call_sessionkill;
|
uint32_t call_sessionkill;
|
||||||
uint32_t call_sessionshutdown;
|
uint32_t call_sessionshutdown;
|
||||||
|
|
@ -396,6 +402,7 @@ struct Tstats
|
||||||
uint32_t call_processlcp;
|
uint32_t call_processlcp;
|
||||||
uint32_t call_processipcp;
|
uint32_t call_processipcp;
|
||||||
uint32_t call_processipin;
|
uint32_t call_processipin;
|
||||||
|
uint32_t call_processipv6in;
|
||||||
uint32_t call_processccp;
|
uint32_t call_processccp;
|
||||||
uint32_t call_sendchap;
|
uint32_t call_sendchap;
|
||||||
uint32_t call_processrad;
|
uint32_t call_processrad;
|
||||||
|
|
@ -500,6 +507,8 @@ typedef struct
|
||||||
int cluster_hb_timeout; // How many missed heartbeats trigger an election.
|
int cluster_hb_timeout; // How many missed heartbeats trigger an election.
|
||||||
uint64_t cluster_table_version; // # state changes processed by cluster
|
uint64_t cluster_table_version; // # state changes processed by cluster
|
||||||
|
|
||||||
|
struct in6_addr ipv6_prefix; // Our IPv6 network pool.
|
||||||
|
|
||||||
#ifdef BGP
|
#ifdef BGP
|
||||||
#define BGP_NUM_PEERS 2
|
#define BGP_NUM_PEERS 2
|
||||||
uint16_t as_number;
|
uint16_t as_number;
|
||||||
|
|
@ -582,7 +591,9 @@ 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 processchap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
||||||
void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
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 processipcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
||||||
|
void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
||||||
void processipin(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
void processipin(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
||||||
|
void processipv6in(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
||||||
void processccp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
void processccp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
|
||||||
void sendchap(tunnelidt t, sessionidt s);
|
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);
|
uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, tunnelidt t, sessionidt s, uint16_t mtype);
|
||||||
|
|
@ -601,7 +612,10 @@ void radiusclear(uint16_t r, sessionidt s);
|
||||||
|
|
||||||
// l2tpns.c
|
// l2tpns.c
|
||||||
clockt backoff(uint8_t try);
|
clockt backoff(uint8_t try);
|
||||||
|
void send_ipv6_ra(tunnelidt t, sessionidt s, struct in6_addr *ip);
|
||||||
|
void route6set(sessionidt s, struct in6_addr ip, int prefixlen, int add);
|
||||||
sessionidt sessionbyip(in_addr_t ip);
|
sessionidt sessionbyip(in_addr_t ip);
|
||||||
|
sessionidt sessionbyipv6(struct in6_addr ip);
|
||||||
sessionidt sessionbyuser(char *username);
|
sessionidt sessionbyuser(char *username);
|
||||||
void random_data(uint8_t *buf, int len);
|
void random_data(uint8_t *buf, int len);
|
||||||
void sessionshutdown(sessionidt s, char *reason);
|
void sessionshutdown(sessionidt s, char *reason);
|
||||||
|
|
|
||||||
|
|
@ -43,5 +43,5 @@ rm -rf %{buildroot}
|
||||||
%attr(644,root,root) /usr/share/man/man[58]/*
|
%attr(644,root,root) /usr/share/man/man[58]/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Thu Jan 13 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0-1
|
* Tue Jan 25 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0-1
|
||||||
- 2.1.0 release, see /usr/share/doc/l2tpns-2.1.0/Changes
|
- 2.1.0 release, see /usr/share/doc/l2tpns-2.1.0/Changes
|
||||||
|
|
|
||||||
227
ppp.c
227
ppp.c
|
|
@ -1,6 +1,6 @@
|
||||||
// L2TPNS PPP Stuff
|
// L2TPNS PPP Stuff
|
||||||
|
|
||||||
char const *cvs_id_ppp = "$Id: ppp.c,v 1.41 2005-01-13 07:57:39 bodea Exp $";
|
char const *cvs_id_ppp = "$Id: ppp.c,v 1.42 2005-01-25 04:19:06 bodea Exp $";
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -139,9 +139,6 @@ void processchap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
|
||||||
if (!r)
|
if (!r)
|
||||||
{
|
{
|
||||||
LOG(1, s, t, "Unexpected CHAP message\n");
|
LOG(1, s, t, "Unexpected CHAP message\n");
|
||||||
|
|
||||||
// FIXME: Need to drop the session here.
|
|
||||||
|
|
||||||
STAT(tunnel_rx_errors);
|
STAT(tunnel_rx_errors);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -492,6 +489,20 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
|
||||||
{
|
{
|
||||||
sessionshutdown(s, "Connection closed.");
|
sessionshutdown(s, "Connection closed.");
|
||||||
}
|
}
|
||||||
|
else if (*p == ProtocolRej)
|
||||||
|
{
|
||||||
|
if (*(uint16_t *) (p+4) == htons(PPPIPV6CP))
|
||||||
|
{
|
||||||
|
LOG(3, s, t, "IPv6 rejected\n");
|
||||||
|
session[s].flags |= SF_IPV6_NACKED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(1, s, t, "Unexpected LCP protocol reject 0x%X\n",
|
||||||
|
ntohs(*(uint16_t *) (p+4)));
|
||||||
|
STAT(tunnel_rx_errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (*p == EchoReq)
|
else if (*p == EchoReq)
|
||||||
{
|
{
|
||||||
LOG(5, s, t, "LCP: Received EchoReq. Sending EchoReply\n");
|
LOG(5, s, t, "LCP: Received EchoReq. Sending EchoReply\n");
|
||||||
|
|
@ -685,6 +696,128 @@ void processipcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process IPV6CP messages
|
||||||
|
void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
|
||||||
|
{
|
||||||
|
|
||||||
|
CSTAT(processipv6cp);
|
||||||
|
|
||||||
|
LOG_HEX(5, "IPV6CP", p, l);
|
||||||
|
if (l < 4)
|
||||||
|
{
|
||||||
|
LOG(1, s, t, "Short IPV6CP %d bytes\n", 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)
|
||||||
|
{
|
||||||
|
LOG(1, s, t, "Unexpected IPV6CP code %d\n", *p);
|
||||||
|
STAT(tunnel_rx_errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(4, s, t, "IPV6CP ConfigReq received\n");
|
||||||
|
if (ntohs(*(uint16_t *) (p + 2)) > l)
|
||||||
|
{
|
||||||
|
LOG(1, s, t, "Length mismatch IPV6CP %d/%d\n", ntohs(*(uint16_t *) (p + 2)), l);
|
||||||
|
STAT(tunnel_rx_errors);
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 (*q != 1)
|
||||||
|
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, PPPIPV6CP)))
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "Failed to send IPV6CP ConfigRej\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*q = ConfigRej;
|
||||||
|
p += 4;
|
||||||
|
while (p < i && p[1])
|
||||||
|
{
|
||||||
|
if (*p != 1)
|
||||||
|
{
|
||||||
|
LOG(2, s, t, "IPV6CP reject %d\n", *p);
|
||||||
|
memcpy(q + n, p, p[1]);
|
||||||
|
n += p[1];
|
||||||
|
}
|
||||||
|
p += p[1];
|
||||||
|
}
|
||||||
|
*(uint16_t *) (q + 2) = htons(n);
|
||||||
|
LOG(4, s, t, "Sending ConfigRej\n");
|
||||||
|
tunnelsend(b, n + (q - b), t); // send it
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// process IP packet received
|
// process IP packet received
|
||||||
//
|
//
|
||||||
// This MUST be called with at least 4 byte behind 'p'.
|
// This MUST be called with at least 4 byte behind 'p'.
|
||||||
|
|
@ -759,6 +892,92 @@ void processipin(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
|
||||||
INC_STAT(tun_tx_bytes, l - 4);
|
INC_STAT(tun_tx_bytes, l - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process IPv6 packet received
|
||||||
|
//
|
||||||
|
// This MUST be called with at least 4 byte behind 'p'.
|
||||||
|
// (i.e. this routine writes to p[-4]).
|
||||||
|
void processipv6in(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
|
||||||
|
{
|
||||||
|
struct in6_addr ip;
|
||||||
|
in_addr_t ipv4;
|
||||||
|
|
||||||
|
CSTAT(processipv6in);
|
||||||
|
|
||||||
|
LOG_HEX(5, "IPv6", p, l);
|
||||||
|
|
||||||
|
ip = *(struct in6_addr *) (p + 8);
|
||||||
|
ipv4 = ntohl(*(uint32_t *)(p + 16));
|
||||||
|
|
||||||
|
if (l > MAXETHER)
|
||||||
|
{
|
||||||
|
LOG(1, s, t, "IP packet too long %d\n", l);
|
||||||
|
STAT(tunnel_rx_errors);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no spoof
|
||||||
|
if (ipv4 != session[s].ip && memcmp(&config->ipv6_prefix, &ip, 8) && sessionbyipv6(ip) != s)
|
||||||
|
{
|
||||||
|
char str[INET6_ADDRSTRLEN];
|
||||||
|
LOG(5, s, t, "Dropping packet with spoofed IP %s\n",
|
||||||
|
inet_ntop(AF_INET6, &ip, str, INET6_ADDRSTRLEN));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a Router Solicition message.
|
||||||
|
if (*(p + 6) == 58 && *(p + 7) == 255 && *(p + 24) == 0xFF && *(p + 25) == 2 &&
|
||||||
|
*(uint32_t *)(p + 26) == 0 && *(uint32_t *)(p + 30) == 0 &&
|
||||||
|
*(uint32_t *)(p + 34) == 0 &&
|
||||||
|
*(p + 38) == 0 && *(p + 39) == 2 && *(p + 40) == 133) {
|
||||||
|
LOG(3, s, t, "Got IPv6 RS\n");
|
||||||
|
send_ipv6_ra(t, s, &ip);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add on the tun header
|
||||||
|
p -= 4;
|
||||||
|
*(uint32_t *)p = htonl(PKTIPV6);
|
||||||
|
l += 4;
|
||||||
|
|
||||||
|
// Are we throttled and a slave?
|
||||||
|
if (session[s].tbf_in && !config->cluster_iam_master) {
|
||||||
|
// Pass it to the master for handling.
|
||||||
|
master_throttle_packet(session[s].tbf_in, p, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we throttled and a master?? actually handle the throttled
|
||||||
|
// packets.
|
||||||
|
if (session[s].tbf_in && config->cluster_iam_master) {
|
||||||
|
tbf_queue_packet(session[s].tbf_in, p, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send to ethernet
|
||||||
|
if (tun_write(p, l) < 0)
|
||||||
|
{
|
||||||
|
STAT(tun_tx_errors);
|
||||||
|
LOG(0, s, t, "Error writing %d bytes to TUN device: %s" " (tunfd=%d, p=%p)\n",
|
||||||
|
l, strerror(errno), tunfd, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session[s].snoop_ip && session[s].snoop_port)
|
||||||
|
{
|
||||||
|
// Snooping this session
|
||||||
|
snoop_send_packet(p, l, session[s].snoop_ip, session[s].snoop_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
session[s].cin += l - 4;
|
||||||
|
session[s].total_cin += l - 4;
|
||||||
|
sess_local[s].cin += l - 4;
|
||||||
|
|
||||||
|
session[s].pin++;
|
||||||
|
eth_tx += l - 4;
|
||||||
|
|
||||||
|
STAT(tun_tx_packets);
|
||||||
|
INC_STAT(tun_tx_bytes, l - 4);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Helper routine for the TBF filters.
|
// Helper routine for the TBF filters.
|
||||||
// Used to send queued data in from the user.
|
// Used to send queued data in from the user.
|
||||||
|
|
|
||||||
30
radius.c
30
radius.c
|
|
@ -1,6 +1,6 @@
|
||||||
// L2TPNS Radius Stuff
|
// L2TPNS Radius Stuff
|
||||||
|
|
||||||
char const *cvs_id_radius = "$Id: radius.c,v 1.22 2005-01-05 14:35:01 bodea Exp $";
|
char const *cvs_id_radius = "$Id: radius.c,v 1.23 2005-01-25 04:19:06 bodea Exp $";
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -619,12 +619,38 @@ void processrad(uint8_t *buf, int len, char socket_index)
|
||||||
} while (newp);
|
} while (newp);
|
||||||
free(avpair);
|
free(avpair);
|
||||||
}
|
}
|
||||||
|
else if (*p == 99)
|
||||||
|
{
|
||||||
|
// Framed-IPv6-Route
|
||||||
|
struct in6_addr r6;
|
||||||
|
int prefixlen;
|
||||||
|
uint8_t *n = p + 2;
|
||||||
|
uint8_t *e = p + p[1];
|
||||||
|
uint8_t *m = strchr(n, '/');
|
||||||
|
|
||||||
|
*m++ = 0;
|
||||||
|
inet_pton(AF_INET6, n, &r6);
|
||||||
|
|
||||||
|
prefixlen = 0;
|
||||||
|
while (m < e && isdigit(*m)) {
|
||||||
|
prefixlen = prefixlen * 10 + *m++ - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefixlen)
|
||||||
|
{
|
||||||
|
LOG(3, s, session[s].tunnel,
|
||||||
|
" Radius reply contains route for %s/%d\n",
|
||||||
|
n, prefixlen);
|
||||||
|
session[s].ipv6route = r6;
|
||||||
|
session[s].ipv6prefixlen = prefixlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (r_code == AccessReject)
|
else if (r_code == AccessReject)
|
||||||
{
|
{
|
||||||
LOG(2, s, session[s].tunnel, " Authentication denied for %s\n", session[s].user);
|
LOG(2, s, session[s].tunnel, " Authentication denied for %s\n", session[s].user);
|
||||||
//FIXME: We should tear down the session here!
|
sessionshutdown(s, "Authentication denied");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
5
util.c
5
util.c
|
|
@ -1,6 +1,6 @@
|
||||||
/* Misc util functions */
|
/* Misc util functions */
|
||||||
|
|
||||||
char const *cvs_id_util = "$Id: util.c,v 1.9 2004-12-20 07:23:53 bodea Exp $";
|
char const *cvs_id_util = "$Id: util.c,v 1.10 2005-01-25 04:19:07 bodea Exp $";
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
@ -40,7 +40,7 @@ void *shared_malloc(unsigned int size)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int forked;
|
extern int forked;
|
||||||
extern int udpfd, controlfd, tunfd, snoopfd, ifrfd, cluster_sockfd;
|
extern int udpfd, controlfd, tunfd, snoopfd, ifrfd, ifr6fd, cluster_sockfd;
|
||||||
extern int *radfds;
|
extern int *radfds;
|
||||||
|
|
||||||
pid_t fork_and_close()
|
pid_t fork_and_close()
|
||||||
|
|
@ -78,6 +78,7 @@ pid_t fork_and_close()
|
||||||
if (controlfd != -1) close(controlfd);
|
if (controlfd != -1) close(controlfd);
|
||||||
if (snoopfd != -1) close(snoopfd);
|
if (snoopfd != -1) close(snoopfd);
|
||||||
if (ifrfd != -1) close(ifrfd);
|
if (ifrfd != -1) close(ifrfd);
|
||||||
|
if (ifr6fd != -1) close(ifr6fd);
|
||||||
if (cluster_sockfd != -1) close(cluster_sockfd);
|
if (cluster_sockfd != -1) close(cluster_sockfd);
|
||||||
if (clifd != -1) close(clifd);
|
if (clifd != -1) close(clifd);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue