Fix: Incorrect delegation of IPv6 prefixes when multiple of 4 bits (nibble) (eg: /44, /52 ...).
pinfo->nd_opt_pi_preferred_time = htonl(604800);
pinfo->nd_opt_pi_reserved2 = 0;
pinfo->nd_opt_pi_prefix_len = 64; // prefix length
pinfo->nd_opt_pi_preferred_time = htonl(604800);
pinfo->nd_opt_pi_reserved2 = 0;
pinfo->nd_opt_pi_prefix_len = 64; // prefix length
- pinfo->nd_opt_pi_prefix = config->ipv6_prefix;
+ if (session[s].ipv6address.s6_addr[0])
+ {
+ // MSB 64bits of assigned IPv6 address to user (see radius attribut Framed-IPv6-Address)
+ memcpy(&pinfo->nd_opt_pi_prefix, &session[s].ipv6address.s6_addr[0], 8);
+ }
+ else
+ pinfo->nd_opt_pi_prefix = config->ipv6_prefix;
// // Length of payload (not header)
p_ip6_hdr->ip6_plen = htons(sizeof(*pinfo) + sizeof(*p_nra));
// // Length of payload (not header)
p_ip6_hdr->ip6_plen = htons(sizeof(*pinfo) + sizeof(*p_nra));
struct ipv6radix {
sessionidt sess;
struct ipv6radix *branch;
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;
// Traffic counters.
static uint32_t udp_rx = 0, udp_rx_pkt = 0, udp_tx = 0;
char ipv6addr[INET6_ADDRSTRLEN];
curnode = &ipv6_hash[ip.s6_addr[0]];
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;
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",
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),
+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.
//
// Take an IP address in HOST byte order and
// add it to the sessionid by IP cache.
static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
{
int i;
static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
{
int i;
struct ipv6radix *curnode;
char ipv6addr[INET6_ADDRSTRLEN];
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;
+
+ while (i < niblles)
+ {
if (curnode->branch == NULL)
{
if (curnode->branch == NULL)
{
- if (!(curnode->branch = calloc(256,
- sizeof (struct ipv6radix))))
+ if (!(curnode->branch = calloc(16, sizeof (struct ipv6radix))))
- 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];
+
if (s > 0)
LOG(4, s, session[s].tunnel, "Caching ip address %s/%d\n",
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",
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),
// 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
// 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
sessionidt s;
sessiont *sp;
tunnelidt t;
sessionidt s;
sessiont *sp;
tunnelidt t;
struct in6_addr ip6;
uint8_t *data = buf; // Keep a copy of the originals.
struct in6_addr ip6;
uint8_t *data = buf; // Keep a copy of the originals.
- ip = *(uint32_t *)(buf + 32);
- s = sessionbyip(ip);
+ s = sessionbyipv6new(ip6);
if (s == 0)
{
// Is this a packet for a session that doesn't exist?
if (s == 0)
{
// Is this a packet for a session that doesn't exist?
uint32_t call_processudp;
uint32_t call_sessionbyip;
uint32_t call_sessionbyipv6;
uint32_t call_processudp;
uint32_t call_sessionbyip;
uint32_t call_sessionbyipv6;
+ uint32_t call_sessionbyipv6new;
uint32_t call_sessionbyuser;
uint32_t call_sendarp;
uint32_t call_sendipcp;
uint32_t call_sessionbyuser;
uint32_t call_sendarp;
uint32_t call_sendipcp;
void route6set(sessionidt s, struct in6_addr ip, int prefixlen, int add);
sessionidt sessionbyip(in_addr_t ip);
sessionidt sessionbyipv6(struct in6_addr ip);
void route6set(sessionidt s, struct in6_addr ip, int prefixlen, int add);
sessionidt sessionbyip(in_addr_t ip);
sessionidt sessionbyipv6(struct in6_addr ip);
+sessionidt sessionbyipv6new(struct in6_addr ip);
sessionidt sessionbyuser(char *username);
void increment_counter(uint32_t *counter, uint32_t *wrap, uint32_t delta);
void random_data(uint8_t *buf, int len);
sessionidt sessionbyuser(char *username);
void increment_counter(uint32_t *counter, uint32_t *wrap, uint32_t delta);
void random_data(uint8_t *buf, int len);
gotip++; // seen address
if (o[1] != 10) return;
gotip++; // seen address
if (o[1] != 10) return;
- ident[0] = htonl(session[s].ip);
- ident[1] = 0;
+ if (session[s].ipv6address.s6_addr[0])
+ {
+ // LSB 64bits of assigned IPv6 address to user (see radius attribut Framed-IPv6-Address)
+ memcpy(&ident[0], &session[s].ipv6address.s6_addr[8], 8);
+ }
+ else
+ {
+ ident[0] = htonl(session[s].ip);
+ ident[1] = 0;
+ }
if (memcmp(o + 2, ident, sizeof(ident)))
{
if (memcmp(o + 2, ident, sizeof(ident)))
{
- if ((ipv4 != session[s].ip || memcmp(&config->ipv6_prefix, &ip, 8)) && sessionbyipv6(ip) != s)
+ if (session[s].ipv6address.s6_addr[0])
+ {
+ if ((sessionbyipv6new(ip) != s) &&
+ (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))
+ {
+ char str[INET6_ADDRSTRLEN];
+ LOG(5, s, t, "Dropping packet with spoofed IP %s\n",
+ inet_ntop(AF_INET6, &ip, str, INET6_ADDRSTRLEN));
+ return;
+ }
+ }
+ else 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",
{
char str[INET6_ADDRSTRLEN];
LOG(5, s, t, "Dropping packet with spoofed IP %s\n",