#ifdef LAC
#include "l2tplac.h"
#endif
+#include "pppoe.h"
#ifdef LAC
char * Vendor_name = "Linux L2TPNS";
CONFIG("echo_timeout", echo_timeout, INT),
CONFIG("idle_echo_timeout", idle_echo_timeout, INT),
CONFIG("iftun_address", iftun_address, IPv4),
+ CONFIG("tundevicename", tundevicename, STRING),
#ifdef LAC
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),
#endif
- { NULL, 0, 0, 0 },
+ 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),
+ { NULL, 0, 0, 0 }
};
static char *plugin_functions[] = {
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");
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");
else
{
// Send it as one frame (NO MPPP Frame)
- 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...
+ 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 = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0);
- if (!p) return;
- tunnelsend(fragbuf, len + (p-fragbuf), t); // send it...
+ 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);
}
static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m)
{
uint16_t l = (m ? 0x8008 : 0x0008);
- c->buf16[c->length/2 + 0] = htons(l);
- c->buf16[c->length/2 + 1] = htons(0);
- c->buf16[c->length/2 + 2] = htons(avp);
- c->buf16[c->length/2 + 3] = htons(val);
+ *(uint16_t *) (c->buf + c->length + 0) = htons(l);
+ *(uint16_t *) (c->buf + c->length + 2) = htons(0);
+ *(uint16_t *) (c->buf + c->length + 4) = htons(avp);
+ *(uint16_t *) (c->buf + c->length + 6) = htons(val);
c->length += 8;
}
static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m)
{
uint16_t l = (m ? 0x800A : 0x000A);
- c->buf16[c->length/2 + 0] = htons(l);
- c->buf16[c->length/2 + 1] = htons(0);
- c->buf16[c->length/2 + 2] = htons(avp);
- *(uint32_t *) &c->buf[c->length + 6] = htonl(val);
+ *(uint16_t *) (c->buf + c->length + 0) = htons(l);
+ *(uint16_t *) (c->buf + c->length + 2) = htons(0);
+ *(uint16_t *) (c->buf + c->length + 4) = htons(avp);
+ *(uint32_t *) (c->buf + c->length + 6) = htonl(val);
c->length += 10;
}
static void controls(controlt * c, uint16_t avp, char *val, uint8_t m)
{
uint16_t l = ((m ? 0x8000 : 0) + strlen(val) + 6);
- c->buf16[c->length/2 + 0] = htons(l);
- c->buf16[c->length/2 + 1] = htons(0);
- c->buf16[c->length/2 + 2] = htons(avp);
- memcpy(&c->buf[c->length + 6], val, strlen(val));
+ *(uint16_t *) (c->buf + c->length + 0) = htons(l);
+ *(uint16_t *) (c->buf + c->length + 2) = htons(0);
+ *(uint16_t *) (c->buf + c->length + 4) = htons(avp);
+ memcpy(c->buf + c->length + 6, val, strlen(val));
c->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);
- c->buf16[c->length/2 + 0] = htons(l);
- c->buf16[c->length/2 + 1] = htons(0);
- c->buf16[c->length/2 + 2] = htons(avp);
- memcpy(&c->buf[c->length + 6], val, len);
+ *(uint16_t *) (c->buf + c->length + 0) = htons(l);
+ *(uint16_t *) (c->buf + c->length + 2) = htons(0);
+ *(uint16_t *) (c->buf + c->length + 4) = htons(avp);
+ memcpy(c->buf + c->length + 6, val, len);
c->length += 6 + len;
}
}
assert(c);
c->next = 0;
- c->buf16[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;
// add a control message to a tunnel, and send if within window
static void controladd(controlt *c, sessionidt far, tunnelidt t)
{
- c->buf16[1] = htons(c->length); // length
- c->buf16[2] = htons(tunnel[t].far); // tunnel
- c->buf16[3] = htons(far); // session
- c->buf16[4] = htons(tunnel[t].ns); // sequence
+ *(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
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
int r;
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)
{
- uint16_t buf[2];
- buf[0] = htons(cdn_result);
- buf[1] = htons(cdn_error);
- controlb(c, 1, (uint8_t *)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
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 (session[s].forwardtosession)
{
LOG(5, s, t, "Forwarding data session to session %u\n", session[s].forwardtosession);
- // Forward to LAC or Remote LNS session
+ // Forward to LAC/BAS or Remote LNS session
lac_session_forward(buf, len, s, proto, addr->sin_addr.s_addr, addr->sin_port);
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);
+ }
+ }
#endif /* LAC */
if (s && !session[s].opened) // Is something wrong??
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
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++;
}
#endif
#ifdef LAC
-// the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink, udplac
-#define BASE_FDS 8
+// the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink, udplac, pppoedisc, pppoesess
+#define BASE_FDS 10
#else
-// 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, control, dae, netlink, pppoedisc, pppoesess
+#define BASE_FDS 9
#endif
// additional polled fds
{
int i;
uint8_t buf[65536];
- uint8_t *p = buf + 8; // for the hearder of the forwarded MPPP packet (see C_MPPP_FORWARD)
- int size_bufp = sizeof(buf) - 8;
+ 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);
}
#ifdef LAC
- 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\n",
- clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd, udplacfd);
+ 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, controlfd, daefd, nlfd, udplacfd, pppoediscfd, pppoesessfd);
#else
- 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, pppoefd=%d, pppoesessfd=%d\n",
+ clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd, pppoediscfd, pppoesessfd);
#endif
/* setup our fds to poll for input */
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, udplacfd, &e);
#endif
+
+ 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);
}
#ifdef BGP
int udplac_ready = 0;
int udplac_pkts = 0;
#endif
+ int pppoesess_ready = 0;
+ int pppoesess_pkts = 0;
int tun_ready = 0;
int cluster_ready = 0;
int udp_pkts = 0;
#ifdef LAC
case FD_TYPE_UDPLAC: udplac_ready++; break;
#endif
+ 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));
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);
if (udp_ready)
{
alen = sizeof(addr);
- if ((s = recvfrom(udpfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0)
+ if ((s = recvfrom(udpfd, p, size_bufp, 0, (void *) &addr, &alen)) > 0)
{
- processudp(buf, s, &addr);
+ processudp(p, s, &addr);
udp_pkts++;
}
else
if (udplac_ready)
{
alen = sizeof(addr);
- if ((s = recvfrom(udplacfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0)
+ if ((s = recvfrom(udplacfd, p, size_bufp, 0, (void *) &addr, &alen)) > 0)
{
if (!config->disable_lac_func)
- processudp(buf, s, &addr);
+ processudp(p, s, &addr);
udplac_pkts++;
}
}
}
+ // pppoe session
+ if (pppoesess_ready)
+ {
+ if ((s = read(pppoesessfd, p, size_bufp)) > 0)
+ {
+ process_pppoe_sess(p, s);
+ pppoesess_pkts++;
+ }
+ else
+ {
+ pppoesess_ready = 0;
+ n--;
+ }
+ }
+
// cluster
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 (c >= config->multi_read_count)
{
#ifdef LAC
- LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster and %d rmlns packets\n",
- config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, udplac_pkts);
+ LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster %d rmlns and %d pppoe packets\n",
+ config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, udplac_pkts, pppoesess_pkts);
#else
- 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, tun_pkts, cluster_pkts, pppoesess_pkts);
#endif
STAT(multi_read_exceeded);
more++;
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);
+ }
initudp();
initrad();
initippool();
if(!config->iftun_address)
config->iftun_address = config->bind_address;
+ 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);
if (ip == session[i].ip)
{
- sessionkill(i, "Duplicate IP address");
- cluster_listinvert_session(s, i);
+ sessionshutdown(i, "Duplicate IP address", CDN_ADMIN_DISC, TERM_ADMIN_RESET); // close radius/routes, etc.
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.
}
}
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)