X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/26a2025a1b7f12e9d962294583d76da30fb668d9..9c77145f71b0e669421d00ae0b34680f875121ae:/l2tpns.c diff --git a/l2tpns.c b/l2tpns.c index fcd054d..114981f 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -10,6 +10,7 @@ #include #include #define SYSLOG_NAMES +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -40,6 +40,7 @@ #include #include "md5.h" +#include "dhcp6.h" #include "l2tpns.h" #include "cluster.h" #include "plugin.h" @@ -55,6 +56,7 @@ #include "l2tplac.h" #include "pppoe.h" +#include "dhcp6.h" char * Vendor_name = "Linux L2TPNS"; uint32_t call_serial_number = 0; @@ -100,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; @@ -188,6 +190,14 @@ config_descriptt config_values[] = { CONFIG("bind_multi_address", bind_multi_address, STRING), 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("dns6_lifetime", dns6_lifetime, 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 } }; @@ -973,20 +983,24 @@ static sessionidt lookup_ipv6map(struct in6_addr ip) 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; @@ -1027,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. @@ -1066,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++; } @@ -1089,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); } @@ -1146,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 @@ -1417,7 +1449,7 @@ void processipout(uint8_t *buf, int len) sessionidt s; sessiont *sp; tunnelidt t; - in_addr_t ip; + in_addr_t ip, ip_src; uint8_t *data = buf; // Keep a copy of the originals. int size = len; @@ -1450,6 +1482,7 @@ void processipout(uint8_t *buf, int len) return; } + ip_src = *(uint32_t *)(buf + 12); ip = *(uint32_t *)(buf + 16); if (!(s = sessionbyip(ip))) { @@ -1534,12 +1567,15 @@ void processipout(uint8_t *buf, int len) 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) @@ -1679,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. @@ -1718,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? @@ -1801,6 +1835,8 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) { sessiont *sp; tunnelidt t; + uint8_t *p; + uint8_t *data = buf; // Keep a copy of the originals. uint8_t b[MAXETHER + 20]; @@ -1823,11 +1859,14 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) LOG(5, s, t, "Ethernet -> Tunnel (%d bytes)\n", len); // Add on L2TP header - { - uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP, 0, 0, 0); - if (!p) return; - tunnelsend(b, len + (p-b), t); // send it... - } + if (*(uint16_t *) (data + 2) == htons(PKTIPV6)) + p = makeppp(b, sizeof(b), buf, len, s, t, PPPIPV6, 0, 0, 0); // IPV6 + else + p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP, 0, 0, 0); // IPV4 + + if (!p) return; + + tunnelsend(b, len + (p-b), t); // send it... // Snooping this session. if (sp->snoop_ip && sp->snoop_port) @@ -2110,9 +2149,17 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e 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 @@ -2166,8 +2213,15 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e 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); + } } } } @@ -3405,6 +3459,20 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu 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) @@ -4532,6 +4600,8 @@ static void initdata(int optdebug, char *optconfig) // Set default value echo_timeout and idle_echo_timeout config->echo_timeout = ECHO_TIMEOUT; config->idle_echo_timeout = IDLE_ECHO_TIMEOUT; + // Set default RDNSS lifetime + config->dns6_lifetime = 1200; log_stream = stderr; @@ -5050,9 +5120,9 @@ int main(int argc, char *argv[]) case 'd': if (fork()) exit(0); setsid(); - freopen("/dev/null", "r", stdin); - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); + if(!freopen("/dev/null", "r", stdin)) LOG(0, 0, 0, "Error freopen stdin: %s\n", strerror(errno)); + if(!freopen("/dev/null", "w", stdout)) LOG(0, 0, 0, "Error freopen stdout: %s\n", strerror(errno)); + if(!freopen("/dev/null", "w", stderr)) LOG(0, 0, 0, "Error freopen stderr: %s\n", strerror(errno)); break; case 'v': optdebug++; @@ -5092,6 +5162,7 @@ int main(int argc, char *argv[]) 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"); { @@ -5103,7 +5174,7 @@ int main(int argc, char *argv[]) LOG(0, 0, 0, "Can't set ulimit: %s\n", strerror(errno)); // Make core dumps go to /tmp - chdir("/tmp"); + if(chdir("/tmp")) LOG(0, 0, 0, "Error chdir /tmp: %s\n", strerror(errno)); } if (config->scheduler_fifo) @@ -5167,6 +5238,7 @@ int main(int argc, char *argv[]) initrad(); initippool(); + dhcpv6_init(); // seed prng { @@ -5786,7 +5858,7 @@ int load_session(sessionidt s, sessiont *new) // needs update if (newip) { - int routed = 0; + int routed = 0; // remove old routes... for (i = 0; i < MAXROUTE && session[s].route[i].ip; i++) @@ -5809,6 +5881,17 @@ int load_session(sessionidt s, sessiont *new) uncache_ipmap(session[s].ip); } + // remove old IPV6 routes... + 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; // add new routes... @@ -5835,8 +5918,20 @@ int load_session(sessionidt s, sessiont *new) } // 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]))