X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/3cdac878d7531dcb0af7792b58ef58c5ff2a7fb6..e020fbba4d413aada69619e5048f0ae4132611b5:/l2tpns.c diff --git a/l2tpns.c b/l2tpns.c index 22187e1..45ed04f 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,7 +4,7 @@ // 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 #include @@ -60,6 +60,7 @@ int tunfd = -1; // tun interface file handle. (network device) 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 @@ -114,6 +115,7 @@ config_descriptt config_values[] = { 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), @@ -148,6 +150,7 @@ static char *plugin_functions[] = { "plugin_kill_session", "plugin_control", "plugin_radius_response", + "plugin_radius_reset", "plugin_become_master", "plugin_new_session_master", }; @@ -163,7 +166,7 @@ sessiont *session = NULL; // Array of session 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. -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 @@ -326,7 +329,8 @@ static void initrandom(char *source) return; // close previous source, if any - if (rand_fd >= 0) close(rand_fd); + if (rand_fd >= 0) + close(rand_fd); rand_fd = -1; @@ -343,13 +347,6 @@ static void initrandom(char *source) 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 @@ -370,7 +367,7 @@ void random_data(uint8_t *buf, int len) strerror(errno)); // fall back to rand() - initrandom(0); + initrandom(NULL); } n = 0; @@ -584,7 +581,7 @@ static void inittun(void) } } -// set up UDP port +// set up UDP ports static void initudp(void) { int on = 1; @@ -606,7 +603,6 @@ static void initudp(void) 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)); @@ -619,6 +615,21 @@ static void initudp(void) 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); } // @@ -1421,7 +1432,7 @@ void throttle_session(sessionidt s, int rate_in, int rate_out) } // 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. @@ -2030,8 +2041,6 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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); @@ -2052,7 +2061,9 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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 @@ -2274,6 +2285,8 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) 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; @@ -2721,7 +2734,8 @@ static void regular_cleanups(double period) 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"); @@ -2837,7 +2851,8 @@ static void regular_cleanups(double period) && !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); @@ -2847,7 +2862,7 @@ static void regular_cleanups(double period) 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++; } @@ -2961,8 +2976,8 @@ static int still_busy(void) # 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 @@ -2986,8 +3001,8 @@ static void mainloop(void) 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 */ { @@ -2997,25 +3012,29 @@ static void mainloop(void) 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 @@ -3082,12 +3101,6 @@ static void mainloop(void) 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; @@ -3106,9 +3119,21 @@ static void mainloop(void) } // 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); @@ -3929,6 +3954,13 @@ int main(int argc, char *argv[]) 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); @@ -4181,6 +4213,9 @@ static void update_config() 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); @@ -5008,11 +5043,11 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec 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); @@ -5039,6 +5074,31 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec } } +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)