X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/e6bb332ba271c0cbedffa131333710e0d95ca06d..007f5d2cacfdc20eded3610fbbec8388564db1b2:/l2tpns.c?ds=sidebyside diff --git a/l2tpns.c b/l2tpns.c index 60fc7c8..0ed0337 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,7 +4,7 @@ // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // vim: sw=8 ts=8 -char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.167 2006/06/11 12:46:18 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.171 2006/08/02 13:35:39 bodea Exp $"; #include #include @@ -82,9 +82,13 @@ uint16_t MSS = 0; // TCP MSS 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 -static void *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 { - int sess; + sessionidt sess; struct ipv6radix *branch; } ipv6_hash[256]; // Mapping from IPv6 address to session structures. @@ -126,6 +130,8 @@ config_descriptt config_values[] = { CONFIG("radius_secret", radiussecret, STRING), CONFIG("radius_authtypes", radius_authtypes_s, STRING), CONFIG("radius_dae_port", radius_dae_port, SHORT), + CONFIG("radius_bind_min", radius_bind_min, SHORT), + CONFIG("radius_bind_max", radius_bind_max, SHORT), CONFIG("allow_duplicate_users", allow_duplicate_users, BOOL), CONFIG("guest_account", guest_user, STRING), CONFIG("bind_address", bind_address, IPv4), @@ -187,9 +193,9 @@ struct Tstats *_statistics = NULL; struct Tringbuffer *ringbuffer = NULL; #endif -static void cache_ipmap(in_addr_t ip, int s); +static void cache_ipmap(in_addr_t ip, sessionidt s); static void uncache_ipmap(in_addr_t ip); -static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s); +static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s); static void free_ip_address(sessionidt s); static void dump_acct_info(int all); static void sighup_handler(int sig); @@ -625,7 +631,7 @@ static void initudp(void) int flags = fcntl(udpfd, F_GETFL, 0); fcntl(udpfd, F_SETFL, flags | O_NONBLOCK); } - if (bind(udpfd, (void *) &addr, sizeof(addr)) < 0) + if (bind(udpfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno)); exit(1); @@ -638,7 +644,7 @@ static void initudp(void) controlfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(controlfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); setsockopt(controlfd, SOL_IP, IP_PKTINFO, &on, sizeof(on)); // recvfromto - if (bind(controlfd, (void *) &addr, sizeof(addr)) < 0) + if (bind(controlfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno)); exit(1); @@ -651,7 +657,7 @@ static void initudp(void) daefd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(daefd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); setsockopt(daefd, SOL_IP, IP_PKTINFO, &on, sizeof(on)); // recvfromto - if (bind(daefd, (void *) &addr, sizeof(addr)) < 0) + if (bind(daefd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno)); exit(1); @@ -676,19 +682,19 @@ static void initudp(void) // IP address. // -static int lookup_ipmap(in_addr_t ip) +static sessionidt lookup_ipmap(in_addr_t ip) { uint8_t *a = (uint8_t *) &ip; - uint8_t **d = (uint8_t **) ip_hash; + union iphash *h = ip_hash; - if (!(d = (uint8_t **) d[(size_t) *a++])) return 0; - if (!(d = (uint8_t **) d[(size_t) *a++])) return 0; - if (!(d = (uint8_t **) d[(size_t) *a++])) return 0; + if (!(h = h[*a++].idx)) return 0; + if (!(h = h[*a++].idx)) return 0; + if (!(h = h[*a++].idx)) return 0; - return (int) (intptr_t) d[(size_t) *a]; + return h[*a].sess; } -static int lookup_ipv6map(struct in6_addr ip) +static sessionidt lookup_ipv6map(struct in6_addr ip) { struct ipv6radix *curnode; int i; @@ -716,18 +722,18 @@ static int lookup_ipv6map(struct in6_addr ip) sessionidt sessionbyip(in_addr_t ip) { - int s = lookup_ipmap(ip); + sessionidt s = lookup_ipmap(ip); CSTAT(sessionbyip); if (s > 0 && s < MAXSESSION && session[s].opened) - return (sessionidt) s; + return s; return 0; } sessionidt sessionbyipv6(struct in6_addr ip) { - int s; + sessionidt s; CSTAT(sessionbyipv6); if (!memcmp(&config->ipv6_prefix, &ip, 8) || @@ -753,25 +759,22 @@ sessionidt sessionbyipv6(struct in6_addr ip) // // (It's actually cached in network order) // -static void cache_ipmap(in_addr_t ip, int s) +static void cache_ipmap(in_addr_t ip, sessionidt s) { in_addr_t nip = htonl(ip); // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0] uint8_t *a = (uint8_t *) &nip; - uint8_t **d = (uint8_t **) ip_hash; + union iphash *h = ip_hash; int i; for (i = 0; i < 3; i++) { - if (!d[(size_t) a[i]]) - { - if (!(d[(size_t) a[i]] = calloc(256, sizeof(void *)))) - return; - } + if (!(h[a[i]].idx || (h[a[i]].idx = calloc(256, sizeof(union iphash))))) + return; - d = (uint8_t **) d[(size_t) a[i]]; + h = h[a[i]].idx; } - d[(size_t) a[3]] = (uint8_t *) (intptr_t) s; + h[a[3]].sess = s; if (s > 0) LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0)); @@ -786,7 +789,7 @@ static void uncache_ipmap(in_addr_t ip) cache_ipmap(ip, 0); // Assign it to the NULL session. } -static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s) +static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s) { int i; int bytes; @@ -827,7 +830,7 @@ static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s) // int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc) { - char **d = (char **) ip_hash, **e, **f, **g; + union iphash *d = ip_hash, *e, *f, *g; int i, j, k, l; int count = 0; @@ -838,24 +841,28 @@ int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc) for (i = 0; i < 256; ++i) { - if (!d[i]) + if (!d[i].idx) continue; - e = (char **) d[i]; + + e = d[i].idx; for (j = 0; j < 256; ++j) { - if (!e[j]) + if (!e[j].idx) continue; - f = (char **) e[j]; + + f = e[j].idx; for (k = 0; k < 256; ++k) { - if (!f[k]) + if (!f[k].idx) continue; - g = (char **)f[k]; + + g = f[k].idx; for (l = 0; l < 256; ++l) { - if (!g[l]) + if (!g[l].sess) continue; - cli_print(cli, "%7d %d.%d.%d.%d", (int) (intptr_t) g[l], i, j, k, l); + + cli_print(cli, "%7d %d.%d.%d.%d", g[l].sess, i, j, k, l); ++count; } } @@ -2184,9 +2191,10 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) int error = 0; char *msg = 0; - // default disconnect cause/message on receipt - // of CDN (set to more specific value from - // attribute 46 if present below). + // Default disconnect cause/message on receipt of CDN. Set to + // more specific value from attribute 1 (result code) or 46 + // (disconnect cause) if present below. + int disc_cause_set = 0; int disc_cause = TERM_NAS_REQUEST; char const *disc_reason = "Closed (Received CDN)."; @@ -2296,25 +2304,41 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) case 1: // result code { uint16_t rescode = ntohs(*(uint16_t *) b); - const char* resdesc = "(unknown)"; + char const *resdesc = "(unknown)"; + char const *errdesc = NULL; + int cause = 0; + if (message == 4) { /* StopCCN */ resdesc = l2tp_stopccn_result_code(rescode); + cause = TERM_LOST_SERVICE; } else if (message == 14) { /* CDN */ resdesc = l2tp_cdn_result_code(rescode); + if (rescode == 1) + cause = TERM_LOST_CARRIER; + else + cause = TERM_ADMIN_RESET; } LOG(4, s, t, " Result Code %u: %s\n", rescode, resdesc); if (n >= 4) { uint16_t errcode = ntohs(*(uint16_t *)(b + 2)); - LOG(4, s, t, " Error Code %u: %s\n", errcode, l2tp_error_code(errcode)); + errdesc = l2tp_error_code(errcode); + LOG(4, s, t, " Error Code %u: %s\n", errcode, errdesc); } if (n > 4) LOG(4, s, t, " Error String: %.*s\n", n-4, b+4); + if (cause && disc_cause_set < mtype) // take cause from attrib 46 in preference + { + disc_cause_set = mtype; + disc_reason = errdesc ? errdesc : resdesc; + disc_cause = cause; + } + break; } break; @@ -2506,6 +2530,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) "(code=%u, proto=%04X, dir=%u, msg=\"%.*s\")\n", code, proto, dir, n - 5, b + 5); + disc_cause_set = mtype; + switch (code) { case 1: // admin disconnect @@ -3027,37 +3053,6 @@ static void regular_cleanups(double period) continue; } - // check for timed out sessions - if (session[s].timeout) - { - bundleidt bid = session[s].bundle; - if (bid) - { - clockt curr_time = time_now; - if (curr_time - bundle[bid].last_check >= 1) - { - bundle[bid].online_time += (curr_time-bundle[bid].last_check)*bundle[bid].num_of_links; - bundle[bid].last_check = curr_time; - if (bundle[bid].online_time >= session[s].timeout) - { - int ses; - for (ses = bundle[bid].num_of_links - 1; ses >= 0; ses--) - { - sessionshutdown(bundle[bid].members[ses], "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); - s_actions++; - continue; - } - } - } - } - else if (session[s].timeout <= time_now - session[s].opened) - { - sessionshutdown(s, "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); - s_actions++; - continue; - } - } - // PPP timeouts if (sess_local[s].lcp.restart <= time_now) { @@ -3200,12 +3195,33 @@ static void regular_cleanups(double period) } // Drop sessions who have reached session_timeout seconds - if (session[s].session_timeout && (time_now - session[s].opened >= session[s].session_timeout)) + if (session[s].session_timeout) { - sessionshutdown(s, "Session Timeout Reached", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); - STAT(session_timeout); - s_actions++; - continue; + bundleidt bid = session[s].bundle; + if (bid) + { + if (time_now - bundle[bid].last_check >= 1) + { + bundle[bid].online_time += (time_now - bundle[bid].last_check) * bundle[bid].num_of_links; + bundle[bid].last_check = time_now; + if (bundle[bid].online_time >= session[s].session_timeout) + { + int ses; + for (ses = bundle[bid].num_of_links - 1; ses >= 0; ses--) + { + sessionshutdown(bundle[bid].members[ses], "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); + s_actions++; + continue; + } + } + } + } + else if (time_now - session[s].opened >= session[s].session_timeout) + { + sessionshutdown(s, "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); + s_actions++; + continue; + } } // Drop sessions who have reached idle_timeout seconds