int epollfd = -1; // event polling
time_t basetime = 0; // base clock
char hostname[MAXHOSTNAME] = ""; // us.
-static int tunidx; // ifr_ifindex of tun device
+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
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
-union iphash {
+union iphash
+{
sessionidt sess;
union iphash *idx;
-} ip_hash[256]; // Mapping from IP address to session structures.
+}ip_hash[256]; // Mapping from IP address to session structures.
struct ipv6radix {
sessionidt sess;
struct ipv6radix *branch;
-} ipv6_hash[256]; // Mapping from IPv6 address to session structures.
+} ipv6_hash[16]; // Mapping from IPv6 address to session structures.
// Traffic counters.
static uint32_t udp_rx = 0, udp_rx_pkt = 0, udp_tx = 0;
CONFIG("disable_sending_hello", disable_sending_hello, BOOL),
CONFIG("disable_no_spoof", disable_no_spoof, BOOL),
CONFIG("bind_multi_address", bind_multi_address, STRING),
+ CONFIG("grp_txrate_average_time", grp_txrate_average_time, INT),
CONFIG("pppoe_only_equal_svc_name", pppoe_only_equal_svc_name, BOOL),
CONFIG("multi_hostname", multi_hostname, STRING),
CONFIG("no_throttle_local_IP", no_throttle_local_IP, BOOL),
bundlet *bundle = NULL; // Array of bundle structures.
fragmentationt *frag = NULL; // Array of fragmentation structures.
sessiont *session = NULL; // Array of session structures.
+groupsesst *grpsession = NULL; // Array of groupsesst structures.
sessionlocalt *sess_local = NULL; // Array of local per-session counters.
radiust *radius = NULL; // Array of radius structures.
ippoolt *ip_address_pool = NULL; // Array of dynamic IP addresses.
struct Tringbuffer *ringbuffer = NULL;
#endif
-static ssize_t netlink_send(struct nlmsghdr *nh);
-static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen);
-static void cache_ipmap(in_addr_t ip, sessionidt s);
static void uncache_ipmap(in_addr_t ip);
static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s);
static void free_ip_address(sessionidt s);
if (f) *f = t.tv_sec + t.tv_usec / 1000000.0;
if (t.tv_sec != time_now)
{
- time_now = t.tv_sec;
- time_changed++;
+ time_now = t.tv_sec;
+ time_changed++;
+ grp_time_changed();
}
// Time in milliseconds
}
}
-static ssize_t netlink_send(struct nlmsghdr *nh)
+ssize_t netlink_send(struct nlmsghdr *nh)
{
struct sockaddr_nl nladdr;
struct iovec iov;
}
/* adapted from iproute2 */
-static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen)
+void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen)
{
int len = RTA_LENGTH(alen);
struct rtattr *rta;
int s;
char ipv6addr[INET6_ADDRSTRLEN];
- curnode = &ipv6_hash[ip.s6_addr[0]];
+ curnode = &ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
i = 1;
s = curnode->sess;
- while (s == 0 && i < 15 && curnode->branch != NULL)
+ while (s == 0 && i < 32 && curnode->branch != NULL)
{
- curnode = &curnode->branch[ip.s6_addr[i]];
+ if (i & 1)
+ curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
+ else
+ curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
+
s = curnode->sess;
i++;
}
LOG(4, s, session[s].tunnel, "Looking up address %s and got %d\n",
- inet_ntop(AF_INET6, &ip, ipv6addr,
- INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &ip, ipv6addr,
+ INET6_ADDRSTRLEN),
s);
return s;
return 0;
}
+sessionidt sessionbyipv6new(struct in6_addr ip)
+{
+ sessionidt s;
+ CSTAT(sessionbyipv6new);
+
+ s = lookup_ipv6map(ip);
+
+ if (s > 0 && s < MAXSESSION && session[s].opened)
+ return s;
+
+ return 0;
+}
+
//
// Take an IP address in HOST byte order and
// add it to the sessionid by IP cache.
//
// (It's actually cached in network order)
//
-static void cache_ipmap(in_addr_t ip, sessionidt s)
+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;
if (s > 0)
LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0));
-
else if (s == 0)
LOG(4, 0, 0, "Un-caching ip address %s\n", fmtaddr(nip, 0));
// else a map to an ip pool index.
static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
{
int i;
- int bytes;
+ int niblles;
struct ipv6radix *curnode;
char ipv6addr[INET6_ADDRSTRLEN];
- curnode = &ipv6_hash[ip.s6_addr[0]];
+ curnode = &ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
- bytes = prefixlen >> 3;
+ niblles = prefixlen >> 2;
i = 1;
- while (i < bytes) {
+
+ while (i < niblles)
+ {
if (curnode->branch == NULL)
{
- if (!(curnode->branch = calloc(256,
- sizeof (struct ipv6radix))))
+ if (!(curnode->branch = calloc(16, sizeof (struct ipv6radix))))
return;
}
- curnode = &curnode->branch[ip.s6_addr[i]];
+
+ if (i & 1)
+ curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
+ else
+ curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
+
i++;
}
if (s > 0)
LOG(4, s, session[s].tunnel, "Caching ip address %s/%d\n",
- inet_ntop(AF_INET6, &ip, ipv6addr,
- INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &ip, ipv6addr,
+ INET6_ADDRSTRLEN),
prefixlen);
else if (s == 0)
LOG(4, 0, 0, "Un-caching ip address %s/%d\n",
- inet_ntop(AF_INET6, &ip, ipv6addr,
- INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &ip, ipv6addr,
+ INET6_ADDRSTRLEN),
prefixlen);
}
return CLI_OK;
}
-
// Find session by username, 0 for not found
// walled garden users aren't authenticated, so the username is
// reasonably useless. Ignore them to avoid incorrect actions
void processipout(uint8_t *buf, int len)
{
sessionidt s;
+ groupidt g;
sessiont *sp;
tunnelidt t;
in_addr_t ip, ip_src;
ip_src = *(uint32_t *)(buf + 12);
ip = *(uint32_t *)(buf + 16);
- if (!(s = sessionbyip(ip)))
+ if ((g = grp_groupbyip(ip)))
+ {
+ s = grp_getnextsession(g, &ip, &ip_src, 0);
+ if (!s)
+ {
+ // Is this a packet for a session that doesn't exist?
+ static int rate = 0; // Number of ICMP packets we've sent this second.
+ static int last = 0; // Last time we reset the ICMP packet counter 'rate'.
+
+ if (last != time_now)
+ {
+ last = time_now;
+ rate = 0;
+ }
+
+ if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second.
+ {
+ LOG(4, 0, 0, "IP: Sending ICMP host unreachable to %s\n", fmtaddr(*(in_addr_t *)(buf + 12), 0));
+ host_unreachable(*(in_addr_t *)(buf + 12), *(uint16_t *)(buf + 4),
+ config->bind_address ? config->bind_address : my_address, buf, len);
+ }
+ return;
+ }
+ }
+ else if (!(s = sessionbyip(ip)))
{
// Is this a packet for a session that doesn't exist?
static int rate = 0; // Number of ICMP packets we've sent this second.
static void processipv6out(uint8_t * buf, int len)
{
sessionidt s;
+ groupidt g;
sessiont *sp;
tunnelidt t;
- in_addr_t ip;
- struct in6_addr ip6;
+ struct in6_addr *p_ip6;
+ struct in6_addr *p_ip6_src;
uint8_t *data = buf; // Keep a copy of the originals.
int size = len;
return;
}
- ip6 = *(struct in6_addr *)(buf+24);
- s = sessionbyipv6(ip6);
+ p_ip6_src = (struct in6_addr *)(buf+8);
+ p_ip6 = (struct in6_addr *)(buf+24);
- if (s == 0)
+ if ((g = grp_groupbyipv6(*p_ip6)))
{
- ip = *(uint32_t *)(buf + 32);
- s = sessionbyip(ip);
+ s = grp_getnextsession(g, p_ip6, p_ip6_src, 1);
}
-
+ else if (!(s = sessionbyipv6(*p_ip6)))
+ {
+ s = sessionbyipv6new(*p_ip6);
+ }
+
if (s == 0)
{
// Is this a packet for a session that doesn't exist?
session[s].die = TIME + 150; // Clean up in 15 seconds
if (session[s].ip)
- { // IP allocated, clear and unroute
+ { // IP allocated, clear and unroute
int r;
int routed = 0;
for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
// kill a session now
void sessionkill(sessionidt s, char *reason)
{
+ groupidt g;
+
CSTAT(sessionkill);
if (!session[s].opened) // not alive
}
LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
+
+ if ((g = grp_groupbysession(s)))
+ {
+ grp_removesession(g, s);
+ }
+
sessionclear(s);
cluster_send_session(s);
}
// No data in ECHO_TIMEOUT seconds, send LCP ECHO
if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) &&
- (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT))
+ (time_now - sess_local[s].last_echo >= config->echo_timeout))
{
uint8_t b[MAXETHER];
#endif /* BGP */
lac_initremotelnsdata();
+
+ grp_initdata();
}
static int assign_ip_address(sessionidt s)
LOG(0, 0, 0, "Can't lock pages: %s\n", strerror(errno));
}
+ //LOG(3, 0, 0, "Debug sizeof struct: sessiont %lu, tunnelt %lu, bundlet %lu, groupsesst %lu\n",
+ // sizeof(sessiont), sizeof(tunnelt), sizeof(bundlet), sizeof(groupsesst));
+
mainloop();
/* remove plugins (so cleanup code gets run) */
if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1))
{
int routed = 0;
+ groupidt g;
// Add the route for this session.
for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
}
else
cache_ipmap(session[s].ip, s);
+
+ if ((g = grp_groupbysession(s)))
+ {
+ grp_setgrouproute(g, 1);
+ cluster_send_groupe(g);
+ }
}
sess_local[s].lcp_authtype = 0; // RADIUS authentication complete
}
// check v6 routing
- for (i = 0; i < MAXROUTE6 && new->route6[i].ipv6prefixlen; i++)
+ if (new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
{
- route6set(s, new->route6[i].ipv6route, new->route6[i].ipv6prefixlen, 1);
+ for (i = 0; i < MAXROUTE6 && new->route6[i].ipv6prefixlen; i++)
+ {
+ route6set(s, new->route6[i].ipv6route, new->route6[i].ipv6prefixlen, 1);
+ }
}
if (new->ipv6address.s6_addr[0] && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)