// 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.109 2005/06/12 06:10:29 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.113 2005/06/28 14:48:20 bodea Exp $";
#include <arpa/inet.h>
#include <assert.h>
int udpfd = -1; // UDP 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 snoopfd = -1; // UDP file handle for sending out intercept data
int *radfds = NULL; // RADIUS requests file handles
int ifrfd = -1; // File descriptor for routing, etc
CONFIG("radius_interim", radius_interim, INT),
CONFIG("radius_secret", radiussecret, STRING),
CONFIG("radius_authtypes", radius_authtypes_s, STRING),
+ CONFIG("radius_dae_port", radius_dae_port, SHORT),
CONFIG("allow_duplicate_users", allow_duplicate_users, BOOL),
CONFIG("bind_address", bind_address, IPv4),
CONFIG("peer_address", peer_address, IPv4),
"plugin_kill_session",
"plugin_control",
"plugin_radius_response",
+ "plugin_radius_reset",
"plugin_become_master",
"plugin_new_session_master",
};
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.
-ip_filtert *ip_filters = NULL; // Array of named filters.
+ip_filtert *ip_filters = NULL; // Array of named filters.
static controlt *controlfree = 0;
struct Tstats *_statistics = NULL;
#ifdef RINGBUFFER
return;
// close previous source, if any
- if (rand_fd >= 0) close(rand_fd);
+ if (rand_fd >= 0)
+ close(rand_fd);
rand_fd = -1;
path, strerror(errno));
}
}
-
- // no source: seed prng
- {
- unsigned seed = time_now ^ getpid();
- LOG(4, 0, 0, "Seeding the pseudo random generator: %u\n", seed);
- srand(seed);
- }
}
// fill buffer with random data
strerror(errno));
// fall back to rand()
- initrandom(0);
+ initrandom(NULL);
}
n = 0;
}
}
-// set up UDP port
+// set up UDP ports
static void initudp(void)
{
int on = 1;
LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno));
exit(1);
}
- snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Control
memset(&addr, 0, sizeof(addr));
LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno));
exit(1);
}
+
+ // Dynamic Authorization Extensions to RADIUS
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(config->radius_dae_port);
+ daefd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ setsockopt(daefd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ if (bind(daefd, (void *) &addr, sizeof(addr)) < 0)
+ {
+ LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ // Intercept
+ snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
//
}
// add/remove filters from session (-1 = no change)
-static void filter_session(sessionidt s, int filter_in, int filter_out)
+void filter_session(sessionidt s, int filter_in, int filter_out)
{
if (!session[s].opened)
return; // No-one home.
continue;
}
- LOG(4, s, t, "Hidden AVP\n");
-
// Unhide the AVP
unhide_value(b, n, mtype, session[s].random_vector, session[s].random_vector_length);
n = orig_len;
}
- LOG(4, s, t, " AVP %d (%s) len %d\n", mtype, avp_name(mtype), n);
+ LOG(4, s, t, " AVP %d (%s) len %d%s%s\n", mtype, avp_name(mtype), n,
+ flags & 0x40 ? ", hidden" : "", flags & 0x80 ? ", mandatory" : "");
+
switch (mtype)
{
case 0: // message type
case 36: // Random Vector
LOG(4, s, t, " Random Vector received. Enabled AVP Hiding.\n");
memset(session[s].random_vector, 0, sizeof(session[s].random_vector));
+ if (n > sizeof(session[s].random_vector))
+ n = sizeof(session[s].random_vector);
memcpy(session[s].random_vector, b, n);
session[s].random_vector_length = n;
break;
continue;
}
- if (session[s].ip && !(session[s].flags & SF_IPCP_ACKED))
+ if (session[s].ip && !(session[s].flags & SF_IPCP_ACKED)
+ && !(sess_local[s].radius && radius[sess_local[s].radius].state == RADIUSIPCP))
{
// IPCP has not completed yet. Resend
LOG(3, s, session[s].tunnel, "No ACK for initial IPCP ConfigReq... resending\n");
&& !sess_local[s].radius // RADIUS already in progress
&& time_now - sess_local[s].last_interim >= config->radius_interim)
{
- if (!(r = radiusnew(s)))
+ int rad = radiusnew(s);
+ if (!rad)
{
LOG(1, s, session[s].tunnel, "No free RADIUS sessions for Interim message\n");
STAT(radius_overflow);
LOG(3, s, session[s].tunnel, "Sending RADIUS Interim for %s (%u)\n",
session[s].user, session[s].unique_id);
- radiussend(r, RADIUSINTERIM);
+ radiussend(rad, RADIUSINTERIM);
sess_local[s].last_interim = time_now;
s_actions++;
}
# include "fake_epoll.h"
#endif
-// the base set of fds polled: control, cli, udp, tun, cluster
-#define BASE_FDS 5
+// the base set of fds polled: cli, cluster, tun, udp, control, dae
+#define BASE_FDS 6
// additional polled fds
#ifdef BGP
exit(1);
}
- LOG(4, 0, 0, "Beginning of main loop. udpfd=%d, tunfd=%d, cluster_sockfd=%d, controlfd=%d\n",
- udpfd, tunfd, cluster_sockfd, controlfd);
+ LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d\n",
+ clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd);
/* setup our fds to poll for input */
{
e.events = EPOLLIN;
i = 0;
- d[i].type = FD_TYPE_CONTROL;
- e.data.ptr = &d[i++];
- epoll_ctl(epollfd, EPOLL_CTL_ADD, controlfd, &e);
-
d[i].type = FD_TYPE_CLI;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, clifd, &e);
- d[i].type = FD_TYPE_UDP;
+ d[i].type = FD_TYPE_CLUSTER;
e.data.ptr = &d[i++];
- epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd, &e);
+ epoll_ctl(epollfd, EPOLL_CTL_ADD, cluster_sockfd, &e);
d[i].type = FD_TYPE_TUN;
e.data.ptr = &d[i++];
epoll_ctl(epollfd, EPOLL_CTL_ADD, tunfd, &e);
- d[i].type = FD_TYPE_CLUSTER;
+ d[i].type = FD_TYPE_UDP;
e.data.ptr = &d[i++];
- epoll_ctl(epollfd, EPOLL_CTL_ADD, cluster_sockfd, &e);
+ 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_DAE;
+ e.data.ptr = &d[i++];
+ epoll_ctl(epollfd, EPOLL_CTL_ADD, daefd, &e);
}
#ifdef BGP
struct event_data *d = events[i].data.ptr;
switch (d->type)
{
- case FD_TYPE_CONTROL: // nsctl commands
- alen = sizeof(addr);
- processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
- n--;
- break;
-
case FD_TYPE_CLI: // CLI connections
{
int cli;
}
// these are handled below, with multiple interleaved reads
- case FD_TYPE_UDP: udp_ready++; break;
- case FD_TYPE_TUN: tun_ready++; break;
case FD_TYPE_CLUSTER: cluster_ready++; break;
+ case FD_TYPE_TUN: tun_ready++; break;
+ case FD_TYPE_UDP: udp_ready++; break;
+
+ case FD_TYPE_CONTROL: // nsctl commands
+ alen = sizeof(addr);
+ processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
+ n--;
+ break;
+
+ case FD_TYPE_DAE: // DAE requests
+ alen = sizeof(addr);
+ processdae(buf, recvfrom(daefd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
+ n--;
+ break;
case FD_TYPE_RADIUS: // RADIUS response
s = recv(radfds[d->index], buf, sizeof(buf), 0);
initrad();
initippool();
+ // seed prng
+ {
+ unsigned seed = time_now ^ getpid();
+ LOG(4, 0, 0, "Seeding the pseudo random generator: %u\n", seed);
+ srand(seed);
+ }
+
signal(SIGHUP, sighup_handler);
signal(SIGCHLD, sigchild_handler);
signal(SIGTERM, shutdown_handler);
strcat(config->radius_authtypes_s, ", pap");
}
+ if (!config->radius_dae_port)
+ config->radius_dae_port = DAEPORT;
+
// re-initialise the random number source
initrandom(config->random_device);
uint8_t digest[16];
uint8_t *last;
size_t d = 0;
+ uint16_t m = htons(type);
// Compute initial pad
MD5Init(&ctx);
- MD5Update(&ctx, (uint8_t) (type >> 8) & 0xff, 1);
- MD5Update(&ctx, (uint8_t) type & 0xff, 1);
+ MD5Update(&ctx, (unsigned char *) &m, 2);
MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
MD5Update(&ctx, vector, vec_len);
MD5Final(digest, &ctx);
}
}
+int find_filter(char const *name, size_t len)
+{
+ int free = -1;
+ int i;
+
+ for (i = 0; i < MAXFILTER; i++)
+ {
+ if (!*ip_filters[i].name)
+ {
+ if (free < 0)
+ free = i;
+
+ continue;
+ }
+
+ if (strlen(ip_filters[i].name) != len)
+ continue;
+
+ if (!strncmp(ip_filters[i].name, name, len))
+ return i;
+ }
+
+ return free;
+}
+
static int ip_filter_port(ip_filter_portt *p, uint16_t port)
{
switch (p->op)