// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
// vim: sw=8 ts=8
-char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp $";
-
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/if_tun.h>
#define SYSLOG_NAMES
+#include <stdio.h>
#include <syslog.h>
#include <malloc.h>
#include <net/route.h>
#include <netinet/ip6.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <linux/rtnetlink.h>
#include "md5.h"
+#include "dhcp6.h"
#include "l2tpns.h"
#include "cluster.h"
#include "plugin.h"
#include "bgp.h"
#endif
+#include "l2tplac.h"
+#include "pppoe.h"
+#include "dhcp6.h"
+
+char * Vendor_name = "Linux L2TPNS";
+uint32_t call_serial_number = 0;
+
// Globals
configt *config = NULL; // all configuration
int nlfd = -1; // netlink socket
int tunfd = -1; // tun interface file handle. (network device)
-int udpfd = -1; // UDP file handle
+int udpfd[MAX_UDPFD + 1] = INIT_TABUDPFD; // array UDP file handle + 1 for lac udp
+int udplacfd = -1; // UDP LAC file handle
int controlfd = -1; // Control signal handle
int clifd = -1; // Socket listening for CLI connections.
int daefd = -1; // Socket listening for DAE connections.
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
+char hostname[MAXHOSTNAME] = ""; // us.
+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 {
- sessionidt sess;
- union iphash *idx;
-} ip_hash[256]; // Mapping from IP address to session structures.
+union iphash ip_hash[256]; // Mapping from IP address to session structures.
struct ipv6radix {
sessionidt sess;
static uint32_t ip_pool_size = 1; // Size of the pool of addresses used for dynamic address allocation.
time_t time_now = 0; // Current time in seconds since epoch.
+uint64_t time_now_ms = 0; // Current time in milliseconds since epoch.
static char time_now_string[64] = {0}; // Current time as a string.
static int time_changed = 0; // time_now changed
char main_quit = 0; // True if we're in the process of exiting.
CONFIG("throttle_speed", rl_rate, UNSIGNED_LONG),
CONFIG("throttle_buckets", num_tbfs, INT),
CONFIG("accounting_dir", accounting_dir, STRING),
+ CONFIG("account_all_origin", account_all_origin, BOOL),
CONFIG("dump_speed", dump_speed, BOOL),
CONFIG("multi_read_count", multi_read_count, INT),
CONFIG("scheduler_fifo", scheduler_fifo, BOOL),
CONFIG("cluster_hb_timeout", cluster_hb_timeout, INT),
CONFIG("cluster_master_min_adv", cluster_master_min_adv, INT),
CONFIG("ipv6_prefix", ipv6_prefix, IPv6),
- { NULL, 0, 0, 0 },
+ CONFIG("cli_bind_address", cli_bind_address, IPv4),
+ CONFIG("hostname", hostname, STRING),
+#ifdef BGP
+ CONFIG("nexthop_address", nexthop_address, IPv4),
+ CONFIG("nexthop6_address", nexthop6_address, IPv6),
+#endif
+ CONFIG("echo_timeout", echo_timeout, INT),
+ CONFIG("idle_echo_timeout", idle_echo_timeout, INT),
+ CONFIG("iftun_address", iftun_address, IPv4),
+ CONFIG("tundevicename", tundevicename, STRING),
+ CONFIG("disable_lac_func", disable_lac_func, BOOL),
+ CONFIG("auth_tunnel_change_addr_src", auth_tunnel_change_addr_src, BOOL),
+ CONFIG("bind_address_remotelns", bind_address_remotelns, IPv4),
+ CONFIG("bind_portremotelns", bind_portremotelns, SHORT),
+ CONFIG("pppoe_if_to_bind", pppoe_if_to_bind, STRING),
+ CONFIG("pppoe_service_name", pppoe_service_name, STRING),
+ CONFIG("pppoe_ac_name", pppoe_ac_name, STRING),
+ CONFIG("disable_sending_hello", disable_sending_hello, BOOL),
+ CONFIG("disable_no_spoof", disable_no_spoof, BOOL),
+ CONFIG("bind_multi_address", bind_multi_address, STRING),
+ CONFIG("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),
+ CONFIG("dhcp6_preferred_lifetime", dhcp6_preferred_lifetime, INT),
+ CONFIG("dhcp6_valid_lifetime", dhcp6_valid_lifetime, INT),
+ CONFIG("dhcp6_server_duid", dhcp6_server_duid, INT),
+ CONFIG("primary_ipv6_dns", default_ipv6_dns1, IPv6),
+ CONFIG("secondary_ipv6_dns", default_ipv6_dns2, IPv6),
+ CONFIG("default_ipv6_domain_list", default_ipv6_domain_list, STRING),
+ { NULL, 0, 0, 0 }
};
static char *plugin_functions[] = {
NULL,
"plugin_pre_auth",
"plugin_post_auth",
- "plugin_packet_rx",
- "plugin_packet_tx",
"plugin_timer",
"plugin_new_session",
"plugin_kill_session",
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);
static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vector, size_t vec_len);
static void bundleclear(bundleidt b);
-// on slaves, alow BGP to withdraw cleanly before exiting
-#define QUIT_DELAY 5
-
-// quit actions (master)
-#define QUIT_FAILOVER 1 // SIGTERM: exit when all control messages have been acked (for cluster failover)
-#define QUIT_SHUTDOWN 2 // SIGQUIT: shutdown sessions/tunnels, reject new connections
-
// return internal time (10ths since process startup), set f if given
// as a side-effect sets time_now, and time_changed
static clockt now(double *f)
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
+ // TODO FOR MLPPP DEV
+ //time_now_ms = (t.tv_sec * 1000) + (t.tv_usec/1000);
+
return (t.tv_sec - basetime) * 10 + t.tv_usec / 100000 + 1;
}
ringbuffer->buffer[ringbuffer->tail].session = s;
ringbuffer->buffer[ringbuffer->tail].tunnel = t;
va_start(ap, format);
- vsnprintf(ringbuffer->buffer[ringbuffer->tail].message, 4095, format, ap);
+ vsnprintf(ringbuffer->buffer[ringbuffer->tail].message, MAX_LOG_LENGTH, format, ap);
va_end(ap);
}
#endif
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_INET;
req.rt.rtm_dst_len = prefixlen;
req.rt.rtm_table = RT_TABLE_MAIN;
- req.rt.rtm_protocol = RTPROT_BOOT; // XXX
+ req.rt.rtm_protocol = 42;
req.rt.rtm_scope = RT_SCOPE_LINK;
req.rt.rtm_type = RTN_UNICAST;
netlink_addattr(&req.nh, RTA_GATEWAY, &n_ip, sizeof(n_ip));
}
- LOG(1, s, 0, "Route %s %s/%d%s%s\n", add ? "add" : "del",
+ 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) : "");
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 = RTPROT_BOOT; // XXX
+ req.rt.rtm_protocol = 42;
req.rt.rtm_scope = RT_SCOPE_LINK;
req.rt.rtm_type = RTN_UNICAST;
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 (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)
{
}
}
-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 flags = fcntl(tunfd, F_GETFL, 0);
fcntl(tunfd, F_SETFL, flags | O_NONBLOCK);
}
+
+ if (*config->tundevicename)
+ strncpy(ifr.ifr_name, config->tundevicename, IFNAMSIZ);
+
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0)
{
LOG(0, 0, 0, "Can't set tun interface: %s\n", strerror(errno));
exit(1);
}
- assert(strlen(ifr.ifr_name) < sizeof(config->tundevice) - 1);
- strncpy(config->tundevice, ifr.ifr_name, sizeof(config->tundevice));
+ assert(strlen(ifr.ifr_name) < sizeof(config->tundevicename) - 1);
+ strncpy(config->tundevicename, ifr.ifr_name, sizeof(config->tundevicename));
- tunidx = if_nametoindex(config->tundevice);
+ tunidx = if_nametoindex(config->tundevicename);
if (tunidx == 0)
{
LOG(0, 0, 0, "Can't get tun interface index\n");
req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_UNIVERSE;
req.ifmsg.ifaddr.ifa_index = tunidx;
- if (config->bind_address)
- ip = config->bind_address;
+ if (config->nbmultiaddress > 1)
+ {
+ int i;
+ for (i = 0; i < config->nbmultiaddress ; i++)
+ {
+ ip = config->iftun_n_address[i];
+ netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip));
+ if (netlink_send(&req.nh) < 0)
+ goto senderror;
+ }
+ }
else
- ip = 0x01010101; // 1.1.1.1
- netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip));
+ {
+ if (config->iftun_address)
+ ip = config->iftun_address;
+ else
+ ip = 0x01010101; // 1.1.1.1
+ netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip));
+
+ if (netlink_send(&req.nh) < 0)
+ goto senderror;
+ }
+
- 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]) {
exit(1);
}
-// set up UDP ports
-static void initudp(void)
+// set up LAC UDP ports
+static void initlacudp(void)
{
int on = 1;
struct sockaddr_in addr;
- // Tunnel
+ // Tunnel to Remote LNS
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
- addr.sin_port = htons(L2TPPORT);
- addr.sin_addr.s_addr = config->bind_address;
- udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ addr.sin_port = htons(config->bind_portremotelns);
+ addr.sin_addr.s_addr = config->bind_address_remotelns;
+ udplacfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ setsockopt(udplacfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
{
- int flags = fcntl(udpfd, F_GETFL, 0);
- fcntl(udpfd, F_SETFL, flags | O_NONBLOCK);
+ int flags = fcntl(udplacfd, F_GETFL, 0);
+ fcntl(udplacfd, F_SETFL, flags | O_NONBLOCK);
}
- if (bind(udpfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ if (bind(udplacfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
- LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno));
+ LOG(0, 0, 0, "Error in UDP REMOTE LNS bind: %s\n", strerror(errno));
exit(1);
}
+}
+
+// set up control ports
+static void initcontrol(void)
+{
+ int on = 1;
+ struct sockaddr_in addr;
// Control
memset(&addr, 0, sizeof(addr));
LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno));
exit(1);
}
+}
+
+// set up Dynamic Authorization Extensions to RADIUS port
+static void initdae(void)
+{
+ int on = 1;
+ struct sockaddr_in addr;
// Dynamic Authorization Extensions to RADIUS
memset(&addr, 0, sizeof(addr));
LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno));
exit(1);
}
+}
- // Intercept
- snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+// set up UDP ports
+static void initudp(int * pudpfd, in_addr_t ip_bind)
+{
+ int on = 1;
+ struct sockaddr_in addr;
+
+ // Tunnel
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(L2TPPORT);
+ addr.sin_addr.s_addr = ip_bind;
+ (*pudpfd) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ setsockopt((*pudpfd), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ {
+ int flags = fcntl((*pudpfd), F_GETFL, 0);
+ fcntl((*pudpfd), F_SETFL, flags | O_NONBLOCK);
+ }
+ if (bind((*pudpfd), (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
+ LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno));
+ exit(1);
+ }
}
//
ip.s6_addr[1] == 0x80 &&
ip.s6_addr16[1] == 0 &&
ip.s6_addr16[2] == 0 &&
- ip.s6_addr16[3] == 0)) {
- s = lookup_ipmap(*(in_addr_t *) &ip.s6_addr[8]);
+ ip.s6_addr16[3] == 0))
+ {
+ in_addr_t *pipv4 = (in_addr_t *) &ip.s6_addr[8];
+ s = lookup_ipmap(*pipv4);
} else {
s = lookup_ipv6map(ip);
}
//
// (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;
//
// CLI list to dump current ipcache.
//
-int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc)
+int cmd_show_ipcache(struct cli_def *cli, const char *command, char **argv, int argc)
{
union iphash *d = ip_hash, *e, *f, *g;
int i, j, k, l;
return;
}
+ if (t == TUNNEL_ID_PPPOE)
+ {
+ pppoe_sess_send(buf, l, t);
+ return;
+ }
+
if (!tunnel[t].ip)
{
LOG(1, 0, t, "Error sending data out tunnel: no remote endpoint (tunnel not set up)\n");
}
}
- if (sendto(udpfd, buf, l, 0, (void *) &addr, sizeof(addr)) < 0)
+ if (sendto(udpfd[tunnel[t].indexudp], buf, l, 0, (void *) &addr, sizeof(addr)) < 0)
{
LOG(0, ntohs((*(uint16_t *) (buf + 6))), t, "Error sending data out tunnel: %s (udpfd=%d, buf=%p, len=%d, dest=%s)\n",
- strerror(errno), udpfd, buf, l, inet_ntoa(addr.sin_addr));
+ strerror(errno), udpfd[tunnel[t].indexudp], buf, l, inet_ntoa(addr.sin_addr));
STAT(tunnel_tx_errors);
return;
}
// process outgoing (to tunnel) IP
//
-static void processipout(uint8_t *buf, int len)
+// (i.e. this routine writes to data[-8]).
+void processipout(uint8_t *buf, int len)
{
sessionidt s;
+ groupidt g;
sessiont *sp;
tunnelidt t;
- in_addr_t ip;
+ in_addr_t ip, ip_src;
uint8_t *data = buf; // Keep a copy of the originals.
int size = len;
return;
}
+ 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);
+ 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.
if (sp->tbf_out)
{
- // Are we throttling this session?
- if (config->cluster_iam_master)
- tbf_queue_packet(sp->tbf_out, data, size);
- else
- master_throttle_packet(sp->tbf_out, data, size);
- return;
+ if (!config->no_throttle_local_IP || !sessionbyip(ip_src))
+ {
+ // Are we throttling this session?
+ if (config->cluster_iam_master)
+ tbf_queue_packet(sp->tbf_out, data, size);
+ else
+ master_throttle_packet(sp->tbf_out, data, size);
+ return;
+ }
}
if (sp->walled_garden && !config->cluster_iam_master)
return;
}
- // Add on L2TP header
- {
- bundleidt bid = 0;
- if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1)
- {
- bid = session[s].bundle;
- s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links];
- t = session[s].tunnel;
- sp = &session[s];
- LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s);
- if(len > MINFRAGLEN)
- {
- // Partition the packet to "bundle[b].num_of_links" fragments
- bundlet *b = &bundle[bid];
- uint32_t num_of_links = b->num_of_links;
- uint32_t fraglen = len / num_of_links;
- fraglen = (fraglen > session[s].mru ? session[s].mru : fraglen);
- uint32_t last_fraglen = fraglen + len % num_of_links;
- last_fraglen = (last_fraglen > session[s].mru ? len % num_of_links : last_fraglen);
+ if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1)
+ {
+
+ if (!config->cluster_iam_master)
+ {
+ // The MPPP packets must be managed by the Master.
+ master_forward_mppp_packet(s, data, size);
+ return;
+ }
+
+ // Add on L2TP header
+ sessionidt members[MAXBUNDLESES];
+ bundleidt bid = session[s].bundle;
+ bundlet *b = &bundle[bid];
+ uint32_t num_of_links, nb_opened;
+ int i;
+
+ num_of_links = b->num_of_links;
+ nb_opened = 0;
+ for (i = 0;i < num_of_links;i++)
+ {
+ s = b->members[i];
+ if (session[s].ppp.lcp == Opened)
+ {
+ members[nb_opened] = s;
+ nb_opened++;
+ }
+ }
+
+ if (nb_opened < 1)
+ {
+ LOG(3, s, t, "MPPP: PROCESSIPOUT ERROR, no session opened in bundle:%d\n", bid);
+ return;
+ }
+
+ num_of_links = nb_opened;
+ b->current_ses = (b->current_ses + 1) % num_of_links;
+ s = members[b->current_ses];
+ t = session[s].tunnel;
+ sp = &session[s];
+ LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s);
+
+ if (num_of_links > 1)
+ {
+ if(len > MINFRAGLEN)
+ {
+ //for rotate traffic among the member links
+ uint32_t divisor = num_of_links;
+ if (divisor > 2)
+ divisor = divisor/2 + (divisor & 1);
+
+ // Partition the packet to "num_of_links" fragments
+ uint32_t fraglen = len / divisor;
+ uint32_t last_fraglen = fraglen + len % divisor;
uint32_t remain = len;
// send the first packet
- uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, fraglen, s, t, PPPIP, 0, bid, MP_BEGIN);
- if (!p) return;
- tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it...
+ uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, fraglen, s, t, PPPIP, 0, bid, MP_BEGIN);
+ if (!p) return;
+ tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it...
+
// statistics
update_session_out_stat(s, sp, fraglen);
+
remain -= fraglen;
while (remain > last_fraglen)
- {
- s = b->members[b->current_ses = ++b->current_ses % num_of_links];
+ {
+ b->current_ses = (b->current_ses + 1) % num_of_links;
+ s = members[b->current_ses];
t = session[s].tunnel;
sp = &session[s];
- LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s);
- p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0);
- if (!p) return;
- tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it...
+ LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s);
+ p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0);
+ if (!p) return;
+ tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it...
update_session_out_stat(s, sp, fraglen);
remain -= fraglen;
}
// send the last fragment
- s = b->members[b->current_ses = ++b->current_ses % num_of_links];
+ b->current_ses = (b->current_ses + 1) % num_of_links;
+ s = members[b->current_ses];
t = session[s].tunnel;
sp = &session[s];
- LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s);
- p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END);
- if (!p) return;
- tunnelsend(fragbuf, remain + (p-fragbuf), t); // send it...
+ LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s);
+ p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END);
+ if (!p) return;
+ tunnelsend(fragbuf, remain + (p-fragbuf), t); // send it...
update_session_out_stat(s, sp, remain);
if (remain != last_fraglen)
LOG(3, s, t, "PROCESSIPOUT ERROR REMAIN != LAST_FRAGLEN, %d != %d\n", remain, last_fraglen);
- }
- else {
- // Send it as one frame
- uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS);
- if (!p) return;
- tunnelsend(fragbuf, len + (p-fragbuf), t); // send it...
+ }
+ else
+ {
+ // Send it as one frame
+ uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS);
+ if (!p) return;
+ tunnelsend(fragbuf, len + (p-fragbuf), t); // send it...
LOG(4, s, t, "MPPP: packet sent as one frame\n");
update_session_out_stat(s, sp, len);
- }
- }
- else
- {
- uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0);
- if (!p) return;
- tunnelsend(fragbuf, len + (p-fragbuf), t); // send it...
+ }
+ }
+ else
+ {
+ // Send it as one frame (NO MPPP Frame)
+ uint8_t *p = opt_makeppp(buf, len, s, t, PPPIP, 0, 0, 0);
+ tunnelsend(p, len + (buf-p), t); // send it...
update_session_out_stat(s, sp, len);
- }
- }
+ }
+ }
+ else
+ {
+ uint8_t *p = opt_makeppp(buf, len, s, t, PPPIP, 0, 0, 0);
+ tunnelsend(p, len + (buf-p), t); // send it...
+ update_session_out_stat(s, sp, len);
+ }
// Snooping this session, send it to intercept box
if (sp->snoop_ip && sp->snoop_port)
if (session[s].bundle && bundle[session[s].bundle].num_of_links > 1)
{
bundleidt bid = session[s].bundle;
- s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links];
+ bundlet *b = &bundle[bid];
+
+ b->current_ses = (b->current_ses + 1) % b->num_of_links;
+ s = b->members[b->current_ses];
LOG(3, s, session[s].tunnel, "MPPP: Session number becomes: %u\n", s);
}
t = session[s].tunnel;
{
sessiont *sp;
tunnelidt t;
- in_addr_t ip;
+ uint8_t *p;
+ uint8_t *data = buf; // Keep a copy of the originals.
uint8_t b[MAXETHER + 20];
buf += 4;
len -= 4;
- ip = *(in_addr_t *)(buf + 16);
-
if (!session[s].ip)
return;
LOG(5, s, t, "Ethernet -> Tunnel (%d bytes)\n", len);
// Add on L2TP header
- {
- uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP, 0, 0, 0);
- if (!p) return;
- tunnelsend(b, len + (p-b), t); // send it...
- }
+ if (*(uint16_t *) (data + 2) == htons(PKTIPV6))
+ p = makeppp(b, sizeof(b), buf, len, s, t, PPPIPV6, 0, 0, 0); // IPV6
+ else
+ p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP, 0, 0, 0); // IPV4
+
+ if (!p) return;
+
+ tunnelsend(b, len + (p-b), t); // send it...
// Snooping this session.
if (sp->snoop_ip && sp->snoop_port)
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);
+ uint16_t *pint16 = (uint16_t *) (c->buf + c->length + 0);
+ pint16[0] = htons(l);
+ pint16[1] = htons(0);
+ pint16[2] = htons(avp);
+ pint16[3] = htons(val);
c->length += 8;
}
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);
+ uint16_t *pint16 = (uint16_t *) (c->buf + c->length + 0);
+ uint32_t *pint32 = (uint32_t *) (c->buf + c->length + 6);
+ pint16[0] = htons(l);
+ pint16[1] = htons(0);
+ pint16[2] = htons(avp);
+ pint32[0] = htonl(val);
c->length += 10;
}
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);
+ uint16_t *pint16 = (uint16_t *) (c->buf + c->length + 0);
+ pint16[0] = htons(l);
+ pint16[1] = htons(0);
+ pint16[2] = htons(avp);
memcpy(c->buf + c->length + 6, val, strlen(val));
c->length += 6 + strlen(val);
}
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);
+ uint16_t *pint16 = (uint16_t *) (c->buf + c->length + 0);
+ pint16[0] = htons(l);
+ pint16[1] = htons(0);
+ pint16[2] = htons(avp);
memcpy(c->buf + c->length + 6, val, len);
c->length += 6 + len;
}
}
assert(c);
c->next = 0;
- *(uint16_t *) (c->buf + 0) = htons(0xC802); // flags/ver
+ c->buf[0] = 0xC8; // flags
+ c->buf[1] = 0x02; // ver
c->length = 12;
control16(c, 0, mtype, 1);
return c;
// (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
+ uint16_t *pint16 = (uint16_t *) (c->buf + 2);
+ pint16[0] = htons(c->length); // length
+ pint16[1] = htons(tunnel[t].far); // tunnel
+ pint16[2] = htons(far); // session
+ pint16[3] = htons(tunnel[t].ns); // sequence
tunnel[t].ns++; // advance sequence
// link in message in to queue
if (tunnel[t].controlc)
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)
memcpy(&shut_acct[shut_acct_n++], &session[s], sizeof(session[s]));
}
+ if (!session[s].die)
+ session[s].die = TIME + 150; // Clean up in 15 seconds
+
if (session[s].ip)
- { // IP allocated, clear and unroute
+ { // IP allocated, clear and unroute
int r;
int routed = 0;
for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
free_ip_address(s);
// unroute IPv6, if setup
- if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen && del_routes)
+ if (session[s].ipv6route.s6_addr[0] && session[s].ipv6prefixlen && del_routes)
route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
-
- if (b)
+
+ if (session[s].ipv6address.s6_addr[0] && del_routes)
+ {
+ route6set(s, session[s].ipv6address, 128, 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)
+ // This session was part of a bundle
+ bundle[b].num_of_links--;
+ LOG(3, s, session[s].tunnel, "MPPP: Dropping member link: %d from bundle %d\n",s,b);
+ if(bundle[b].num_of_links == 0)
{
- bundleclear(b);
- LOG(3, s, 0, "MPPP: Kill bundle: %d (No remaing member links)\n",b);
- }
- else
+ bundleclear(b);
+ LOG(3, s, session[s].tunnel, "MPPP: Kill bundle: %d (No remaing member links)\n",b);
+ }
+ else
{
- // Adjust the members array to accomodate the new change
- uint8_t mem_num = 0;
- // It should be here num_of_links instead of num_of_links-1 (previous instruction "num_of_links--")
- if(bundle[b].members[bundle[b].num_of_links] != s)
+ // Adjust the members array to accomodate the new change
+ uint8_t mem_num = 0;
+ // It should be here num_of_links instead of num_of_links-1 (previous instruction "num_of_links--")
+ if(bundle[b].members[bundle[b].num_of_links] != s)
{
- uint8_t ml;
- for(ml = 0; 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);
- }
+ 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, session[s].tunnel, "MPPP: Adjusted member links array\n");
+
+ // If the killed session is the first of the bundle,
+ // the new first session must be stored in the cache_ipmap
+ // else the function sessionbyip return 0 and the sending not work any more (processipout).
+ if (mem_num == 0)
+ {
+ sessionidt new_s = bundle[b].members[0];
+
+ routed = 0;
+ // Add the route for this session.
+ for (r = 0; r < MAXROUTE && session[new_s].route[r].ip; r++)
+ {
+ int i, prefixlen;
+ in_addr_t ip;
+
+ prefixlen = session[new_s].route[r].prefixlen;
+ ip = session[new_s].route[r].ip;
+
+ if (!prefixlen) prefixlen = 32;
+ ip &= 0xffffffff << (32 - prefixlen); // Force the ip to be the first one in the route.
+
+ for (i = ip; i < ip+(1<<(32-prefixlen)) ; ++i)
+ cache_ipmap(i, new_s);
+ }
+ cache_ipmap(session[new_s].ip, new_s);
+
+ // IPV6 route
+ if (session[new_s].ipv6prefixlen)
+ cache_ipv6map(session[new_s].ipv6route, session[new_s].ipv6prefixlen, new_s);
+
+ if (session[new_s].ipv6address.s6_addr[0])
+ {
+ cache_ipv6map(session[new_s].ipv6address, 128, new_s);
+ }
+ }
+ }
+ }
+
+ cluster_send_bundle(b);
+ }
}
if (session[s].throttle_in || session[s].throttle_out) // Unthrottle if throttled.
throttle_session(s, 0, 0);
if (cdn_result)
- { // Send CDN
- controlt *c = controlnew(14); // sending CDN
- if (cdn_error)
+ {
+ if (session[s].tunnel == TUNNEL_ID_PPPOE)
{
- uint8_t buf[4];
- *(uint16_t *) buf = htons(cdn_result);
- *(uint16_t *) (buf+2) = htons(cdn_error);
- controlb(c, 1, buf, 4, 1);
+ pppoe_shutdown_session(s);
}
else
- control16(c, 1, cdn_result, 1);
+ {
+ // Send CDN
+ controlt *c = controlnew(14); // sending CDN
+ if (cdn_error)
+ {
+ uint16_t buf[2];
+ buf[0] = htons(cdn_result);
+ buf[1] = htons(cdn_error);
+ controlb(c, 1, (uint8_t *)buf, 4, 1);
+ }
+ else
+ control16(c, 1, cdn_result, 1);
- control16(c, 14, s, 1); // assigned session (our end)
- controladd(c, session[s].far, session[s].tunnel); // send the message
+ control16(c, 14, s, 1); // assigned session (our end)
+ controladd(c, session[s].far, session[s].tunnel); // send the message
+ }
}
// update filter refcounts
q[4] = 3; // ip address option
q[5] = 6; // option length
*(in_addr_t *) (q + 6) = config->peer_address ? config->peer_address :
- config->bind_address ? config->bind_address :
+ config->iftun_n_address[tunnel[t].indexudp] ? config->iftun_n_address[tunnel[t].indexudp] :
my_address; // send my IP
tunnelsend(buf, 10 + (q - buf), t); // send it
// kill a session now
void sessionkill(sessionidt s, char *reason)
{
+ groupidt g;
+
CSTAT(sessionkill);
if (!session[s].opened) // not alive
if (sess_local[s].radius)
radiusclear(sess_local[s].radius, s); // cant send clean accounting data, session is killed
+ if (session[s].forwardtosession)
+ {
+ sessionidt sess = session[s].forwardtosession;
+ if (session[sess].forwardtosession == s)
+ {
+ // Shutdown the linked session also.
+ sessionshutdown(sess, reason, CDN_ADMIN_DISC, TERM_ADMIN_RESET);
+ }
+ }
+
LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
+
+ if ((g = grp_groupbysession(s)))
+ {
+ grp_removesession(g, s);
+ }
+
sessionclear(s);
cluster_send_session(s);
}
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);
}
// read and process packet on tunnel (UDP)
-void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
+void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexudpfd)
{
- uint8_t *chapresponse = NULL;
+ uint8_t *sendchalresponse = NULL;
+ uint8_t *recvchalresponse = NULL;
uint16_t l = len, t = 0, s = 0, ns = 0, nr = 0;
uint8_t *p = buf + 2;
STAT(tunnel_rx_errors);
return;
}
+ if (t == TUNNEL_ID_PPPOE)
+ {
+ LOG(1, s, t, "Received UDP packet with tunnel ID reserved for pppoe\n");
+ STAT(tunnel_rx_errors);
+ return;
+ }
if (*buf & 0x08)
{ // ns/nr
ns = ntohs(*(uint16_t *) p);
if (!config->cluster_iam_master)
{
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
tunnel[t].ip = ntohl(*(in_addr_t *) & addr->sin_addr);
tunnel[t].port = ntohs(addr->sin_port);
tunnel[t].window = 4; // default window
+ tunnel[t].indexudp = indexudpfd;
STAT(tunnel_created);
LOG(1, 0, t, " New tunnel from %s:%u ID %u\n",
fmtaddr(htonl(tunnel[t].ip), 0), tunnel[t].port, t);
case 0: // message type
message = ntohs(*(uint16_t *) b);
mandatory = flags & 0x80;
- LOG(4, s, t, " Message type = %u (%s)\n", *b, l2tp_code(message));
+ LOG(4, s, t, " Message type = %u (%s)\n", message, l2tp_code(message));
break;
case 1: // result code
{
tunnel[t].window = 1; // window of 0 is silly
LOG(4, s, t, " rx window = %u\n", tunnel[t].window);
break;
- case 11: // Challenge
+ case 11: // Request Challenge
{
LOG(4, s, t, " LAC requested CHAP authentication for tunnel\n");
- build_chap_response(b, 2, n, &chapresponse);
+ if (message == 1)
+ build_chap_response(b, 2, n, &sendchalresponse);
+ else if (message == 2)
+ build_chap_response(b, 3, n, &sendchalresponse);
}
break;
- case 13: // Response
+ case 13: // receive challenge Response
+ if (tunnel[t].isremotelns)
+ {
+ recvchalresponse = calloc(17, 1);
+ memcpy(recvchalresponse, b, (n < 17) ? n : 16);
+ LOG(3, s, t, "received challenge response from REMOTE LNS\n");
+ }
+ else
// Why did they send a response? We never challenge.
LOG(2, s, t, " received unexpected challenge response\n");
break;
{
case 1: // SCCRQ - Start Control Connection Request
tunnel[t].state = TUNNELOPENING;
+ LOG(3, s, t, "Received SCCRQ\n");
if (main_quit != QUIT_SHUTDOWN)
{
+ LOG(3, s, t, "sending SCCRP\n");
controlt *c = controlnew(2); // sending SCCRP
control16(c, 2, version, 1); // protocol version
control32(c, 3, 3, 1); // framing
- controls(c, 7, hostname, 1); // host name
- if (chapresponse) controlb(c, 13, chapresponse, 16, 1); // Challenge response
+ controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
+ if (sendchalresponse) controlb(c, 13, sendchalresponse, 16, 1); // Send Challenge response
control16(c, 9, t, 1); // assigned tunnel
controladd(c, 0, t); // send the resply
}
case 2: // SCCRP
tunnel[t].state = TUNNELOPEN;
tunnel[t].lastrec = time_now;
+ LOG(3, s, t, "Received SCCRP\n");
+ if (main_quit != QUIT_SHUTDOWN)
+ {
+ if (tunnel[t].isremotelns && recvchalresponse)
+ {
+ hasht hash;
+
+ lac_calc_rlns_auth(t, 2, hash); // id = 2 (SCCRP)
+ // check authenticator
+ if (memcmp(hash, recvchalresponse, 16) == 0)
+ {
+ LOG(3, s, t, "sending SCCCN to REMOTE LNS\n");
+ controlt *c = controlnew(3); // sending SCCCN
+ controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
+ controls(c, 8, Vendor_name, 1); // Vendor name
+ control16(c, 2, version, 1); // protocol version
+ control32(c, 3, 3, 1); // framing Capabilities
+ if (sendchalresponse) controlb(c, 13, sendchalresponse, 16, 1); // Challenge response
+ control16(c, 9, t, 1); // assigned tunnel
+ controladd(c, 0, t); // send
+ }
+ else
+ {
+ tunnelshutdown(t, "Bad chap response from REMOTE LNS", 4, 0, 0);
+ }
+ }
+ }
+ else
+ {
+ tunnelshutdown(t, "Shutting down", 6, 0, 0);
+ }
break;
case 3: // SCCN
+ LOG(3, s, t, "Received SCCN\n");
tunnel[t].state = TUNNELOPEN;
tunnel[t].lastrec = time_now;
controlnull(t); // ack
break;
case 4: // StopCCN
+ LOG(3, s, t, "Received StopCCN\n");
controlnull(t); // ack
tunnelshutdown(t, "Stopped", 0, 0, 0); // Shut down cleanly
break;
case 6: // HELLO
+ LOG(3, s, t, "Received HELLO\n");
controlnull(t); // simply ACK
break;
case 7: // OCRQ
// TBA
+ LOG(3, s, t, "Received OCRQ\n");
break;
case 8: // OCRO
// TBA
+ LOG(3, s, t, "Received OCRO\n");
break;
case 9: // OCCN
// TBA
+ LOG(3, s, t, "Received OCCN\n");
break;
case 10: // ICRQ
+ LOG(3, s, t, "Received ICRQ\n");
if (sessionfree && main_quit != QUIT_SHUTDOWN)
{
controlt *c = controlnew(11); // ICRP
+ LOG(3, s, t, "Sending ICRP\n");
+
s = sessionfree;
sessionfree = session[s].next;
memset(&session[s], 0, sizeof(session[s]));
{
controlt *c = controlnew(14); // CDN
+ LOG(3, s, t, "Sending CDN\n");
if (!sessionfree)
{
STAT(session_overflow);
}
return;
case 11: // ICRP
- // TBA
+ LOG(3, s, t, "Received ICRP\n");
+ if (session[s].forwardtosession)
+ {
+ controlt *c = controlnew(12); // ICCN
+
+ session[s].opened = time_now;
+ session[s].tunnel = t;
+ session[s].far = asession;
+ session[s].last_packet = session[s].last_data = time_now;
+
+ control32(c, 19, 1, 1); // Framing Type
+ control32(c, 24, 10000000, 1); // Tx Connect Speed
+ controladd(c, asession, t); // send the message
+ LOG(3, s, t, "Sending ICCN\n");
+ }
break;
case 12: // ICCN
+ LOG(3, s, t, "Received ICCN\n");
if (amagic == 0) amagic = time_now;
session[s].magic = amagic; // set magic number
session[s].flags = aflags; // set flags received
// Set multilink options before sending initial LCP packet
sess_local[s].mp_mrru = 1614;
- sess_local[s].mp_epdis = config->bind_address ? config->bind_address : my_address;
+ sess_local[s].mp_epdis = ntohl(config->iftun_address ? config->iftun_address : my_address);
sendlcp(s, t);
change_state(s, lcp, RequestSent);
break;
case 14: // CDN
+ LOG(3, s, t, "Received CDN\n");
controlnull(t); // ack
sessionshutdown(s, disc_reason, CDN_NONE, disc_cause);
break;
LOG(1, s, t, "Unknown message type %u\n", message);
break;
}
- if (chapresponse) free(chapresponse);
+ if (sendchalresponse) free(sendchalresponse);
+ if (recvchalresponse) free(recvchalresponse);
cluster_send_tunnel(t);
}
else
l -= 2;
}
+ if (session[s].forwardtosession)
+ {
+ LOG(5, s, t, "Forwarding data session to session %u\n", session[s].forwardtosession);
+ // Forward to LAC/BAS or Remote LNS session
+ lac_session_forward(buf, len, s, proto, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
+ return;
+ }
+ else if (config->auth_tunnel_change_addr_src)
+ {
+ if (tunnel[t].ip != ntohl(addr->sin_addr.s_addr) &&
+ tunnel[t].port == ntohs(addr->sin_port))
+ {
+ // The remotes BAS are a clustered l2tpns server and the source IP has changed
+ LOG(5, s, t, "The tunnel IP source (%s) has changed by new IP (%s)\n",
+ fmtaddr(htonl(tunnel[t].ip), 0), fmtaddr(addr->sin_addr.s_addr, 0));
+
+ tunnel[t].ip = ntohl(addr->sin_addr.s_addr);
+ }
+ }
+
if (s && !session[s].opened) // Is something wrong??
{
if (!config->cluster_iam_master)
{
// Pass it off to the master to deal with..
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
-
LOG(1, s, t, "UDP packet contains session which is not opened. Dropping packet.\n");
STAT(tunnel_rx_errors);
return;
if (proto == PPPPAP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processpap(s, t, p, l);
}
else if (proto == PPPCHAP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processchap(s, t, p, l);
}
else if (proto == PPPLCP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processlcp(s, t, p, l);
}
else if (proto == PPPIPCP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processipcp(s, t, p, l);
}
else if (proto == PPPIPV6CP && config->ipv6_prefix.s6_addr[0])
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processipv6cp(s, t, p, l);
}
else if (proto == PPPCCP)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
processccp(s, t, p, l);
}
else if (proto == PPPIP)
session[s].last_packet = session[s].last_data = time_now;
if (session[s].walled_garden && !config->cluster_iam_master)
{
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
}
session[s].last_packet = session[s].last_data = time_now;
- if (session[s].walled_garden && !config->cluster_iam_master)
+ if (!config->cluster_iam_master)
{
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ // The fragments reconstruction is managed by the Master.
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
session[s].last_packet = session[s].last_data = time_now;
if (session[s].walled_garden && !config->cluster_iam_master)
{
- master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
return;
}
+ if (!config->cluster_iam_master)
+ {
+ // Check if DhcpV6, IP dst: FF02::1:2, Src Port 0x0222 (546), Dst Port 0x0223 (547)
+ if (*(p + 6) == 17 && *(p + 24) == 0xFF && *(p + 25) == 2 &&
+ *(uint32_t *)(p + 26) == 0 && *(uint32_t *)(p + 30) == 0 &&
+ *(uint16_t *)(p + 34) == 0 && *(p + 36) == 0 && *(p + 37) == 1 && *(p + 38) == 0 && *(p + 39) == 2 &&
+ *(p + 40) == 2 && *(p + 41) == 0x22 && *(p + 42) == 2 && *(p + 43) == 0x23)
+ {
+ // DHCPV6 must be managed by the Master.
+ master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
+ return;
+ }
+ }
+
processipv6in(s, t, p, l);
}
else if (session[s].ppp.lcp == Opened)
{
session[s].last_packet = time_now;
- if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+ if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); return; }
protoreject(s, t, p, l, proto);
}
else
}
// read and process packet on tun
+// (i.e. this routine writes to buf[-8]).
static void processtun(uint8_t * buf, int len)
{
LOG_HEX(5, "Receive TUN Data", buf, len);
if (t > config->cluster_highest_tunnelid)
t = 1;
+ if (t == TUNNEL_ID_PPPOE)
+ continue;
+
// check for expired tunnels
if (tunnel[t].die && tunnel[t].die <= TIME)
{
// Send hello
if (tunnel[t].state == TUNNELOPEN && !tunnel[t].controlc && (time_now - tunnel[t].lastrec) > 60)
{
- controlt *c = controlnew(6); // sending HELLO
- controladd(c, 0, t); // send the message
- LOG(3, 0, t, "Sending HELLO message\n");
- t_actions++;
+ if (!config->disable_sending_hello)
+ {
+ controlt *c = controlnew(6); // sending HELLO
+ controladd(c, 0, t); // send the message
+ LOG(3, 0, t, "Sending HELLO message\n");
+ t_actions++;
+ }
}
// Check for tunnel changes requested from the CLI
}
}
- // Drop sessions who have not responded within IDLE_TIMEOUT seconds
- if (session[s].last_packet && (time_now - session[s].last_packet >= IDLE_TIMEOUT))
+ // Drop sessions who have not responded within IDLE_ECHO_TIMEOUT seconds
+ if (session[s].last_packet && (time_now - session[s].last_packet >= config->idle_echo_timeout))
{
sessionshutdown(s, "No response to LCP ECHO requests.", CDN_ADMIN_DISC, TERM_LOST_SERVICE);
STAT(session_timeout);
}
// No data in ECHO_TIMEOUT seconds, send LCP ECHO
- if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= ECHO_TIMEOUT) &&
- (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT))
+ if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) &&
+ (time_now - sess_local[s].last_echo >= config->echo_timeout))
{
uint8_t b[MAXETHER];
LOG(4, s, session[s].tunnel, "No data in %d seconds, sending LCP ECHO\n",
(int)(time_now - session[s].last_packet));
- tunnelsend(b, 24, session[s].tunnel); // send it
+
+ tunnelsend(b, (q - b) + 8, session[s].tunnel); // send it
sess_local[s].last_echo = time_now;
s_actions++;
}
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)
{
# include "fake_epoll.h"
#endif
-// the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink
-#define BASE_FDS 7
+// the base set of fds polled: cli, cluster, tun, udp (MAX_UDPFD), control, dae, netlink, udplac, pppoedisc, pppoesess
+#define BASE_FDS (9 + MAX_UDPFD)
// additional polled fds
#ifdef BGP
// main loop - gets packets on tun or udp and processes them
static void mainloop(void)
{
- int i;
+ int i, j;
uint8_t buf[65536];
+ uint8_t *p = buf + 32; // for the hearder of the forwarded MPPP packet (see C_MPPP_FORWARD)
+ // and the forwarded pppoe session
+ int size_bufp = sizeof(buf) - 32;
clockt next_cluster_ping = 0; // send initial ping immediately
struct epoll_event events[BASE_FDS + RADIUS_FDS + EXTRA_FDS];
int maxevent = sizeof(events)/sizeof(*events);
exit(1);
}
- LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d\n",
- clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd);
+ LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d , udplacfd=%d, pppoefd=%d, pppoesessfd=%d\n",
+ clifd, cluster_sockfd, tunfd, udpfd[0], controlfd, daefd, nlfd, udplacfd, pppoediscfd, pppoesessfd);
/* setup our fds to poll for input */
{
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, tunfd, &e);
- d[i].type = FD_TYPE_UDP;
- e.data.ptr = &d[i++];
- epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd, &e);
-
d[i].type = FD_TYPE_CONTROL;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, controlfd, &e);
d[i].type = FD_TYPE_NETLINK;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, nlfd, &e);
+
+ d[i].type = FD_TYPE_PPPOEDISC;
+ e.data.ptr = &d[i++];
+ epoll_ctl(epollfd, EPOLL_CTL_ADD, pppoediscfd, &e);
+
+ d[i].type = FD_TYPE_PPPOESESS;
+ e.data.ptr = &d[i++];
+ epoll_ctl(epollfd, EPOLL_CTL_ADD, pppoesessfd, &e);
+
+ for (j = 0; j < config->nbudpfd; j++)
+ {
+ d[i].type = FD_TYPE_UDP;
+ d[i].index = j;
+ e.data.ptr = &d[i++];
+ epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd[j], &e);
+ }
}
#ifdef BGP
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 */
struct in_addr local;
socklen_t alen;
int c, s;
- int udp_ready = 0;
+ int udp_ready[MAX_UDPFD + 1] = INIT_TABUDPVAR;
+ int pppoesess_ready = 0;
+ int pppoesess_pkts = 0;
int tun_ready = 0;
int cluster_ready = 0;
- int udp_pkts = 0;
+ int udp_pkts[MAX_UDPFD + 1] = INIT_TABUDPVAR;
int tun_pkts = 0;
int cluster_pkts = 0;
#ifdef BGP
// these are handled below, with multiple interleaved reads
case FD_TYPE_CLUSTER: cluster_ready++; break;
case FD_TYPE_TUN: tun_ready++; break;
- case FD_TYPE_UDP: udp_ready++; break;
+ case FD_TYPE_UDP: udp_ready[d->index]++; break;
+ case FD_TYPE_PPPOESESS: pppoesess_ready++; break;
+
+ case FD_TYPE_PPPOEDISC: // pppoe discovery
+ s = read(pppoediscfd, p, size_bufp);
+ if (s > 0) process_pppoe_disc(p, s);
+ n--;
+ break;
case FD_TYPE_CONTROL: // nsctl commands
alen = sizeof(addr);
- s = recvfromto(controlfd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
- if (s > 0) processcontrol(buf, s, &addr, alen, &local);
+ s = recvfromto(controlfd, p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
+ if (s > 0) processcontrol(p, s, &addr, alen, &local);
n--;
break;
case FD_TYPE_DAE: // DAE requests
alen = sizeof(addr);
- s = recvfromto(daefd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
- if (s > 0) processdae(buf, s, &addr, alen, &local);
+ s = recvfromto(daefd, p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
+ if (s > 0) processdae(p, s, &addr, alen, &local);
n--;
break;
case FD_TYPE_RADIUS: // RADIUS response
alen = sizeof(addr);
- s = recvfrom(radfds[d->index], buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen);
+ s = recvfrom(radfds[d->index], p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen);
if (s >= 0 && config->cluster_iam_master)
{
if (addr.sin_addr.s_addr == config->radiusserver[0] ||
addr.sin_addr.s_addr == config->radiusserver[1])
- processrad(buf, s, d->index);
+ processrad(p, s, d->index);
else
LOG(3, 0, 0, "Dropping RADIUS packet from unknown source %s\n",
fmtaddr(addr.sin_addr.s_addr, 0));
#ifdef BGP
case FD_TYPE_BGP:
- bgp_events[d->index] = events[i].events;
- n--;
+ bgp_events[d->index] = events[i].events;
+ n--;
break;
#endif /* BGP */
case FD_TYPE_NETLINK:
{
- struct nlmsghdr *nh = (struct nlmsghdr *)buf;
- s = netlink_recv(buf, sizeof(buf));
+ struct nlmsghdr *nh = (struct nlmsghdr *)p;
+ s = netlink_recv(p, size_bufp);
if (nh->nlmsg_type == NLMSG_ERROR)
{
struct nlmsgerr *errmsg = NLMSG_DATA(nh);
exit(1);
}
else
-
LOG(0, 0, 0, "Got a netlink error: %s\n", strerror(-errmsg->error));
}
// else it's a ack
}
default:
- LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type);
+ LOG(0, 0, 0, "Unexpected fd type returned from epoll_wait: %d\n", d->type);
}
}
for (c = 0; n && c < config->multi_read_count; c++)
{
- // L2TP
- if (udp_ready)
+ for (j = 0; j < config->nbudpfd; j++)
{
- alen = sizeof(addr);
- if ((s = recvfrom(udpfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0)
+ // L2TP and L2TP REMOTE LNS
+ if (udp_ready[j])
+ {
+ alen = sizeof(addr);
+ if ((s = recvfrom(udpfd[j], p, size_bufp, 0, (void *) &addr, &alen)) > 0)
+ {
+ processudp(p, s, &addr, j);
+ udp_pkts[j]++;
+ }
+ else
+ {
+ udp_ready[j] = 0;
+ n--;
+ }
+ }
+ }
+
+ // incoming IP
+ if (tun_ready)
+ {
+ if ((s = read(tunfd, p, size_bufp)) > 0)
{
- processudp(buf, s, &addr);
- udp_pkts++;
+ processtun(p, s);
+ tun_pkts++;
}
else
{
- udp_ready = 0;
+ tun_ready = 0;
n--;
}
}
- // incoming IP
- if (tun_ready)
+ // pppoe session
+ if (pppoesess_ready)
{
- if ((s = read(tunfd, buf, sizeof(buf))) > 0)
+ if ((s = read(pppoesessfd, p, size_bufp)) > 0)
{
- processtun(buf, s);
- tun_pkts++;
+ process_pppoe_sess(p, s);
+ pppoesess_pkts++;
}
else
{
- tun_ready = 0;
+ pppoesess_ready = 0;
n--;
}
}
if (cluster_ready)
{
alen = sizeof(addr);
- if ((s = recvfrom(cluster_sockfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen)) > 0)
+ if ((s = recvfrom(cluster_sockfd, p, size_bufp, MSG_WAITALL, (void *) &addr, &alen)) > 0)
{
- processcluster(buf, s, addr.sin_addr.s_addr);
+ processcluster(p, s, addr.sin_addr.s_addr);
cluster_pkts++;
}
else
}
}
- if (udp_pkts > 1 || tun_pkts > 1 || cluster_pkts > 1)
+ if (udp_pkts[0] > 1 || tun_pkts > 1 || cluster_pkts > 1)
STAT(multi_read_used);
if (c >= config->multi_read_count)
{
- LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun and %d cluster packets\n",
- config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts);
-
+ LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster and %d pppoe packets\n",
+ config->multi_read_count, udp_pkts[0], tun_pkts, cluster_pkts, pppoesess_pkts);
STAT(multi_read_exceeded);
more++;
}
}
+#ifdef BGP
+ else
+ /* no event received, but timers could still have expired */
+ bgp_process_peers_timers();
+#endif /* BGP */
if (time_changed)
{
config->ppp_max_failure = 5;
config->kill_timedout_sessions = 1;
strcpy(config->random_device, RANDOMDEVICE);
+ // Set default value echo_timeout and idle_echo_timeout
+ config->echo_timeout = ECHO_TIMEOUT;
+ config->idle_echo_timeout = IDLE_ECHO_TIMEOUT;
log_stream = stderr;
exit(1);
}
#endif /* BGP */
+
+ lac_initremotelnsdata();
+
+ grp_initdata();
}
static int assign_ip_address(sessionidt s)
static int dump_session(FILE **f, sessiont *s)
{
- if (!s->opened || !s->ip || !(s->cin_delta || s->cout_delta) || !*s->user || s->walled_garden)
+ if (!s->opened || (!s->ip && !s->forwardtosession) || !(s->cin_delta || s->cout_delta) || !*s->user || s->walled_garden)
return 1;
if (!*f)
}
LOG(3, 0, 0, "Dumping accounting information to %s\n", filename);
+ if(config->account_all_origin)
+ {
+ fprintf(*f, "# dslwatch.pl dump file V1.01\n"
+ "# host: %s\n"
+ "# endpoint: %s\n"
+ "# time: %ld\n"
+ "# uptime: %ld\n"
+ "# format: username ip qos uptxoctets downrxoctets origin(L=LAC, R=Remote LNS, P=PPPOE)\n",
+ hostname,
+ fmtaddr(config->iftun_n_address[tunnel[s->tunnel].indexudp] ? config->iftun_n_address[tunnel[s->tunnel].indexudp] : my_address, 0),
+ now,
+ now - basetime);
+ }
+ else
+ {
fprintf(*f, "# dslwatch.pl dump file V1.01\n"
"# host: %s\n"
"# endpoint: %s\n"
"# uptime: %ld\n"
"# format: username ip qos uptxoctets downrxoctets\n",
hostname,
- fmtaddr(config->bind_address ? config->bind_address : my_address, 0),
+ fmtaddr(config->iftun_n_address[tunnel[s->tunnel].indexudp] ? config->iftun_n_address[tunnel[s->tunnel].indexudp] : my_address, 0),
now,
now - basetime);
+ }
}
LOG(4, 0, 0, "Dumping accounting information for %s\n", s->user);
+ if(config->account_all_origin)
+ {
+ fprintf(*f, "%s %s %d %u %u %s\n",
+ s->user, // username
+ fmtaddr(htonl(s->ip), 0), // ip
+ (s->throttle_in || s->throttle_out) ? 2 : 1, // qos
+ (uint32_t) s->cin_delta, // uptxoctets
+ (uint32_t) s->cout_delta, // downrxoctets
+ (s->tunnel == TUNNEL_ID_PPPOE)?"P":(tunnel[s->tunnel].isremotelns?"R":"L")); // Origin
+ }
+ else if (!tunnel[s->tunnel].isremotelns && (s->tunnel != TUNNEL_ID_PPPOE))
+ {
fprintf(*f, "%s %s %d %u %u\n",
s->user, // username
fmtaddr(htonl(s->ip), 0), // ip
(s->throttle_in || s->throttle_out) ? 2 : 1, // qos
(uint32_t) s->cin_delta, // uptxoctets
(uint32_t) s->cout_delta); // downrxoctets
+ }
s->cin_delta = s->cout_delta = 0;
case 'd':
if (fork()) exit(0);
setsid();
- freopen("/dev/null", "r", stdin);
- freopen("/dev/null", "w", stdout);
- freopen("/dev/null", "w", stderr);
+ if(!freopen("/dev/null", "r", stdin)) LOG(0, 0, 0, "Error freopen stdin: %s\n", strerror(errno));
+ if(!freopen("/dev/null", "w", stdout)) LOG(0, 0, 0, "Error freopen stdout: %s\n", strerror(errno));
+ if(!freopen("/dev/null", "w", stderr)) LOG(0, 0, 0, "Error freopen stderr: %s\n", strerror(errno));
break;
case 'v':
optdebug++;
initplugins();
initdata(optdebug, optconfig);
- init_cli(hostname);
+ init_cli();
read_config_file();
+ /* set hostname /after/ having read the config file */
+ if (*config->hostname)
+ strcpy(hostname, config->hostname);
+ cli_init_complete(hostname);
update_config();
init_tbf(config->num_tbfs);
LOG(0, 0, 0, "L2TPNS version " VERSION "\n");
+ LOG(0, 0, 0, "Copyright (c) 2012, 2013, 2014 ISP FDN & SAMESWIRELESS\n");
LOG(0, 0, 0, "Copyright (c) 2003, 2004, 2005, 2006 Optus Internet Engineering\n");
LOG(0, 0, 0, "Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n");
{
LOG(0, 0, 0, "Can't set ulimit: %s\n", strerror(errno));
// Make core dumps go to /tmp
- chdir("/tmp");
+ if(chdir("/tmp")) LOG(0, 0, 0, "Error chdir /tmp: %s\n", strerror(errno));
}
if (config->scheduler_fifo)
exit(1);
inittun();
- LOG(1, 0, 0, "Set up on interface %s\n", config->tundevice);
+ LOG(1, 0, 0, "Set up on interface %s\n", config->tundevicename);
+
+ if (*config->pppoe_if_to_bind)
+ {
+ init_pppoe();
+ LOG(1, 0, 0, "Set up on pppoe interface %s\n", config->pppoe_if_to_bind);
+ }
+
+ if (!config->nbmultiaddress)
+ {
+ config->bind_n_address[0] = config->bind_address;
+ config->nbmultiaddress++;
+ }
+ config->nbudpfd = config->nbmultiaddress;
+ for (i = 0; i < config->nbudpfd; i++)
+ initudp(&udpfd[i], config->bind_n_address[i]);
+ initlacudp();
+ config->indexlacudpfd = config->nbudpfd;
+ udpfd[config->indexlacudpfd] = udplacfd;
+ config->nbudpfd++;
+
+ initcontrol();
+ initdae();
+
+ // Intercept
+ snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- initudp();
initrad();
initippool();
+ dhcpv6_init();
// seed prng
{
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 (!config->radius_dae_port)
config->radius_dae_port = DAEPORT;
+ if(!config->bind_portremotelns)
+ config->bind_portremotelns = L2TPLACPORT;
+ if(!config->bind_address_remotelns)
+ config->bind_address_remotelns = INADDR_ANY;
+
+ if (*config->bind_multi_address)
+ {
+ char *sip = config->bind_multi_address;
+ char *n = sip;
+ char *e = config->bind_multi_address + strlen(config->bind_multi_address);
+ config->nbmultiaddress = 0;
+
+ while (*sip && (sip < e))
+ {
+ in_addr_t ip = 0;
+ uint8_t u = 0;
+
+ while (n < e && (*n == ',' || *n == ' ')) n++;
+
+ while (n < e && (isdigit(*n) || *n == '.'))
+ {
+ if (*n == '.')
+ {
+ ip = (ip << 8) + u;
+ u = 0;
+ }
+ else
+ u = u * 10 + *n - '0';
+ n++;
+ }
+ ip = (ip << 8) + u;
+ n++;
+
+ if (ip)
+ {
+ config->bind_n_address[config->nbmultiaddress] = htonl(ip);
+ config->iftun_n_address[config->nbmultiaddress] = htonl(ip);
+ config->nbmultiaddress++;
+ LOG(1, 0, 0, "Bind address %s\n", fmtaddr(htonl(ip), 0));
+
+ if (config->nbmultiaddress >= MAX_BINDADDR) break;
+ }
+
+ sip = n;
+ }
+
+ if (config->nbmultiaddress >= 1)
+ {
+ config->bind_address = config->bind_n_address[0];
+ config->iftun_address = config->bind_address;
+ }
+ }
+
+ if(!config->iftun_address)
+ {
+ config->iftun_address = config->bind_address;
+ config->iftun_n_address[0] = config->iftun_address;
+ }
+
+ if (*config->multi_hostname)
+ {
+ char *shost = config->multi_hostname;
+ char *n = shost;
+ char *e = config->multi_hostname + strlen(config->multi_hostname);
+ config->nbmultihostname = 0;
+
+ while (*shost && (shost < e))
+ {
+ while ((n < e) && (*n == ' ' || *n == ',' || *n == '\t')) n++;
+
+ i = 0;
+ while (n < e && (*n != ',') && (*n != '\t'))
+ {
+ config->multi_n_hostname[config->nbmultihostname][i] = *n;
+ n++;i++;
+ }
+
+ if (i > 0)
+ {
+ config->multi_n_hostname[config->nbmultihostname][i] = 0;
+ LOG(1, 0, 0, "Bind Hostname %s\n", config->multi_n_hostname[config->nbmultihostname]);
+ config->nbmultihostname++;
+ if (config->nbmultihostname >= MAX_NBHOSTNAME) break;
+ }
+
+ shost = n;
+ }
+
+ if (config->nbmultihostname >= 1)
+ {
+ strcpy(hostname, config->multi_n_hostname[0]);
+ strcpy(config->hostname, hostname);
+ }
+ }
+
+ if (!*config->pppoe_ac_name)
+ strncpy(config->pppoe_ac_name, DEFAULT_PPPOE_AC_NAME, sizeof(config->pppoe_ac_name) - 1);
+
// re-initialise the random number source
initrandom(config->random_device);
LOG(3, s, t, "Doing session setup for session\n");
// Join a bundle if the MRRU option is accepted
- if(session[s].mrru > 0 && session[s].bundle == 0)
- {
- LOG(3, s, t, "This session can be part of multilink bundle\n");
- if (join_bundle(s) > 0)
- cluster_send_bundle(session[s].bundle);
+ if(session[s].mrru > 0 && session[s].bundle == 0)
+ {
+ LOG(3, s, t, "This session can be part of multilink bundle\n");
+ if (join_bundle(s) > 0)
+ cluster_send_bundle(session[s].bundle);
else
{
LOG(0, s, t, "MPPP: Mismaching mssf option with other sessions in bundle\n");
sessionshutdown(s, "Mismaching mssf option.", CDN_NONE, TERM_SERVICE_UNAVAILABLE);
return 0;
}
- }
+ }
if (!session[s].ip)
{
fmtaddr(htonl(session[s].ip), 0));
}
-
// Make sure this is right
session[s].tunnel = t;
for (i = 1; i <= config->cluster_highest_sessionid; i++)
{
if (i == s) continue;
- if (!session[s].opened) continue;
+ if (!session[s].opened) break;
// Allow duplicate sessions for multilink ones of the same bundle.
- if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle)
- continue;
+ if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle) continue;
+
if (ip == session[i].ip)
{
- sessionkill(i, "Duplicate IP address");
+ sessionshutdown(i, "Duplicate IP address", CDN_ADMIN_DISC, TERM_ADMIN_RESET); // close radius/routes, etc.
continue;
}
if (session[s].walled_garden || session[i].walled_garden) continue;
// Guest change
int found = 0;
- int gu;
- for (gu = 0; gu < guest_accounts_num; gu++)
- {
- if (!strcasecmp(user, guest_users[gu]))
- {
- found = 1;
- break;
- }
- }
- if (found) continue;
+ int gu;
+ for (gu = 0; gu < guest_accounts_num; gu++)
+ {
+ if (!strcasecmp(user, guest_users[gu]))
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (found) continue;
// Drop the new session in case of duplicate sessionss, not the old one.
if (!strcasecmp(user, session[i].user))
- sessionkill(i, "Duplicate session for users");
+ sessionshutdown(i, "Duplicate session for users", CDN_ADMIN_DISC, TERM_ADMIN_RESET); // close radius/routes, etc.
}
}
// no need to set a route for the same IP address of the bundle
if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1))
{
- int routed = 0;
+ int routed = 0;
+ 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
uncache_ipmap(session[s].ip);
}
+ // remove old IPV6 routes...
+ if (session[s].ipv6route.s6_addr[0] && session[s].ipv6prefixlen)
+ route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
+
+ if (session[s].ipv6address.s6_addr[0])
+ {
+ route6set(s, session[s].ipv6address, 128, 0);
+ }
+
routed = 0;
// add new routes...
// check v6 routing
if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
- route6set(s, new->ipv6route, new->ipv6prefixlen, 1);
+ route6set(s, new->ipv6route, new->ipv6prefixlen, 1);
+
+ if (new->ipv6address.s6_addr[0] && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
+ {
+ // Check if included in prefix
+ if (sessionbyipv6(new->ipv6address) != s)
+ route6set(s, new->ipv6address, 128, 1);
+ }
// check filters
if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0]))
tunnelidt i;
for (i = 1; i < MAXTUNNEL; i++)
{
- if (tunnel[i].state == TUNNELFREE)
+ if ((tunnel[i].state == TUNNELFREE) && (i != TUNNEL_ID_PPPOE))
{
LOG(4, 0, i, "Assigning tunnel ID %u\n", i);
if (i > config->cluster_highest_tunnelid)
}
}
-int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc)
+int cmd_show_hist_idle(struct cli_def *cli, const char *command, char **argv, int argc)
{
int s, i;
int count = 0;
return CLI_OK;
}
-int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc)
+int cmd_show_hist_open(struct cli_def *cli, const char *command, char **argv, int argc)
{
int s, i;
int count = 0;
// default deny
return 0;
}
+
+tunnelidt lac_new_tunnel()
+{
+ return new_tunnel();
+}
+
+void lac_tunnelclear(tunnelidt t)
+{
+ tunnelclear(t);
+}
+
+void lac_send_SCCRQ(tunnelidt t, uint8_t * auth, unsigned int auth_len)
+{
+ uint16_t version = 0x0100; // protocol version
+
+ tunnel[t].state = TUNNELOPENING;
+
+ // Sent SCCRQ - Start Control Connection Request
+ controlt *c = controlnew(1); // sending SCCRQ
+ controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
+ controls(c, 8, Vendor_name, 1); // Vendor name
+ control16(c, 2, version, 1); // protocol version
+ control32(c, 3, 3, 1); // framing Capabilities
+ control16(c, 9, t, 1); // assigned tunnel
+ controlb(c, 11, (uint8_t *) auth, auth_len, 1); // CHAP Challenge
+ LOG(3, 0, t, "Sent SCCRQ to REMOTE LNS\n");
+ controladd(c, 0, t); // send
+}
+
+void lac_send_ICRQ(tunnelidt t, sessionidt s)
+{
+ // Sent ICRQ Incoming-call-request
+ controlt *c = controlnew(10); // ICRQ
+
+ control16(c, 14, s, 1); // assigned sesion
+ call_serial_number++;
+ control32(c, 15, call_serial_number, 1); // call serial number
+ LOG(3, s, t, "Sent ICRQ to REMOTE LNS (far ID %u)\n", tunnel[t].far);
+ controladd(c, 0, t); // send
+}
+
+void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char *msg)
+{
+ tunnelshutdown(t, reason, result, error, msg);
+}
+