new feature: If the user attribute "Framed-IPv6-Address" is defined then the ICMPv6_RA advertise this IPv6 address.

Fix: Incorrect delegation of IPv6 prefixes when multiple of 4 bits (nibble) (eg: /44, /52 ...).
This commit is contained in:
fendo 2014-09-18 18:16:21 +02:00
parent e98fe68174
commit 8d94f2020d
4 changed files with 73 additions and 25 deletions

8
icmp.c
View file

@ -143,7 +143,13 @@ void send_ipv6_ra(sessionidt s, tunnelidt t, struct in6_addr *ip)
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));

View file

@ -102,7 +102,7 @@ union iphash {
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;
@ -983,19 +983,24 @@ static sessionidt lookup_ipv6map(struct in6_addr ip)
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;
@ -1036,6 +1041,19 @@ sessionidt sessionbyipv6(struct in6_addr ip)
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.
@ -1075,22 +1093,28 @@ static void uncache_ipmap(in_addr_t ip)
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++;
}
@ -1098,13 +1122,13 @@ static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
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);
}
@ -1155,7 +1179,6 @@ int cmd_show_ipcache(struct cli_def *cli, const char *command, char **argv, int
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
@ -1692,7 +1715,6 @@ static void processipv6out(uint8_t * buf, int len)
sessionidt s;
sessiont *sp;
tunnelidt t;
in_addr_t ip;
struct in6_addr ip6;
uint8_t *data = buf; // Keep a copy of the originals.
@ -1731,10 +1753,9 @@ static void processipv6out(uint8_t * buf, int len)
if (s == 0)
{
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?

View file

@ -606,6 +606,7 @@ struct Tstats
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;
@ -951,6 +952,7 @@ void send_ipv6_ra(sessionidt s, tunnelidt t, 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);

25
ppp.c
View file

@ -1580,8 +1580,16 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
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)))
{
@ -2254,7 +2262,18 @@ void processipv6in(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
return;
// no spoof
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",