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:
parent
e98fe68174
commit
8d94f2020d
4 changed files with 73 additions and 25 deletions
8
icmp.c
8
icmp.c
|
|
@ -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));
|
||||
|
|
|
|||
63
l2tpns.c
63
l2tpns.c
|
|
@ -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?
|
||||
|
|
|
|||
2
l2tpns.h
2
l2tpns.h
|
|
@ -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
25
ppp.c
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue