X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/272e831e8071da5296e8dd2061f8a166fd70fd07..cb6bbd1db1d8ee44a33cee7e2a40ed290d83dc73:/l2tpns.c diff --git a/l2tpns.c b/l2tpns.c index eb7783b..e3bb2a2 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.25 2004/09/02 04:18:07 fred_nerk Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.31 2004/10/25 15:07:51 bodea Exp $"; #include #include @@ -57,7 +57,7 @@ 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 time_t basetime = 0; // base clock -char hostname[1000] = ""; // us. +char *hostname = NULL; // us. int tunidx; // ifr_ifindex of tun device u32 sessionid = 0; // session id for radius accounting int syslog_log = 0; // are we logging to syslog @@ -95,6 +95,7 @@ struct config_descriptt config_values[] = { CONFIG("debug", debug, INT), CONFIG("log_file", log_filename, STRING), CONFIG("pid_file", pid_file, STRING), + CONFIG("hostname", hostname, STRING), CONFIG("l2tp_secret", l2tpsecret, STRING), CONFIG("primary_dns", default_dns1, IP), CONFIG("secondary_dns", default_dns2, IP), @@ -169,6 +170,7 @@ void dump_state(); void tunnel_clean(); tunnelidt new_tunnel(); void update_config(); +int unhide_avp(u8 *avp, tunnelidt t, sessionidt s, u16 length); static void cache_ipmap(ipt ip, int s); static void uncache_ipmap(ipt ip); @@ -1452,6 +1454,13 @@ void processudp(u8 * buf, int len, struct sockaddr_in *addr) continue; } log(4, ntohl(addr->sin_addr.s_addr), s, t, "Hidden AVP\n"); + // Unhide the AVP + n = unhide_avp(b, t, s, n); + if (n == 0) + { + fatal = flags; + continue; + } } if (*b & 0x3C) { @@ -1566,6 +1575,11 @@ void processudp(u8 * buf, int len, struct sockaddr_in *addr) build_chap_response(b, 2, n, &chapresponse); } break; + case 13: // Response + // Why did they send a response? We never challenge. + log(2, ntohl(addr->sin_addr.s_addr), s, t, " received unexpected challenge response\n"); + break; + case 14: // assigned session asession = session[s].far = ntohs(*(u16 *) (b)); log(4, ntohl(addr->sin_addr.s_addr), s, t, " assigned session = %d\n", asession); @@ -2166,8 +2180,7 @@ int regular_cleanups(void) if (++count >= MAX_ACTIONS) break; } } - - if (config->accounting_dir && next_acct <= TIME) + if (*config->accounting_dir && next_acct <= TIME) { // Dump accounting data next_acct = TIME + ACCT_TIME; @@ -2445,54 +2458,56 @@ void mainloop(void) } // Init data structures -void initdata(void) +void initdata(int optdebug, char *optconfig) { int i; + char *p; - if ((_statistics = shared_malloc(sizeof(struct Tstats))) == MAP_FAILED) + if (!(_statistics = shared_malloc(sizeof(struct Tstats)))) { log(0, 0, 0, 0, "Error doing malloc for _statistics: %s\n", strerror(errno)); exit(1); } - if ((config = shared_malloc(sizeof(struct configt))) == MAP_FAILED) + if (!(config = shared_malloc(sizeof(struct configt)))) { log(0, 0, 0, 0, "Error doing malloc for configuration: %s\n", strerror(errno)); exit(1); } memset(config, 0, sizeof(struct configt)); time(&config->start_time); - strncpy(config->config_file, CONFIGFILE, sizeof(config->config_file) - 1); - if ((tunnel = shared_malloc(sizeof(tunnelt) * MAXTUNNEL)) == MAP_FAILED); + config->debug = optdebug; + strncpy(config->config_file, optconfig, strlen(optconfig)); + if (!(tunnel = shared_malloc(sizeof(tunnelt) * MAXTUNNEL))) { log(0, 0, 0, 0, "Error doing malloc for tunnels: %s\n", strerror(errno)); exit(1); } - if ((session = shared_malloc(sizeof(sessiont) * MAXSESSION)) == MAP_FAILED) + if (!(session = shared_malloc(sizeof(sessiont) * MAXSESSION))) { log(0, 0, 0, 0, "Error doing malloc for sessions: %s\n", strerror(errno)); exit(1); } - if ((sess_count = shared_malloc(sizeof(sessioncountt) * MAXSESSION)) == MAP_FAILED) + if (!(sess_count = shared_malloc(sizeof(sessioncountt) * MAXSESSION))) { log(0, 0, 0, 0, "Error doing malloc for sessions_count: %s\n", strerror(errno)); exit(1); } - if ((radius = shared_malloc(sizeof(radiust) * MAXRADIUS)) == MAP_FAILED) + if (!(radius = shared_malloc(sizeof(radiust) * MAXRADIUS))) { log(0, 0, 0, 0, "Error doing malloc for radius: %s\n", strerror(errno)); exit(1); } - if ((ip_address_pool = shared_malloc(sizeof(ippoolt) * MAXIPPOOL)) == MAP_FAILED) + if (!(ip_address_pool = shared_malloc(sizeof(ippoolt) * MAXIPPOOL))) { log(0, 0, 0, 0, "Error doing malloc for ip_address_pool: %s\n", strerror(errno)); exit(1); } #ifdef RINGBUFFER - if ((ringbuffer = shared_malloc(sizeof(struct Tringbuffer))) == MAP_FAILED) + if (!(ringbuffer = shared_malloc(sizeof(struct Tringbuffer)))) { log(0, 0, 0, 0, "Error doing malloc for ringbuffer: %s\n", strerror(errno)); exit(1); @@ -2500,16 +2515,14 @@ void initdata(void) memset(ringbuffer, 0, sizeof(struct Tringbuffer)); #endif - if ((cli_session_actions = shared_malloc(sizeof(struct cli_session_actions) * MAXSESSION)) - == MAP_FAILED) + if (!(cli_session_actions = shared_malloc(sizeof(struct cli_session_actions) * MAXSESSION))) { log(0, 0, 0, 0, "Error doing malloc for cli session actions: %s\n", strerror(errno)); exit(1); } memset(cli_session_actions, 0, sizeof(struct cli_session_actions) * MAXSESSION); - if ((cli_tunnel_actions = shared_malloc(sizeof(struct cli_tunnel_actions) * MAXSESSION)) - == MAP_FAILED) + if (!(cli_tunnel_actions = shared_malloc(sizeof(struct cli_tunnel_actions) * MAXSESSION))) { log(0, 0, 0, 0, "Error doing malloc for cli tunnel actions: %s\n", strerror(errno)); exit(1); @@ -2534,17 +2547,15 @@ void initdata(void) for (i = 1; i < MAXTUNNEL- 1; i++) tunnel[i].state = TUNNELUNDEF; // mark it as not filled in. - if (!*hostname) - { - char *p; - // Grab my hostname unless it's been specified - gethostname(hostname, sizeof(hostname)); - if ((p = strchr(hostname, '.'))) *p = 0; - } + // Grab my hostname unless it's been specified + gethostname(config->hostname, sizeof(config->hostname)); + if ((p = strchr(config->hostname, '.'))) *p = 0; + hostname = config->hostname; + _statistics->start_time = _statistics->last_reset = time(NULL); #ifdef BGP - if ((bgp_peers = shared_malloc(sizeof(struct bgp_peer) * BGP_NUM_PEERS)) == MAP_FAILED) + if (!(bgp_peers = shared_malloc(sizeof(struct bgp_peer) * BGP_NUM_PEERS))) { log(0, 0, 0, 0, "Error doing malloc for bgp: %s\n", strerror(errno)); exit(1); @@ -2854,7 +2865,7 @@ void dump_acct_info() for (i = 0; i < MAXSESSION; i++) { - if (!session[i].opened || !session[i].ip || !session[i].cin || !session[i].cout || !*session[i].user || session[i].walled_garden) + if (!session[i].opened || !session[i].ip || (!session[i].cin && !session[i].cout) || !*session[i].user || session[i].walled_garden) continue; if (!f) { @@ -2896,13 +2907,14 @@ int main(int argc, char *argv[]) { int o; int optdebug = 0; + char *optconfig = CONFIGFILE; _program_name = strdup(argv[0]); time(&basetime); // start clock // scan args - while ((o = getopt(argc, argv, "vc:h:a:")) >= 0) + while ((o = getopt(argc, argv, "dvc:h:")) >= 0) { switch (o) { @@ -2914,10 +2926,12 @@ int main(int argc, char *argv[]) case 'v': optdebug++; break; + case 'c': + optconfig = optarg; + break; case 'h': snprintf(hostname, sizeof(hostname), "%s", optarg); break; - case '?': default: printf("Args are:\n" "\t-d\tDetach from terminal\n" @@ -2939,12 +2953,10 @@ int main(int argc, char *argv[]) initiptables(); initplugins(); - initdata(); - - config->debug = optdebug; + initdata(optdebug, optconfig); init_tbf(); - init_cli(hostname); + init_cli(); read_config_file(); log(0, 0, 0, 0, "L2TPNS version " VERSION "\n"); @@ -3516,7 +3528,6 @@ int sessionsetup(tunnelidt t, sessionidt s) CSTAT(call_sessionsetup); - log(3, session[s].ip, s, t, "Doing session setup for session\n"); if (!session[s].ip || session[s].ip == 0xFFFFFFFE) @@ -3526,7 +3537,11 @@ int sessionsetup(tunnelidt t, sessionidt s) log(3, 0, s, t, " No IP allocated. Assigned %s from pool\n", inet_toa(htonl(session[s].ip))); else + { log(0, 0, s, t, " No IP allocated. The IP address pool is FULL!\n"); + sessionshutdown(s, "No IP addresses available"); + return 0; + } } @@ -4013,3 +4028,77 @@ int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc cli_print(cli, "%d total sessions open.", count); return CLI_OK; } + +/* Unhide an avp. + * + * This unencodes the AVP using the L2TP CHAP secret and the + * previously stored random vector. It replaces the hidden data with + * the cleartext data and returns the length of the cleartext data + * (including the AVP "header" of 6 bytes). + * + * Based on code from rp-l2tpd by Roaring Penguin Software Inc. + */ +int unhide_avp(u8 *avp, tunnelidt t, sessionidt s, u16 length) +{ + MD5_CTX ctx; + u8 *cursor; + u8 digest[16]; + u8 working_vector[16]; + uint16_t hidden_length; + u8 type[2]; + size_t done, todo; + u8 *output; + + // Find the AVP type. + type[0] = *(avp + 4); + type[1] = *(avp + 5); + + // Line up with the hidden data + cursor = output = avp + 6; + + // Compute initial pad + MD5Init(&ctx); + MD5Update(&ctx, type, 2); + MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret)); + MD5Update(&ctx, session[s].random_vector, session[s].random_vector_length); + MD5Final(digest, &ctx); + + // Get hidden length + hidden_length = ((uint16_t) (digest[0] ^ cursor[0])) * 256 + (uint16_t) (digest[1] ^ cursor[1]); + + // Keep these for later use + working_vector[0] = *cursor; + working_vector[1] = *(cursor + 1); + cursor += 2; + + if (hidden_length > length - 8) + { + log(1, 0, s, t, "Hidden length %d too long in AVP of length %d\n", (int) hidden_length, (int) length); + return 0; + } + + /* Decrypt remainder */ + done = 2; + todo = hidden_length; + while (todo) + { + working_vector[done] = *cursor; + *output = digest[done] ^ *cursor; + ++output; + ++cursor; + --todo; + ++done; + if (done == 16 && todo) + { + // Compute new digest + done = 0; + MD5Init(&ctx); + MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret)); + MD5Update(&ctx, &working_vector, 16); + MD5Final(digest, &ctx); + } + } + + return hidden_length + 6; +} +