/* only for debugging, it helds the lock too long for "production" use */ void dst_blst_debug(rpc_t* rpc, void* ctx) { int h; struct dst_blst_entry* e; ticks_t now; struct ip_addr ip; if (!cfg_get(core, core_cfg, use_dst_blacklist)){ rpc->fault(ctx, 500, "dst blacklist support disabled"); return; } now=get_ticks_raw(); for(h=0; h<DST_BLST_HASH_SIZE; h++){ LOCK_BLST(h); for(e=dst_blst_hash[h].first; e; e=e->next){ dst_blst_entry2ip(&ip, e); rpc->add(ctx, "ssddd", get_proto_name(e->proto), ip_addr2a(&ip), e->port, (s_ticks_t)(now-e->expire)<=0? TICKS_TO_S(e->expire-now): -TICKS_TO_S(now-e->expire) , e->flags); } UNLOCK_BLST(h); } }
/* time(2) equivalent, using ser internal timers (faster then a syscall) */ time_t ser_time(time_t *t) { if (likely(t==0)) return last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks); *t=last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks); return *t; }
/* dumps the content of the blacklist in a human-readable format */ void dst_blst_view(rpc_t* rpc, void* ctx) { int h; int expires; struct dst_blst_entry* e; ticks_t now; struct ip_addr ip; if (!cfg_get(core, core_cfg, use_dst_blacklist)){ rpc->fault(ctx, 500, "dst blacklist support disabled"); return; } now=get_ticks_raw(); for(h=0; h<DST_BLST_HASH_SIZE; h++) { LOCK_BLST(h); for(e=dst_blst_hash[h].first; e; e=e->next) { expires = (s_ticks_t)(now-e->expire)<=0? TICKS_TO_S(e->expire-now): -TICKS_TO_S(now-e->expire); /* don't include expired entries into view report */ if (expires < 0) { continue; } dst_blst_entry2ip(&ip, e); rpc->printf(ctx, "{\n protocol: %s", get_proto_name(e->proto)); rpc->printf(ctx, " ip: %s", ip_addr2a(&ip)); rpc->printf(ctx, " port: %d", e->port); rpc->printf(ctx, " expires in (s): %d", expires); rpc->printf(ctx, " flags: %d\n}", e->flags); } UNLOCK_BLST(h); } }
/** * \brief Forks a separate simple sleep() -&- sync periodic timer * * Forks a very basic periodic timer process, that just sleep()s for * the specified interval and then calls the timer function. * The new "sync timer" process execution start immediately, the sleep() * is called first (so the first call to the timer function will happen * \<interval\> seconds after the call to fork_sync_timer) * @param child_id @see fork_process() * @param desc @see fork_process() * @param make_sock @see fork_process() * @param f timer function/callback * @param param parameter passed to the timer function * @param interval interval in seconds. * @return pid of the new process on success, -1 on error * (doesn't return anything in the child process) */ int fork_sync_timer(int child_id, char* desc, int make_sock, timer_function* f, void* param, int interval) { int pid; ticks_t ts1 = 0; ticks_t ts2 = 0; pid=fork_process(child_id, desc, make_sock); if (pid<0) return -1; if (pid==0){ /* child */ interval *= 1000; /* miliseconds */ ts2 = interval; if (cfg_child_init()) return -1; for(;;){ if (ts2>interval) sleep_us(1000); /* 1 milisecond sleep to catch up */ else sleep_us(ts2*1000); /* microseconds sleep */ ts1 = get_ticks_raw(); cfg_update(); f(TICKS_TO_S(ts1), param); /* ticks in sec for compatibility with old timers */ /* adjust the next sleep duration */ ts2 = interval - TICKS_TO_MS(get_ticks_raw()) + TICKS_TO_MS(ts1); } } /* parent */ return pid; }
static void tls_options(rpc_t* rpc, void* c) { void* handle; rpc->add(c, "{", &handle); rpc->struct_add(handle, "dSdddSSSSdSSdddddddddddddd", "force_run", cfg_get(tls, tls_cfg, force_run), "method", &cfg_get(tls, tls_cfg, method), "verify_certificate", cfg_get(tls, tls_cfg, verify_cert), "verify_depth", cfg_get(tls, tls_cfg, verify_depth), "require_certificate", cfg_get(tls, tls_cfg, require_cert), "private_key", &cfg_get(tls, tls_cfg, private_key), "ca_list", &cfg_get(tls, tls_cfg, ca_list), "certificate", &cfg_get(tls, tls_cfg, certificate), "cipher_list", &cfg_get(tls, tls_cfg, cipher_list), "session_cache", cfg_get(tls, tls_cfg, session_cache), "session_id", &cfg_get(tls, tls_cfg, session_id), "config", &cfg_get(tls, tls_cfg, config_file), "log", cfg_get(tls, tls_cfg, log), "debug", cfg_get(tls, tls_cfg, debug), "connection_timeout", TICKS_TO_S(cfg_get(tls, tls_cfg, con_lifetime)), "disable_compression", cfg_get(tls, tls_cfg, disable_compression), "ssl_release_buffers", cfg_get(tls, tls_cfg, ssl_release_buffers), "ssl_freelist_max", cfg_get(tls, tls_cfg, ssl_freelist_max), "ssl_max_send_fragment", cfg_get(tls, tls_cfg, ssl_max_send_fragment), "ssl_read_ahead", cfg_get(tls, tls_cfg, ssl_read_ahead), "send_close_notify", cfg_get(tls, tls_cfg, send_close_notify), "low_mem_threshold1", cfg_get(tls, tls_cfg, low_mem_threshold1), "low_mem_threshold2", cfg_get(tls, tls_cfg, low_mem_threshold2), "ct_wq_max", cfg_get(tls, tls_cfg, ct_wq_max), "con_ct_wq_max", cfg_get(tls, tls_cfg, con_ct_wq_max), "ct_wq_blk_size", cfg_get(tls, tls_cfg, ct_wq_blk_size) ); }
/* gettimeofday(2) equivalent, using ser internal timers (faster * but more imprecise) * WARNING: ignores tz (it's obsolete anyway)*/ int ser_gettimeofday(struct timeval* tv, struct timezone* tz) { if (likely(tv!=0)){ tv->tv_sec=last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks); tv->tv_usec=last_time.tv_usec+ (TICKS_TO_MS(*ticks-last_ticks)%1000)*1000; } return 0; }
/* returns tick in s (for compatibility with the old code) */ ticks_t get_ticks() { #ifndef SHM_MEM LM_CRIT("no shared memory support compiled in" ", returning 0 (probably wrong)"); return 0; #endif return TICKS_TO_S(*ticks); }
static void core_tcp_options(rpc_t* rpc, void* c) { #ifdef USE_TCP void *handle; struct cfg_group_tcp t; if (!tcp_disable){ tcp_options_get(&t); rpc->add(c, "{", &handle); rpc->struct_add(handle, "dddddddddddddddddddddd", "connect_timeout", t.connect_timeout_s, "send_timeout", TICKS_TO_S(t.send_timeout), "connection_lifetime", TICKS_TO_S(t.con_lifetime), "max_connections(soft)", t.max_connections, "no_connect", t.no_connect, "fd_cache", t.fd_cache, "async", t.async, "connect_wait", t.tcp_connect_wait, "conn_wq_max", t.tcpconn_wq_max, "wq_max", t.tcp_wq_max, "defer_accept", t.defer_accept, "delayed_ack", t.delayed_ack, "syncnt", t.syncnt, "linger2", t.linger2, "keepalive", t.keepalive, "keepidle", t.keepidle, "keepintvl", t.keepintvl, "keepcnt", t.keepcnt, "crlf_ping", t.crlf_ping, "accept_aliases", t.accept_aliases, "alias_flags", t.alias_flags, "new_conn_alias_flags", t.new_conn_alias_flags ); }else{ rpc->fault(c, 500, "tcp support disabled"); } #else rpc->fault(c, 500, "tcp support not compiled"); #endif }
/* generic call back for the old style timer functions */ static ticks_t compat_old_handler(ticks_t ti, struct timer_ln* tl, void * data) { struct sr_timer* t; #ifdef TIMER_DEBUG LM_DBG("calling, ticks=%u/%u, tl=%p, t=%p\n", prev_ticks, (unsigned)*ticks, tl, data); #endif t=(struct sr_timer*)data; t->timer_f(TICKS_TO_S(*ticks), t->t_param); return (ticks_t)-1; /* periodic */ }
/* returns tick in s (for compatibility with the old code) */ ticks_t get_ticks() { return TICKS_TO_S(*ticks); }
static int mod_init(void) { int method; if (tls_disable){ LOG(L_WARN, "WARNING: tls: mod_init: tls support is disabled " "(set enable_tls=1 in the config to enable it)\n"); return 0; } if (cfg_get(tcp, tcp_cfg, async) && !tls_force_run){ ERR("tls does not support tcp in async mode, please use" " tcp_async=no in the config file\n"); return -1; } /* Convert tls_method parameter to integer */ method = tls_parse_method(&tls_method); if (method < 0) { ERR("Invalid tls_method parameter value\n"); return -1; } mod_params.method = method; /* Update relative paths of files configured through modparams, relative * pathnames will be converted to absolute and the directory of the main * SER configuration file will be used as reference. */ if (fix_rel_pathnames() < 0) return -1; tls_cfg = (tls_cfg_t**)shm_malloc(sizeof(tls_cfg_t*)); if (!tls_cfg) { ERR("Not enough shared memory left\n"); return -1; } *tls_cfg = NULL; register_tls_hooks(&tls_h); register_select_table(tls_sel); /* if (init_tls() < 0) return -1; */ tls_cfg_lock = lock_alloc(); if (tls_cfg_lock == 0) { ERR("Unable to create TLS configuration lock\n"); return -1; } if (lock_init(tls_cfg_lock) == 0) { lock_dealloc(tls_cfg_lock); ERR("Unable to initialize TLS configuration lock\n"); return -1; } if (tls_cfg_file.s) { *tls_cfg = tls_load_config(&tls_cfg_file); if (!(*tls_cfg)) return -1; } else { *tls_cfg = tls_new_cfg(); if (!(*tls_cfg)) return -1; } if (tls_check_sockets(*tls_cfg) < 0) return -1; /* fix the timeouts from s to ticks */ if (tls_con_lifetime<0){ /* set to max value (~ 1/2 MAX_INT) */ tls_con_lifetime=MAX_TLS_CON_LIFETIME; }else{ if ((unsigned)tls_con_lifetime > (unsigned)TICKS_TO_S(MAX_TLS_CON_LIFETIME)){ LOG(L_WARN, "tls: mod_init: tls_con_lifetime too big (%u s), " " the maximum value is %u\n", tls_con_lifetime, TICKS_TO_S(MAX_TLS_CON_LIFETIME)); tls_con_lifetime=MAX_TLS_CON_LIFETIME; }else{ tls_con_lifetime=S_TO_TICKS(tls_con_lifetime); } } return 0; }
static void tls_list(rpc_t* rpc, void* c) { char buf[128]; char src_ip[IP_ADDR_MAX_STR_SIZE]; char dst_ip[IP_ADDR_MAX_STR_SIZE]; void* handle; char* tls_info; char* state; struct tls_extra_data* tls_d; struct tcp_connection* con; int i, len, timeout; TCPCONN_LOCK; for(i = 0; i < TCP_ID_HASH_SIZE; i++) { for (con = tcpconn_id_hash[i]; con; con = con->id_next) { if (con->rcv.proto != PROTO_TLS) continue; tls_d = con->extra_data; rpc->add(c, "{", &handle); /* tcp data */ if ((len = ip_addr2sbuf(&con->rcv.src_ip, src_ip, sizeof(src_ip))) == 0) BUG("failed to convert source ip"); src_ip[len] = 0; if ((len = ip_addr2sbuf(&con->rcv.dst_ip, dst_ip, sizeof(dst_ip))) == 0) BUG("failed to convert destination ip"); dst_ip[len] = 0; timeout = TICKS_TO_S(con->timeout - get_ticks_raw()); rpc->struct_add(handle, "ddsdsd", "id", con->id, "timeout", timeout, "src_ip", src_ip, "src_port", con->rcv.src_port, "dst_ip", dst_ip, "dst_port", con->rcv.dst_port); if (tls_d) { if(SSL_get_current_cipher(tls_d->ssl)) { tls_info = SSL_CIPHER_description( SSL_get_current_cipher(tls_d->ssl), buf, sizeof(buf)); len = strlen(buf); if (len && buf[len - 1] == '\n') buf[len - 1] = '\0'; } else { tls_info = "unknown"; } /* tls data */ state = "unknown/error"; lock_get(&con->write_lock); switch(tls_d->state) { case S_TLS_NONE: state = "none/init"; break; case S_TLS_ACCEPTING: state = "tls_accept"; break; case S_TLS_CONNECTING: state = "tls_connect"; break; case S_TLS_ESTABLISHED: state = "established"; break; } rpc->struct_add(handle, "sddds", "cipher", tls_info, "ct_wq_size", tls_d->ct_wq? tls_d->ct_wq->queued:0, "enc_rd_buf", tls_d->enc_rd_buf? tls_d->enc_rd_buf->size:0, "flags", tls_d->flags, "state", state ); lock_release(&con->write_lock); } else { rpc->struct_add(handle, "sddds", "cipher", "unknown", "ct_wq_size", 0, "enc_rd_buf", 0, "flags", 0, "state", "pre-init" ); } } } TCPCONN_UNLOCK; }