X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/8f01a9dbf21dbd39368a62fe3102c975e1e7be89..2c6957f223400fb892349fac5d521b89d12610df:/l2tpns.c diff --git a/l2tpns.c b/l2tpns.c index f950c58..2d53ea2 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.165 2006/05/04 01:01:56 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp $"; #include #include @@ -14,7 +14,6 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.165 2006/05/04 01:01:56 bodea Exp #define SYSLOG_NAMES #include #include -#include #include #include #include @@ -31,7 +30,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.165 2006/05/04 01:01:56 bodea Exp #include #include #include -#include +#include #include #include #include @@ -39,6 +38,8 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.165 2006/05/04 01:01:56 bodea Exp #include #include #include +#include +#include #include "md5.h" #include "l2tpns.h" @@ -56,6 +57,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.165 2006/05/04 01:01:56 bodea Exp // 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 controlfd = -1; // Control signal handle @@ -63,17 +65,20 @@ 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 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 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). uint32_t last_id = 0; // Unique ID for radius accounting +// Guest change +char guest_users[10][32]; // Array of guest users +int guest_accounts_num = 0; // Number of guest users // calculated from config->l2tp_mtu uint16_t MRU = 0; // PPP MRU @@ -82,9 +87,13 @@ uint16_t MSS = 0; // TCP MSS struct cli_session_actions *cli_session_actions = NULL; // Pending session changes requested by CLI struct cli_tunnel_actions *cli_tunnel_actions = NULL; // Pending tunnel changes required by CLI -static void *ip_hash[256]; // Mapping from IP address to session structures. +union iphash { + sessionidt sess; + union iphash *idx; +} ip_hash[256]; // Mapping from IP address to session structures. + struct ipv6radix { - int sess; + sessionidt sess; struct ipv6radix *branch; } ipv6_hash[256]; // Mapping from IPv6 address to session structures. @@ -126,7 +135,10 @@ config_descriptt config_values[] = { CONFIG("radius_secret", radiussecret, STRING), CONFIG("radius_authtypes", radius_authtypes_s, STRING), CONFIG("radius_dae_port", radius_dae_port, SHORT), + CONFIG("radius_bind_min", radius_bind_min, SHORT), + CONFIG("radius_bind_max", radius_bind_max, SHORT), CONFIG("allow_duplicate_users", allow_duplicate_users, BOOL), + CONFIG("kill_timedout_sessions", kill_timedout_sessions, BOOL), CONFIG("guest_account", guest_user, STRING), CONFIG("bind_address", bind_address, IPv4), CONFIG("peer_address", peer_address, IPv4), @@ -147,6 +159,10 @@ 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), + CONFIG("cli_bind_address", cli_bind_address, IPv4), + CONFIG("hostname", hostname, STRING), + CONFIG("nexthop_address", nexthop_address, IPv4), + CONFIG("nexthop6_address", nexthop6_address, IPv6), { NULL, 0, 0, 0 }, }; @@ -154,8 +170,6 @@ 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", @@ -187,9 +201,11 @@ struct Tstats *_statistics = NULL; struct Tringbuffer *ringbuffer = NULL; #endif -static void cache_ipmap(in_addr_t ip, int s); +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, int s); +static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s); static void free_ip_address(sessionidt s); static void dump_acct_info(int all); static void sighup_handler(int sig); @@ -406,43 +422,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. - if (!mask) mask = 0xffffffff; + memset(&req, 0, sizeof(req)); + + 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; + } - ip &= mask; // Force the ip to be the first one in the route. + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt)); - 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); + 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; + + 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. @@ -458,40 +496,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)); + + 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)); + + 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; - 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; + 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, 0, 0, "Route %s %s/%d\n", + 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) { @@ -504,12 +570,86 @@ void route6set(sessionidt s, struct in6_addr ip, int prefixlen, int add) return; } -// defined in linux/ipv6.h, but tricky to include from user-space -// TODO: move routing to use netlink rather than ioctl -struct in6_ifreq { - struct in6_addr ifr6_addr; - __u32 ifr6_prefixlen; - unsigned int ifr6_ifindex; +// +// Set up netlink socket +static void initnetlink(void) +{ + struct sockaddr_nl nladdr; + + nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (nlfd < 0) + { + LOG(0, 0, 0, "Can't create netlink socket: %s\n", strerror(errno)); + exit(1); + } + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = getpid(); + + if (bind(nlfd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) + { + LOG(0, 0, 0, "Can't bind netlink socket: %s\n", strerror(errno)); + exit(1); + } +} + +static ssize_t netlink_send(struct nlmsghdr *nh) +{ + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg; + + nh->nlmsg_pid = getpid(); + nh->nlmsg_seq = ++nlseqnum; + + // set kernel address + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + iov = (struct iovec){ (void *)nh, nh->nlmsg_len }; + msg = (struct msghdr){ (void *)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; + + return sendmsg(nlfd, &msg, 0); +} + +static ssize_t netlink_recv(void *buf, ssize_t len) +{ + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg; + + // set kernel address + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + iov = (struct iovec){ buf, len }; + msg = (struct msghdr){ (void *)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; + + 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", + "getting tun interface index", + "setting tun interface parameters", + "setting tun IPv4 address", + "setting tun LL IPv6 address", + "setting tun global IPv6 address", }; // @@ -517,8 +657,7 @@ struct in6_ifreq { static void inittun(void) { struct ifreq ifr; - struct in6_ifreq ifr6; - struct sockaddr_in sin = {0}; + memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN; @@ -537,75 +676,136 @@ static void inittun(void) LOG(0, 0, 0, "Can't set tun interface: %s\n", strerror(errno)); exit(1); } - assert(strlen(ifr.ifr_name) < sizeof(config->tundevice)); - strncpy(config->tundevice, ifr.ifr_name, sizeof(config->tundevice) - 1); - ifrfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = config->bind_address ? config->bind_address : 0x01010101; // 1.1.1.1 - memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr)); + assert(strlen(ifr.ifr_name) < sizeof(config->tundevice) - 1); + strncpy(config->tundevice, ifr.ifr_name, sizeof(config->tundevice)); - if (ioctl(ifrfd, SIOCSIFADDR, (void *) &ifr) < 0) + tunidx = if_nametoindex(config->tundevice); + if (tunidx == 0) { - LOG(0, 0, 0, "Error setting tun address: %s\n", strerror(errno)); + LOG(0, 0, 0, "Can't get tun interface index\n"); exit(1); } - /* Bump up the qlen to deal with bursts from the network */ - ifr.ifr_qlen = 1000; - if (ioctl(ifrfd, SIOCSIFTXQLEN, (void *) &ifr) < 0) - { - LOG(0, 0, 0, "Error setting tun queue length: %s\n", strerror(errno)); - exit(1); - } - /* set MTU to modem MRU */ - ifr.ifr_mtu = MRU; - if (ioctl(ifrfd, SIOCSIFMTU, (void *) &ifr) < 0) - { - LOG(0, 0, 0, "Error setting tun MTU: %s\n", strerror(errno)); - exit(1); - } - ifr.ifr_flags = IFF_UP; - if (ioctl(ifrfd, SIOCSIFFLAGS, (void *) &ifr) < 0) - { - LOG(0, 0, 0, "Error setting tun flags: %s\n", strerror(errno)); - exit(1); - } - if (ioctl(ifrfd, SIOCGIFINDEX, (void *) &ifr) < 0) + { - LOG(0, 0, 0, "Error getting tun ifindex: %s\n", strerror(errno)); - exit(1); - } - tunidx = ifr.ifr_ifindex; + struct { + // interface setting + struct nlmsghdr nh; + union { + struct ifinfomsg ifinfo; + struct ifaddrmsg ifaddr; + } ifmsg; + char rtdata[32]; // 32 should be enough + } req; + uint32_t txqlen, mtu; + in_addr_t ip; - // Only setup IPv6 on the tun device if we have a configured prefix - if (config->ipv6_prefix.s6_addr[0]) { - ifr6fd = socket(PF_INET6, SOCK_DGRAM, 0); + memset(&req, 0, sizeof(req)); - // Link local address is FE80::1 - memset(&ifr6.ifr6_addr, 0, sizeof(ifr6.ifr6_addr)); - ifr6.ifr6_addr.s6_addr[0] = 0xFE; - ifr6.ifr6_addr.s6_addr[1] = 0x80; - ifr6.ifr6_addr.s6_addr[15] = 1; - ifr6.ifr6_prefixlen = 64; - ifr6.ifr6_ifindex = ifr.ifr_ifindex; - if (ioctl(ifr6fd, SIOCSIFADDR, (void *) &ifr6) < 0) - { - LOG(0, 0, 0, "Error setting tun IPv6 link local address:" - " %s\n", strerror(errno)); - } + 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)); - // Global address is prefix::1 - memset(&ifr6.ifr6_addr, 0, sizeof(ifr6.ifr6_addr)); - ifr6.ifr6_addr = config->ipv6_prefix; - ifr6.ifr6_addr.s6_addr[15] = 1; - ifr6.ifr6_prefixlen = 64; - ifr6.ifr6_ifindex = ifr.ifr_ifindex; - if (ioctl(ifr6fd, SIOCSIFADDR, (void *) &ifr6) < 0) - { - LOG(0, 0, 0, "Error setting tun IPv6 global address: %s\n", - strerror(errno)); + 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 + + /* Bump up the qlen to deal with bursts from the network */ + txqlen = 1000; + netlink_addattr(&req.nh, IFLA_TXQLEN, &txqlen, sizeof(txqlen)); + /* set MTU to modem MRU */ + mtu = MRU; + netlink_addattr(&req.nh, IFLA_MTU, &mtu, sizeof(mtu)); + + if (netlink_send(&req.nh) < 0) + 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_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_scope = RT_SCOPE_UNIVERSE; + req.ifmsg.ifaddr.ifa_index = tunidx; + + if (config->bind_address) + ip = config->bind_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_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 = tunidx; + + // Link local address is FE80::1 + 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) + 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_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 = tunidx; + + // Global address is prefix::1 + ip6 = config->ipv6_prefix; + ip6.s6_addr[15] = 1; + netlink_addattr(&req.nh, IFA_LOCAL, &ip6, sizeof(ip6)); + + if (netlink_send(&req.nh) < 0) + goto senderror; } + + memset(&req, 0, sizeof(req)); + + req.nh.nlmsg_type = NLMSG_DONE; + req.nh.nlmsg_len = NLMSG_LENGTH(0); + + if (netlink_send(&req.nh) < 0) + goto senderror; + + // if we get an error for seqnum < min_initok_nlseqnum, + // we must exit as initialization went wrong + if (config->ipv6_prefix.s6_addr[0]) + min_initok_nlseqnum = 5 + 1; // idx + if + addr + 2*addr6 + 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 @@ -625,7 +825,7 @@ static void initudp(void) int flags = fcntl(udpfd, F_GETFL, 0); fcntl(udpfd, F_SETFL, flags | O_NONBLOCK); } - if (bind(udpfd, (void *) &addr, sizeof(addr)) < 0) + if (bind(udpfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno)); exit(1); @@ -638,7 +838,7 @@ static void initudp(void) controlfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(controlfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); setsockopt(controlfd, SOL_IP, IP_PKTINFO, &on, sizeof(on)); // recvfromto - if (bind(controlfd, (void *) &addr, sizeof(addr)) < 0) + if (bind(controlfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno)); exit(1); @@ -651,7 +851,7 @@ static void initudp(void) daefd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(daefd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); setsockopt(daefd, SOL_IP, IP_PKTINFO, &on, sizeof(on)); // recvfromto - if (bind(daefd, (void *) &addr, sizeof(addr)) < 0) + if (bind(daefd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno)); exit(1); @@ -676,19 +876,19 @@ static void initudp(void) // IP address. // -static int lookup_ipmap(in_addr_t ip) +static sessionidt lookup_ipmap(in_addr_t ip) { uint8_t *a = (uint8_t *) &ip; - uint8_t **d = (uint8_t **) ip_hash; + union iphash *h = ip_hash; - if (!(d = (uint8_t **) d[(size_t) *a++])) return 0; - if (!(d = (uint8_t **) d[(size_t) *a++])) return 0; - if (!(d = (uint8_t **) d[(size_t) *a++])) return 0; + if (!(h = h[*a++].idx)) return 0; + if (!(h = h[*a++].idx)) return 0; + if (!(h = h[*a++].idx)) return 0; - return (int) (intptr_t) d[(size_t) *a]; + return h[*a].sess; } -static int lookup_ipv6map(struct in6_addr ip) +static sessionidt lookup_ipv6map(struct in6_addr ip) { struct ipv6radix *curnode; int i; @@ -716,18 +916,18 @@ static int lookup_ipv6map(struct in6_addr ip) sessionidt sessionbyip(in_addr_t ip) { - int s = lookup_ipmap(ip); + sessionidt s = lookup_ipmap(ip); CSTAT(sessionbyip); if (s > 0 && s < MAXSESSION && session[s].opened) - return (sessionidt) s; + return s; return 0; } sessionidt sessionbyipv6(struct in6_addr ip) { - int s; + sessionidt s; CSTAT(sessionbyipv6); if (!memcmp(&config->ipv6_prefix, &ip, 8) || @@ -753,25 +953,22 @@ sessionidt sessionbyipv6(struct in6_addr ip) // // (It's actually cached in network order) // -static void cache_ipmap(in_addr_t ip, int s) +static void cache_ipmap(in_addr_t ip, sessionidt s) { in_addr_t nip = htonl(ip); // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0] uint8_t *a = (uint8_t *) &nip; - uint8_t **d = (uint8_t **) ip_hash; + union iphash *h = ip_hash; int i; for (i = 0; i < 3; i++) { - if (!d[(size_t) a[i]]) - { - if (!(d[(size_t) a[i]] = calloc(256, sizeof(void *)))) - return; - } + if (!(h[a[i]].idx || (h[a[i]].idx = calloc(256, sizeof(union iphash))))) + return; - d = (uint8_t **) d[(size_t) a[i]]; + h = h[a[i]].idx; } - d[(size_t) a[3]] = (uint8_t *) (intptr_t) s; + h[a[3]].sess = s; if (s > 0) LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0)); @@ -786,7 +983,7 @@ static void uncache_ipmap(in_addr_t ip) cache_ipmap(ip, 0); // Assign it to the NULL session. } -static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s) +static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s) { int i; int bytes; @@ -827,7 +1024,7 @@ static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s) // int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc) { - char **d = (char **) ip_hash, **e, **f, **g; + union iphash *d = ip_hash, *e, *f, *g; int i, j, k, l; int count = 0; @@ -838,24 +1035,28 @@ int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc) for (i = 0; i < 256; ++i) { - if (!d[i]) + if (!d[i].idx) continue; - e = (char **) d[i]; + + e = d[i].idx; for (j = 0; j < 256; ++j) { - if (!e[j]) + if (!e[j].idx) continue; - f = (char **) e[j]; + + f = e[j].idx; for (k = 0; k < 256; ++k) { - if (!f[k]) + if (!f[k].idx) continue; - g = (char **)f[k]; + + g = f[k].idx; for (l = 0; l < 256; ++l) { - if (!g[l]) + if (!g[l].sess) continue; - cli_print(cli, "%7d %d.%d.%d.%d", (int) (intptr_t) g[l], i, j, k, l); + + cli_print(cli, "%7d %d.%d.%d.%d", g[l].sess, i, j, k, l); ++count; } } @@ -1063,43 +1264,63 @@ void processmpframe(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint8_t e l -= 4; } - // Process this frame - if (*p & 1) - { - proto = *p++; - l--; - } - else - { - proto = ntohs(*(uint16_t *) p); - p += 2; - l -= 2; - } - if (proto == PPPIP) - { - if (session[s].die) - { - LOG(4, s, t, "MPPP: Session %d is closing. Don't process PPP packets\n", s); - return; // closing session, PPP not processed - } - session[s].last_packet = time_now; - processipin(s, t, p, l); - } - else if (proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0]) - { - if (session[s].die) - { - LOG(4, s, t, "MPPP: Session %d is closing. Don't process PPP packets\n", s); - return; // closing session, PPP not processed - } + if (*p & 1) + { + proto = *p++; + l--; + } + else + { + proto = ntohs(*(uint16_t *) p); + p += 2; + l -= 2; + } + if (proto == PPPIP) + { + if (session[s].die) + { + LOG(4, s, t, "MPPP: Session %d is closing. Don't process PPP packets\n", s); + return; // closing session, PPP not processed + } + session[s].last_packet = session[s].last_data = time_now; + processipin(s, t, p, l); + } + else if (proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0]) + { + if (session[s].die) + { + LOG(4, s, t, "MPPP: Session %d is closing. Don't process PPP packets\n", s); + return; // closing session, PPP not processed + } + + session[s].last_packet = session[s].last_data = time_now; + processipv6in(s, t, p, l); + } + else if (proto == PPPIPCP) + { + session[s].last_packet = session[s].last_data = time_now; + processipcp(s, t, p, l); + } + else if (proto == PPPCCP) + { + session[s].last_packet = session[s].last_data = time_now; + processccp(s, t, p, l); + } + else + { + LOG(2, s, t, "MPPP: Unsupported MP protocol 0x%04X received\n",proto); + } +} - session[s].last_packet = time_now; - processipv6in(s, t, p, l); - } - else - { - LOG(2, s, t, "MPPP: Unsupported MP protocol 0x%04X received\n",proto); - } +static void update_session_out_stat(sessionidt s, sessiont *sp, int len) +{ + increment_counter(&sp->cout, &sp->cout_wrap, len); // byte count + sp->cout_delta += len; + sp->pout++; + sp->last_data = time_now; + + sess_local[s].cout += len; // To send to master.. + sess_local[s].pout++; } // process outgoing (to tunnel) IP @@ -1114,8 +1335,7 @@ static void processipout(uint8_t *buf, int len) uint8_t *data = buf; // Keep a copy of the originals. int size = len; - uint8_t b1[MAXETHER + 20]; - uint8_t b2[MAXETHER + 20]; + uint8_t fragbuf[MAXETHER + 20]; CSTAT(processipout); @@ -1164,7 +1384,14 @@ static void processipout(uint8_t *buf, int len) } return; } + t = session[s].tunnel; + if (len > session[s].mru || (session[s].mrru && len > session[s].mrru)) + { + LOG(3, s, t, "Packet size more than session MRU\n"); + return; + } + sp = &session[s]; // DoS prevention: enforce a maximum number of packets per 0.1s for a session @@ -1235,56 +1462,82 @@ static void processipout(uint8_t *buf, int len) return; } - // Add on L2TP header + if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1) { - bundleidt bid = 0; - if (session[s].bundle && 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]; - LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); - if (len > 256) - { - // Partition the packet to 2 fragments - uint32_t frag1len = len / 2; - uint32_t frag2len = len - frag1len; - uint8_t *p = makeppp(b1, sizeof(b1), buf, frag1len, s, t, PPPIP, 0, bid, MP_BEGIN); - uint8_t *q; - - if (!p) return; - tunnelsend(b1, frag1len + (p-b1), t); // send it... - s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links]; + // Add on L2TP header + bundleidt bid = session[s].bundle; + bundlet *b = &bundle[bid]; + + b->current_ses = (b->current_ses + 1) % b->num_of_links; + s = b->members[b->current_ses]; + 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 + 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); + 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... + // statistics + update_session_out_stat(s, sp, fraglen); + remain -= fraglen; + while (remain > last_fraglen) + { + b->current_ses = (b->current_ses + 1) % num_of_links; + s = b->members[b->current_ses]; + t = session[s].tunnel; + sp = &session[s]; LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); - q = makeppp(b2, sizeof(b2), buf+frag1len, frag2len, s, t, PPPIP, 0, bid, MP_END); - if (!q) return; - tunnelsend(b2, frag2len + (q-b2), t); // send it... - } - else { - // Send it as one frame - uint8_t *p = makeppp(b1, sizeof(b1), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS); + p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0); if (!p) return; - tunnelsend(b1, len + (p-b1), t); // send it... + tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + update_session_out_stat(s, sp, fraglen); + remain -= fraglen; } - } - else - { - uint8_t *p = makeppp(b1, sizeof(b1), buf, len, s, t, PPPIP, 0, 0, 0); + // send the last fragment + b->current_ses = (b->current_ses + 1) % num_of_links; + s = b->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... + 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(b1, len + (p-b1), t); // send it... + 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... + update_session_out_stat(s, sp, len); + } // Snooping this session, send it to intercept box if (sp->snoop_ip && sp->snoop_port) snoop_send_packet(buf, len, sp->snoop_ip, sp->snoop_port); - increment_counter(&sp->cout, &sp->cout_wrap, len); // byte count - sp->cout_delta += len; - sp->pout++; udp_tx += len; - - sess_local[s].cout += len; // To send to master.. - sess_local[s].pout++; } // process outgoing (to tunnel) IPv6 @@ -1358,11 +1611,15 @@ 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]; - LOG(3, s, session[s].tunnel, "MPPP: Session number becomes: %d\n", s); + 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; sp = &session[s]; + sp->last_data = time_now; // FIXME: add DoS prevention/filters? @@ -1412,7 +1669,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]; @@ -1426,8 +1682,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; @@ -1460,10 +1714,10 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m) { uint16_t l = (m ? 0x8008 : 0x0008); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - *(uint16_t *) (c->buf + c->length + 6) = htons(val); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + c->buf16[c->length/2 + 3] = htons(val); c->length += 8; } @@ -1471,10 +1725,10 @@ static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m) static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m) { uint16_t l = (m ? 0x800A : 0x000A); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - *(uint32_t *) (c->buf + c->length + 6) = htonl(val); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + *(uint32_t *) &c->buf[c->length + 6] = htonl(val); c->length += 10; } @@ -1482,10 +1736,10 @@ static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m) static void controls(controlt * c, uint16_t avp, char *val, uint8_t m) { uint16_t l = ((m ? 0x8000 : 0) + strlen(val) + 6); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - memcpy(c->buf + c->length + 6, val, strlen(val)); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + memcpy(&c->buf[c->length + 6], val, strlen(val)); c->length += 6 + strlen(val); } @@ -1493,10 +1747,10 @@ static void controls(controlt * c, uint16_t avp, char *val, 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); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - memcpy(c->buf + c->length + 6, val, len); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + memcpy(&c->buf[c->length + 6], val, len); c->length += 6 + len; } @@ -1513,7 +1767,7 @@ static controlt *controlnew(uint16_t mtype) } assert(c); c->next = 0; - *(uint16_t *) (c->buf + 0) = htons(0xC802); // flags/ver + c->buf16[0] = htons(0xC802); // flags/ver c->length = 12; control16(c, 0, mtype, 1); return c; @@ -1523,26 +1777,26 @@ 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 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 - *(uint16_t *) (c->buf + 6) = htons(far); // session - *(uint16_t *) (c->buf + 8) = htons(tunnel[t].ns); // sequence + c->buf16[1] = htons(c->length); // length + c->buf16[2] = htons(tunnel[t].far); // tunnel + c->buf16[3] = htons(far); // session + c->buf16[4] = htons(tunnel[t].ns); // sequence tunnel[t].ns++; // advance sequence // link in message in to queue if (tunnel[t].controlc) @@ -1650,7 +1904,9 @@ void filter_session(sessionidt s, int filter_in, int filter_out) void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_error, int term_cause) { int walled_garden = session[s].walled_garden; - + bundleidt b = session[s].bundle; + //delete routes only for last session in bundle (in case of MPPP) + int del_routes = !b || (bundle[b].num_of_links == 1); CSTAT(sessionshutdown); @@ -1663,8 +1919,9 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e if (!session[s].die) { struct param_kill_session data = { &tunnel[session[s].tunnel], &session[s] }; - LOG(2, s, session[s].tunnel, "Shutting down session %d: %s\n", s, reason); + 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) @@ -1695,25 +1952,56 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e 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++; - 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; } if (session[s].ip_pool_index == -1) // static ip { - if (!routed) routeset(s, session[s].ip, 0, 0, 0); + if (!routed && del_routes) routeset(s, session[s].ip, 0, 0, 0); session[s].ip = 0; } else free_ip_address(s); // unroute IPv6, if setup - if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen) + if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen && del_routes) route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0); + + if (b) + { + // 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, 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) + { + uint8_t ml; + for(ml = 0; mlcluster_highest_sessionid ; ++s) @@ -1952,21 +2204,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); @@ -1999,7 +2251,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } if ((buf[1] & 0x0F) != 2) { - LOG(1, 0, 0, "Bad L2TP ver %d\n", (buf[1] & 0x0F) != 2); + LOG(1, 0, 0, "Bad L2TP ver %d\n", buf[1] & 0x0F); STAT(tunnel_rx_errors); return; } @@ -2096,7 +2348,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } } - LOG(3, s, t, "Control message (%d bytes): (unacked %d) l-ns %d l-nr %d r-ns %d r-nr %d\n", + LOG(3, s, t, "Control message (%d bytes): (unacked %d) l-ns %u l-nr %u r-ns %u r-nr %u\n", l, tunnel[t].controlc, tunnel[t].ns, tunnel[t].nr, ns, nr); // if no tunnel specified, assign one @@ -2113,7 +2365,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) tunnel[t].port = ntohs(addr->sin_port); tunnel[t].window = 4; // default window STAT(tunnel_created); - LOG(1, 0, t, " New tunnel from %s:%u ID %d\n", + LOG(1, 0, t, " New tunnel from %s:%u ID %u\n", fmtaddr(htonl(tunnel[t].ip), 0), tunnel[t].port, t); } @@ -2127,7 +2379,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { // is this the sequence we were expecting? STAT(tunnel_rx_errors); - LOG(1, 0, t, " Out of sequence tunnel %d, (%d is not the expected %d)\n", + LOG(1, 0, t, " Out of sequence tunnel %u, (%u is not the expected %u)\n", t, ns, tunnel[t].nr); if (l) // Is this not a ZLB? @@ -2180,9 +2432,10 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) int error = 0; char *msg = 0; - // default disconnect cause/message on receipt - // of CDN (set to more specific value from - // attribute 46 if present below). + // Default disconnect cause/message on receipt of CDN. Set to + // more specific value from attribute 1 (result code) or 46 + // (disconnect cause) if present below. + int disc_cause_set = 0; int disc_cause = TERM_NAS_REQUEST; char const *disc_reason = "Closed (Received CDN)."; @@ -2214,7 +2467,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) b += 2; if (*(uint16_t *) (b)) { - LOG(2, s, t, "Unknown AVP vendor %d\n", ntohs(*(uint16_t *) (b))); + LOG(2, s, t, "Unknown AVP vendor %u\n", ntohs(*(uint16_t *) (b))); fatal = flags; result = 2; // general error error = 6; // generic vendor-specific error @@ -2279,7 +2532,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) n = orig_len; } - LOG(4, s, t, " AVP %d (%s) len %d%s%s\n", mtype, l2tp_avp_name(mtype), n, + LOG(4, s, t, " AVP %u (%s) len %d%s%s\n", mtype, l2tp_avp_name(mtype), n, flags & 0x40 ? ", hidden" : "", flags & 0x80 ? ", mandatory" : ""); switch (mtype) @@ -2287,37 +2540,53 @@ 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 = %d (%s)\n", *b, l2tp_code(message)); + LOG(4, s, t, " Message type = %u (%s)\n", *b, l2tp_code(message)); break; case 1: // result code { uint16_t rescode = ntohs(*(uint16_t *) b); - const char* resdesc = "(unknown)"; + char const *resdesc = "(unknown)"; + char const *errdesc = NULL; + int cause = 0; + if (message == 4) { /* StopCCN */ resdesc = l2tp_stopccn_result_code(rescode); + cause = TERM_LOST_SERVICE; } else if (message == 14) { /* CDN */ resdesc = l2tp_cdn_result_code(rescode); + if (rescode == 1) + cause = TERM_LOST_CARRIER; + else + cause = TERM_ADMIN_RESET; } - LOG(4, s, t, " Result Code %d: %s\n", rescode, resdesc); + LOG(4, s, t, " Result Code %u: %s\n", rescode, resdesc); if (n >= 4) { uint16_t errcode = ntohs(*(uint16_t *)(b + 2)); - LOG(4, s, t, " Error Code %d: %s\n", errcode, l2tp_error_code(errcode)); + errdesc = l2tp_error_code(errcode); + LOG(4, s, t, " Error Code %u: %s\n", errcode, errdesc); } if (n > 4) LOG(4, s, t, " Error String: %.*s\n", n-4, b+4); + if (cause && disc_cause_set < mtype) // take cause from attrib 46 in preference + { + disc_cause_set = mtype; + disc_reason = errdesc ? errdesc : resdesc; + disc_cause = cause; + } + break; } break; case 2: // protocol version { version = ntohs(*(uint16_t *) (b)); - LOG(4, s, t, " Protocol version = %d\n", version); + LOG(4, s, t, " Protocol version = %u\n", version); if (version && version != 0x0100) { // allow 0.0 and 1.0 LOG(1, s, t, " Bad protocol version %04X\n", version); @@ -2351,13 +2620,13 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) break; case 9: // assigned tunnel tunnel[t].far = ntohs(*(uint16_t *) (b)); - LOG(4, s, t, " Remote tunnel id = %d\n", tunnel[t].far); + LOG(4, s, t, " Remote tunnel id = %u\n", tunnel[t].far); break; case 10: // rx window tunnel[t].window = ntohs(*(uint16_t *) (b)); if (!tunnel[t].window) tunnel[t].window = 1; // window of 0 is silly - LOG(4, s, t, " rx window = %d\n", tunnel[t].window); + LOG(4, s, t, " rx window = %u\n", tunnel[t].window); break; case 11: // Challenge { @@ -2372,17 +2641,17 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) case 14: // assigned session asession = session[s].far = ntohs(*(uint16_t *) (b)); - LOG(4, s, t, " assigned session = %d\n", asession); + LOG(4, s, t, " assigned session = %u\n", asession); break; case 15: // call serial number - LOG(4, s, t, " call serial number = %d\n", ntohl(*(uint32_t *)b)); + LOG(4, s, t, " call serial number = %u\n", ntohl(*(uint32_t *)b)); break; case 18: // bearer type - LOG(4, s, t, " bearer type = %d\n", ntohl(*(uint32_t *)b)); + LOG(4, s, t, " bearer type = %u\n", ntohl(*(uint32_t *)b)); // TBA - for RADIUS break; case 19: // framing type - LOG(4, s, t, " framing type = %d\n", ntohl(*(uint32_t *)b)); + LOG(4, s, t, " framing type = %u\n", ntohl(*(uint32_t *)b)); // TBA break; case 21: // called number @@ -2436,7 +2705,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, ppp_auth_type(atype)); + LOG(4, s, t, " Proxy Auth Type %u (%s)\n", atype, ppp_auth_type(atype)); break; } case 30: // Proxy Authentication Name @@ -2456,7 +2725,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) case 32: // Proxy Authentication ID { uint16_t authid = ntohs(*(uint16_t *)(b)); - LOG(4, s, t, " Proxy Auth ID (%d)\n", authid); + LOG(4, s, t, " Proxy Auth ID (%u)\n", authid); break; } case 33: // Proxy Authentication Response @@ -2502,6 +2771,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) "(code=%u, proto=%04X, dir=%u, msg=\"%.*s\")\n", code, proto, dir, n - 5, b + 5); + disc_cause_set = mtype; + switch (code) { case 1: // admin disconnect @@ -2572,7 +2843,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) default: { static char e[] = "unknown AVP 0xXXXX"; - LOG(2, s, t, " Unknown AVP type %d\n", mtype); + LOG(2, s, t, " Unknown AVP type %u\n", mtype); fatal = flags; result = 2; // general error error = 8; // unknown mandatory AVP @@ -2606,9 +2877,11 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) break; case 2: // SCCRP tunnel[t].state = TUNNELOPEN; + tunnel[t].lastrec = time_now; break; case 3: // SCCN tunnel[t].state = TUNNELOPEN; + tunnel[t].lastrec = time_now; controlnull(t); // ack break; case 4: // StopCCN @@ -2642,8 +2915,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) 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); + session[s].last_packet = session[s].last_data = time_now; + LOG(3, s, t, "New session (%u/%u)\n", tunnel[t].far, session[s].far); control16(c, 14, s, 1); // assigned session controladd(c, asession, t); // send the reply @@ -2687,7 +2960,7 @@ 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->bind_address ? config->bind_address : my_address); sendlcp(s, t); change_state(s, lcp, RequestSent); @@ -2705,7 +2978,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) if (mandatory) tunnelshutdown(t, "Unknown message type", 2, 6, "unknown message type"); else - LOG(1, s, t, "Unknown message type %d\n", message); + LOG(1, s, t, "Unknown message type %u\n", message); break; } if (chapresponse) free(chapresponse); @@ -2799,11 +3072,11 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { if (session[s].die) { - LOG(4, s, t, "Session %d is closing. Don't process PPP packets\n", s); + LOG(4, s, t, "Session %u is closing. Don't process PPP packets\n", s); return; // closing session, PPP not processed } - session[s].last_packet = time_now; + 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); @@ -2816,11 +3089,11 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { if (session[s].die) { - LOG(4, s, t, "Session %d is closing. Don't process PPP packets\n", s); + LOG(4, s, t, "Session %u is closing. Don't process PPP packets\n", s); return; // closing session, PPP not processed } - session[s].last_packet = time_now; + 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); @@ -2833,11 +3106,11 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) { if (session[s].die) { - LOG(4, s, t, "Session %d is closing. Don't process PPP packets\n", s); + LOG(4, s, t, "Session %u is closing. Don't process PPP packets\n", s); return; // closing session, PPP not processed } - session[s].last_packet = time_now; + 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); @@ -2951,7 +3224,7 @@ static void regular_cleanups(double period) if (tunnel[t].retry <= TIME) { controlt *c = tunnel[t].controls; - uint8_t w = tunnel[t].window; + uint16_t w = tunnel[t].window; tunnel[t].try++; // another try if (tunnel[t].try > 5) tunnelkill(t, "Timeout on control message"); // game over @@ -3023,37 +3296,6 @@ static void regular_cleanups(double period) continue; } - // check for timed out sessions - if (session[s].timeout) - { - bundleidt bid = session[s].bundle; - if (bid) - { - clockt curr_time = time_now; - if (curr_time - bundle[bid].last_check >= 1) - { - bundle[bid].online_time += (curr_time-bundle[bid].last_check)*bundle[bid].num_of_links; - bundle[bid].last_check = curr_time; - if (bundle[bid].online_time >= session[s].timeout) - { - int ses; - for (ses = bundle[bid].num_of_links - 1; ses >= 0; ses--) - { - sessionshutdown(bundle[bid].members[ses], "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); - s_actions++; - continue; - } - } - } - } - else if (session[s].timeout <= time_now - session[s].opened) - { - sessionshutdown(s, "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); - s_actions++; - continue; - } - } - // PPP timeouts if (sess_local[s].lcp.restart <= time_now) { @@ -3195,6 +3437,45 @@ static void regular_cleanups(double period) s_actions++; } + // Drop sessions who have reached session_timeout seconds + if (session[s].session_timeout) + { + bundleidt bid = session[s].bundle; + if (bid) + { + if (time_now - bundle[bid].last_check >= 1) + { + bundle[bid].online_time += (time_now - bundle[bid].last_check) * bundle[bid].num_of_links; + bundle[bid].last_check = time_now; + if (bundle[bid].online_time >= session[s].session_timeout) + { + int ses; + for (ses = bundle[bid].num_of_links - 1; ses >= 0; ses--) + { + sessionshutdown(bundle[bid].members[ses], "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); + s_actions++; + continue; + } + } + } + } + else if (time_now - session[s].opened >= session[s].session_timeout) + { + sessionshutdown(s, "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT); + s_actions++; + continue; + } + } + + // Drop sessions who have reached idle_timeout seconds + if (session[s].last_data && session[s].idle_timeout && (time_now - session[s].last_data >= session[s].idle_timeout)) + { + sessionshutdown(s, "Idle Timeout Reached", CDN_ADMIN_DISC, TERM_IDLE_TIMEOUT); + STAT(session_timeout); + s_actions++; + continue; + } + // Check for actions requested from the CLI if ((a = cli_session_actions[s].action)) { @@ -3219,7 +3500,7 @@ static void regular_cleanups(double period) } else if (a & CLI_SESS_SNOOP) { - LOG(2, s, session[s].tunnel, "Snooping session by CLI (to %s:%d)\n", + LOG(2, s, session[s].tunnel, "Snooping session by CLI (to %s:%u)\n", fmtaddr(cli_session_actions[s].snoop_ip, 0), cli_session_actions[s].snoop_port); @@ -3273,7 +3554,8 @@ static void regular_cleanups(double period) if (config->radius_accounting && config->radius_interim > 0 && session[s].ip && !session[s].walled_garden && !sess_local[s].radius // RADIUS already in progress - && time_now - sess_local[s].last_interim >= config->radius_interim) + && time_now - sess_local[s].last_interim >= config->radius_interim + && session[s].flags & SESSION_STARTED) { int rad = radiusnew(s); if (!rad) @@ -3306,35 +3588,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) { @@ -3362,7 +3645,7 @@ static int still_busy(void) if (last_talked != TIME) { - LOG(2, 0, 0, "Tunnel %d still has un-acked control messages.\n", i); + LOG(2, 0, 0, "Tunnel %u still has un-acked control messages.\n", i); last_talked = TIME; } return 1; @@ -3384,7 +3667,7 @@ static int still_busy(void) if (last_talked != TIME) { - LOG(2, 0, 0, "Radius session %d is still busy (sid %d)\n", i, radius[i].session); + LOG(2, 0, 0, "Radius session %u is still busy (sid %u)\n", i, radius[i].session); last_talked = TIME; } return 1; @@ -3400,8 +3683,8 @@ static int still_busy(void) # include "fake_epoll.h" #endif -// the base set of fds polled: cli, cluster, tun, udp, control, dae -#define BASE_FDS 6 +// the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink +#define BASE_FDS 7 // additional polled fds #ifdef BGP @@ -3425,8 +3708,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\n", - clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd); + 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); /* setup our fds to poll for input */ { @@ -3462,6 +3745,10 @@ static void mainloop(void) d[i].type = FD_TYPE_DAE; e.data.ptr = &d[i++]; epoll_ctl(epollfd, EPOLL_CTL_ADD, daefd, &e); + + d[i].type = FD_TYPE_NETLINK; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, nlfd, &e); } #ifdef BGP @@ -3475,7 +3762,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 */ @@ -3598,6 +3886,32 @@ static void mainloop(void) break; #endif /* BGP */ + case FD_TYPE_NETLINK: + { + struct nlmsghdr *nh = (struct nlmsghdr *)buf; + s = netlink_recv(buf, sizeof(buf)); + if (nh->nlmsg_type == NLMSG_ERROR) + { + struct nlmsgerr *errmsg = NLMSG_DATA(nh); + if (errmsg->error) + { + if (errmsg->msg.nlmsg_seq < min_initok_nlseqnum) + { + LOG(0, 0, 0, "Got a fatal netlink error (while %s): %s\n", tun_nl_phase_msg[nh->nlmsg_seq], strerror(-errmsg->error)); + exit(1); + } + else + + LOG(0, 0, 0, "Got a netlink error: %s\n", strerror(-errmsg->error)); + } + // else it's a ack + } + else + LOG(1, 0, 0, "Got a unknown netlink message: type %d seq %d flags %d\n", nh->nlmsg_type, nh->nlmsg_seq, nh->nlmsg_flags); + n--; + break; + } + default: LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type); } @@ -3669,6 +3983,11 @@ static void mainloop(void) more++; } } +#ifdef BGP + else + /* no event received, but timers could still have expired */ + bgp_process_peers_timers(); +#endif /* BGP */ if (time_changed) { @@ -3872,6 +4191,7 @@ static void initdata(int optdebug, char *optconfig) config->ppp_restart_time = 3; config->ppp_max_configure = 10; config->ppp_max_failure = 5; + config->kill_timedout_sessions = 1; strcpy(config->random_device, RANDOMDEVICE); log_stream = stderr; @@ -4107,7 +4427,7 @@ void rebuild_address_pool(void) if (ipid < 1) // Not found in the pool either? good. continue; - LOG(0, i, 0, "Session %d has an IP address (%s) that was marked static, but is in the pool (%d)!\n", + LOG(0, i, 0, "Session %u has an IP address (%s) that was marked static, but is in the pool (%d)!\n", i, fmtaddr(session[i].ip, 0), ipid); // Fall through and process it as part of the pool. @@ -4116,7 +4436,7 @@ void rebuild_address_pool(void) if (ipid > MAXIPPOOL || ipid < 0) { - LOG(0, i, 0, "Session %d has a pool IP that's not found in the pool! (%d)\n", i, ipid); + LOG(0, i, 0, "Session %u has a pool IP that's not found in the pool! (%d)\n", i, ipid); ipid = -1; session[i].ip_pool_index = ipid; continue; @@ -4155,18 +4475,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. @@ -4224,7 +4544,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; @@ -4234,15 +4554,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 { @@ -4264,7 +4583,7 @@ void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, ui snoop_addr.sin_addr.s_addr = destination; snoop_addr.sin_port = ntohs(port); - LOG(5, 0, 0, "Snooping %d byte packet to %s:%d\n", size, + LOG(5, 0, 0, "Snooping %d byte packet to %s:%u\n", size, fmtaddr(snoop_addr.sin_addr.s_addr, 0), htons(snoop_addr.sin_port)); @@ -4393,8 +4712,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_hostname(hostname); update_config(); init_tbf(config->num_tbfs); @@ -4438,6 +4761,8 @@ int main(int argc, char *argv[]) } } + initnetlink(); + /* Set up the cluster communications port. */ if (cluster_init() < 0) exit(1); @@ -4698,6 +5023,40 @@ static void update_config() } } + // Guest change + guest_accounts_num = 0; + char *p2 = config->guest_user; + while (p2 && *p2) + { + char *s = strpbrk(p2, " \t,"); + if (s) + { + *s++ = 0; + while (*s == ' ' || *s == '\t') + s++; + + if (!*s) + s = 0; + } + + strcpy(guest_users[guest_accounts_num], p2); + LOG(1, 0, 0, "Guest account[%d]: %s\n", guest_accounts_num, guest_users[guest_accounts_num]); + guest_accounts_num++; + p2 = s; + } + // Rebuild the guest_user array + strcpy(config->guest_user, ""); + int ui = 0; + for (ui=0; uiguest_user, guest_users[ui]); + if (uiguest_user, ","); + } + } + + memcpy(config->old_plugins, config->plugins, sizeof(config->plugins)); if (!config->multi_read_count) config->multi_read_count = 10; if (!config->cluster_address) config->cluster_address = inet_addr(DEFAULT_MCAST_ADDR); @@ -4776,6 +5135,20 @@ 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); + 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) { assign_ip_address(s); @@ -4793,14 +5166,6 @@ int sessionsetup(sessionidt s, tunnelidt t) // Make sure this is right session[s].tunnel = t; - // Join a bundle if the MRRU option is accepted - if (session[s].mrru > 0 && !session[s].bundle) - { - LOG(3, s, t, "This session can be part of multilink bundle\n"); - if (join_bundle(s)) - cluster_send_bundle(session[s].bundle); - } - // zap old sessions with same IP and/or username // Don't kill gardened sessions - doing so leads to a DoS // from someone who doesn't need to know the password @@ -4811,25 +5176,29 @@ int sessionsetup(sessionidt s, tunnelidt t) { if (i == s) continue; if (!session[s].opened) continue; + // 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 (ip == session[i].ip) { sessionkill(i, "Duplicate IP address"); continue; } - if (config->allow_duplicate_users) - continue; - - if (session[s].walled_garden || session[i].walled_garden) - continue; - - // Allow duplicate sessions for guest account. - if (*config->guest_user && !strcasecmp(user, config->guest_user)) - continue; - - // 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 (config->allow_duplicate_users) continue; + 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; // Drop the new session in case of duplicate sessionss, not the old one. if (!strcasecmp(user, session[i].user)) @@ -4837,17 +5206,19 @@ int sessionsetup(sessionidt s, tunnelidt t) } } + // 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; // 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 @@ -4876,7 +5247,7 @@ int sessionsetup(sessionidt s, tunnelidt t) if (session[s].throttle_in || session[s].throttle_out) throttle_session(s, session[s].throttle_in, session[s].throttle_out); - session[s].last_packet = time_now; + session[s].last_packet = session[s].last_data = time_now; LOG(2, s, t, "Login by %s at %s from %s (%s)\n", session[s].user, fmtaddr(htonl(session[s].ip), 0), @@ -4918,7 +5289,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 @@ -4929,11 +5300,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 @@ -4952,11 +5323,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 @@ -4979,13 +5350,13 @@ int load_session(sessionidt s, sessiont *new) // check filters if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0])) { - LOG(2, s, session[s].tunnel, "Dropping invalid input filter %d\n", (int) new->filter_in); + LOG(2, s, session[s].tunnel, "Dropping invalid input filter %u\n", (int) new->filter_in); new->filter_in = 0; } if (new->filter_out && (new->filter_out > MAXFILTER || !ip_filters[new->filter_out - 1].name[0])) { - LOG(2, s, session[s].tunnel, "Dropping invalid output filter %d\n", (int) new->filter_out); + LOG(2, s, session[s].tunnel, "Dropping invalid output filter %u\n", (int) new->filter_out); new->filter_out = 0; } @@ -5369,7 +5740,7 @@ static tunnelidt new_tunnel() { if (tunnel[i].state == TUNNELFREE) { - LOG(4, 0, i, "Assigning tunnel ID %d\n", i); + LOG(4, 0, i, "Assigning tunnel ID %u\n", i); if (i > config->cluster_highest_tunnelid) config->cluster_highest_tunnelid = i; return i; @@ -5439,7 +5810,7 @@ int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc if (!session[s].opened) continue; - idle = time_now - session[s].last_packet; + idle = time_now - session[s].last_data; idle /= 5 ; // In multiples of 5 seconds. if (idle < 0) idle = 0;