#include <linux/rtnetlink.h>
#include "md5.h"
+#include "dhcp6.h"
#include "l2tpns.h"
#include "cluster.h"
#include "plugin.h"
#include "l2tplac.h"
#include "pppoe.h"
+#include "dhcp6.h"
char * Vendor_name = "Linux L2TPNS";
uint32_t call_serial_number = 0;
struct cli_session_actions *cli_session_actions = NULL; // Pending session changes requested by CLI
struct cli_tunnel_actions *cli_tunnel_actions = NULL; // Pending tunnel changes required by CLI
-union iphash ip_hash[256]; // Mapping from IP address to session structures.
+union iphash
+{
+ sessionidt sess;
+ union iphash *idx;
+}ip_hash[256]; // Mapping from IP address to session structures.
struct ipv6radix {
sessionidt sess;
struct ipv6radix *branch;
-} ipv6_hash[256]; // Mapping from IPv6 address to session structures.
+} ipv6_hash[16]; // Mapping from IPv6 address to session structures.
// Traffic counters.
static uint32_t udp_rx = 0, udp_rx_pkt = 0, udp_tx = 0;
CONFIG("grp_txrate_average_time", grp_txrate_average_time, INT),
CONFIG("pppoe_only_equal_svc_name", pppoe_only_equal_svc_name, BOOL),
CONFIG("multi_hostname", multi_hostname, STRING),
+ CONFIG("no_throttle_local_IP", no_throttle_local_IP, BOOL),
+ CONFIG("dhcp6_preferred_lifetime", dhcp6_preferred_lifetime, INT),
+ CONFIG("dhcp6_valid_lifetime", dhcp6_valid_lifetime, INT),
+ CONFIG("dhcp6_server_duid", dhcp6_server_duid, INT),
+ CONFIG("primary_ipv6_dns", default_ipv6_dns1, IPv6),
+ CONFIG("secondary_ipv6_dns", default_ipv6_dns2, IPv6),
+ CONFIG("default_ipv6_domain_list", default_ipv6_domain_list, STRING),
{ NULL, 0, 0, 0 }
};
int s;
char ipv6addr[INET6_ADDRSTRLEN];
- curnode = &ipv6_hash[ip.s6_addr[0]];
+ curnode = &ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
i = 1;
s = curnode->sess;
- while (s == 0 && i < 15 && curnode->branch != NULL)
+ while (s == 0 && i < 32 && curnode->branch != NULL)
{
- curnode = &curnode->branch[ip.s6_addr[i]];
+ if (i & 1)
+ curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
+ else
+ curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
+
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),
+ inet_ntop(AF_INET6, &ip, ipv6addr,
+ INET6_ADDRSTRLEN),
s);
return s;
return 0;
}
+sessionidt sessionbyipv6new(struct in6_addr ip)
+{
+ sessionidt s;
+ CSTAT(sessionbyipv6new);
+
+ s = lookup_ipv6map(ip);
+
+ if (s > 0 && s < MAXSESSION && session[s].opened)
+ return s;
+
+ return 0;
+}
+
//
// Take an IP address in HOST byte order and
// add it to the sessionid by IP cache.
if (s > 0)
LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0));
-
else if (s == 0)
LOG(4, 0, 0, "Un-caching ip address %s\n", fmtaddr(nip, 0));
// else a map to an ip pool index.
static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
{
int i;
- int bytes;
+ int niblles;
struct ipv6radix *curnode;
char ipv6addr[INET6_ADDRSTRLEN];
- curnode = &ipv6_hash[ip.s6_addr[0]];
+ curnode = &ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
- bytes = prefixlen >> 3;
+ niblles = prefixlen >> 2;
i = 1;
- while (i < bytes) {
+
+ while (i < niblles)
+ {
if (curnode->branch == NULL)
{
- if (!(curnode->branch = calloc(256,
- sizeof (struct ipv6radix))))
+ if (!(curnode->branch = calloc(16, sizeof (struct ipv6radix))))
return;
}
- curnode = &curnode->branch[ip.s6_addr[i]];
+
+ if (i & 1)
+ curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
+ else
+ curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
+
i++;
}
if (s > 0)
LOG(4, s, session[s].tunnel, "Caching ip address %s/%d\n",
- inet_ntop(AF_INET6, &ip, ipv6addr,
- INET6_ADDRSTRLEN),
+ 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),
+ inet_ntop(AF_INET6, &ip, ipv6addr,
+ INET6_ADDRSTRLEN),
prefixlen);
}
return CLI_OK;
}
-
// Find session by username, 0 for not found
// walled garden users aren't authenticated, so the username is
// reasonably useless. Ignore them to avoid incorrect actions
ip = *(uint32_t *)(buf + 16);
if ((g = grp_groupbyip(ip)))
{
- s = grp_getnextsession(g, ip, ip_src);
+ s = grp_getnextsession(g, &ip, &ip_src, 0);
if (!s)
{
// Is this a packet for a session that doesn't exist?
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;
+ if (!config->no_throttle_local_IP || !sessionbyip(ip_src))
+ {
+ // 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;
+ }
}
if (sp->walled_garden && !config->cluster_iam_master)
static void processipv6out(uint8_t * buf, int len)
{
sessionidt s;
+ groupidt g;
sessiont *sp;
tunnelidt t;
- in_addr_t ip;
- struct in6_addr ip6;
+ struct in6_addr *p_ip6;
+ struct in6_addr *p_ip6_src;
uint8_t *data = buf; // Keep a copy of the originals.
int size = len;
return;
}
- ip6 = *(struct in6_addr *)(buf+24);
- s = sessionbyipv6(ip6);
+ p_ip6_src = (struct in6_addr *)(buf+8);
+ p_ip6 = (struct in6_addr *)(buf+24);
- if (s == 0)
+ if ((g = grp_groupbyipv6(*p_ip6)))
{
- ip = *(uint32_t *)(buf + 32);
- s = sessionbyip(ip);
+ s = grp_getnextsession(g, p_ip6, p_ip6_src, 1);
}
-
+ else if (!(s = sessionbyipv6(*p_ip6)))
+ {
+ s = sessionbyipv6new(*p_ip6);
+ }
+
if (s == 0)
{
// Is this a packet for a session that doesn't exist?
free_ip_address(s);
// unroute IPv6, if setup
- if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen && del_routes)
- route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
-
+ for (r = 0; r < MAXROUTE6 && session[s].route6[r].ipv6route.s6_addr[0] && session[s].route6[r].ipv6prefixlen; r++)
+ {
+ if (del_routes) route6set(s, session[s].route6[r].ipv6route, session[s].route6[r].ipv6prefixlen, 0);
+ memset(&session[s].route6[r], 0, sizeof(session[s].route6[r]));
+ }
+
+ if (session[s].ipv6address.s6_addr[0] && del_routes)
+ {
+ route6set(s, session[s].ipv6address, 128, 0);
+ }
+
if (b)
{
// This session was part of a bundle
cache_ipmap(session[new_s].ip, new_s);
// IPV6 route
- if (session[new_s].ipv6prefixlen)
- cache_ipv6map(session[new_s].ipv6route, session[new_s].ipv6prefixlen, new_s);
+ for (r = 0; r < MAXROUTE6 && session[new_s].route6[r].ipv6prefixlen; r++)
+ {
+ cache_ipv6map(session[new_s].route6[r].ipv6route, session[new_s].route6[r].ipv6prefixlen, new_s);
+ }
+
+ if (session[new_s].ipv6address.s6_addr[0])
+ {
+ cache_ipv6map(session[new_s].ipv6address, 128, new_s);
+ }
}
}
}
return;
}
+ if (!config->cluster_iam_master)
+ {
+ // Check if DhcpV6, IP dst: FF02::1:2, Src Port 0x0222 (546), Dst Port 0x0223 (547)
+ if (*(p + 6) == 17 && *(p + 24) == 0xFF && *(p + 25) == 2 &&
+ *(uint32_t *)(p + 26) == 0 && *(uint32_t *)(p + 30) == 0 &&
+ *(uint16_t *)(p + 34) == 0 && *(p + 36) == 0 && *(p + 37) == 1 && *(p + 38) == 0 && *(p + 39) == 2 &&
+ *(p + 40) == 2 && *(p + 41) == 0x22 && *(p + 42) == 2 && *(p + 43) == 0x23)
+ {
+ // DHCPV6 must be managed by the Master.
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
+ return;
+ }
+ }
+
processipv6in(s, t, p, l);
}
else if (session[s].ppp.lcp == Opened)
init_tbf(config->num_tbfs);
LOG(0, 0, 0, "L2TPNS version " VERSION "\n");
+ LOG(0, 0, 0, "Copyright (c) 2012, 2013, 2014 ISP FDN & SAMESWIRELESS\n");
LOG(0, 0, 0, "Copyright (c) 2003, 2004, 2005, 2006 Optus Internet Engineering\n");
LOG(0, 0, 0, "Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n");
{
initrad();
initippool();
+ dhcpv6_init();
// seed prng
{
// needs update
if (newip)
{
- int routed = 0;
+ int routed = 0;
// remove old routes...
for (i = 0; i < MAXROUTE && session[s].route[i].ip; i++)
}
// remove old IPV6 routes...
- if (session[s].ipv6route.s6_addr[0] && session[s].ipv6prefixlen)
- route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
+ for (i = 0; i < MAXROUTE6 && session[s].route6[i].ipv6route.s6_addr[0] && session[s].route6[i].ipv6prefixlen; i++)
+ {
+ route6set(s, session[s].route6[i].ipv6route, session[s].route6[i].ipv6prefixlen, 0);
+ }
+
+ if (session[s].ipv6address.s6_addr[0])
+ {
+ route6set(s, session[s].ipv6address, 128, 0);
+ }
routed = 0;
}
// check v6 routing
- if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
- route6set(s, new->ipv6route, new->ipv6prefixlen, 1);
+ if (new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
+ {
+ for (i = 0; i < MAXROUTE6 && new->route6[i].ipv6prefixlen; i++)
+ {
+ route6set(s, new->route6[i].ipv6route, new->route6[i].ipv6prefixlen, 1);
+ }
+ }
+
+ if (new->ipv6address.s6_addr[0] && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
+ {
+ // Check if included in prefix
+ if (sessionbyipv6(new->ipv6address) != s)
+ route6set(s, new->ipv6address, 128, 1);
+ }
// check filters
if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0]))