X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/10b6ddcfc1600dfdfe2390350970ff399939f1d7..cbb16f7b0b312220880c756aa8fbe4eeb300267a:/l2tpns.c?ds=sidebyside diff --git a/l2tpns.c b/l2tpns.c index 1489318..e616b0d 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.107 2005/06/02 11:32:30 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.134 2005/09/16 05:30:30 bodea Exp $"; #include #include @@ -52,7 +52,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.107 2005/06/02 11:32:30 bodea Exp #ifdef BGP #include "bgp.h" -#endif /* BGP */ +#endif // Globals configt *config = NULL; // all configuration @@ -60,19 +60,25 @@ int tunfd = -1; // tun interface file handle. (network device) int udpfd = -1; // UDP file handle int controlfd = -1; // Control signal handle int clifd = -1; // Socket listening for CLI connections. +int daefd = -1; // Socket listening for DAE connections. int snoopfd = -1; // UDP file handle for sending out intercept data int *radfds = NULL; // RADIUS requests file handles int ifrfd = -1; // File descriptor for routing, etc int ifr6fd = -1; // File descriptor for IPv6 routing, etc -static int rand_fd = -1; // Random data source +int rand_fd = -1; // Random data source +int cluster_sockfd = -1; // Intra-cluster communications socket. +int epollfd = -1; // event polling time_t basetime = 0; // base clock char hostname[1000] = ""; // us. static int tunidx; // ifr_ifindex of tun device static int syslog_log = 0; // are we logging to syslog static FILE *log_stream = 0; // file handle for direct logging (i.e. direct into file, not via syslog). -extern int cluster_sockfd; // Intra-cluster communications socket. uint32_t last_id = 0; // Unique ID for radius accounting +// calculated from config->l2tp_mtu +uint16_t MRU = 0; // PPP MRU +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 @@ -102,7 +108,11 @@ config_descriptt config_values[] = { CONFIG("log_file", log_filename, STRING), CONFIG("pid_file", pid_file, STRING), CONFIG("random_device", random_device, STRING), - CONFIG("l2tp_secret", l2tpsecret, STRING), + CONFIG("l2tp_secret", l2tp_secret, STRING), + CONFIG("l2tp_mtu", l2tp_mtu, INT), + CONFIG("ppp_restart_time", ppp_restart_time, INT), + CONFIG("ppp_max_configure", ppp_max_configure, INT), + CONFIG("ppp_max_failure", ppp_max_failure, INT), CONFIG("primary_dns", default_dns1, IPv4), CONFIG("secondary_dns", default_dns2, IPv4), CONFIG("primary_radius", radiusserver[0], IPv4), @@ -113,6 +123,7 @@ config_descriptt config_values[] = { CONFIG("radius_interim", radius_interim, INT), CONFIG("radius_secret", radiussecret, STRING), CONFIG("radius_authtypes", radius_authtypes_s, STRING), + CONFIG("radius_dae_port", radius_dae_port, SHORT), CONFIG("allow_duplicate_users", allow_duplicate_users, BOOL), CONFIG("bind_address", bind_address, IPv4), CONFIG("peer_address", peer_address, IPv4), @@ -129,6 +140,7 @@ config_descriptt config_values[] = { CONFIG("packet_limit", max_packets, INT), CONFIG("cluster_address", cluster_address, IPv4), CONFIG("cluster_interface", cluster_interface, STRING), + CONFIG("cluster_mcast_ttl", cluster_mcast_ttl, INT), CONFIG("cluster_hb_interval", cluster_hb_interval, INT), CONFIG("cluster_hb_timeout", cluster_hb_timeout, INT), CONFIG("cluster_master_min_adv", cluster_master_min_adv, INT), @@ -147,6 +159,7 @@ static char *plugin_functions[] = { "plugin_kill_session", "plugin_control", "plugin_radius_response", + "plugin_radius_reset", "plugin_become_master", "plugin_new_session_master", }; @@ -162,7 +175,7 @@ sessiont *session = NULL; // Array of session structures. sessionlocalt *sess_local = NULL; // Array of local per-session counters. radiust *radius = NULL; // Array of radius structures. ippoolt *ip_address_pool = NULL; // Array of dynamic IP addresses. -ip_filtert *ip_filters = NULL; // Array of named filters. +ip_filtert *ip_filters = NULL; // Array of named filters. static controlt *controlfree = 0; struct Tstats *_statistics = NULL; #ifdef RINGBUFFER @@ -176,10 +189,9 @@ static void free_ip_address(sessionidt s); static void dump_acct_info(int all); static void sighup_handler(int sig); static void sigalrm_handler(int sig); -static void sigterm_handler(int sig); -static void sigquit_handler(int sig); +static void shutdown_handler(int sig); static void sigchild_handler(int sig); -static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_length, char **challenge_response); +static void build_chap_response(uint8_t *challenge, uint8_t id, uint16_t challenge_length, uint8_t **challenge_response); static void update_config(void); static void read_config_file(void); static void initplugins(void); @@ -193,6 +205,10 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec // on slaves, alow BGP to withdraw cleanly before exiting #define QUIT_DELAY 5 +// quit actions (master) +#define QUIT_FAILOVER 1 // SIGTERM: exit when all control messages have been acked (for cluster failover) +#define QUIT_SHUTDOWN 2 // SIGQUIT: shutdown sessions/tunnels, reject new connections + // return internal time (10ths since process startup), set f if given static clockt now(double *f) { @@ -251,10 +267,10 @@ void _log(int level, sessionidt s, tunnelidt t, const char *format, ...) va_end(ap); } -void _log_hex(int level, const char *title, const char *data, int maxsize) +void _log_hex(int level, const char *title, const uint8_t *data, int maxsize) { int i, j; - const uint8_t *d = (const uint8_t *) data; + const uint8_t *d = data; if (config->debug < level) return; @@ -322,7 +338,8 @@ static void initrandom(char *source) return; // close previous source, if any - if (rand_fd >= 0) close(rand_fd); + if (rand_fd >= 0) + close(rand_fd); rand_fd = -1; @@ -339,13 +356,6 @@ static void initrandom(char *source) path, strerror(errno)); } } - - // no source: seed prng - { - unsigned seed = time_now ^ getpid(); - LOG(4, 0, 0, "Seeding the pseudo random generator: %u\n", seed); - srand(seed); - } } // fill buffer with random data @@ -366,7 +376,7 @@ void random_data(uint8_t *buf, int len) strerror(errno)); // fall back to rand() - initrandom(0); + initrandom(NULL); } n = 0; @@ -550,7 +560,7 @@ static void inittun(void) tunidx = ifr.ifr_ifindex; // Only setup IPv6 on the tun device if we have a configured prefix - if (config->ipv6_prefix.s6_addr[0] > 0) { + if (config->ipv6_prefix.s6_addr[0]) { ifr6fd = socket(PF_INET6, SOCK_DGRAM, 0); // Link local address is FE80::1 @@ -580,7 +590,7 @@ static void inittun(void) } } -// set up UDP port +// set up UDP ports static void initudp(void) { int on = 1; @@ -602,7 +612,6 @@ static void initudp(void) LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno)); exit(1); } - snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Control memset(&addr, 0, sizeof(addr)); @@ -615,6 +624,21 @@ static void initudp(void) LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno)); exit(1); } + + // Dynamic Authorization Extensions to RADIUS + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(config->radius_dae_port); + daefd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + setsockopt(daefd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (bind(daefd, (void *) &addr, sizeof(addr)) < 0) + { + LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno)); + exit(1); + } + + // Intercept + snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); } // @@ -687,8 +711,11 @@ sessionidt sessionbyipv6(struct in6_addr ip) CSTAT(sessionbyipv6); if (!memcmp(&config->ipv6_prefix, &ip, 8) || - (ip.s6_addr[0] == 0xFE && ip.s6_addr[1] == 0x80 && - (ip.s6_addr16[1] == ip.s6_addr16[2] == ip.s6_addr16[3] == 0))) { + (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)) { s = lookup_ipmap(*(in_addr_t *) &ip.s6_addr[8]); } else { s = lookup_ipv6map(ip); @@ -956,16 +983,60 @@ int tun_write(uint8_t * data, int size) return write(tunfd, data, size); } +// adjust tcp mss to avoid fragmentation (called only for tcp packets with syn set) +void adjust_tcp_mss(sessionidt s, tunnelidt t, uint8_t *buf, int len, uint8_t *tcp) +{ + int d = (tcp[12] >> 4) * 4; + uint8_t *mss = 0; + uint8_t *data; + + if ((tcp[13] & 0x3f) & ~(TCP_FLAG_SYN|TCP_FLAG_ACK)) // only want SYN and SYN,ACK + return; + + if (tcp + d > buf + len) // short? + return; + + data = tcp + d; + tcp += 20; + + while (tcp < data) + { + if (*tcp == 2 && tcp[1] == 4) // mss option (2), length 4 + { + mss = tcp + 2; + if (mss + 2 > data) return; // short? + break; + } + + if (*tcp == 0) return; // end of options + if (*tcp == 1 || !tcp[1]) // no op (one byte), or no length (prevent loop) + tcp++; + else + tcp += tcp[1]; // skip over option + } + + if (!mss) return; // not found + if (ntohs(*(uint16_t *) mss) <= MSS) return; // mss OK + + LOG(5, s, t, "TCP: %s:%u -> %s:%u SYN%s, adjusted mss from %u to %u\n", + fmtaddr(*(in_addr_t *)(buf + 12), 0), ntohs(*(uint16_t *)tcp), + fmtaddr(*(in_addr_t *)(buf + 16), 1), ntohs(*(uint16_t *)(tcp + 2)), + (tcp[13] & TCP_FLAG_ACK) ? ",ACK" : "", + ntohs(*(uint16_t *) mss), MSS); + + // FIXME +} + // process outgoing (to tunnel) IP // -static void processipout(uint8_t * buf, int len) +static void processipout(uint8_t *buf, int len) { sessionidt s; sessiont *sp; tunnelidt t; in_addr_t ip; - char *data = buf; // Keep a copy of the originals. + uint8_t *data = buf; // Keep a copy of the originals. int size = len; uint8_t b[MAXETHER + 20]; @@ -1012,7 +1083,8 @@ static void processipout(uint8_t * buf, int len) if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second. { LOG(4, 0, 0, "IP: Sending ICMP host unreachable to %s\n", fmtaddr(*(in_addr_t *)(buf + 12), 0)); - host_unreachable(*(in_addr_t *)(buf + 12), *(uint16_t *)(buf + 4), ip, buf, (len < 64) ? 64 : len); + host_unreachable(*(in_addr_t *)(buf + 12), *(uint16_t *)(buf + 4), + config->bind_address ? config->bind_address : my_address, buf, len); } return; } @@ -1062,6 +1134,14 @@ static void processipout(uint8_t * buf, int len) if (session[s].filter_out && !ip_filter(buf, len, session[s].filter_out - 1)) return; + // adjust MSS on SYN and SYN,ACK packets with options + if ((ntohs(*(uint16_t *) (buf + 6)) & 0x1fff) == 0 && buf[9] == IPPROTO_TCP) // first tcp fragment + { + int ihl = (buf[0] & 0xf) * 4; // length of IP header + if (len >= ihl + 20 && (buf[ihl + 13] & TCP_FLAG_SYN) && ((buf[ihl + 12] >> 4) > 5)) + adjust_tcp_mss(s, t, buf, len, buf + ihl); + } + if (sp->tbf_out) { // Are we throttling this session? @@ -1082,7 +1162,7 @@ static void processipout(uint8_t * buf, int len) // Add on L2TP header { - uint8_t *p = makeppp(b, sizeof(b), buf, len, t, s, PPPIP); + uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP); if (!p) return; tunnelsend(b, len + (p-b), t); // send it... } @@ -1110,7 +1190,7 @@ static void processipv6out(uint8_t * buf, int len) in_addr_t ip; struct in6_addr ip6; - char *data = buf; // Keep a copy of the originals. + uint8_t *data = buf; // Keep a copy of the originals. int size = len; uint8_t b[MAXETHER + 20]; @@ -1193,7 +1273,7 @@ static void processipv6out(uint8_t * buf, int len) // Add on L2TP header { - uint8_t *p = makeppp(b, sizeof(b), buf, len, t, s, PPPIPV6); + uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIPV6); if (!p) return; tunnelsend(b, len + (p-b), t); // send it... } @@ -1245,7 +1325,7 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) // Add on L2TP header { - uint8_t *p = makeppp(b, sizeof(b), buf, len, t, s, PPPIP); + uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP); if (!p) return; tunnelsend(b, len + (p-b), t); // send it... } @@ -1297,7 +1377,7 @@ static void controls(controlt * c, uint16_t avp, char *val, uint8_t m) } // add a binary AVP -static void controlb(controlt * c, uint16_t avp, char *val, unsigned int len, uint8_t m) +static void controlb(controlt * c, uint16_t avp, uint8_t *val, unsigned int len, uint8_t m) { uint16_t l = ((m ? 0x8000 : 0) + len + 6); *(uint16_t *) (c->buf + c->length + 0) = htons(l); @@ -1344,7 +1424,7 @@ static void controlnull(tunnelidt t) } // add a control message to a tunnel, and send if within window -static void controladd(controlt * c, tunnelidt t, sessionidt far) +static void controladd(controlt *c, sessionidt far, tunnelidt t) { *(uint16_t *) (c->buf + 2) = htons(c->length); // length *(uint16_t *) (c->buf + 4) = htons(tunnel[t].far); // tunnel @@ -1416,7 +1496,7 @@ void throttle_session(sessionidt s, int rate_in, int rate_out) } // add/remove filters from session (-1 = no change) -static void filter_session(sessionidt s, int filter_in, int filter_out) +void filter_session(sessionidt s, int filter_in, int filter_out) { if (!session[s].opened) return; // No-one home. @@ -1477,10 +1557,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) if (session[s].ip && !walled_garden && !session[s].die) { // RADIUS Stop message - uint16_t r = sess_local[s].radius; - if (!r) - r = radiusnew(s); - + uint16_t r = radiusnew(s); if (r) { // stop, if not already trying @@ -1518,7 +1595,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) free_ip_address(s); // unroute IPv6, if setup - if (session[s].flags & SF_IPV6_ROUTED) + if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen) route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0); } @@ -1530,7 +1607,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) controlt *c = controlnew(14); // sending CDN if (error) { - char buf[4]; + uint8_t buf[4]; *(uint16_t *) buf = htons(result); *(uint16_t *) (buf+2) = htons(error); controlb(c, 1, buf, 4, 1); @@ -1539,7 +1616,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) control16(c, 1, result, 1); control16(c, 14, s, 1); // assigned session (our end) - controladd(c, session[s].tunnel, session[s].far); // send the message + controladd(c, session[s].far, session[s].tunnel); // send the message } if (!session[s].die) @@ -1549,78 +1626,68 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error) if (session[s].filter_in) ip_filters[session[s].filter_in - 1].used--; if (session[s].filter_out) ip_filters[session[s].filter_out - 1].used--; + // clear PPP state + memset(&session[s].ppp, 0, sizeof(session[s].ppp)); + sess_local[s].lcp.restart = 0; + sess_local[s].ipcp.restart = 0; + sess_local[s].ipv6cp.restart = 0; + sess_local[s].ccp.restart = 0; + cluster_send_session(s); } -void sendipcp(tunnelidt t, sessionidt s) +void sendipcp(sessionidt s, tunnelidt t) { - uint8_t buf[MAXCONTROL]; - uint16_t r = sess_local[s].radius; + uint8_t buf[MAXETHER]; uint8_t *q; CSTAT(sendipcp); + LOG(3, s, t, "IPCP: send ConfigReq\n"); - if (!r) - r = radiusnew(s); - - if (!r) - { - sessionshutdown(s, "No free RADIUS sessions for IPCP", 3, 0); - return; - } - - if (radius[r].state != RADIUSIPCP) - { - radius[r].state = RADIUSIPCP; - radius[r].try = 0; - } - - radius[r].retry = backoff(radius[r].try++); - if (radius[r].try > 10) + if (!session[s].unique_id) { - radiusclear(r, s); // Clear radius session. - sessionshutdown(s, "No reply to IPCP.", 3, 0); - return; + if (!++last_id) ++last_id; // skip zero + session[s].unique_id = last_id; } - q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPCP); + q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPIPCP); if (!q) return; *q = ConfigReq; - q[1] = r >> RADIUS_SHIFT; // ID, dont care, we only send one type of request - *(uint16_t *) (q + 2) = htons(10); - q[4] = 3; - q[5] = 6; + q[1] = session[s].unique_id & 0xf; // ID, dont care, we only send one type of request + *(uint16_t *) (q + 2) = htons(10); // packet length + q[4] = 3; // ip address option + q[5] = 6; // option length *(in_addr_t *) (q + 6) = config->peer_address ? config->peer_address : config->bind_address ? config->bind_address : my_address; // send my IP tunnelsend(buf, 10 + (q - buf), t); // send it - session[s].flags &= ~SF_IPCP_ACKED; // Clear flag. - - // If we have an IPv6 prefix length configured, assume we should - // try to negotiate an IPv6 session as well. Unless we've had a - // (N)ACK for IPV6CP. - if (config->ipv6_prefix.s6_addr[0] > 0 && - !(session[s].flags & SF_IPV6CP_ACKED) && - !(session[s].flags & SF_IPV6_NACKED)) - { - q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPV6CP); - if (!q) return; - - *q = ConfigReq; - q[1] = r >> RADIUS_SHIFT; // ID, don't care, we - // only send one type - // of request - *(uint16_t *) (q + 2) = htons(14); - q[4] = 1; - q[5] = 10; - *(uint32_t *) (q + 6) = 0; // We'll be prefix::1 - *(uint32_t *) (q + 10) = 0; - q[13] = 1; - - tunnelsend(buf, 14 + (q - buf), t); // send it - } +} + +void sendipv6cp(sessionidt s, tunnelidt t) +{ + uint8_t buf[MAXETHER]; + uint8_t *q; + + CSTAT(sendipv6cp); + LOG(3, s, t, "IPV6CP: send ConfigReq\n"); + + q = makeppp(buf, sizeof(buf), 0, 0, s, t, PPPIPV6CP); + if (!q) return; + + *q = ConfigReq; + q[1] = session[s].unique_id & 0xf; // ID, don't care, we + // only send one type + // of request + *(uint16_t *) (q + 2) = htons(14); + q[4] = 1; // interface identifier option + q[5] = 10; // option length + *(uint32_t *) (q + 6) = 0; // We'll be prefix::1 + *(uint32_t *) (q + 10) = 0; + q[13] = 1; + + tunnelsend(buf, 14 + (q - buf), t); // send it } static void sessionclear(sessionidt s) @@ -1715,7 +1782,7 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha // close session for (s = 1; s <= config->cluster_highest_sessionid ; ++s) if (session[s].tunnel == t) - sessionshutdown(s, reason, 3, 0); + sessionshutdown(s, reason, 0, 0); tunnel[t].state = TUNNELDIE; tunnel[t].die = TIME + 700; // Clean up in 70 seconds @@ -1726,7 +1793,7 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha controlt *c = controlnew(4); // sending StopCCN if (error) { - char buf[64]; + uint8_t buf[64]; int l = 4; *(uint16_t *) buf = htons(result); *(uint16_t *) (buf+2) = htons(error); @@ -1746,14 +1813,14 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha control16(c, 1, result, 1); control16(c, 9, t, 1); // assigned tunnel (our end) - controladd(c, t, 0); // send the message + controladd(c, 0, t); // send the message } } // read and process packet on tunnel (UDP) -void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) +void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { - char *chapresponse = NULL; + uint8_t *chapresponse = NULL; uint16_t l = len, t = 0, s = 0, ns = 0, nr = 0; uint8_t *p = buf + 2; @@ -1817,12 +1884,16 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) return; } l -= (p - buf); + + // used to time out old tunnels + if (t && tunnel[t].state == TUNNELOPEN) + tunnel[t].lastrec = time_now; + if (*buf & 0x80) { // control uint16_t message = 0xFFFF; // message type uint8_t fatal = 0; uint8_t mandatory = 0; - uint8_t authtype = 0; // proxy auth type uint16_t asession = 0; // assigned session uint32_t amagic = 0; // magic number uint8_t aflags = 0; // flags from last LCF @@ -1905,9 +1976,6 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) return; } - // This is used to time out old tunnels - tunnel[t].lastrec = time_now; - // check sequence of this message { int skip = tunnel[t].window; // track how many in-window packets are still in queue @@ -1997,7 +2065,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) uint16_t orig_len; // handle hidden AVPs - if (!*config->l2tpsecret) + if (!*config->l2tp_secret) { LOG(1, s, t, "Hidden AVP requested, but no L2TP secret.\n"); fatal = flags; @@ -2025,8 +2093,6 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) continue; } - LOG(4, s, t, "Hidden AVP\n"); - // Unhide the AVP unhide_value(b, n, mtype, session[s].random_vector, session[s].random_vector_length); @@ -2047,13 +2113,15 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) n = orig_len; } - LOG(4, s, t, " AVP %d (%s) len %d\n", mtype, avp_name(mtype), n); + LOG(4, s, t, " AVP %d (%s) len %d%s%s\n", mtype, l2tp_avp_name(mtype), n, + flags & 0x40 ? ", hidden" : "", flags & 0x80 ? ", mandatory" : ""); + switch (mtype) { case 0: // message type message = ntohs(*(uint16_t *) b); mandatory = flags & 0x80; - LOG(4, s, t, " Message type = %d (%s)\n", *b, l2tp_message_type(message)); + LOG(4, s, t, " Message type = %d (%s)\n", *b, l2tp_code(message)); break; case 1: // result code { @@ -2061,18 +2129,18 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) const char* resdesc = "(unknown)"; if (message == 4) { /* StopCCN */ - resdesc = stopccn_result_code(rescode); + resdesc = l2tp_stopccn_result_code(rescode); } else if (message == 14) { /* CDN */ - resdesc = cdn_result_code(rescode); + resdesc = l2tp_cdn_result_code(rescode); } LOG(4, s, t, " Result Code %d: %s\n", rescode, resdesc); if (n >= 4) { uint16_t errcode = ntohs(*(uint16_t *)(b + 2)); - LOG(4, s, t, " Error Code %d: %s\n", errcode, error_code(errcode)); + LOG(4, s, t, " Error Code %d: %s\n", errcode, l2tp_error_code(errcode)); } if (n > 4) LOG(4, s, t, " Error String: %.*s\n", n-4, b+4); @@ -2206,12 +2274,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) case 29: // Proxy Authentication Type { uint16_t atype = ntohs(*(uint16_t *)b); - LOG(4, s, t, " Proxy Auth Type %d (%s)\n", atype, auth_type(atype)); - if (atype == 2) - authtype = AUTHCHAP; - else if (atype == 3) - authtype = AUTHPAP; - + LOG(4, s, t, " Proxy Auth Type %d (%s)\n", atype, ppp_auth_type(atype)); break; } case 30: // Proxy Authentication Name @@ -2226,16 +2289,12 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) case 31: // Proxy Authentication Challenge { LOG(4, s, t, " Proxy Auth Challenge\n"); - if (sess_local[s].radius) - memcpy(radius[sess_local[s].radius].auth, b, 16); break; } case 32: // Proxy Authentication ID { uint16_t authid = ntohs(*(uint16_t *)(b)); LOG(4, s, t, " Proxy Auth ID (%d)\n", authid); - if (sess_local[s].radius) - radius[sess_local[s].radius].id = authid; break; } case 33: // Proxy Authentication Response @@ -2248,10 +2307,6 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) { if (*p == 5 && p[1] == 6) // Magic-Number amagic = ntohl(*(uint32_t *) (p + 2)); - else if (*p == 3 && p[1] == 4 && *(uint16_t *) (p + 2) == htons(PPPPAP)) // Authentication-Protocol (PAP) - authtype = AUTHPAP; - else if (*p == 3 && p[1] == 5 && *(uint16_t *) (p + 2) == htons(PPPCHAP) && p[4] == 5) // Authentication-Protocol (CHAP) - authtype = AUTHCHAP; else if (*p == 7) // Protocol-Field-Compression aflags |= SESSIONPFC; else if (*p == 8) // Address-and-Control-Field-Compression @@ -2269,6 +2324,8 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) case 36: // Random Vector LOG(4, s, t, " Random Vector received. Enabled AVP Hiding.\n"); memset(session[s].random_vector, 0, sizeof(session[s].random_vector)); + if (n > sizeof(session[s].random_vector)) + n = sizeof(session[s].random_vector); memcpy(session[s].random_vector, b, n); session[s].random_vector_length = n; break; @@ -2291,16 +2348,21 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) switch (message) { case 1: // SCCRQ - Start Control Connection Request + tunnel[t].state = TUNNELOPENING; + if (main_quit != QUIT_SHUTDOWN) { controlt *c = controlnew(2); // sending SCCRP control16(c, 2, version, 1); // protocol version control32(c, 3, 3, 1); // framing - controls(c, 7, tunnel[t].hostname, 1); // host name (TBA) + controls(c, 7, hostname, 1); // host name if (chapresponse) controlb(c, 13, chapresponse, 16, 1); // Challenge response control16(c, 9, t, 1); // assigned tunnel - controladd(c, t, 0); // send the resply + controladd(c, 0, t); // send the resply + } + else + { + tunnelshutdown(t, "Shutting down", 6, 0, 0); } - tunnel[t].state = TUNNELOPENING; break; case 2: // SCCRP tunnel[t].state = TUNNELOPEN; @@ -2326,9 +2388,9 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) // TBA break; case 10: // ICRQ - if (sessionfree) + if (sessionfree && main_quit != QUIT_SHUTDOWN) { - uint16_t r; + controlt *c = controlnew(11); // ICRP s = sessionfree; sessionfree = session[s].next; @@ -2337,39 +2399,36 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) if (s > config->cluster_highest_sessionid) config->cluster_highest_sessionid = s; - // make a RADIUS session - if ((r = radiusnew(s))) - { - controlt *c = controlnew(11); // sending ICRP - session[s].opened = time_now; - session[s].tunnel = t; - session[s].far = asession; - session[s].last_packet = time_now; - LOG(3, s, t, "New session (%d/%d)\n", tunnel[t].far, session[s].far); - control16(c, 14, s, 1); // assigned session - controladd(c, t, asession); // send the reply - - strncpy(radius[r].calling, calling, sizeof(radius[r].calling) - 1); - strncpy(session[s].called, called, sizeof(session[s].called) - 1); - strncpy(session[s].calling, calling, sizeof(session[s].calling) - 1); - STAT(session_created); - break; - } + session[s].opened = time_now; + session[s].tunnel = t; + session[s].far = asession; + session[s].last_packet = time_now; + LOG(3, s, t, "New session (%d/%d)\n", tunnel[t].far, session[s].far); + control16(c, 14, s, 1); // assigned session + controladd(c, asession, t); // send the reply + strncpy(session[s].called, called, sizeof(session[s].called) - 1); + strncpy(session[s].calling, calling, sizeof(session[s].calling) - 1); - LOG(1, s, t, "No free RADIUS sessions for ICRQ\n"); - sessionclear(s); - } - else - { - STAT(session_overflow); - LOG(1, 0, t, "No free sessions\n"); + session[s].ppp.phase = Establish; + session[s].ppp.lcp = Starting; + + STAT(session_created); + break; } { controlt *c = controlnew(14); // CDN - control16(c, 1, 4, 1); // temporary lack of resources - controladd(c, session[s].tunnel, asession); // send the message + if (!sessionfree) + { + STAT(session_overflow); + LOG(1, 0, t, "No free sessions\n"); + control16(c, 1, 4, 0); // temporary lack of resources + } + else + control16(c, 1, 2, 7); // shutting down, try another + + controladd(c, asession, t); // send the message } return; case 11: // ICRP @@ -2379,14 +2438,18 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) if (amagic == 0) amagic = time_now; session[s].magic = amagic; // set magic number session[s].l2tp_flags = aflags; // set flags received - LOG(3, s, t, "Magic %X Flags %X\n", amagic, aflags); + session[s].mru = PPPMTU; // default controlnull(t); // ack - // proxy authentication type is not supported - if (!(config->radius_authtypes & authtype)) - authtype = config->radius_authprefer; // start LCP - sendlcp(t, s, authtype); + sess_local[s].lcp.restart = time_now + config->ppp_restart_time; + sess_local[s].lcp.conf_sent = 1; + sess_local[s].lcp.nak_sent = 0; + sess_local[s].lcp_authtype = config->radius_authprefer; + sess_local[s].ppp_mru = MRU; + session[s].ppp.lcp = RequestSent; + sendlcp(s, t); + break; case 14: // CDN controlnull(t); // ack @@ -2413,7 +2476,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) } else { // data - uint16_t prot; + uint16_t proto; LOG_HEX(5, "Receive Tunnel Data", p, l); if (l > 2 && p[0] == 0xFF && p[1] == 0x03) @@ -2429,12 +2492,12 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) } if (*p & 1) { - prot = *p++; + proto = *p++; l--; } else { - prot = ntohs(*(uint16_t *) p); + proto = ntohs(*(uint16_t *) p); p += 2; l -= 2; } @@ -2454,50 +2517,43 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) return; } - if (prot == PPPPAP) + if (proto == PPPPAP) { session[s].last_packet = time_now; if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; } - processpap(t, s, p, l); + processpap(s, t, p, l); } - else if (prot == PPPCHAP) + else if (proto == PPPCHAP) { session[s].last_packet = time_now; if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; } - processchap(t, s, p, l); + processchap(s, t, p, l); } - else if (prot == PPPLCP) + else if (proto == PPPLCP) { session[s].last_packet = time_now; if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; } - processlcp(t, s, p, l); + processlcp(s, t, p, l); } - else if (prot == PPPIPCP) + else if (proto == PPPIPCP) { session[s].last_packet = time_now; if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; } - processipcp(t, s, p, l); + processipcp(s, t, p, l); } - else if (prot == PPPIPV6CP) + else if (proto == PPPIPV6CP && config->ipv6_prefix.s6_addr[0]) { - if (config->ipv6_prefix.s6_addr[0] > 0) - { - session[s].last_packet = time_now; - if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; } - processipv6cp(t, s, p, l); - } - else - { - LOG(1, s, t, "IPv6 not configured; ignoring IPv6CP\n"); - } + session[s].last_packet = time_now; + if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; } + processipv6cp(s, t, p, l); } - else if (prot == PPPCCP) + else if (proto == PPPCCP) { session[s].last_packet = time_now; if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; } - processccp(t, s, p, l); + processccp(s, t, p, l); } - else if (prot == PPPIP) + else if (proto == PPPIP) { if (session[s].die) { @@ -2512,15 +2568,10 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) return; } - processipin(t, s, p, l); + processipin(s, t, p, l); } - else if (prot == PPPIPV6) + else if (proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0]) { - if (!config->ipv6_prefix.s6_addr[0] > 0) - { - LOG(1, s, t, "IPv6 not configured; yet received IPv6 packet. Ignoring.\n"); - return; - } if (session[s].die) { LOG(4, s, t, "Session %d is closing. Don't process PPP packets\n", s); @@ -2534,12 +2585,38 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) return; } - processipv6in(t, s, p, l); + processipv6in(s, t, p, l); + } + else if (session[s].ppp.lcp == Opened) + { + uint8_t buf[MAXETHER]; + uint8_t *q; + int mru = session[s].mru; + if (mru > sizeof(buf)) mru = sizeof(buf); + + l += 6; + if (l > mru) l = mru; + + q = makeppp(buf, sizeof(buf), 0, 0, s, t, proto); + if (!q) return; + + *q = CodeRej; + *(q + 1) = ++sess_local[s].lcp_ident; + *(uint16_t *)(q + 2) = l; + *(uint16_t *)(q + 4) = htons(proto); + memcpy(q + 6, p, l - 6); + + if (proto == PPPIPV6CP) + LOG(3, s, t, "LCP: send ProtocolRej (IPV6CP: not configured)\n"); + else + LOG(2, s, t, "LCP: sent ProtocolRej (0x%04X: unsupported)\n", proto); + + tunnelsend(buf, l + (q - buf), t); } else { - STAT(tunnel_rx_errors); - LOG(1, s, t, "Unknown PPP protocol %04X\n", prot); + LOG(2, s, t, "Unknown PPP protocol 0x%04X received in LCP %s state\n", + proto, ppp_state(session[s].ppp.lcp)); } } } @@ -2565,7 +2642,7 @@ static void processtun(uint8_t * buf, int len) if (*(uint16_t *) (buf + 2) == htons(PKTIP)) // IPv4 processipout(buf, len); else if (*(uint16_t *) (buf + 2) == htons(PKTIPV6) // IPV6 - && config->ipv6_prefix.s6_addr[0] > 0) + && config->ipv6_prefix.s6_addr[0]) processipv6out(buf, len); // Else discard. @@ -2650,10 +2727,10 @@ static void regular_cleanups(double period) } } // Send hello - if (tunnel[t].state == TUNNELOPEN && tunnel[t].lastrec < TIME + 600) + if (tunnel[t].state == TUNNELOPEN && (time_now - tunnel[t].lastrec) > 60) { controlt *c = controlnew(6); // sending HELLO - controladd(c, t, 0); // send the message + controladd(c, 0, t); // send the message LOG(3, 0, t, "Sending HELLO message\n"); t_actions++; } @@ -2707,12 +2784,123 @@ static void regular_cleanups(double period) continue; } - if (session[s].ip && !(session[s].flags & SF_IPCP_ACKED)) + // PPP timeouts + if (sess_local[s].lcp.restart <= time_now) { - // IPCP has not completed yet. Resend - LOG(3, s, session[s].tunnel, "No ACK for initial IPCP ConfigReq... resending\n"); - sendipcp(session[s].tunnel, s); - s_actions++; + int next_state = session[s].ppp.lcp; + switch (session[s].ppp.lcp) + { + case RequestSent: + case AckReceived: + next_state = RequestSent; + + case AckSent: + if (sess_local[s].lcp.conf_sent < config->ppp_max_configure) + { + LOG(3, s, session[s].tunnel, "No ACK for LCP ConfigReq... resending\n"); + sess_local[s].lcp.restart = time_now + config->ppp_restart_time; + sess_local[s].lcp.conf_sent++; + sendlcp(s, session[s].tunnel); + change_state(s, lcp, next_state); + } + else + { + sessionshutdown(s, "No response to LCP ConfigReq.", 3, 0); + STAT(session_timeout); + } + + s_actions++; + } + + if (session[s].die) + continue; + } + + if (sess_local[s].ipcp.restart <= time_now) + { + int next_state = session[s].ppp.ipcp; + switch (session[s].ppp.ipcp) + { + case RequestSent: + case AckReceived: + next_state = RequestSent; + + case AckSent: + if (sess_local[s].ipcp.conf_sent < config->ppp_max_configure) + { + LOG(3, s, session[s].tunnel, "No ACK for IPCP ConfigReq... resending\n"); + sess_local[s].ipcp.restart = time_now + config->ppp_restart_time; + sess_local[s].ipcp.conf_sent++; + sendipcp(s, session[s].tunnel); + change_state(s, ipcp, next_state); + } + else + { + sessionshutdown(s, "No response to IPCP ConfigReq.", 3, 0); + STAT(session_timeout); + } + + s_actions++; + } + + if (session[s].die) + continue; + } + + if (sess_local[s].ipv6cp.restart <= time_now) + { + int next_state = session[s].ppp.ipv6cp; + switch (session[s].ppp.ipv6cp) + { + case RequestSent: + case AckReceived: + next_state = RequestSent; + + case AckSent: + if (sess_local[s].ipv6cp.conf_sent < config->ppp_max_configure) + { + LOG(3, s, session[s].tunnel, "No ACK for IPV6CP ConfigReq... resending\n"); + sess_local[s].ipv6cp.restart = time_now + config->ppp_restart_time; + sess_local[s].ipv6cp.conf_sent++; + sendipv6cp(s, session[s].tunnel); + change_state(s, ipv6cp, next_state); + } + else + { + LOG(3, s, session[s].tunnel, "No ACK for IPV6CP ConfigReq\n"); + change_state(s, ipv6cp, Stopped); + } + + s_actions++; + } + } + + if (sess_local[s].ccp.restart <= time_now) + { + int next_state = session[s].ppp.ccp; + switch (session[s].ppp.ccp) + { + case RequestSent: + case AckReceived: + next_state = RequestSent; + + case AckSent: + if (sess_local[s].ccp.conf_sent < config->ppp_max_configure) + { + LOG(3, s, session[s].tunnel, "No ACK for CCP ConfigReq... resending\n"); + sess_local[s].ccp.restart = time_now + config->ppp_restart_time; + sess_local[s].ccp.conf_sent++; + sendccp(s, session[s].tunnel); + change_state(s, ccp, next_state); + } + else + { + LOG(3, s, session[s].tunnel, "No ACK for CCP ConfigReq\n"); + change_state(s, ccp, Stopped); + } + + s_actions++; + } } // Drop sessions who have not responded within IDLE_TIMEOUT seconds @@ -2725,11 +2913,11 @@ static void regular_cleanups(double period) } // No data in ECHO_TIMEOUT seconds, send LCP ECHO - if (session[s].user[0] && (time_now - session[s].last_packet >= ECHO_TIMEOUT)) + if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= ECHO_TIMEOUT)) { - uint8_t b[MAXCONTROL] = {0}; + uint8_t b[MAXETHER]; - uint8_t *q = makeppp(b, sizeof(b), 0, 0, session[s].tunnel, s, PPPLCP); + uint8_t *q = makeppp(b, sizeof(b), 0, 0, s, session[s].tunnel, PPPLCP); if (!q) continue; *q = EchoReq; @@ -2823,7 +3011,8 @@ static void regular_cleanups(double period) && !sess_local[s].radius // RADIUS already in progress && time_now - sess_local[s].last_interim >= config->radius_interim) { - if (!(r = radiusnew(s))) + int rad = radiusnew(s); + if (!rad) { LOG(1, s, session[s].tunnel, "No free RADIUS sessions for Interim message\n"); STAT(radius_overflow); @@ -2833,7 +3022,7 @@ static void regular_cleanups(double period) LOG(3, s, session[s].tunnel, "Sending RADIUS Interim for %s (%u)\n", session[s].user, session[s].unique_id); - radiussend(r, RADIUSINTERIM); + radiussend(rad, RADIUSINTERIM); sess_local[s].last_interim = time_now; s_actions++; } @@ -2850,13 +3039,13 @@ static void regular_cleanups(double period) static int still_busy(void) { int i; - static time_t stopped_bgp = 0; static clockt last_talked = 0; static clockt start_busy_wait = 0; if (!config->cluster_iam_master) { #ifdef BGP + static time_t stopped_bgp = 0; if (bgp_configured) { if (!stopped_bgp) @@ -2883,6 +3072,22 @@ static int still_busy(void) return 0; } + if (main_quit == QUIT_SHUTDOWN) + { + static int dropped = 0; + if (!dropped) + { + int i; + + LOG(1, 0, 0, "Dropping sessions and tunnels\n"); + for (i = 1; i < MAXTUNNEL; i++) + if (tunnel[i].ip || tunnel[i].state) + tunnelshutdown(i, "L2TPNS Closing", 6, 0, 0); + + dropped = 1; + } + } + if (start_busy_wait == 0) start_busy_wait = TIME; @@ -2924,41 +3129,93 @@ static int still_busy(void) return 0; } -static fd_set readset; -static int readset_n = 0; +#ifdef HAVE_EPOLL +# include +#else +# define FAKE_EPOLL_IMPLEMENTATION /* include the functions */ +# include "fake_epoll.h" +#endif + +// the base set of fds polled: cli, cluster, tun, udp, control, dae +#define BASE_FDS 6 + +// additional polled fds +#ifdef BGP +# define EXTRA_FDS BGP_NUM_PEERS +#else +# define EXTRA_FDS 0 +#endif // main loop - gets packets on tun or udp and processes them static void mainloop(void) { int i; uint8_t buf[65536]; - struct timeval to; clockt next_cluster_ping = 0; // send initial ping immediately + struct epoll_event events[BASE_FDS + RADIUS_FDS + EXTRA_FDS]; + int maxevent = sizeof(events)/sizeof(*events); + + if ((epollfd = epoll_create(maxevent)) < 0) + { + LOG(0, 0, 0, "epoll_create failed: %s\n", strerror(errno)); + exit(1); + } - LOG(4, 0, 0, "Beginning of main loop. udpfd=%d, tunfd=%d, cluster_sockfd=%d, controlfd=%d\n", - udpfd, tunfd, cluster_sockfd, controlfd); - - FD_ZERO(&readset); - FD_SET(udpfd, &readset); - FD_SET(tunfd, &readset); - FD_SET(controlfd, &readset); - FD_SET(clifd, &readset); - if (cluster_sockfd) FD_SET(cluster_sockfd, &readset); - readset_n = udpfd; - if (tunfd > readset_n) readset_n = tunfd; - if (controlfd > readset_n) readset_n = controlfd; - if (clifd > readset_n) readset_n = clifd; - if (cluster_sockfd > readset_n) readset_n = cluster_sockfd; + LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d\n", + clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd); - while (!main_quit || still_busy()) + /* setup our fds to poll for input */ { - fd_set r; - int n = readset_n; + static struct event_data d[BASE_FDS]; + struct epoll_event e; + + e.events = EPOLLIN; + i = 0; + + d[i].type = FD_TYPE_CLI; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, clifd, &e); + + d[i].type = FD_TYPE_CLUSTER; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, cluster_sockfd, &e); + + d[i].type = FD_TYPE_TUN; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, tunfd, &e); + + d[i].type = FD_TYPE_UDP; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd, &e); + + d[i].type = FD_TYPE_CONTROL; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, controlfd, &e); + + d[i].type = FD_TYPE_DAE; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, daefd, &e); + } + #ifdef BGP - fd_set w; - int bgp_set[BGP_NUM_PEERS]; + signal(SIGPIPE, SIG_IGN); + bgp_setup(config->as_number); + if (config->bind_address) + bgp_add_route(config->bind_address, 0xffffffff); + + for (i = 0; i < BGP_NUM_PEERS; i++) + { + if (config->neighbour[i].name[0]) + bgp_start(&bgp_peers[i], config->neighbour[i].name, + config->neighbour[i].as, config->neighbour[i].keepalive, + config->neighbour[i].hold, 0); /* 0 = routing disabled */ + } #endif /* BGP */ + + while (!main_quit || still_busy()) + { int more = 0; + int n; if (config->reload_config) { @@ -2966,35 +3223,11 @@ static void mainloop(void) update_config(); } - memcpy(&r, &readset, sizeof(fd_set)); - to.tv_sec = 0; - to.tv_usec = 100000; // 1/10th of a second. - #ifdef BGP - FD_ZERO(&w); - for (i = 0; i < BGP_NUM_PEERS; i++) - { - bgp_set[i] = bgp_select_state(&bgp_peers[i]); - if (bgp_set[i] & 1) - { - FD_SET(bgp_peers[i].sock, &r); - if (bgp_peers[i].sock > n) - n = bgp_peers[i].sock; - } - - if (bgp_set[i] & 2) - { - FD_SET(bgp_peers[i].sock, &w); - if (bgp_peers[i].sock > n) - n = bgp_peers[i].sock; - } - } - - n = select(n + 1, &r, &w, 0, &to); -#else /* BGP */ - n = select(n + 1, &r, 0, 0, &to); + bgp_set_poll(); #endif /* BGP */ + n = epoll_wait(epollfd, events, maxevent, 100); // timeout 100ms (1/10th sec) STAT(select_called); TIME = now(NULL); @@ -3005,70 +3238,92 @@ static void mainloop(void) continue; LOG(0, 0, 0, "Error returned from select(): %s\n", strerror(errno)); - main_quit++; - break; + break; // exit } - else if (n) + + if (n) { struct sockaddr_in addr; - int alen, c, s; + socklen_t alen; + int c, s; + int udp_ready = 0; + int tun_ready = 0; + int cluster_ready = 0; int udp_pkts = 0; int tun_pkts = 0; int cluster_pkts = 0; +#ifdef BGP + uint32_t bgp_events[BGP_NUM_PEERS]; + memset(bgp_events, 0, sizeof(bgp_events)); +#endif /* BGP */ - // nsctl commands - if (FD_ISSET(controlfd, &r)) - { - alen = sizeof(addr); - processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen); - n--; - } - - // RADIUS responses - if (config->cluster_iam_master) + for (c = n, i = 0; i < c; i++) { - for (i = 0; i < config->num_radfds; i++) + struct event_data *d = events[i].data.ptr; + switch (d->type) + { + case FD_TYPE_CLI: // CLI connections { - if (FD_ISSET(radfds[i], &r)) + int cli; + + alen = sizeof(addr); + if ((cli = accept(clifd, (struct sockaddr *)&addr, &alen)) >= 0) { - processrad(buf, recv(radfds[i], buf, sizeof(buf), 0), i); - n--; + cli_do(cli); + close(cli); } - } - } + else + LOG(0, 0, 0, "accept error: %s\n", strerror(errno)); - // CLI connections - if (FD_ISSET(clifd, &r)) - { - int cli; - - alen = sizeof(addr); - if ((cli = accept(clifd, (struct sockaddr *)&addr, &alen)) >= 0) - { - cli_do(cli); - close(cli); + n--; + break; } - else - LOG(0, 0, 0, "accept error: %s\n", strerror(errno)); - n--; - } + // these are handled below, with multiple interleaved reads + case FD_TYPE_CLUSTER: cluster_ready++; break; + case FD_TYPE_TUN: tun_ready++; break; + case FD_TYPE_UDP: udp_ready++; break; + + case FD_TYPE_CONTROL: // nsctl commands + alen = sizeof(addr); + processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen); + n--; + break; + + case FD_TYPE_DAE: // DAE requests + alen = sizeof(addr); + processdae(buf, recvfrom(daefd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen); + n--; + break; + + case FD_TYPE_RADIUS: // RADIUS response + s = recv(radfds[d->index], buf, sizeof(buf), 0); + if (s >= 0 && config->cluster_iam_master) + processrad(buf, s, d->index); + + n--; + break; #ifdef BGP - for (i = 0; i < BGP_NUM_PEERS; i++) - { - int isr = bgp_set[i] ? FD_ISSET(bgp_peers[i].sock, &r) : 0; - int isw = bgp_set[i] ? FD_ISSET(bgp_peers[i].sock, &w) : 0; - bgp_process(&bgp_peers[i], isr, isw); - if (isr) n--; - if (isw) n--; + case FD_TYPE_BGP: + bgp_events[d->index] = events[i].events; + n--; + break; +#endif /* BGP */ + + default: + LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type); + } } + +#ifdef BGP + bgp_process(bgp_events); #endif /* BGP */ for (c = 0; n && c < config->multi_read_count; c++) { // L2TP - if (FD_ISSET(udpfd, &r)) + if (udp_ready) { alen = sizeof(addr); if ((s = recvfrom(udpfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0) @@ -3078,13 +3333,13 @@ static void mainloop(void) } else { - FD_CLR(udpfd, &r); + udp_ready = 0; n--; } } // incoming IP - if (FD_ISSET(tunfd, &r)) + if (tun_ready) { if ((s = read(tunfd, buf, sizeof(buf))) > 0) { @@ -3093,13 +3348,13 @@ static void mainloop(void) } else { - FD_CLR(tunfd, &r); + tun_ready = 0; n--; } } // cluster - if (FD_ISSET(cluster_sockfd, &r)) + if (cluster_ready) { alen = sizeof(addr); if ((s = recvfrom(cluster_sockfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen)) > 0) @@ -3109,7 +3364,7 @@ static void mainloop(void) } else { - FD_CLR(cluster_sockfd, &r); + cluster_ready = 0; n--; } } @@ -3129,7 +3384,7 @@ static void mainloop(void) } // Runs on every machine (master and slaves). - if (cluster_sockfd && next_cluster_ping <= TIME) + if (next_cluster_ping <= TIME) { // Check to see which of the cluster is still alive.. @@ -3211,7 +3466,7 @@ static void mainloop(void) // // Important!!! We MUST not process any packets past this point! - LOG(1, 0, 0, "Clean shutdown complete\n"); + LOG(1, 0, 0, "Shutdown complete\n"); } static void stripdomain(char *host) @@ -3296,7 +3551,11 @@ static void initdata(int optdebug, char *optconfig) config->debug = optdebug; config->num_tbfs = MAXTBFS; config->rl_rate = 28; // 28kbps + config->cluster_mcast_ttl = 1; config->cluster_master_min_adv = 1; + config->ppp_restart_time = 3; + config->ppp_max_configure = 10; + config->ppp_max_failure = 5; strcpy(config->random_device, RANDOMDEVICE); log_stream = stderr; @@ -3664,7 +3923,7 @@ static void initippool() LOG(1, 0, 0, "IP address pool is %d addresses\n", ip_pool_size - 1); } -void snoop_send_packet(char *packet, uint16_t size, in_addr_t destination, uint16_t port) +void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, uint16_t port) { struct sockaddr_in snoop_addr = {0}; if (!destination || !port || snoopfd <= 0 || size <= 0 || !packet) @@ -3707,10 +3966,12 @@ static int dump_session(FILE **f, sessiont *s) LOG(3, 0, 0, "Dumping accounting information to %s\n", filename); fprintf(*f, "# dslwatch.pl dump file V1.01\n" "# host: %s\n" + "# endpoint: %s\n" "# time: %ld\n" "# uptime: %ld\n" "# format: username ip qos uptxoctets downrxoctets\n", hostname, + fmtaddr(config->bind_address ? config->bind_address : my_address, 0), now, now - basetime); } @@ -3851,19 +4112,6 @@ int main(int argc, char *argv[]) if (cluster_init() < 0) exit(1); -#ifdef BGP - signal(SIGPIPE, SIG_IGN); - bgp_setup(config->as_number); - bgp_add_route(config->bind_address, 0xffffffff); - for (i = 0; i < BGP_NUM_PEERS; i++) - { - if (config->neighbour[i].name[0]) - bgp_start(&bgp_peers[i], config->neighbour[i].name, - config->neighbour[i].as, config->neighbour[i].keepalive, - config->neighbour[i].hold, 0); /* 0 = routing disabled */ - } -#endif /* BGP */ - inittun(); LOG(1, 0, 0, "Set up on interface %s\n", config->tundevice); @@ -3871,11 +4119,18 @@ int main(int argc, char *argv[]) initrad(); initippool(); - signal(SIGHUP, sighup_handler); - signal(SIGTERM, sigterm_handler); - signal(SIGINT, sigterm_handler); - signal(SIGQUIT, sigquit_handler); + // seed prng + { + unsigned seed = time_now ^ getpid(); + LOG(4, 0, 0, "Seeding the pseudo random generator: %u\n", seed); + srand(seed); + } + + signal(SIGHUP, sighup_handler); signal(SIGCHLD, sigchild_handler); + signal(SIGTERM, shutdown_handler); + signal(SIGINT, shutdown_handler); + signal(SIGQUIT, shutdown_handler); // Prevent us from getting paged out if (config->lock_pages) @@ -3953,33 +4208,10 @@ static void sigalrm_handler(int sig) } -static void sigterm_handler(int sig) -{ - LOG(1, 0, 0, "Shutting down cleanly\n"); - main_quit++; -} - -static void sigquit_handler(int sig) +static void shutdown_handler(int sig) { - int i; - - LOG(1, 0, 0, "Shutting down without saving sessions\n"); - - if (config->cluster_iam_master) - { - for (i = 1; i < MAXSESSION; i++) - { - if (session[i].opened) - sessionkill(i, "L2TPNS Closing"); - } - for (i = 1; i < MAXTUNNEL; i++) - { - if (tunnel[i].ip || tunnel[i].state) - tunnelshutdown(i, "L2TPNS Closing", 6, 0, 0); - } - } - - main_quit++; + LOG(1, 0, 0, "Shutting down\n"); + main_quit = (sig == SIGQUIT) ? QUIT_SHUTDOWN : QUIT_FAILOVER; } static void sigchild_handler(int sig) @@ -3988,12 +4220,12 @@ static void sigchild_handler(int sig) ; } -static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_length, char **challenge_response) +static void build_chap_response(uint8_t *challenge, uint8_t id, uint16_t challenge_length, uint8_t **challenge_response) { MD5_CTX ctx; *challenge_response = NULL; - if (!*config->l2tpsecret) + if (!*config->l2tp_secret) { LOG(0, 0, 0, "LNS requested CHAP authentication, but no l2tp secret is defined\n"); return; @@ -4001,13 +4233,13 @@ static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_ LOG(4, 0, 0, " Building challenge response for CHAP request\n"); - *challenge_response = (char *)calloc(17, 1); + *challenge_response = calloc(17, 1); - MD5Init(&ctx); - MD5Update(&ctx, &id, 1); - MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret)); - MD5Update(&ctx, challenge, challenge_length); - MD5Final(*challenge_response, &ctx); + MD5_Init(&ctx); + MD5_Update(&ctx, &id, 1); + MD5_Update(&ctx, config->l2tp_secret, strlen(config->l2tp_secret)); + MD5_Update(&ctx, challenge, challenge_length); + MD5_Final(*challenge_response, &ctx); return; } @@ -4072,6 +4304,17 @@ static void update_config() setbuf(log_stream, NULL); } +#define L2TP_HDRS (20+8+6+4) // L2TP data encaptulation: ip + udp + l2tp (data) + ppp (inc hdlc) +#define TCP_HDRS (20+20) // TCP encapsulation: ip + tcp + + if (config->l2tp_mtu <= 0) config->l2tp_mtu = PPPMTU; + else if (config->l2tp_mtu < MINMTU) config->l2tp_mtu = MINMTU; + else if (config->l2tp_mtu > MAXMTU) config->l2tp_mtu = MAXMTU; + + // reset MRU/MSS globals + MRU = config->l2tp_mtu - L2TP_HDRS; + MSS = MRU - TCP_HDRS; + // Update radius config->numradiusservers = 0; for (i = 0; i < MAXRADSERVER; i++) @@ -4094,8 +4337,6 @@ static void update_config() if (!config->numradiusservers) LOG(0, 0, 0, "No RADIUS servers defined!\n"); - config->num_radfds = 1 << RADIUS_SHIFT; - // parse radius_authtypes_s config->radius_authtypes = config->radius_authprefer = 0; p = config->radius_authtypes_s; @@ -4148,6 +4389,9 @@ static void update_config() strcat(config->radius_authtypes_s, ", pap"); } + if (!config->radius_dae_port) + config->radius_dae_port = DAEPORT; + // re-initialise the random number source initrandom(config->random_device); @@ -4238,7 +4482,7 @@ static void read_config_file() update_config(); } -int sessionsetup(tunnelidt t, sessionidt s) +int sessionsetup(sessionidt s, tunnelidt t) { // A session now exists, set it up in_addr_t ip; @@ -4256,7 +4500,7 @@ int sessionsetup(tunnelidt t, sessionidt s) if (!session[s].ip) { LOG(0, s, t, " No IP allocated. The IP address pool is FULL!\n"); - sessionshutdown(s, "No IP addresses available.", 2, 7); + sessionshutdown(s, "No IP addresses available.", 2, 7); // try another return 0; } LOG(3, s, t, " No IP allocated. Assigned %s from pool\n", @@ -4316,13 +4560,8 @@ int sessionsetup(tunnelidt t, sessionidt s) cache_ipmap(session[s].ip, s); } - if (!session[s].unique_id) - { - // did this session just finish radius? - LOG(3, s, t, "Sending initial IPCP to client\n"); - sendipcp(t, s); - session[s].unique_id = ++last_id; - } + sess_local[s].lcp_authtype = 0; // RADIUS authentication complete + lcp_open(s, t); // transition to Network phase and send initial IPCP // Run the plugin's against this new session. { @@ -4431,7 +4670,7 @@ int load_session(sessionidt s, sessiont *new) } // check v6 routing - if (new->flags & SF_IPV6_ROUTED && !(session[s].flags & SF_IPV6_ROUTED)) + if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened) route6set(s, new->ipv6route, new->ipv6prefixlen, 1); // check filters @@ -4463,12 +4702,6 @@ int load_session(sessionidt s, sessiont *new) // for walking the sessions to forward byte counts to the master. config->cluster_highest_sessionid = s; - // TEMP: old session struct used a uint32_t to define the throttle - // speed for both up/down, new uses a uint16_t for each. Deal with - // sessions from an old master for migration. - if (new->throttle_out == 0 && new->tbf_out) - new->throttle_out = new->throttle_in; - memcpy(&session[s], new, sizeof(session[s])); // Copy over.. // Do fixups into address pool. @@ -4654,7 +4887,7 @@ static void plugins_done() run_plugin_done(p); } -static void processcontrol(uint8_t * buf, int len, struct sockaddr_in *addr, int alen) +static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen) { struct nsctl request; struct nsctl response; @@ -4853,6 +5086,9 @@ static tunnelidt new_tunnel() void become_master(void) { int s, i; + static struct event_data d[RADIUS_FDS]; + struct epoll_event e; + run_plugins(PLUGIN_BECOME_MASTER, NULL); // running a bunch of iptables commands is slow and can cause @@ -4871,11 +5107,14 @@ void become_master(void) } // add radius fds - for (i = 0; i < config->num_radfds; i++) + e.events = EPOLLIN; + for (i = 0; i < RADIUS_FDS; i++) { - FD_SET(radfds[i], &readset); - if (radfds[i] > readset_n) - readset_n = radfds[i]; + d[i].type = FD_TYPE_RADIUS; + d[i].index = i; + e.data.ptr = &d[i]; + + epoll_ctl(epollfd, EPOLL_CTL_ADD, radfds[i], &e); } } @@ -4969,14 +5208,14 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec uint8_t digest[16]; uint8_t *last; size_t d = 0; + uint16_t m = htons(type); // Compute initial pad - MD5Init(&ctx); - MD5Update(&ctx, (uint8_t) (type >> 8) & 0xff, 1); - MD5Update(&ctx, (uint8_t) type & 0xff, 1); - MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret)); - MD5Update(&ctx, vector, vec_len); - MD5Final(digest, &ctx); + MD5_Init(&ctx); + MD5_Update(&ctx, (unsigned char *) &m, 2); + MD5_Update(&ctx, config->l2tp_secret, strlen(config->l2tp_secret)); + MD5_Update(&ctx, vector, vec_len); + MD5_Final(digest, &ctx); // pointer to last decoded 16 octets last = value; @@ -4986,10 +5225,10 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec // calculate a new pad based on the last decoded block if (d >= sizeof(digest)) { - MD5Init(&ctx); - MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret)); - MD5Update(&ctx, last, sizeof(digest)); - MD5Final(digest, &ctx); + MD5_Init(&ctx); + MD5_Update(&ctx, config->l2tp_secret, strlen(config->l2tp_secret)); + MD5_Update(&ctx, last, sizeof(digest)); + MD5_Final(digest, &ctx); d = 0; last = value; @@ -5000,6 +5239,31 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec } } +int find_filter(char const *name, size_t len) +{ + int free = -1; + int i; + + for (i = 0; i < MAXFILTER; i++) + { + if (!*ip_filters[i].name) + { + if (free < 0) + free = i; + + continue; + } + + if (strlen(ip_filters[i].name) != len) + continue; + + if (!strncmp(ip_filters[i].name, name, len)) + return i; + } + + return free; +} + static int ip_filter_port(ip_filter_portt *p, uint16_t port) { switch (p->op)