/** * Acquire existing session from sotrage or create new one. * All session MUST be requested through this function. * @param[in] ip IPv4 address of client. * @param[in] existing_only Do only existing sssion search. * @return New client. */ struct zsession *session_acquire(uint32_t ip, bool existing_only) { struct zsession *sess = NULL; size_t sidx = STORAGE_IDX(ip); // search for existing session pthread_rwlock_rdlock(&zinst()->sessions_lock[sidx]); HASH_FIND(hh, zinst()->sessions[sidx], &ip, sizeof(ip), sess); if (NULL != sess) { __atomic_add_fetch(&sess->refcnt, 1, __ATOMIC_RELAXED); } pthread_rwlock_unlock(&zinst()->sessions_lock[sidx]); // or create new session if (!existing_only && NULL == sess) { pthread_rwlock_wrlock(&zinst()->sessions_lock[sidx]); HASH_FIND(hh, zinst()->sessions[sidx], &ip, sizeof(ip), sess); if (NULL != sess) { __atomic_add_fetch(&sess->refcnt, 1, __ATOMIC_RELAXED); } else { sess = session_create(); sess->ip = ip; __atomic_store_n(&sess->last_activity, ztime(false), __ATOMIC_RELAXED); __atomic_add_fetch(&sess->refcnt, 1, __ATOMIC_RELAXED); // sessions storage reference HASH_ADD(hh, zinst()->sessions[sidx], ip, sizeof(ip), sess); } pthread_rwlock_unlock(&zinst()->sessions_lock[sidx]); } return sess; }
/** * Prepare accounting request data. * @param[in] session Session. * @param[in,out] req Accounting data request. */ static void zrad_acct_prepare(zscope_t *scope, zsession_t *session, zrad_acct_req_t *req) { zclient_t *client = zsession_get_client(session); pthread_spin_lock(&client->lock); req->username = client->login; snprintf(req->session_id, sizeof(req->session_id), "%s-%" PRIu32, client->login, session->ip); pthread_spin_unlock(&client->lock); zclient_release(client); req->calling_station_id = session->ip_str; req->framed_ip_addr = session->ip; req->nas_id = scope->cfg->radius.nas_id; req->traff_down = atomic_load_acquire(&session->traff_down); req->traff_up = atomic_load_acquire(&session->traff_up); req->octets_down = (uint32_t) (req->traff_down % UINT32_MAX); req->octets_up = (uint32_t) (req->traff_up % UINT32_MAX); req->packets_down = atomic_load_acquire(&session->packets_down) % UINT32_MAX; req->packets_up = atomic_load_acquire(&session->packets_up) % UINT32_MAX; req->gigawords_down = (uint32_t) (req->traff_down / UINT32_MAX); req->gigawords_up = (uint32_t) (req->traff_up / UINT32_MAX); req->authentic = PW_RADIUS; if (PW_STATUS_STOP == req->status) { req->session_time = (uint32_t) USEC2SEC(ztime() - session->create_time); } }
static void overlord_auth(struct zsession *sess) { uint64_t last_auth = atomic_load_explicit(&sess->last_auth, memory_order_acquire); uint64_t curr_time = ztime(false); if ((curr_time - last_auth) > zcfg()->session_auth_interval) { if (0 == last_auth) { zero_syslog(LOG_INFO, "New session %s", ipv4_to_str(htonl(sess->ip))); } session_authenticate(sess); atomic_store_explicit(&sess->last_auth, curr_time, memory_order_release); } }
/** * Apply filters on packet and send it to listeners on success. * @param[in] mon Monitor instance. * @param[in] packet Packet buffer. * @param[in] len Packet length. */ void zmonitor_mirror_packet(struct zmonitor *mon, unsigned const char *packet, size_t len) { pthread_rwlock_rdlock(&mon->lock); if (likely(!utarray_len(&mon->monitors))) { goto end; } uint64_t ts = ztime(false); struct pcap_pkthdr pkthdr = { .ts = {0}, .caplen = (uint32_t) len, .len = (uint32_t) len };
static void overlord_acct(struct zsession *sess) { // update accounting int ret; if (sess->accounting_alive) { ret = session_accounting(sess, PW_STATUS_ALIVE, 0); } else { ret = session_accounting(sess, PW_STATUS_START, 0); sess->accounting_alive = (0 == ret); } if (REJECT_RC == ret) { // accounting rejected, mark session for deletion atomic_store_explicit(&sess->delete_flag, true, memory_order_release); } else { atomic_store_explicit(&sess->last_acct, ztime(false), memory_order_release); } }
/** * Server session. * - Authenticate sessions. * - Upload accounting. * - Remove inactive sessions. */ static void overlord_serve_session(struct zsession *sess) { uint64_t curr_time = ztime(true); zclock(true); // refresh // remove inactive, long duration or marked for deletion session uint32_t term_cause = 0; if (atomic_load_explicit(&sess->delete_flag, memory_order_acquire)) { term_cause = PW_ADMIN_RESET; zero_syslog(LOG_INFO, "Removed marked for deletion session %s", ipv4_to_str(htonl(sess->ip))); } else if (overlord_sess_is_idle_timeout(sess, curr_time)) { term_cause = PW_IDLE_TIMEOUT; zero_syslog(LOG_INFO, "Removed inactive session %s", ipv4_to_str(htonl(sess->ip))); } else if ((curr_time - sess->create_time) > atomic_load_explicit(&sess->max_duration, memory_order_acquire)) { term_cause = PW_SESSION_TIMEOUT; zero_syslog(LOG_INFO, "Removed long duration session %s", ipv4_to_str(htonl(sess->ip))); } if (term_cause) { if (sess->accounting_alive) { session_accounting(sess, PW_STATUS_STOP, term_cause); } session_remove(sess); } else { overlord_nat_cleanup(sess); overlord_apply_deferred_rules(sess); // authenticate session if (0 == sess->client->id) { overlord_auth(sess); } else if ((curr_time - atomic_load_explicit(&sess->last_acct, memory_order_acquire)) > atomic_load_explicit(&sess->acct_interval, memory_order_acquire)) { overlord_acct(sess); } } }