X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/32ab43cf2988574c4485685889ec6c4139e7daf2..c23922ce7c5a688ba6f77e90992c15242a139ea7:/l2tpns.c diff --git a/l2tpns.c b/l2tpns.c index 545a3cd..7548771 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.172 2006/12/18 12:05:36 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp $"; #include #include @@ -39,6 +39,8 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.172 2006/12/18 12:05:36 bodea Exp #include #include #include +#include +#include #include "md5.h" #include "l2tpns.h" @@ -56,6 +58,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.172 2006/12/18 12:05:36 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 +66,19 @@ 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. static int tunidx; // ifr_ifindex of tun device +int nlseqnum = 0; // netlink sequence number 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 @@ -133,6 +138,7 @@ config_descriptt config_values[] = { 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), @@ -510,21 +516,108 @@ 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, int want_ack) +{ + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg; + + nh->nlmsg_pid = getpid(); + nh->nlmsg_seq = ++nlseqnum; + if (want_ack) + nh->nlmsg_flags |= NLM_F_ACK; + + // 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(char *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); +} + +static ssize_t netlink_check_ack(struct nlmsghdr *ack_nh, int msg_count) +{ + ssize_t len; + uint32_t seqnum; + + // expect ack + for (; NLMSG_OK (ack_nh, len); ack_nh = NLMSG_NEXT (ack_nh, len)) + { + if (ack_nh->nlmsg_type == NLMSG_DONE) + return msg_count != 0 || seqnum != nlseqnum; + // 1 => lost an ack + + if (ack_nh->nlmsg_type == NLMSG_ERROR) + { + struct nlmsgerr *errmsg = NLMSG_DATA(ack_nh); + if (errmsg->error) + return errmsg->error; // got an error back + else + { + // ack received + --msg_count; + if (errmsg->msg.nlmsg_seq > seqnum); + seqnum = errmsg->msg.nlmsg_seq; + } + } + else + // unknown message + LOG(3, 0, 0, "Got an unknown netlink message: type %d\n", ack_nh->nlmsg_type); + } + + return 1; // malformed message?! +} // // Set up TUN interface static void inittun(void) { + struct ifinfomsg ifinfo; struct ifreq ifr; - struct in6_ifreq ifr6; - struct sockaddr_in sin = {0}; + char buf[4096]; + memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN; @@ -545,71 +638,185 @@ static void inittun(void) } 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)); - - if (ioctl(ifrfd, SIOCSIFADDR, (void *) &ifr) < 0) - { - LOG(0, 0, 0, "Error setting tun address: %s\n", strerror(errno)); - 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; + // get the interface index + ssize_t len; + struct { + struct nlmsghdr nh; + struct ifinfomsg ifinfo __attribute__ ((aligned(NLMSG_ALIGNTO))); + struct rtattr ifname_rta __attribute__ ((aligned(RTA_ALIGNTO))); + char ifname[IFNAMSIZ]; + } req; + struct nlmsghdr *resp_nh; + + req.nh.nlmsg_type = RTM_GETLINK; + req.nh.nlmsg_flags = NLM_F_REQUEST; - // 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); + req.ifinfo.ifi_family = AF_UNSPEC; // as the man says - // 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) + 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); + + if(netlink_send(&req.nh, 0) < 0 || (len = netlink_recv(buf, sizeof(buf))) < 0) { - LOG(0, 0, 0, "Error setting tun IPv6 link local address:" - " %s\n", strerror(errno)); + LOG(0, 0, 0, "Error getting tun ifindex: %s\n", strerror(errno)); + exit(1); } - // 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) + resp_nh = (struct nlmsghdr *)buf; + if (NLMSG_OK (resp_nh, len) && resp_nh->nlmsg_type == RTM_GETLINK) { - LOG(0, 0, 0, "Error setting tun IPv6 global address: %s\n", - strerror(errno)); + memcpy(&ifinfo, NLMSG_DATA(resp_nh), sizeof(ifinfo)); + // got index + tunidx = ifinfo.ifi_index; + } + else + { + LOG(0, 0, 0, "Malformed answer getting tun ifindex\n"); + exit(1); + } + } + { + ssize_t err; + struct { + // interface setting + struct nlmsghdr nh; + struct ifinfomsg ifinfo __attribute__ ((aligned(NLMSG_ALIGNTO))); + struct rtattr txqlen_rta __attribute__ ((aligned(RTA_ALIGNTO))); + uint32_t txqlen; + struct rtattr mtu_rta __attribute__ ((aligned(RTA_ALIGNTO))); + uint32_t mtu; + + // IPv4 address + struct nlmsghdr addr_nh __attribute__ ((aligned(NLMSG_ALIGNTO))); + struct ifaddrmsg ifaddr __attribute__ ((aligned(NLMSG_ALIGNTO))); + struct rtattr addr_rta __attribute__ ((aligned(RTA_ALIGNTO))); + struct in_addr addr; + + // IPv6 LL address + struct nlmsghdr lladdr6_nh __attribute__ ((aligned(NLMSG_ALIGNTO))); + struct ifaddrmsg llifaddr6 __attribute__ ((aligned(NLMSG_ALIGNTO))); + struct rtattr lladdr6_rta __attribute__ ((aligned(RTA_ALIGNTO))); + struct in6_addr lladdr6; + + // IPv6 global address + struct nlmsghdr addr6_nh __attribute__ ((aligned(NLMSG_ALIGNTO))); + struct ifaddrmsg ifaddr6 __attribute__ ((aligned(NLMSG_ALIGNTO))); + struct rtattr addr6_rta __attribute__ ((aligned(RTA_ALIGNTO))); + struct in6_addr addr6; + + // end header + struct nlmsghdr end_nh __attribute__ ((aligned(NLMSG_ALIGNTO))); + } req; + char buf[4096]; + + memset(&req, 0, sizeof(req)); + + req.nh.nlmsg_type = RTM_NEWLINK; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_MULTI; + + req.ifinfo = ifinfo; + req.ifinfo.ifi_flags |= IFF_UP; // set interface up + req.ifinfo.ifi_change = IFF_UP; // only change this flag + + req.txqlen_rta.rta_len = RTA_LENGTH(sizeof(req.txqlen)); + req.txqlen_rta.rta_type = IFLA_TXQLEN; + /* Bump up the qlen to deal with bursts from the network */ + req.txqlen = 1000; + + req.mtu_rta.rta_len = RTA_LENGTH(sizeof(req.txqlen)); + req.mtu_rta.rta_type = IFLA_MTU; + /* set MTU to modem MRU */ + req.mtu = MRU; + + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifinfo) + + req.txqlen_rta.rta_len + + req.mtu_rta.rta_len); + + req.addr_nh.nlmsg_type = RTM_NEWADDR; + req.addr_nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + + req.ifaddr.ifa_family = AF_INET; + req.ifaddr.ifa_prefixlen = 32; + req.ifaddr.ifa_index = ifinfo.ifi_index; + + req.addr_rta.rta_len = RTA_LENGTH(sizeof(req.addr)); + req.addr_rta.rta_type = IFA_ADDRESS; + req.addr.s_addr = config->bind_address ? + config->bind_address : 0x01010101; // 1.1.1.1 + + req.addr_nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifaddr) + + req.addr_rta.rta_len); + + // Only setup IPv6 on the tun device if we have a configured prefix + if (config->ipv6_prefix.s6_addr[0]) { + req.lladdr6_nh.nlmsg_type = RTM_NEWADDR; + req.lladdr6_nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + + req.llifaddr6.ifa_family = AF_INET6; + req.llifaddr6.ifa_prefixlen = 64; + req.llifaddr6.ifa_scope = RT_SCOPE_LINK; + req.llifaddr6.ifa_index = ifinfo.ifi_index; + + req.lladdr6_rta.rta_len = RTA_LENGTH(sizeof(req.lladdr6)); + req.lladdr6_rta.rta_type = IFA_LOCAL; + // Link local address is FE80::1 + memset(&req.lladdr6, 0, sizeof(req.lladdr6)); + req.lladdr6.s6_addr[0] = 0xFE; + req.lladdr6.s6_addr[1] = 0x80; + req.lladdr6.s6_addr[15] = 1; + + req.lladdr6_nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifaddr) + + req.lladdr6_rta.rta_len); + + req.addr6_nh.nlmsg_type = RTM_NEWADDR; + req.addr6_nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + + req.ifaddr6.ifa_family = AF_INET6; + req.ifaddr6.ifa_prefixlen = 64; + req.ifaddr6.ifa_scope = RT_SCOPE_UNIVERSE; + req.ifaddr6.ifa_index = ifinfo.ifi_index; + + req.addr6_rta.rta_len = RTA_LENGTH(sizeof(req.addr6)); + req.addr6_rta.rta_type = IFA_LOCAL; + // Global address is prefix::1 + req.addr6 = config->ipv6_prefix; + req.addr6.s6_addr[15] = 1; + + req.lladdr6_nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifaddr) + + req.lladdr6_rta.rta_len); + + req.end_nh.nlmsg_type = NLMSG_DONE; + req.end_nh.nlmsg_len = NLMSG_LENGTH(0); + } + else + { + // we terminate at the beginning of IPv6 stuff + req.lladdr6_nh.nlmsg_type = NLMSG_DONE; + req.lladdr6_nh.nlmsg_len = NLMSG_LENGTH(0); + } + + if (netlink_send(&req.nh, 1) < 0) + { + LOG(0, 0, 0, "Error setting up tun device: %s\n", strerror(errno)); + exit(1); + } + + if (netlink_recv(buf, sizeof(buf)) < 0) + { + LOG(0, 0, 0, "Error waiting ack for setting up tun device: %s\n", strerror(errno)); + exit(1); + } + + if ((err = netlink_check_ack((struct nlmsghdr *)buf, 4))) + { + if (err < 0) + LOG(0, 0, 0, "Error while receiving tun device ack: %s\n", strerror(errno)); + else + LOG(0, 0, 0, "Error while receiving tun device ack\n"); + exit(1); } } } @@ -1070,45 +1277,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 %u 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 = 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 %u is closing. Don't process PPP packets\n", s); - return; // closing session, PPP not processed - } +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; - session[s].last_packet = session[s].last_data = time_now; - processipv6in(s, t, p, l); - } - else - { - LOG(2, s, t, "MPPP: Unsupported MP protocol 0x%04X received\n",proto); - } + sess_local[s].cout += len; // To send to master.. + sess_local[s].pout++; } // process outgoing (to tunnel) IP @@ -1123,8 +1348,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); @@ -1173,9 +1397,15 @@ 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]; - sp->last_data = time_now; // DoS prevention: enforce a maximum number of packets per 0.1s for a session if (config->max_packets > 0) @@ -1246,55 +1476,80 @@ static void processipout(uint8_t *buf, int len) } // Add on L2TP header - { - 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: %u\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]; - LOG(4, s, t, "MPPP: (2)Session number becomes: %u\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); - if (!p) return; - tunnelsend(b1, len + (p-b1), t); // send it... - } - } - else - { - uint8_t *p = makeppp(b1, sizeof(b1), buf, len, s, t, PPPIP, 0, 0, 0); - if (!p) return; - tunnelsend(b1, len + (p-b1), t); // send it... - } - } + { + 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); + 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) + { + s = b->members[b->current_ses = ++b->current_ses % num_of_links]; + 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... + 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]; + 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(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 @@ -1661,7 +1916,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); @@ -1676,6 +1933,7 @@ 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) @@ -1710,21 +1968,52 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e (session[s].route[r].ip & session[s].route[r].mask)) 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].mask, 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, 0, "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 + { + // 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; ml 5) tunnelkill(t, "Timeout on control message"); // game over @@ -3911,6 +4166,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; @@ -4477,6 +4733,8 @@ int main(int argc, char *argv[]) } } + initnetlink(); + /* Set up the cluster communications port. */ if (cluster_init() < 0) exit(1); @@ -4737,6 +4995,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); @@ -4815,6 +5107,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); @@ -4832,14 +5138,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 @@ -4850,25 +5148,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)) @@ -4876,6 +5178,8 @@ 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;