X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/4344f5e9c73e2ac36b67e72a400114063f037031..1e722029bc405a555e81840c00708084128c5cdd:/l2tpns.c diff --git a/l2tpns.c b/l2tpns.c index 9f5e901..8f1ace5 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,8 +4,6 @@ // 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.176 2011/01/20 12:48:40 bodea Exp $"; - #include #include #include @@ -14,7 +12,6 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp #define SYSLOG_NAMES #include #include -#include #include #include #include @@ -31,7 +28,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp #include #include #include -#include +#include #include #include #include @@ -56,11 +53,18 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp #include "bgp.h" #endif +#include "l2tplac.h" +#include "pppoe.h" + +char * Vendor_name = "Linux L2TPNS"; +uint32_t call_serial_number = 0; + // Globals configt *config = NULL; // all configuration int nlfd = -1; // netlink socket int tunfd = -1; // tun interface file handle. (network device) -int udpfd = -1; // UDP file handle +int udpfd[MAX_UDPFD + 1] = INIT_TABUDPFD; // array UDP file handle + 1 for lac udp +int udplacfd = -1; // UDP LAC file handle int controlfd = -1; // Control signal handle int clifd = -1; // Socket listening for CLI connections. int daefd = -1; // Socket listening for DAE connections. @@ -70,7 +74,7 @@ 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. +char hostname[MAXHOSTNAME] = ""; // us. static int tunidx; // ifr_ifindex of tun device int nlseqnum = 0; // netlink sequence number int min_initok_nlseqnum = 0; // minimun seq number for messages after init is ok @@ -105,6 +109,7 @@ uint32_t eth_tx = 0; static uint32_t ip_pool_size = 1; // Size of the pool of addresses used for dynamic address allocation. time_t time_now = 0; // Current time in seconds since epoch. +uint64_t time_now_ms = 0; // Current time in milliseconds since epoch. static char time_now_string[64] = {0}; // Current time as a string. static int time_changed = 0; // time_now changed char main_quit = 0; // True if we're in the process of exiting. @@ -160,15 +165,34 @@ config_descriptt config_values[] = { CONFIG("cluster_hb_timeout", cluster_hb_timeout, INT), CONFIG("cluster_master_min_adv", cluster_master_min_adv, INT), CONFIG("ipv6_prefix", ipv6_prefix, IPv6), - { NULL, 0, 0, 0 }, + CONFIG("cli_bind_address", cli_bind_address, IPv4), + CONFIG("hostname", hostname, STRING), +#ifdef BGP + CONFIG("nexthop_address", nexthop_address, IPv4), + CONFIG("nexthop6_address", nexthop6_address, IPv6), +#endif + CONFIG("echo_timeout", echo_timeout, INT), + CONFIG("idle_echo_timeout", idle_echo_timeout, INT), + CONFIG("iftun_address", iftun_address, IPv4), + CONFIG("tundevicename", tundevicename, STRING), + CONFIG("disable_lac_func", disable_lac_func, BOOL), + CONFIG("auth_tunnel_change_addr_src", auth_tunnel_change_addr_src, BOOL), + CONFIG("bind_address_remotelns", bind_address_remotelns, IPv4), + CONFIG("bind_portremotelns", bind_portremotelns, SHORT), + CONFIG("pppoe_if_to_bind", pppoe_if_to_bind, STRING), + CONFIG("pppoe_service_name", pppoe_service_name, STRING), + CONFIG("pppoe_ac_name", pppoe_ac_name, STRING), + CONFIG("disable_sending_hello", disable_sending_hello, BOOL), + CONFIG("disable_no_spoof", disable_no_spoof, BOOL), + CONFIG("bind_multi_address", bind_multi_address, STRING), + CONFIG("pppoe_only_equal_svc_name", pppoe_only_equal_svc_name, BOOL), + { NULL, 0, 0, 0 } }; static char *plugin_functions[] = { NULL, "plugin_pre_auth", "plugin_post_auth", - "plugin_packet_rx", - "plugin_packet_tx", "plugin_timer", "plugin_new_session", "plugin_kill_session", @@ -200,6 +224,8 @@ struct Tstats *_statistics = NULL; struct Tringbuffer *ringbuffer = NULL; #endif +static ssize_t netlink_send(struct nlmsghdr *nh); +static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen); 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, sessionidt s); @@ -220,13 +246,6 @@ static tunnelidt new_tunnel(void); static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vector, size_t vec_len); static void bundleclear(bundleidt b); -// 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 // as a side-effect sets time_now, and time_changed static clockt now(double *f) @@ -239,6 +258,11 @@ static clockt now(double *f) time_now = t.tv_sec; time_changed++; } + + // Time in milliseconds + // TODO FOR MLPPP DEV + //time_now_ms = (t.tv_sec * 1000) + (t.tv_usec/1000); + return (t.tv_sec - basetime) * 10 + t.tv_usec / 100000 + 1; } @@ -273,7 +297,7 @@ void _log(int level, sessionidt s, tunnelidt t, const char *format, ...) ringbuffer->buffer[ringbuffer->tail].session = s; ringbuffer->buffer[ringbuffer->tail].tunnel = t; va_start(ap, format); - vsnprintf(ringbuffer->buffer[ringbuffer->tail].message, 4095, format, ap); + vsnprintf(ringbuffer->buffer[ringbuffer->tail].message, MAX_LOG_LENGTH, format, ap); va_end(ap); } #endif @@ -419,43 +443,65 @@ void random_data(uint8_t *buf, int len) // via BGP if enabled, and stuffs it into the // 'sessionbyip' cache. // -// 'ip' and 'mask' must be in _host_ order. +// 'ip' must be in _host_ order. // -static void routeset(sessionidt s, in_addr_t ip, in_addr_t mask, in_addr_t gw, int add) +static void routeset(sessionidt s, in_addr_t ip, int prefixlen, in_addr_t gw, int add) { - struct rtentry r; + struct { + struct nlmsghdr nh; + struct rtmsg rt; + char buf[32]; + } req; int i; + in_addr_t n_ip; + + if (!prefixlen) prefixlen = 32; + + ip &= 0xffffffff << (32 - prefixlen);; // Force the ip to be the first one in the route. + + memset(&req, 0, sizeof(req)); - if (!mask) mask = 0xffffffff; + if (add) + { + req.nh.nlmsg_type = RTM_NEWROUTE; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; + } + else + { + req.nh.nlmsg_type = RTM_DELROUTE; + req.nh.nlmsg_flags = NLM_F_REQUEST; + } + + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt)); - ip &= mask; // Force the ip to be the first one in the route. + req.rt.rtm_family = AF_INET; + req.rt.rtm_dst_len = prefixlen; + req.rt.rtm_table = RT_TABLE_MAIN; + req.rt.rtm_protocol = 42; + req.rt.rtm_scope = RT_SCOPE_LINK; + req.rt.rtm_type = RTN_UNICAST; - memset(&r, 0, sizeof(r)); - r.rt_dev = config->tundevice; - r.rt_dst.sa_family = AF_INET; - *(uint32_t *) & (((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr) = htonl(ip); - r.rt_gateway.sa_family = AF_INET; - *(uint32_t *) & (((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr) = htonl(gw); - r.rt_genmask.sa_family = AF_INET; - *(uint32_t *) & (((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr) = htonl(mask); - r.rt_flags = (RTF_UP | RTF_STATIC); + netlink_addattr(&req.nh, RTA_OIF, &tunidx, sizeof(int)); + n_ip = htonl(ip); + netlink_addattr(&req.nh, RTA_DST, &n_ip, sizeof(n_ip)); if (gw) - r.rt_flags |= RTF_GATEWAY; - else if (mask == 0xffffffff) - r.rt_flags |= RTF_HOST; + { + n_ip = htonl(gw); + netlink_addattr(&req.nh, RTA_GATEWAY, &n_ip, sizeof(n_ip)); + } - LOG(1, s, 0, "Route %s %s/%s%s%s\n", add ? "add" : "del", - fmtaddr(htonl(ip), 0), fmtaddr(htonl(mask), 1), + LOG(1, s, session[s].tunnel, "Route %s %s/%d%s%s\n", add ? "add" : "del", + fmtaddr(htonl(ip), 0), prefixlen, gw ? " via" : "", gw ? fmtaddr(htonl(gw), 2) : ""); - if (ioctl(ifrfd, add ? SIOCADDRT : SIOCDELRT, (void *) &r) < 0) - LOG(0, 0, 0, "routeset() error in ioctl: %s\n", strerror(errno)); + if (netlink_send(&req.nh) < 0) + LOG(0, 0, 0, "routeset() error in sending netlink message: %s\n", strerror(errno)); #ifdef BGP if (add) - bgp_add_route(htonl(ip), htonl(mask)); + bgp_add_route(htonl(ip), prefixlen); else - bgp_del_route(htonl(ip), htonl(mask)); + bgp_del_route(htonl(ip), prefixlen); #endif /* BGP */ // Add/Remove the IPs to the 'sessionbyip' cache. @@ -471,40 +517,68 @@ static void routeset(sessionidt s, in_addr_t ip, in_addr_t mask, in_addr_t gw, i if (!add) // Are we deleting a route? s = 0; // Caching the session as '0' is the same as uncaching. - for (i = ip; (i&mask) == (ip&mask) ; ++i) + for (i = ip; i < ip+(1<<(32-prefixlen)) ; ++i) cache_ipmap(i, s); } } void route6set(sessionidt s, struct in6_addr ip, int prefixlen, int add) { - struct in6_rtmsg rt; + struct { + struct nlmsghdr nh; + struct rtmsg rt; + char buf[64]; + } req; + int metric; char ipv6addr[INET6_ADDRSTRLEN]; - if (ifr6fd < 0) + if (!config->ipv6_prefix.s6_addr[0]) { LOG(0, 0, 0, "Asked to set IPv6 route, but IPv6 not setup.\n"); return; } - memset(&rt, 0, sizeof(rt)); + memset(&req, 0, sizeof(req)); - memcpy(&rt.rtmsg_dst, &ip, sizeof(struct in6_addr)); - rt.rtmsg_dst_len = prefixlen; - rt.rtmsg_metric = 1; - rt.rtmsg_flags = RTF_UP; - rt.rtmsg_ifindex = tunidx; + if (add) + { + req.nh.nlmsg_type = RTM_NEWROUTE; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; + } + else + { + req.nh.nlmsg_type = RTM_DELROUTE; + req.nh.nlmsg_flags = NLM_F_REQUEST; + } + + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt)); - LOG(1, 0, 0, "Route %s %s/%d\n", + req.rt.rtm_family = AF_INET6; + req.rt.rtm_dst_len = prefixlen; + req.rt.rtm_table = RT_TABLE_MAIN; + req.rt.rtm_protocol = 42; + req.rt.rtm_scope = RT_SCOPE_LINK; + req.rt.rtm_type = RTN_UNICAST; + + netlink_addattr(&req.nh, RTA_OIF, &tunidx, sizeof(int)); + netlink_addattr(&req.nh, RTA_DST, &ip, sizeof(ip)); + metric = 1; + netlink_addattr(&req.nh, RTA_METRICS, &metric, sizeof(metric)); + + LOG(1, s, session[s].tunnel, "Route %s %s/%d\n", add ? "add" : "del", inet_ntop(AF_INET6, &ip, ipv6addr, INET6_ADDRSTRLEN), prefixlen); - if (ioctl(ifr6fd, add ? SIOCADDRT : SIOCDELRT, (void *) &rt) < 0) - LOG(0, 0, 0, "route6set() error in ioctl: %s\n", - strerror(errno)); + if (netlink_send(&req.nh) < 0) + LOG(0, 0, 0, "route6set() error in sending netlink message: %s\n", strerror(errno)); - // FIXME: need to add BGP routing (RFC2858) +#ifdef BGP + if (add) + bgp_add_route6(ip, prefixlen); + else + bgp_del_route6(ip, prefixlen); +#endif /* BGP */ if (s) { @@ -576,6 +650,19 @@ static ssize_t netlink_recv(void *buf, ssize_t len) return recvmsg(nlfd, &msg, 0); } +/* adapted from iproute2 */ +static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + rta = (struct rtattr *)(((void *)nh) + NLMSG_ALIGN(nh->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + RTA_ALIGN(len); +} + // messages corresponding to different phases seq number static char *tun_nl_phase_msg[] = { "initialized", @@ -590,7 +677,6 @@ static char *tun_nl_phase_msg[] = { // Set up TUN interface static void inittun(void) { - struct ifinfomsg ifinfo; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); @@ -606,55 +692,25 @@ static void inittun(void) int flags = fcntl(tunfd, F_GETFL, 0); fcntl(tunfd, F_SETFL, flags | O_NONBLOCK); } + + if (*config->tundevicename) + strncpy(ifr.ifr_name, config->tundevicename, IFNAMSIZ); + if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) { LOG(0, 0, 0, "Can't set tun interface: %s\n", strerror(errno)); exit(1); } - assert(strlen(ifr.ifr_name) < sizeof(config->tundevice) - 1); - strncpy(config->tundevice, ifr.ifr_name, sizeof(config->tundevice)); + assert(strlen(ifr.ifr_name) < sizeof(config->tundevicename) - 1); + strncpy(config->tundevicename, ifr.ifr_name, sizeof(config->tundevicename)); + tunidx = if_nametoindex(config->tundevicename); + if (tunidx == 0) { - // get the interface index - struct { - struct nlmsghdr nh; - struct ifinfomsg ifinfo __attribute__ ((aligned(NLMSG_ALIGNTO))); - struct rtattr ifname_rta __attribute__ ((aligned(RTA_ALIGNTO))); - char ifname[IFNAMSIZ]; - } req; - char buf[4096]; - ssize_t len; - struct nlmsghdr *resp_nh; - - req.nh.nlmsg_type = RTM_GETLINK; - req.nh.nlmsg_flags = NLM_F_REQUEST; - - req.ifinfo.ifi_family = AF_UNSPEC; // as the man says - - req.ifname_rta.rta_len = RTA_LENGTH(strlen(config->tundevice)+1); - req.ifname_rta.rta_type = IFLA_IFNAME; - strncpy(req.ifname, config->tundevice, IFNAMSIZ-1); - - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifinfo) - + req.ifname_rta.rta_len); - - if(netlink_send(&req.nh) < 0 || (len = netlink_recv(buf, sizeof(buf))) < 0) - { - LOG(0, 0, 0, "Error getting tun ifindex: %s\n", strerror(errno)); - exit(1); - } - - resp_nh = (struct nlmsghdr *)buf; - if (!NLMSG_OK (resp_nh, len)) - { - LOG(0, 0, 0, "Malformed answer getting tun ifindex %ld\n", len); - exit(1); - } - - memcpy(&ifinfo, NLMSG_DATA(resp_nh), sizeof(ifinfo)); - // got index - tunidx = ifinfo.ifi_index; + LOG(0, 0, 0, "Can't get tun interface index\n"); + exit(1); } + { struct { // interface setting @@ -662,136 +718,112 @@ static void inittun(void) union { struct ifinfomsg ifinfo; struct ifaddrmsg ifaddr; - } ifmsg __attribute__ ((aligned(NLMSG_ALIGNTO))); + } ifmsg; char rtdata[32]; // 32 should be enough } req; - struct { - struct rtattr rta; - uint32_t u32 __attribute__ ((aligned(RTA_ALIGNTO)));; - } u32_attr; - struct { - struct rtattr rta; - struct in_addr addr __attribute__ ((aligned(RTA_ALIGNTO)));; - } ipv4_attr; - struct { - struct rtattr rta; - struct in6_addr addr6 __attribute__ ((aligned(RTA_ALIGNTO)));; - } ipv6_attr; - char *buf_ptr; + uint32_t txqlen, mtu; + in_addr_t ip; memset(&req, 0, sizeof(req)); - req.nh.nlmsg_type = RTM_SETLINK; + req.nh.nlmsg_type = RTM_NEWLINK; req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifinfo)); - req.ifmsg.ifinfo = ifinfo; + req.ifmsg.ifinfo.ifi_family = AF_UNSPEC; + req.ifmsg.ifinfo.ifi_index = tunidx; req.ifmsg.ifinfo.ifi_flags |= IFF_UP; // set interface up req.ifmsg.ifinfo.ifi_change = IFF_UP; // only change this flag - buf_ptr = NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifinfo); - - u32_attr.rta.rta_len = RTA_LENGTH(sizeof(u32_attr.u32)); - u32_attr.rta.rta_type = IFLA_TXQLEN; /* Bump up the qlen to deal with bursts from the network */ - u32_attr.u32 = 1000; - memcpy(buf_ptr, &u32_attr, sizeof(u32_attr)); - - buf_ptr += RTA_ALIGN(u32_attr.rta.rta_len); - - u32_attr.rta.rta_len = RTA_LENGTH(sizeof(u32_attr.u32)); - u32_attr.rta.rta_type = IFLA_MTU; + txqlen = 1000; + netlink_addattr(&req.nh, IFLA_TXQLEN, &txqlen, sizeof(txqlen)); /* set MTU to modem MRU */ - u32_attr.u32 = MRU; - memcpy(buf_ptr, &u32_attr, sizeof(u32_attr)); - - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifinfo) - + u32_attr.rta.rta_len * 2); + mtu = MRU; + netlink_addattr(&req.nh, IFLA_MTU, &mtu, sizeof(mtu)); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error setting up tun device interface: %s\n", strerror(errno)); - exit(1); - } + goto senderror; memset(&req, 0, sizeof(req)); req.nh.nlmsg_type = RTM_NEWADDR; - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)); req.ifmsg.ifaddr.ifa_family = AF_INET; req.ifmsg.ifaddr.ifa_prefixlen = 32; - req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index; - - ipv4_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv4_attr.addr)); - ipv4_attr.rta.rta_type = IFA_LOCAL; - ipv4_attr.addr.s_addr = config->bind_address ? - config->bind_address : 0x01010101; // 1.1.1.1 - memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv4_attr, sizeof(ipv4_attr)); + req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_UNIVERSE; + req.ifmsg.ifaddr.ifa_index = tunidx; - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr) - + ipv4_attr.rta.rta_len); - - if (netlink_send(&req.nh) < 0) + if (config->nbmultiaddress > 1) { - LOG(0, 0, 0, "Error setting up tun device IPv4 address: %s\n", strerror(errno)); - exit(1); + int i; + for (i = 0; i < config->nbmultiaddress ; i++) + { + ip = config->iftun_n_address[i]; + netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip)); + if (netlink_send(&req.nh) < 0) + goto senderror; + } + } + else + { + if (config->iftun_address) + ip = config->iftun_address; + else + ip = 0x01010101; // 1.1.1.1 + netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip)); + + if (netlink_send(&req.nh) < 0) + goto senderror; } + + // Only setup IPv6 on the tun device if we have a configured prefix if (config->ipv6_prefix.s6_addr[0]) { + struct in6_addr ip6; + memset(&req, 0, sizeof(req)); req.nh.nlmsg_type = RTM_NEWADDR; - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)); req.ifmsg.ifaddr.ifa_family = AF_INET6; req.ifmsg.ifaddr.ifa_prefixlen = 64; req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_LINK; - req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index; + req.ifmsg.ifaddr.ifa_index = tunidx; - ipv6_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv6_attr.addr6)); - ipv6_attr.rta.rta_type = IFA_LOCAL; // Link local address is FE80::1 - memset(&ipv6_attr.addr6, 0, sizeof(ipv6_attr.addr6)); - ipv6_attr.addr6.s6_addr[0] = 0xFE; - ipv6_attr.addr6.s6_addr[1] = 0x80; - ipv6_attr.addr6.s6_addr[15] = 1; - memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv6_attr, sizeof(ipv6_attr)); - - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr) - + ipv6_attr.rta.rta_len); + memset(&ip6, 0, sizeof(ip6)); + ip6.s6_addr[0] = 0xFE; + ip6.s6_addr[1] = 0x80; + ip6.s6_addr[15] = 1; + netlink_addattr(&req.nh, IFA_LOCAL, &ip6, sizeof(ip6)); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error setting up tun device IPv6 LL address: %s\n", strerror(errno)); - exit(1); - } + goto senderror; memset(&req, 0, sizeof(req)); req.nh.nlmsg_type = RTM_NEWADDR; - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)); req.ifmsg.ifaddr.ifa_family = AF_INET6; req.ifmsg.ifaddr.ifa_prefixlen = 64; req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_UNIVERSE; - req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index; + req.ifmsg.ifaddr.ifa_index = tunidx; - ipv6_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv6_attr.addr6)); - ipv6_attr.rta.rta_type = IFA_LOCAL; // Global address is prefix::1 - ipv6_attr.addr6 = config->ipv6_prefix; - ipv6_attr.addr6.s6_addr[15] = 1; - memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv6_attr, sizeof(ipv6_attr)); - - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr) - + ipv6_attr.rta.rta_len); + ip6 = config->ipv6_prefix; + ip6.s6_addr[15] = 1; + netlink_addattr(&req.nh, IFA_LOCAL, &ip6, sizeof(ip6)); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error setting up tun device IPv6 global address: %s\n", strerror(errno)); - exit(1); - } + goto senderror; } memset(&req, 0, sizeof(req)); @@ -800,10 +832,7 @@ static void inittun(void) req.nh.nlmsg_len = NLMSG_LENGTH(0); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error finishing setting up tun device: %s\n", strerror(errno)); - exit(1); - } + goto senderror; // if we get an error for seqnum < min_initok_nlseqnum, // we must exit as initialization went wrong @@ -812,30 +841,43 @@ static void inittun(void) else min_initok_nlseqnum = 3 + 1; // idx + if + addr } + + return; + +senderror: + LOG(0, 0, 0, "Error while setting up tun device: %s\n", strerror(errno)); + exit(1); } -// set up UDP ports -static void initudp(void) +// set up LAC UDP ports +static void initlacudp(void) { int on = 1; struct sockaddr_in addr; - // Tunnel + // Tunnel to Remote LNS memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_port = htons(L2TPPORT); - addr.sin_addr.s_addr = config->bind_address; - udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + addr.sin_port = htons(config->bind_portremotelns); + addr.sin_addr.s_addr = config->bind_address_remotelns; + udplacfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + setsockopt(udplacfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); { - int flags = fcntl(udpfd, F_GETFL, 0); - fcntl(udpfd, F_SETFL, flags | O_NONBLOCK); + int flags = fcntl(udplacfd, F_GETFL, 0); + fcntl(udplacfd, F_SETFL, flags | O_NONBLOCK); } - if (bind(udpfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + if (bind(udplacfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno)); + LOG(0, 0, 0, "Error in UDP REMOTE LNS bind: %s\n", strerror(errno)); exit(1); } +} + +// set up control ports +static void initcontrol(void) +{ + int on = 1; + struct sockaddr_in addr; // Control memset(&addr, 0, sizeof(addr)); @@ -849,6 +891,13 @@ static void initudp(void) LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno)); exit(1); } +} + +// set up Dynamic Authorization Extensions to RADIUS port +static void initdae(void) +{ + int on = 1; + struct sockaddr_in addr; // Dynamic Authorization Extensions to RADIUS memset(&addr, 0, sizeof(addr)); @@ -862,9 +911,30 @@ static void initudp(void) LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno)); exit(1); } +} - // Intercept - snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +// set up UDP ports +static void initudp(int * pudpfd, in_addr_t ip_bind) +{ + int on = 1; + struct sockaddr_in addr; + + // Tunnel + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(L2TPPORT); + addr.sin_addr.s_addr = ip_bind; + (*pudpfd) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + setsockopt((*pudpfd), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + { + int flags = fcntl((*pudpfd), F_GETFL, 0); + fcntl((*pudpfd), F_SETFL, flags | O_NONBLOCK); + } + if (bind((*pudpfd), (struct sockaddr *) &addr, sizeof(addr)) < 0) + { + LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno)); + exit(1); + } } // @@ -1157,6 +1227,12 @@ void tunnelsend(uint8_t * buf, uint16_t l, tunnelidt t) return; } + if (t == TUNNEL_ID_PPPOE) + { + pppoe_sess_send(buf, l, t); + return; + } + if (!tunnel[t].ip) { LOG(1, 0, t, "Error sending data out tunnel: no remote endpoint (tunnel not set up)\n"); @@ -1184,10 +1260,10 @@ void tunnelsend(uint8_t * buf, uint16_t l, tunnelidt t) } } - if (sendto(udpfd, buf, l, 0, (void *) &addr, sizeof(addr)) < 0) + if (sendto(udpfd[tunnel[t].indexudp], buf, l, 0, (void *) &addr, sizeof(addr)) < 0) { LOG(0, ntohs((*(uint16_t *) (buf + 6))), t, "Error sending data out tunnel: %s (udpfd=%d, buf=%p, len=%d, dest=%s)\n", - strerror(errno), udpfd, buf, l, inet_ntoa(addr.sin_addr)); + strerror(errno), udpfd[tunnel[t].indexudp], buf, l, inet_ntoa(addr.sin_addr)); STAT(tunnel_tx_errors); return; } @@ -1331,7 +1407,8 @@ static void update_session_out_stat(sessionidt s, sessiont *sp, int len) // process outgoing (to tunnel) IP // -static void processipout(uint8_t *buf, int len) +// (i.e. this routine writes to data[-8]). +void processipout(uint8_t *buf, int len) { sessionidt s; sessiont *sp; @@ -1468,75 +1545,121 @@ static void processipout(uint8_t *buf, int len) return; } - // Add on L2TP header - { - bundleidt bid = 0; - if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1) - { - bid = session[s].bundle; - s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links]; - t = session[s].tunnel; - sp = &session[s]; - LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); - if(len > MINFRAGLEN) - { - // Partition the packet to "bundle[b].num_of_links" fragments - bundlet *b = &bundle[bid]; - uint32_t num_of_links = b->num_of_links; - uint32_t fraglen = len / num_of_links; - fraglen = (fraglen > session[s].mru ? session[s].mru : fraglen); - uint32_t last_fraglen = fraglen + len % num_of_links; - last_fraglen = (last_fraglen > session[s].mru ? len % num_of_links : last_fraglen); + if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1) + { + + if (!config->cluster_iam_master) + { + // The MPPP packets must be managed by the Master. + master_forward_mppp_packet(s, data, size); + return; + } + + // Add on L2TP header + sessionidt members[MAXBUNDLESES]; + bundleidt bid = session[s].bundle; + bundlet *b = &bundle[bid]; + uint32_t num_of_links, nb_opened; + int i; + + num_of_links = b->num_of_links; + nb_opened = 0; + for (i = 0;i < num_of_links;i++) + { + s = b->members[i]; + if (session[s].ppp.lcp == Opened) + { + members[nb_opened] = s; + nb_opened++; + } + } + + if (nb_opened < 1) + { + LOG(3, s, t, "MPPP: PROCESSIPOUT ERROR, no session opened in bundle:%d\n", bid); + return; + } + + num_of_links = nb_opened; + b->current_ses = (b->current_ses + 1) % num_of_links; + s = members[b->current_ses]; + t = session[s].tunnel; + sp = &session[s]; + LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); + + if (num_of_links > 1) + { + if(len > MINFRAGLEN) + { + //for rotate traffic among the member links + uint32_t divisor = num_of_links; + if (divisor > 2) + divisor = divisor/2 + (divisor & 1); + + // Partition the packet to "num_of_links" fragments + uint32_t fraglen = len / divisor; + uint32_t last_fraglen = fraglen + len % divisor; uint32_t remain = len; // send the first packet - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, fraglen, s, t, PPPIP, 0, bid, MP_BEGIN); - if (!p) return; - tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, fraglen, s, t, PPPIP, 0, bid, MP_BEGIN); + if (!p) return; + tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + // statistics update_session_out_stat(s, sp, fraglen); + remain -= fraglen; while (remain > last_fraglen) - { - s = b->members[b->current_ses = ++b->current_ses % num_of_links]; + { + b->current_ses = (b->current_ses + 1) % num_of_links; + s = members[b->current_ses]; t = session[s].tunnel; sp = &session[s]; - LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); - p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0); - if (!p) return; - tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); + p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0); + if (!p) return; + tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... update_session_out_stat(s, sp, fraglen); remain -= fraglen; } // send the last fragment - s = b->members[b->current_ses = ++b->current_ses % num_of_links]; + b->current_ses = (b->current_ses + 1) % num_of_links; + s = members[b->current_ses]; t = session[s].tunnel; sp = &session[s]; - LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); - p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END); - if (!p) return; - tunnelsend(fragbuf, remain + (p-fragbuf), t); // send it... + LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); + p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END); + if (!p) return; + tunnelsend(fragbuf, remain + (p-fragbuf), t); // send it... update_session_out_stat(s, sp, remain); if (remain != last_fraglen) LOG(3, s, t, "PROCESSIPOUT ERROR REMAIN != LAST_FRAGLEN, %d != %d\n", remain, last_fraglen); - } - else { - // Send it as one frame - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS); - if (!p) return; - tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... + } + else + { + // Send it as one frame + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS); + if (!p) return; + tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... LOG(4, s, t, "MPPP: packet sent as one frame\n"); update_session_out_stat(s, sp, len); - } - } - else - { - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0); - if (!p) return; - tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... + } + } + else + { + // Send it as one frame (NO MPPP Frame) + uint8_t *p = opt_makeppp(buf, len, s, t, PPPIP, 0, 0, 0); + tunnelsend(p, len + (buf-p), t); // send it... update_session_out_stat(s, sp, len); - } - } + } + } + else + { + uint8_t *p = opt_makeppp(buf, len, s, t, PPPIP, 0, 0, 0); + tunnelsend(p, len + (buf-p), t); // send it... + update_session_out_stat(s, sp, len); + } // Snooping this session, send it to intercept box if (sp->snoop_ip && sp->snoop_port) @@ -1616,7 +1739,10 @@ static void processipv6out(uint8_t * buf, int len) if (session[s].bundle && bundle[session[s].bundle].num_of_links > 1) { bundleidt bid = session[s].bundle; - s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links]; + bundlet *b = &bundle[bid]; + + b->current_ses = (b->current_ses + 1) % b->num_of_links; + s = b->members[b->current_ses]; LOG(3, s, session[s].tunnel, "MPPP: Session number becomes: %u\n", s); } t = session[s].tunnel; @@ -1671,7 +1797,6 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) { sessiont *sp; tunnelidt t; - in_addr_t ip; uint8_t b[MAXETHER + 20]; @@ -1685,8 +1810,6 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) buf += 4; len -= 4; - ip = *(in_addr_t *)(buf + 16); - if (!session[s].ip) return; @@ -1772,7 +1895,8 @@ static controlt *controlnew(uint16_t mtype) } assert(c); c->next = 0; - *(uint16_t *) (c->buf + 0) = htons(0xC802); // flags/ver + c->buf[0] = 0xC8; // flags + c->buf[1] = 0x02; // ver c->length = 12; control16(c, 0, mtype, 1); return c; @@ -1782,17 +1906,17 @@ static controlt *controlnew(uint16_t mtype) // (ZLB send). static void controlnull(tunnelidt t) { - uint8_t buf[12]; + uint16_t buf[6]; if (tunnel[t].controlc) // Messages queued; They will carry the ack. return; - *(uint16_t *) (buf + 0) = htons(0xC802); // flags/ver - *(uint16_t *) (buf + 2) = htons(12); // length - *(uint16_t *) (buf + 4) = htons(tunnel[t].far); // tunnel - *(uint16_t *) (buf + 6) = htons(0); // session - *(uint16_t *) (buf + 8) = htons(tunnel[t].ns); // sequence - *(uint16_t *) (buf + 10) = htons(tunnel[t].nr); // sequence - tunnelsend(buf, 12, t); + buf[0] = htons(0xC802); // flags/ver + buf[1] = htons(12); // length + buf[2] = htons(tunnel[t].far); // tunnel + buf[3] = htons(0); // session + buf[4] = htons(tunnel[t].ns); // sequence + buf[5] = htons(tunnel[t].nr); // sequence + tunnelsend((uint8_t *)buf, 12, t); } // add a control message to a tunnel, and send if within window @@ -1926,7 +2050,6 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e struct param_kill_session data = { &tunnel[session[s].tunnel], &session[s] }; LOG(2, s, session[s].tunnel, "Shutting down session %u: %s\n", s, reason); run_plugins(PLUGIN_KILL_SESSION, &data); - session[s].die = TIME + 150; // Clean up in 15 seconds } if (session[s].ip && !walled_garden && !session[s].die) @@ -1951,17 +2074,20 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e memcpy(&shut_acct[shut_acct_n++], &session[s], sizeof(session[s])); } + if (!session[s].die) + session[s].die = TIME + 150; // Clean up in 15 seconds + if (session[s].ip) { // IP allocated, clear and unroute int r; int routed = 0; for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++) { - if ((session[s].ip & session[s].route[r].mask) == - (session[s].route[r].ip & session[s].route[r].mask)) + if ((session[s].ip >> (32-session[s].route[r].prefixlen)) == + (session[s].route[r].ip >> (32-session[s].route[r].prefixlen))) routed++; - if (del_routes) routeset(s, session[s].route[r].ip, session[s].route[r].mask, 0, 0); + if (del_routes) routeset(s, session[s].route[r].ip, session[s].route[r].prefixlen, 0, 0); session[s].route[r].ip = 0; } @@ -1977,56 +2103,95 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen && del_routes) route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0); - if (b) + if (b) { - // This session was part of a bundle - bundle[b].num_of_links--; - LOG(3, s, 0, "MPPP: Dropping member link: %d from bundle %d\n",s,b); - if(bundle[b].num_of_links == 0) + // This session was part of a bundle + bundle[b].num_of_links--; + LOG(3, s, session[s].tunnel, "MPPP: Dropping member link: %d from bundle %d\n",s,b); + if(bundle[b].num_of_links == 0) { - bundleclear(b); - LOG(3, s, 0, "MPPP: Kill bundle: %d (No remaing member links)\n",b); - } - else + bundleclear(b); + LOG(3, s, session[s].tunnel, "MPPP: Kill bundle: %d (No remaing member links)\n",b); + } + else { - // Adjust the members array to accomodate the new change - uint8_t mem_num = 0; - // It should be here num_of_links instead of num_of_links-1 (previous instruction "num_of_links--") - if(bundle[b].members[bundle[b].num_of_links] != s) + // Adjust the members array to accomodate the new change + uint8_t mem_num = 0; + // It should be here num_of_links instead of num_of_links-1 (previous instruction "num_of_links--") + if(bundle[b].members[bundle[b].num_of_links] != s) { - uint8_t ml; - for(ml = 0; mlpeer_address ? config->peer_address : - config->bind_address ? config->bind_address : + config->iftun_n_address[tunnel[t].indexudp] ? config->iftun_n_address[tunnel[t].indexudp] : my_address; // send my IP tunnelsend(buf, 10 + (q - buf), t); // send it @@ -2130,6 +2295,16 @@ void sessionkill(sessionidt s, char *reason) if (sess_local[s].radius) radiusclear(sess_local[s].radius, s); // cant send clean accounting data, session is killed + if (session[s].forwardtosession) + { + sessionidt sess = session[s].forwardtosession; + if (session[sess].forwardtosession == s) + { + // Shutdown the linked session also. + sessionshutdown(sess, reason, CDN_ADMIN_DISC, TERM_ADMIN_RESET); + } + } + LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason); sessionclear(s); cluster_send_session(s); @@ -2209,21 +2384,21 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha controlt *c = controlnew(4); // sending StopCCN if (error) { - uint8_t buf[64]; + uint16_t buf[32]; int l = 4; - *(uint16_t *) buf = htons(result); - *(uint16_t *) (buf+2) = htons(error); + buf[0] = htons(result); + buf[1] = htons(error); if (msg) { int m = strlen(msg); if (m + 4 > sizeof(buf)) m = sizeof(buf) - 4; - memcpy(buf+4, msg, m); + memcpy(buf+2, msg, m); l += m; } - controlb(c, 1, buf, l, 1); + controlb(c, 1, (uint8_t *)buf, l, 1); } else control16(c, 1, result, 1); @@ -2234,7 +2409,7 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha } // 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, uint16_t indexudpfd) { uint8_t *chapresponse = NULL; uint16_t l = len, t = 0, s = 0, ns = 0, nr = 0; @@ -2281,6 +2456,12 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) STAT(tunnel_rx_errors); return; } + if (t == TUNNEL_ID_PPPOE) + { + LOG(1, s, t, "Received UDP packet with tunnel ID reserved for pppoe\n"); + STAT(tunnel_rx_errors); + return; + } if (*buf & 0x08) { // ns/nr ns = ntohs(*(uint16_t *) p); @@ -2319,7 +2500,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) if (!config->cluster_iam_master) { - master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); + master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } @@ -2369,6 +2550,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) tunnel[t].ip = ntohl(*(in_addr_t *) & addr->sin_addr); tunnel[t].port = ntohs(addr->sin_port); tunnel[t].window = 4; // default window + tunnel[t].indexudp = indexudpfd; STAT(tunnel_created); LOG(1, 0, t, " New tunnel from %s:%u ID %u\n", fmtaddr(htonl(tunnel[t].ip), 0), tunnel[t].port, t); @@ -2545,7 +2727,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) case 0: // message type message = ntohs(*(uint16_t *) b); mandatory = flags & 0x80; - LOG(4, s, t, " Message type = %u (%s)\n", *b, l2tp_code(message)); + LOG(4, s, t, " Message type = %u (%s)\n", message, l2tp_code(message)); break; case 1: // result code { @@ -2640,6 +2822,13 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } break; case 13: // Response + if (tunnel[t].isremotelns) + { + chapresponse = calloc(17, 1); + memcpy(chapresponse, b, (n < 17) ? n : 16); + LOG(3, s, t, "received challenge response from REMOTE LNS\n"); + } + else // Why did they send a response? We never challenge. LOG(2, s, t, " received unexpected challenge response\n"); break; @@ -2865,8 +3054,10 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { case 1: // SCCRQ - Start Control Connection Request tunnel[t].state = TUNNELOPENING; + LOG(3, s, t, "Received SCCRQ\n"); if (main_quit != QUIT_SHUTDOWN) { + LOG(3, s, t, "sending SCCRP\n"); controlt *c = controlnew(2); // sending SCCRP control16(c, 2, version, 1); // protocol version control32(c, 3, 3, 1); // framing @@ -2883,33 +3074,72 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) case 2: // SCCRP tunnel[t].state = TUNNELOPEN; tunnel[t].lastrec = time_now; + LOG(3, s, t, "Received SCCRP\n"); + if (main_quit != QUIT_SHUTDOWN) + { + if (tunnel[t].isremotelns && chapresponse) + { + hasht hash; + + lac_calc_rlns_auth(t, 2, hash); // id = 2 (SCCRP) + // check authenticator + if (memcmp(hash, chapresponse, 16) == 0) + { + LOG(3, s, t, "sending SCCCN to REMOTE LNS\n"); + controlt *c = controlnew(3); // sending SCCCN + controls(c, 7, hostname, 1); // host name + controls(c, 8, Vendor_name, 1); // Vendor name + control16(c, 2, version, 1); // protocol version + control32(c, 3, 3, 1); // framing Capabilities + control16(c, 9, t, 1); // assigned tunnel + controladd(c, 0, t); // send + } + else + { + tunnelshutdown(t, "Bad chap response from REMOTE LNS", 4, 0, 0); + } + } + } + else + { + tunnelshutdown(t, "Shutting down", 6, 0, 0); + } break; case 3: // SCCN + LOG(3, s, t, "Received SCCN\n"); tunnel[t].state = TUNNELOPEN; tunnel[t].lastrec = time_now; controlnull(t); // ack break; case 4: // StopCCN + LOG(3, s, t, "Received StopCCN\n"); controlnull(t); // ack tunnelshutdown(t, "Stopped", 0, 0, 0); // Shut down cleanly break; case 6: // HELLO + LOG(3, s, t, "Received HELLO\n"); controlnull(t); // simply ACK break; case 7: // OCRQ // TBA + LOG(3, s, t, "Received OCRQ\n"); break; case 8: // OCRO // TBA + LOG(3, s, t, "Received OCRO\n"); break; case 9: // OCCN // TBA + LOG(3, s, t, "Received OCCN\n"); break; case 10: // ICRQ + LOG(3, s, t, "Received ICRQ\n"); if (sessionfree && main_quit != QUIT_SHUTDOWN) { controlt *c = controlnew(11); // ICRP + LOG(3, s, t, "Sending ICRP\n"); + s = sessionfree; sessionfree = session[s].next; memset(&session[s], 0, sizeof(session[s])); @@ -2937,6 +3167,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { controlt *c = controlnew(14); // CDN + LOG(3, s, t, "Sending CDN\n"); if (!sessionfree) { STAT(session_overflow); @@ -2950,9 +3181,24 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } return; case 11: // ICRP - // TBA + LOG(3, s, t, "Received ICRP\n"); + if (session[s].forwardtosession) + { + controlt *c = controlnew(12); // ICCN + + session[s].opened = time_now; + session[s].tunnel = t; + session[s].far = asession; + session[s].last_packet = session[s].last_data = time_now; + + control32(c, 19, 1, 1); // Framing Type + control32(c, 24, 10000000, 1); // Tx Connect Speed + controladd(c, asession, t); // send the message + LOG(3, s, t, "Sending ICCN\n"); + } break; case 12: // ICCN + LOG(3, s, t, "Received ICCN\n"); if (amagic == 0) amagic = time_now; session[s].magic = amagic; // set magic number session[s].flags = aflags; // set flags received @@ -2965,13 +3211,14 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) // Set multilink options before sending initial LCP packet sess_local[s].mp_mrru = 1614; - sess_local[s].mp_epdis = config->bind_address ? config->bind_address : my_address; + sess_local[s].mp_epdis = ntohl(config->iftun_n_address[tunnel[t].indexudp] ? config->iftun_n_address[tunnel[t].indexudp] : my_address); sendlcp(s, t); change_state(s, lcp, RequestSent); break; case 14: // CDN + LOG(3, s, t, "Received CDN\n"); controlnull(t); // ack sessionshutdown(s, disc_reason, CDN_NONE, disc_cause); break; @@ -3022,16 +3269,35 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) l -= 2; } + if (session[s].forwardtosession) + { + LOG(5, s, t, "Forwarding data session to session %u\n", session[s].forwardtosession); + // Forward to LAC/BAS or Remote LNS session + lac_session_forward(buf, len, s, proto, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); + return; + } + else if (config->auth_tunnel_change_addr_src) + { + if (tunnel[t].ip != ntohl(addr->sin_addr.s_addr) && + tunnel[t].port == ntohs(addr->sin_port)) + { + // The remotes BAS are a clustered l2tpns server and the source IP has changed + LOG(5, s, t, "The tunnel IP source (%s) has changed by new IP (%s)\n", + fmtaddr(htonl(tunnel[t].ip), 0), fmtaddr(addr->sin_addr.s_addr, 0)); + + tunnel[t].ip = ntohl(addr->sin_addr.s_addr); + } + } + if (s && !session[s].opened) // Is something wrong?? { if (!config->cluster_iam_master) { // Pass it off to the master to deal with.. - master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); + master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } - LOG(1, s, t, "UDP packet contains session which is not opened. Dropping packet.\n"); STAT(tunnel_rx_errors); return; @@ -3040,37 +3306,37 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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; } + if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } processpap(s, t, p, l); } 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; } + if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } processchap(s, t, p, l); } 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; } + if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } processlcp(s, t, p, l); } 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; } + if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } processipcp(s, t, p, l); } else if (proto == PPPIPV6CP && config->ipv6_prefix.s6_addr[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; } + if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } processipv6cp(s, t, p, l); } 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; } + if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } processccp(s, t, p, l); } else if (proto == PPPIP) @@ -3084,7 +3350,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) session[s].last_packet = session[s].last_data = time_now; if (session[s].walled_garden && !config->cluster_iam_master) { - master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); + master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } @@ -3099,9 +3365,10 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } session[s].last_packet = session[s].last_data = time_now; - if (session[s].walled_garden && !config->cluster_iam_master) + if (!config->cluster_iam_master) { - master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); + // The fragments reconstruction is managed by the Master. + master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } @@ -3118,7 +3385,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) session[s].last_packet = session[s].last_data = time_now; if (session[s].walled_garden && !config->cluster_iam_master) { - master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); + master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } @@ -3127,7 +3394,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) else if (session[s].ppp.lcp == Opened) { 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; } + if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; } protoreject(s, t, p, l, proto); } else @@ -3139,6 +3406,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } // read and process packet on tun +// (i.e. this routine writes to buf[-8]). static void processtun(uint8_t * buf, int len) { LOG_HEX(5, "Receive TUN Data", buf, len); @@ -3214,6 +3482,9 @@ static void regular_cleanups(double period) if (t > config->cluster_highest_tunnelid) t = 1; + if (t == TUNNEL_ID_PPPOE) + continue; + // check for expired tunnels if (tunnel[t].die && tunnel[t].die <= TIME) { @@ -3246,10 +3517,13 @@ static void regular_cleanups(double period) // Send hello if (tunnel[t].state == TUNNELOPEN && !tunnel[t].controlc && (time_now - tunnel[t].lastrec) > 60) { - controlt *c = controlnew(6); // sending HELLO - controladd(c, 0, t); // send the message - LOG(3, 0, t, "Sending HELLO message\n"); - t_actions++; + if (!config->disable_sending_hello) + { + controlt *c = controlnew(6); // sending HELLO + controladd(c, 0, t); // send the message + LOG(3, 0, t, "Sending HELLO message\n"); + t_actions++; + } } // Check for tunnel changes requested from the CLI @@ -3412,8 +3686,8 @@ static void regular_cleanups(double period) } } - // Drop sessions who have not responded within IDLE_TIMEOUT seconds - if (session[s].last_packet && (time_now - session[s].last_packet >= IDLE_TIMEOUT)) + // Drop sessions who have not responded within IDLE_ECHO_TIMEOUT seconds + if (session[s].last_packet && (time_now - session[s].last_packet >= config->idle_echo_timeout)) { sessionshutdown(s, "No response to LCP ECHO requests.", CDN_ADMIN_DISC, TERM_LOST_SERVICE); STAT(session_timeout); @@ -3422,7 +3696,7 @@ static void regular_cleanups(double period) } // No data in ECHO_TIMEOUT seconds, send LCP ECHO - if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= ECHO_TIMEOUT) && + if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) && (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT)) { uint8_t b[MAXETHER]; @@ -3437,7 +3711,8 @@ static void regular_cleanups(double period) LOG(4, s, session[s].tunnel, "No data in %d seconds, sending LCP ECHO\n", (int)(time_now - session[s].last_packet)); - tunnelsend(b, 24, session[s].tunnel); // send it + + tunnelsend(b, (q - b) + 8, session[s].tunnel); // send it sess_local[s].last_echo = time_now; s_actions++; } @@ -3593,35 +3868,36 @@ static int still_busy(void) 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) + static time_t stopped_bgp = 0; + if (bgp_configured) + { + if (!stopped_bgp) { - if (!stopped_bgp) - { - LOG(1, 0, 0, "Shutting down in %d seconds, stopping BGP...\n", QUIT_DELAY); + LOG(1, 0, 0, "Shutting down in %d seconds, stopping BGP...\n", QUIT_DELAY); - for (i = 0; i < BGP_NUM_PEERS; i++) - if (bgp_peers[i].state == Established) - bgp_stop(&bgp_peers[i]); + for (i = 0; i < BGP_NUM_PEERS; i++) + if (bgp_peers[i].state == Established) + bgp_stop(&bgp_peers[i]); - stopped_bgp = time_now; + stopped_bgp = time_now; + if (!config->cluster_iam_master) + { // we don't want to become master cluster_send_ping(0); return 1; } - - if (time_now < (stopped_bgp + QUIT_DELAY)) - return 1; } + + if (!config->cluster_iam_master && time_now < (stopped_bgp + QUIT_DELAY)) + return 1; + } #endif /* BGP */ + if (!config->cluster_iam_master) return 0; - } if (main_quit == QUIT_SHUTDOWN) { @@ -3687,8 +3963,8 @@ static int still_busy(void) # include "fake_epoll.h" #endif -// the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink -#define BASE_FDS 7 +// the base set of fds polled: cli, cluster, tun, udp (MAX_UDPFD), control, dae, netlink, udplac, pppoedisc, pppoesess +#define BASE_FDS (9 + MAX_UDPFD) // additional polled fds #ifdef BGP @@ -3700,8 +3976,11 @@ static int still_busy(void) // main loop - gets packets on tun or udp and processes them static void mainloop(void) { - int i; + int i, j; uint8_t buf[65536]; + uint8_t *p = buf + 32; // for the hearder of the forwarded MPPP packet (see C_MPPP_FORWARD) + // and the forwarded pppoe session + int size_bufp = sizeof(buf) - 32; 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); @@ -3712,8 +3991,8 @@ static void mainloop(void) exit(1); } - LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d\n", - clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd); + LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d , udplacfd=%d, pppoefd=%d, pppoesessfd=%d\n", + clifd, cluster_sockfd, tunfd, udpfd[0], controlfd, daefd, nlfd, udplacfd, pppoediscfd, pppoesessfd); /* setup our fds to poll for input */ { @@ -3738,10 +4017,6 @@ static void mainloop(void) 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); @@ -3753,6 +4028,22 @@ static void mainloop(void) d[i].type = FD_TYPE_NETLINK; e.data.ptr = &d[i++]; epoll_ctl(epollfd, EPOLL_CTL_ADD, nlfd, &e); + + d[i].type = FD_TYPE_PPPOEDISC; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, pppoediscfd, &e); + + d[i].type = FD_TYPE_PPPOESESS; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, pppoesessfd, &e); + + for (j = 0; j < config->nbudpfd; j++) + { + d[i].type = FD_TYPE_UDP; + d[i].index = j; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd[j], &e); + } } #ifdef BGP @@ -3766,7 +4057,8 @@ static void mainloop(void) 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 */ + config->neighbour[i].hold, config->neighbour[i].update_source, + 0); /* 0 = routing disabled */ } #endif /* BGP */ @@ -3813,10 +4105,12 @@ static void mainloop(void) struct in_addr local; socklen_t alen; int c, s; - int udp_ready = 0; + int udp_ready[MAX_UDPFD + 1] = INIT_TABUDPVAR; + int pppoesess_ready = 0; + int pppoesess_pkts = 0; int tun_ready = 0; int cluster_ready = 0; - int udp_pkts = 0; + int udp_pkts[MAX_UDPFD + 1] = INIT_TABUDPVAR; int tun_pkts = 0; int cluster_pkts = 0; #ifdef BGP @@ -3850,30 +4144,37 @@ static void mainloop(void) // 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_UDP: udp_ready[d->index]++; break; + case FD_TYPE_PPPOESESS: pppoesess_ready++; break; + + case FD_TYPE_PPPOEDISC: // pppoe discovery + s = read(pppoediscfd, p, size_bufp); + if (s > 0) process_pppoe_disc(p, s); + n--; + break; case FD_TYPE_CONTROL: // nsctl commands alen = sizeof(addr); - s = recvfromto(controlfd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local); - if (s > 0) processcontrol(buf, s, &addr, alen, &local); + s = recvfromto(controlfd, p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local); + if (s > 0) processcontrol(p, s, &addr, alen, &local); n--; break; case FD_TYPE_DAE: // DAE requests alen = sizeof(addr); - s = recvfromto(daefd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local); - if (s > 0) processdae(buf, s, &addr, alen, &local); + s = recvfromto(daefd, p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local); + if (s > 0) processdae(p, s, &addr, alen, &local); n--; break; case FD_TYPE_RADIUS: // RADIUS response alen = sizeof(addr); - s = recvfrom(radfds[d->index], buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen); + s = recvfrom(radfds[d->index], p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen); if (s >= 0 && config->cluster_iam_master) { if (addr.sin_addr.s_addr == config->radiusserver[0] || addr.sin_addr.s_addr == config->radiusserver[1]) - processrad(buf, s, d->index); + processrad(p, s, d->index); else LOG(3, 0, 0, "Dropping RADIUS packet from unknown source %s\n", fmtaddr(addr.sin_addr.s_addr, 0)); @@ -3884,15 +4185,15 @@ static void mainloop(void) #ifdef BGP case FD_TYPE_BGP: - bgp_events[d->index] = events[i].events; - n--; + bgp_events[d->index] = events[i].events; + n--; break; #endif /* BGP */ case FD_TYPE_NETLINK: { - struct nlmsghdr *nh = (struct nlmsghdr *)buf; - s = netlink_recv(buf, sizeof(buf)); + struct nlmsghdr *nh = (struct nlmsghdr *)p; + s = netlink_recv(p, size_bufp); if (nh->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *errmsg = NLMSG_DATA(nh); @@ -3904,7 +4205,6 @@ static void mainloop(void) exit(1); } else - LOG(0, 0, 0, "Got a netlink error: %s\n", strerror(-errmsg->error)); } // else it's a ack @@ -3916,7 +4216,7 @@ static void mainloop(void) } default: - LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type); + LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type); } } @@ -3926,33 +4226,51 @@ static void mainloop(void) for (c = 0; n && c < config->multi_read_count; c++) { - // L2TP - if (udp_ready) + for (j = 0; j < config->nbudpfd; j++) { - alen = sizeof(addr); - if ((s = recvfrom(udpfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0) + // L2TP and L2TP REMOTE LNS + if (udp_ready[j]) { - processudp(buf, s, &addr); - udp_pkts++; + alen = sizeof(addr); + if ((s = recvfrom(udpfd[j], p, size_bufp, 0, (void *) &addr, &alen)) > 0) + { + processudp(p, s, &addr, j); + udp_pkts[j]++; + } + else + { + udp_ready[j] = 0; + n--; + } + } + } + + // incoming IP + if (tun_ready) + { + if ((s = read(tunfd, p, size_bufp)) > 0) + { + processtun(p, s); + tun_pkts++; } else { - udp_ready = 0; + tun_ready = 0; n--; } } - // incoming IP - if (tun_ready) + // pppoe session + if (pppoesess_ready) { - if ((s = read(tunfd, buf, sizeof(buf))) > 0) + if ((s = read(pppoesessfd, p, size_bufp)) > 0) { - processtun(buf, s); - tun_pkts++; + process_pppoe_sess(p, s); + pppoesess_pkts++; } else { - tun_ready = 0; + pppoesess_ready = 0; n--; } } @@ -3961,9 +4279,9 @@ static void mainloop(void) if (cluster_ready) { alen = sizeof(addr); - if ((s = recvfrom(cluster_sockfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen)) > 0) + if ((s = recvfrom(cluster_sockfd, p, size_bufp, MSG_WAITALL, (void *) &addr, &alen)) > 0) { - processcluster(buf, s, addr.sin_addr.s_addr); + processcluster(p, s, addr.sin_addr.s_addr); cluster_pkts++; } else @@ -3974,18 +4292,22 @@ static void mainloop(void) } } - if (udp_pkts > 1 || tun_pkts > 1 || cluster_pkts > 1) + if (udp_pkts[0] > 1 || tun_pkts > 1 || cluster_pkts > 1) STAT(multi_read_used); if (c >= config->multi_read_count) { - LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun and %d cluster packets\n", - config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts); - + LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster and %d pppoe packets\n", + config->multi_read_count, udp_pkts[0], tun_pkts, cluster_pkts, pppoesess_pkts); STAT(multi_read_exceeded); more++; } } +#ifdef BGP + else + /* no event received, but timers could still have expired */ + bgp_process_peers_timers(); +#endif /* BGP */ if (time_changed) { @@ -4191,6 +4513,9 @@ static void initdata(int optdebug, char *optconfig) config->ppp_max_failure = 5; config->kill_timedout_sessions = 1; strcpy(config->random_device, RANDOMDEVICE); + // Set default value echo_timeout and idle_echo_timeout + config->echo_timeout = ECHO_TIMEOUT; + config->idle_echo_timeout = IDLE_ECHO_TIMEOUT; log_stream = stderr; @@ -4307,6 +4632,8 @@ static void initdata(int optdebug, char *optconfig) exit(1); } #endif /* BGP */ + + lac_initremotelnsdata(); } static int assign_ip_address(sessionidt s) @@ -4473,18 +4800,18 @@ static void fix_address_pool(int sid) // // Add a block of addresses to the IP pool to hand out. // -static void add_to_ip_pool(in_addr_t addr, in_addr_t mask) +static void add_to_ip_pool(in_addr_t addr, int prefixlen) { int i; - if (mask == 0) - mask = 0xffffffff; // Host route only. + if (prefixlen == 0) + prefixlen = 32; // Host route only. - addr &= mask; + addr &= 0xffffffff << (32 - prefixlen); if (ip_pool_size >= MAXIPPOOL) // Pool is full! return ; - for (i = addr ;(i & mask) == addr; ++i) + for (i = addr ; i < addr+(1<<(32-prefixlen)); ++i) { if ((i & 0xff) == 0 || (i&0xff) == 255) continue; // Skip 0 and broadcast addresses. @@ -4542,7 +4869,7 @@ static void initippool() { // It's a range int numbits = 0; - in_addr_t start = 0, mask = 0; + in_addr_t start = 0; LOG(2, 0, 0, "Adding IP address range %s\n", buf); *p++ = 0; @@ -4552,15 +4879,14 @@ static void initippool() continue; } start = ntohl(inet_addr(pool)); - mask = (in_addr_t) (pow(2, numbits) - 1) << (32 - numbits); // Add a static route for this pool - LOG(5, 0, 0, "Adding route for address pool %s/%u\n", - fmtaddr(htonl(start), 0), 32 + mask); + LOG(5, 0, 0, "Adding route for address pool %s/%d\n", + fmtaddr(htonl(start), 0), numbits); - routeset(0, start, mask, 0, 1); + routeset(0, start, numbits, 0, 1); - add_to_ip_pool(start, mask); + add_to_ip_pool(start, numbits); } else { @@ -4594,7 +4920,7 @@ void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, ui static int dump_session(FILE **f, sessiont *s) { - if (!s->opened || !s->ip || !(s->cin_delta || s->cout_delta) || !*s->user || s->walled_garden) + if (!s->opened || (!s->ip && !s->forwardtosession) || !(s->cin_delta || s->cout_delta) || !*s->user || s->walled_garden) return 1; if (!*f) @@ -4620,7 +4946,7 @@ static int dump_session(FILE **f, sessiont *s) "# uptime: %ld\n" "# format: username ip qos uptxoctets downrxoctets\n", hostname, - fmtaddr(config->bind_address ? config->bind_address : my_address, 0), + fmtaddr(config->iftun_n_address[tunnel[s->tunnel].indexudp] ? config->iftun_n_address[tunnel[s->tunnel].indexudp] : my_address, 0), now, now - basetime); } @@ -4711,8 +5037,12 @@ int main(int argc, char *argv[]) initplugins(); initdata(optdebug, optconfig); - init_cli(hostname); + init_cli(); read_config_file(); + /* set hostname /after/ having read the config file */ + if (*config->hostname) + strcpy(hostname, config->hostname); + cli_init_complete(hostname); update_config(); init_tbf(config->num_tbfs); @@ -4763,9 +5093,33 @@ int main(int argc, char *argv[]) exit(1); inittun(); - LOG(1, 0, 0, "Set up on interface %s\n", config->tundevice); + LOG(1, 0, 0, "Set up on interface %s\n", config->tundevicename); + + if (*config->pppoe_if_to_bind) + { + init_pppoe(); + LOG(1, 0, 0, "Set up on pppoe interface %s\n", config->pppoe_if_to_bind); + } + + if (!config->nbmultiaddress) + { + config->bind_n_address[0] = config->bind_address; + config->nbmultiaddress++; + } + config->nbudpfd = config->nbmultiaddress; + for (i = 0; i < config->nbudpfd; i++) + initudp(&udpfd[i], config->bind_n_address[i]); + initlacudp(); + config->indexlacudpfd = config->nbudpfd; + udpfd[config->indexlacudpfd] = udplacfd; + config->nbudpfd++; + + initcontrol(); + initdae(); + + // Intercept + snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - initudp(); initrad(); initippool(); @@ -4997,6 +5351,66 @@ static void update_config() if (!config->radius_dae_port) config->radius_dae_port = DAEPORT; + if(!config->bind_portremotelns) + config->bind_portremotelns = L2TPLACPORT; + if(!config->bind_address_remotelns) + config->bind_address_remotelns = INADDR_ANY; + + if (*config->bind_multi_address) + { + char *sip = config->bind_multi_address; + char *n = sip; + char *e = config->bind_multi_address + strlen(config->bind_multi_address); + config->nbmultiaddress = 0; + + while (*sip && (sip < e)) + { + in_addr_t ip = 0; + uint8_t u = 0; + + while (n < e && (*n == ',' || *n == ' ')) n++; + + while (n < e && (isdigit(*n) || *n == '.')) + { + if (*n == '.') + { + ip = (ip << 8) + u; + u = 0; + } + else + u = u * 10 + *n - '0'; + n++; + } + ip = (ip << 8) + u; + n++; + + if (ip) + { + config->bind_n_address[config->nbmultiaddress] = htonl(ip); + config->iftun_n_address[config->nbmultiaddress] = htonl(ip); + config->nbmultiaddress++; + LOG(1, 0, 0, "Bind address %s\n", fmtaddr(htonl(ip), 0)); + } + + sip = n; + } + + if (config->nbmultiaddress >= 1) + { + config->bind_address = config->bind_n_address[0]; + config->iftun_address = config->bind_address; + } + } + + if(!config->iftun_address) + { + config->iftun_address = config->bind_address; + config->iftun_n_address[0] = config->iftun_address; + } + + if (!*config->pppoe_ac_name) + strncpy(config->pppoe_ac_name, DEFAULT_PPPOE_AC_NAME, sizeof(config->pppoe_ac_name) - 1); + // re-initialise the random number source initrandom(config->random_device); @@ -5131,18 +5545,18 @@ int sessionsetup(sessionidt s, tunnelidt t) LOG(3, s, t, "Doing session setup for session\n"); // Join a bundle if the MRRU option is accepted - if(session[s].mrru > 0 && session[s].bundle == 0) - { - LOG(3, s, t, "This session can be part of multilink bundle\n"); - if (join_bundle(s) > 0) - cluster_send_bundle(session[s].bundle); + if(session[s].mrru > 0 && session[s].bundle == 0) + { + LOG(3, s, t, "This session can be part of multilink bundle\n"); + if (join_bundle(s) > 0) + cluster_send_bundle(session[s].bundle); else { LOG(0, s, t, "MPPP: Mismaching mssf option with other sessions in bundle\n"); sessionshutdown(s, "Mismaching mssf option.", CDN_NONE, TERM_SERVICE_UNAVAILABLE); return 0; } - } + } if (!session[s].ip) { @@ -5157,7 +5571,6 @@ int sessionsetup(sessionidt s, tunnelidt t) fmtaddr(htonl(session[s].ip), 0)); } - // Make sure this is right session[s].tunnel = t; @@ -5170,13 +5583,13 @@ int sessionsetup(sessionidt s, tunnelidt t) for (i = 1; i <= config->cluster_highest_sessionid; i++) { if (i == s) continue; - if (!session[s].opened) continue; + if (!session[s].opened) break; // Allow duplicate sessions for multilink ones of the same bundle. - if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle) - continue; + if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle) continue; + if (ip == session[i].ip) { - sessionkill(i, "Duplicate IP address"); + sessionshutdown(i, "Duplicate IP address", CDN_ADMIN_DISC, TERM_ADMIN_RESET); // close radius/routes, etc. continue; } @@ -5184,36 +5597,36 @@ int sessionsetup(sessionidt s, tunnelidt t) if (session[s].walled_garden || session[i].walled_garden) continue; // Guest change int found = 0; - int gu; - for (gu = 0; gu < guest_accounts_num; gu++) - { - if (!strcasecmp(user, guest_users[gu])) - { - found = 1; - break; - } - } - if (found) continue; + int gu; + for (gu = 0; gu < guest_accounts_num; gu++) + { + if (!strcasecmp(user, guest_users[gu])) + { + found = 1; + break; + } + } + if (found) continue; // Drop the new session in case of duplicate sessionss, not the old one. if (!strcasecmp(user, session[i].user)) - sessionkill(i, "Duplicate session for users"); + sessionshutdown(i, "Duplicate session for users", CDN_ADMIN_DISC, TERM_ADMIN_RESET); // close radius/routes, etc. } } // no need to set a route for the same IP address of the bundle if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1)) { - int routed = 0; + int routed = 0; // Add the route for this session. for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++) { - if ((session[s].ip & session[s].route[r].mask) == - (session[s].route[r].ip & session[s].route[r].mask)) + if ((session[s].ip >> (32-session[s].route[r].prefixlen)) == + (session[s].route[r].ip >> (32-session[s].route[r].prefixlen))) routed++; - routeset(s, session[s].route[r].ip, session[s].route[r].mask, 0, 1); + routeset(s, session[s].route[r].ip, session[s].route[r].prefixlen, 0, 1); } // Static IPs need to be routed if not already @@ -5284,7 +5697,7 @@ int load_session(sessionidt s, sessiont *new) for (i = 0; !newip && i < MAXROUTE && (session[s].route[i].ip || new->route[i].ip); i++) if (new->route[i].ip != session[s].route[i].ip || - new->route[i].mask != session[s].route[i].mask) + new->route[i].prefixlen != session[s].route[i].prefixlen) newip++; // needs update @@ -5295,11 +5708,11 @@ int load_session(sessionidt s, sessiont *new) // remove old routes... for (i = 0; i < MAXROUTE && session[s].route[i].ip; i++) { - if ((session[s].ip & session[s].route[i].mask) == - (session[s].route[i].ip & session[s].route[i].mask)) + if ((session[s].ip >> (32-session[s].route[i].prefixlen)) == + (session[s].route[i].ip >> (32-session[s].route[i].prefixlen))) routed++; - routeset(s, session[s].route[i].ip, session[s].route[i].mask, 0, 0); + routeset(s, session[s].route[i].ip, session[s].route[i].prefixlen, 0, 0); } // ...ip @@ -5318,11 +5731,11 @@ int load_session(sessionidt s, sessiont *new) // add new routes... for (i = 0; i < MAXROUTE && new->route[i].ip; i++) { - if ((new->ip & new->route[i].mask) == - (new->route[i].ip & new->route[i].mask)) + if ((new->ip >> (32-new->route[i].prefixlen)) == + (new->route[i].ip >> (32-new->route[i].prefixlen))) routed++; - routeset(s, new->route[i].ip, new->route[i].mask, 0, 1); + routeset(s, new->route[i].ip, new->route[i].prefixlen, 0, 1); } // ...ip @@ -5733,7 +6146,7 @@ static tunnelidt new_tunnel() tunnelidt i; for (i = 1; i < MAXTUNNEL; i++) { - if (tunnel[i].state == TUNNELFREE) + if ((tunnel[i].state == TUNNELFREE) && (i != TUNNEL_ID_PPPOE)) { LOG(4, 0, i, "Assigning tunnel ID %u\n", i); if (i > config->cluster_highest_tunnelid) @@ -6050,3 +6463,49 @@ int ip_filter(uint8_t *buf, int len, uint8_t filter) // default deny return 0; } + +tunnelidt lac_new_tunnel() +{ + return new_tunnel(); +} + +void lac_tunnelclear(tunnelidt t) +{ + tunnelclear(t); +} + +void lac_send_SCCRQ(tunnelidt t, uint8_t * auth, unsigned int auth_len) +{ + uint16_t version = 0x0100; // protocol version + + tunnel[t].state = TUNNELOPENING; + + // Sent SCCRQ - Start Control Connection Request + controlt *c = controlnew(1); // sending SCCRQ + controls(c, 7, hostname, 1); // host name + controls(c, 8, Vendor_name, 1); // Vendor name + control16(c, 2, version, 1); // protocol version + control32(c, 3, 3, 1); // framing Capabilities + control16(c, 9, t, 1); // assigned tunnel + controlb(c, 11, (uint8_t *) auth, auth_len, 1); // CHAP Challenge + LOG(3, 0, t, "Sent SCCRQ to REMOTE LNS\n"); + controladd(c, 0, t); // send +} + +void lac_send_ICRQ(tunnelidt t, sessionidt s) +{ + // Sent ICRQ Incoming-call-request + controlt *c = controlnew(10); // ICRQ + + control16(c, 14, s, 1); // assigned sesion + call_serial_number++; + control32(c, 15, call_serial_number, 1); // call serial number + LOG(3, s, t, "Sent ICRQ to REMOTE LNS (far ID %u)\n", tunnel[t].far); + controladd(c, 0, t); // send +} + +void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char *msg) +{ + tunnelshutdown(t, reason, result, error, msg); +} +