// 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.166 2006/05/16 06:46:37 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp $";
#include <arpa/inet.h>
#include <assert.h>
#include <sched.h>
#include <sys/sysinfo.h>
#include <libcli.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
#include "md5.h"
#include "l2tpns.h"
// 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
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
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.
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),
struct Tringbuffer *ringbuffer = NULL;
#endif
-static void cache_ipmap(in_addr_t ip, int s);
+static void cache_ipmap(in_addr_t ip, sessionidt s);
static void uncache_ipmap(in_addr_t ip);
-static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s);
+static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s);
static void free_ip_address(sessionidt s);
static void dump_acct_info(int all);
static void sighup_handler(int sig);
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];
+ struct nlmsghdr resp_nh;
+
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN;
}
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;
- // 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.nh.nlmsg_type = RTM_GETLINK;
+ req.nh.nlmsg_flags = NLM_F_REQUEST;
- // 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.ifinfo.ifi_family = AF_UNSPEC; // as the man says
+
+ req.ifname_rta.rta_len = RTA_LENGTH(strlen(config->tundevice)+1);
+ req.ifname_rta.rta_type = IFLA_IFNAME;
+ strncpy(req.ifname, config->tundevice, IFNAMSIZ-1);
+
+ 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_rla.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);
+ }
+
+ resp_nh = (struct nlmsghdr *)buf;
+ if ((err = netlink_check_ack(resp_nh, 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", strerror(errno));
+ exit(1);
}
}
}
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);
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);
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);
// 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;
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) ||
//
// (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));
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;
//
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;
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;
}
}
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
- }
- 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 %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 = 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
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);
}
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
}
// 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
}
t = session[s].tunnel;
sp = &session[s];
+ sp->last_data = time_now;
// FIXME: add DoS prevention/filters?
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);
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)
(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<bundle[b].num_of_links; ml++)
+ if(bundle[b].members[ml] == s)
+ {
+ mem_num = ml;
+ break;
+ }
+ bundle[b].members[mem_num] = bundle[b].members[bundle[b].num_of_links];
+ LOG(3, s, 0, "MPPP: Adjusted member links array\n");
+ }
+ }
+ cluster_send_bundle(b);
+ }
}
if (session[s].throttle_in || session[s].throttle_out) // Unthrottle if throttled.
controladd(c, session[s].far, session[s].tunnel); // send the message
}
- if (!session[s].die)
- session[s].die = TIME + 150; // Clean up in 15 seconds
-
// update filter refcounts
if (session[s].filter_in) ip_filters[session[s].filter_in - 1].used--;
if (session[s].filter_out) ip_filters[session[s].filter_out - 1].used--;
// kill a session now
void sessionkill(sessionidt s, char *reason)
{
- bundleidt b;
-
CSTAT(sessionkill);
if (!session[s].opened) // not alive
return;
}
- session[s].die = TIME;
- sessionshutdown(s, reason, CDN_ADMIN_DISC, TERM_ADMIN_RESET); // close radius/routes, etc.
+ if (!session[s].die)
+ sessionshutdown(s, reason, CDN_ADMIN_DISC, TERM_ADMIN_RESET); // close radius/routes, etc.
+
if (sess_local[s].radius)
radiusclear(sess_local[s].radius, s); // cant send clean accounting data, session is killed
- LOG(2, s, session[s].tunnel, "Kill session %u (%s): %s\n", s, session[s].user, reason);
- if ((b = session[s].bundle))
- {
- // This session was part of a bundle
- bundle[b].num_of_links--;
- LOG(3, s, 0, "MPPP: Dropping member link: %u from bundle %u\n", s, b);
- if (bundle[b].num_of_links == 0)
- {
- bundleclear(b);
- LOG(3, s, 0, "MPPP: Kill bundle: %u (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<bundle[b].num_of_links; ml++)
- {
- if (bundle[b].members[ml] == s)
- {
- mem_num = ml;
- break;
- }
- }
- bundle[b].members[mem_num] = bundle[b].members[bundle[b].num_of_links];
- LOG(3, s, 0, "MPPP: Adjusted member links array\n");
- }
- }
- cluster_send_bundle(b);
- }
+ LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
sessionclear(s);
cluster_send_session(s);
}
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).";
case 1: // result code
{
uint16_t rescode = ntohs(*(uint16_t *) b);
- const char* resdesc = "(unknown)";
+ char const *resdesc = "(unknown)";
+ char const *errdesc = NULL;
+ int cause = 0;
+
if (message == 4)
{ /* StopCCN */
resdesc = l2tp_stopccn_result_code(rescode);
+ cause = TERM_LOST_SERVICE;
}
else if (message == 14)
{ /* CDN */
resdesc = l2tp_cdn_result_code(rescode);
+ if (rescode == 1)
+ cause = TERM_LOST_CARRIER;
+ else
+ cause = TERM_ADMIN_RESET;
}
LOG(4, s, t, " Result Code %u: %s\n", rescode, resdesc);
if (n >= 4)
{
uint16_t errcode = ntohs(*(uint16_t *)(b + 2));
- LOG(4, s, t, " Error Code %u: %s\n", errcode, l2tp_error_code(errcode));
+ errdesc = l2tp_error_code(errcode);
+ LOG(4, s, t, " Error Code %u: %s\n", errcode, errdesc);
}
if (n > 4)
LOG(4, s, t, " Error String: %.*s\n", n-4, b+4);
+ if (cause && disc_cause_set < mtype) // take cause from attrib 46 in preference
+ {
+ disc_cause_set = mtype;
+ disc_reason = errdesc ? errdesc : resdesc;
+ disc_cause = cause;
+ }
+
break;
}
break;
"(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
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
session[s].opened = time_now;
session[s].tunnel = t;
session[s].far = asession;
- session[s].last_packet = time_now;
+ 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
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);
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);
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);
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
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)
{
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))
{
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)
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;
}
}
+ // 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; ui<guest_accounts_num; ui++)
+ {
+ strcat(config->guest_user, guest_users[ui]);
+ if (ui<guest_accounts_num-1)
+ {
+ strcat(config->guest_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);
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);
// 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
{
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))
}
}
+ // 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;
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),
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;