示例#1
0
/**
 * Process upstream p2p bandwidth limits.
 *
 * @param[in] sess Session.
 * @param[in] packet_len Packet length.
 * @param[in] iph IP header.
 * @param[in] flow_dir Flow direction.
 * @return Zero on pass.
 */
static int packet_process_p2p_ipv4(struct zsession *sess, size_t packet_len, struct ip *iph, struct l4_data *l4,
                                   enum flow_dir flow_dir)
{
    if (PROTO_MAX == l4->proto) {
        return 0;
    }

    uint16_t port = ntohs((DIR_UP == flow_dir) ? *l4->dst_port : *l4->src_port);

    pthread_rwlock_rdlock(&sess->lock_client);

    // p2p police enabled and port greater than 1024 and not whitelisted
    if (sess->client->p2p_policy && (port >= 1024) && !utarray_find(&zcfg()->p2p_ports_whitelist, &port, uint16_cmp)) {
        uint64_t speed = spdm_calc(&sess->client->speed[flow_dir]);
        // 1/4 of bw limit
        uint64_t throttle_speed = token_bucket_get_max(&sess->client->band[flow_dir]) / 4;

        uint64_t diff = zclock(false) - sess->client->last_p2p_throttle;
        if ((speed > throttle_speed) || (diff < P2P_THROTTLE_TIME)) {
            unsigned upstream_id = IPTOS_DSCP(iph->ip_tos) >> 2;
            struct token_bucket *bucket = &zinst()->upstreams[upstream_id].band[flow_dir];
            if (0 != token_bucket_update(bucket, packet_len)) {
                return -1;
            }

            struct speed_meter *spd = &zinst()->upstreams[upstream_id].speed[flow_dir];
            spdm_update(spd, packet_len);

            diff = zclock(false) - atomic_load_explicit(&sess->client->last_p2p_throttle, memory_order_acquire);
            if (diff > P2P_THROTTLE_TIME) {
                atomic_store_explicit(&sess->client->last_p2p_throttle, zclock(false), memory_order_release);
            }
        }
示例#2
0
/**
 * Remove session from storage.
 * @param[in] sess
 */
void session_remove(struct zsession *sess)
{
    size_t sidx = STORAGE_IDX(sess->ip);
    pthread_rwlock_wrlock(&zinst()->sessions_lock[sidx]);
    HASH_DELETE(hh, zinst()->sessions[sidx], sess);
    pthread_rwlock_unlock(&zinst()->sessions_lock[sidx]);
    session_release(sess); // release from session hash
}
示例#3
0
/**
 * Destroy session.
 * @param[in] sess
 */
void session_destroy(struct zsession *sess)
{
    // update counters
    __atomic_sub_fetch(&zinst()->sessions_cnt, 1, __ATOMIC_RELAXED);
    if (0 == sess->client->id) {
        __atomic_sub_fetch(&zinst()->unauth_sessions_cnt, 1, __ATOMIC_RELAXED);
    }

    pthread_rwlock_destroy(&sess->lock_client);
    client_session_remove(sess->client, sess);
    client_release(sess->client);

    if(sess->nat) znat_destroy(sess->nat);

    free(sess);
}
示例#4
0
/**
 * 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;
}
示例#5
0
/**
 * Idle timeout for session reached in:
 * - ARP inspection is ON and DHCP lease is expired.
 * - ARP inspection is OFF and last activity was not earlier than default dhcp lease time.
 * @param[in] sess Session.
 * @param[in] now Current time.
 * @return bool
 */
static inline bool overlord_sess_is_idle_timeout(struct zsession *sess, uint64_t now)
{
    if (atomic_load_explicit(&zinst()->arp.mode, memory_order_acquire)) {
        return now > atomic_load_explicit(&sess->dhcp_lease_end, memory_order_acquire);
    } else {
        return (now - zcfg()->dhcp_default_lease_time) >
               atomic_load_explicit(&sess->last_activity, memory_order_acquire);
    }
}
示例#6
0
/**
 * Create new empty session.
 * @return New session pointer.
 */
struct zsession *session_create()
{
    struct zsession *sess = malloc(sizeof(*sess));

    bzero(sess, sizeof(*sess));
    sess->client = client_create();
    client_session_add(sess->client, sess);

    // set default values
    sess->refcnt = 1; // caller references this entry
    pthread_spin_init(&sess->_nat_lock, PTHREAD_PROCESS_PRIVATE);
    pthread_rwlock_init(&sess->lock_client, NULL);

    __atomic_add_fetch(&zinst()->sessions_cnt, 1, __ATOMIC_RELAXED);
    __atomic_add_fetch(&zinst()->unauth_sessions_cnt, 1, __ATOMIC_RELAXED);

    return sess;
}
示例#7
0
/**
 * Traverse session storage from idx_begin to idx_end.
 */
void overlord_run(size_t idx_begin, size_t idx_end)
{
    for (size_t i = idx_begin; i < idx_end; i++) {
        struct zsession *sess, *tmp_sess;

        pthread_rwlock_rdlock(&zinst()->sessions_lock[i]);
        HASH_ITER(hh, zinst()->sessions[i], sess, tmp_sess) {
            pthread_rwlock_unlock(&zinst()->sessions_lock[i]);

            overlord_dns_attack_detect(sess);

            overlord_serve_session(sess);

            if (unlikely(zero_is_abort())) {
                return;
            }

            pthread_rwlock_rdlock(&zinst()->sessions_lock[i]);
        }
        pthread_rwlock_unlock(&zinst()->sessions_lock[i]);
    }
示例#8
0
文件: radius.c 项目: intersvyaz/zerod
/**
 * Parse authentication reply radius attributes.
 * @param[in] session Session.
 * @param[in] attrs Radius attributes.
 * @param[in] rules Client rules.
 */
static void zrad_auth_parse(zsession_t *session, const VALUE_PAIR *attrs, zclient_rules_t *rules)
{
    zclient_rules_init(rules);

    for (; likely(NULL != attrs); attrs = attrs->next) {
        switch (attrs->attribute) {
            case PW_FILTER_ID:
                zclient_rule_parse(zinst()->client_rule_parser, rules, attrs->strvalue);
                break;
            case PW_SESSION_TIMEOUT:
                atomic_store_release(&session->timeout, SEC2USEC(attrs->lvalue));
                break;
            case PW_ACCT_INTERIM_INTERVAL:
                atomic_store_release(&session->acct_interval, SEC2USEC(attrs->lvalue));
                break;
            case PW_IDLE_TIMEOUT:
                atomic_store_release(&session->idle_timeout, SEC2USEC(attrs->lvalue));
                break;
            default:
                ZLOG(LOG_DEBUG, "Unknown radius attribute %d", attrs->attribute);
        }
    }
}
示例#9
0
/**
 * Authenticate and set client info.
 * @param[in] sess Client session.
 * @return Zero on success (or one of *_RC).
 */
static int session_authenticate(struct zsession *sess)
{
    int ret = OTHER_RC;
    VALUE_PAIR *request_attrs = NULL, *response_attrs = NULL, *attrs = NULL;
    char msg[8192]; // WARNING: libfreeradius-client has unsafe working with this buffer.
    rc_handle *rh = zinst()->radh;
    struct in_addr ip_addr;
    char ip_str[INET_ADDRSTRLEN];
    struct zcrules rules;

    crules_init(&rules);

    ip_addr.s_addr = htonl(sess->ip);
    if (unlikely(NULL == inet_ntop(AF_INET, &ip_addr, ip_str, sizeof(ip_str)))) {
        goto end;
    }

    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_USER_NAME, ip_str, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_USER_PASSWORD, "", -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_NAS_IDENTIFIER, zcfg()->radius_nas_identifier, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_CALLING_STATION_ID, ip_str, -1, 0))) {
        goto end;
    }

    ret = rc_auth(rh, 0, request_attrs, &response_attrs, msg);
    if (OK_RC != ret) {
        ZERO_LOG(LOG_ERR, "Session authentication failed for %s (code:%d)", ip_str, ret);
        goto end;
    }

    attrs = response_attrs;
    while (likely(NULL != attrs)) {
        switch (attrs->attribute) {
            case PW_FILTER_ID:
                crules_parse(&rules, attrs->strvalue);
                break;
            case PW_SESSION_TIMEOUT:
                atomic_store_explicit(&sess->max_duration, SEC2USEC(attrs->lvalue), memory_order_release);
                break;
            case PW_ACCT_INTERIM_INTERVAL:
                atomic_store_explicit(&sess->acct_interval, SEC2USEC(attrs->lvalue), memory_order_release);
                break;
        }
        attrs = attrs->next;
    }

    if (likely(rules.have.user_id && rules.have.login)) {
        struct zclient *client = sess->client;

        client_db_find_or_set_id(zinst()->client_db, rules.user_id, &client);
        if (client != sess->client) {
            // found
            pthread_rwlock_wrlock(&sess->lock_client);
            atomic_fetch_add_explicit(&client->refcnt, 1, memory_order_relaxed);
            client_release(sess->client);
            sess->client = client;
            client_session_add(sess->client, sess);
            pthread_rwlock_unlock(&sess->lock_client);
        } else {
            client_apply_rules(sess->client, &rules);
        }

        atomic_fetch_sub_explicit(&zinst()->unauth_sessions_cnt, 1, memory_order_release);

        // log successful authentication
        {
            UT_string rules_str;
            utstring_init(&rules_str);
            utstring_reserve(&rules_str, 1024);

            attrs = response_attrs;
            while (likely(NULL != attrs)) {
                switch (attrs->attribute) {
                    case PW_FILTER_ID:
                        utstring_printf(&rules_str, " %s", attrs->strvalue);
                        break;
                    default:
                        break;
                }
                attrs = attrs->next;
            }

            zero_syslog(LOG_INFO, "Authenticated session %s (rules:%s)", ip_str, utstring_body(&rules_str));
            utstring_done(&rules_str);
        }
    } else {
        ret = OTHER_RC;
        ZERO_LOG(LOG_ERR, "Session authentication failed for %s (code:%d)", ip_str, ret);
    }

    end:
    crules_free(&rules);
    if (request_attrs) rc_avpair_free(request_attrs);
    if (response_attrs) rc_avpair_free(response_attrs);

    return ret;
}
示例#10
0
/**
 * Send radius accounting packet.
 * @param[in] sess Session
 * @param[in] status Accounting status (PW_STATUS_START, PW_STATUS_STOP, PW_STATUS_ALIVE)
 * @param[in] cause Accounting termination cause (used only in case of PW_STATUS_STOP)
 * @return Zero on success (one of *_RC codes).
 */
static int session_accounting(struct zsession *sess, uint32_t status, uint32_t term_cause)
{
    int ret = OTHER_RC;
    VALUE_PAIR *request_attrs = NULL;
    rc_handle *rh = zinst()->radh;
    struct in_addr ip_addr;
    char ip_str[INET_ADDRSTRLEN];

    uint64_t traff_down = atomic_load_explicit(&sess->traff_down, memory_order_acquire);
    uint64_t traff_up = atomic_load_explicit(&sess->traff_up, memory_order_acquire);
    uint32_t octets_down = (uint32_t) (traff_down % UINT32_MAX);
    uint32_t octets_up = (uint32_t) (traff_up % UINT32_MAX);
    uint32_t packets_down = atomic_load_explicit(&sess->packets_down, memory_order_acquire) % UINT32_MAX;
    uint32_t packets_up = atomic_load_explicit(&sess->packets_up, memory_order_acquire) % UINT32_MAX;
    uint32_t gigawords_down = 0;
    uint32_t gigawords_up = 0;

    char session_id[255];
    snprintf(session_id, sizeof(session_id), "%s-%" PRIu32, sess->client->login, sess->ip);

    ip_addr.s_addr = htonl(sess->ip);
    if (unlikely(NULL == inet_ntop(AF_INET, &ip_addr, ip_str, sizeof(ip_str)))) {
        goto end;
    }

    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_CALLING_STATION_ID, ip_str, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_FRAMED_IP_ADDRESS, &sess->ip, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_USER_NAME, sess->client->login, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_SESSION_ID, session_id, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_NAS_IDENTIFIER, zcfg()->radius_nas_identifier, -1, 0))) {
        goto end;
    }
    if (PW_STATUS_STOP == status) {
        if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_TERMINATE_CAUSE, &term_cause, -1, 0))) {
            goto end;
        }
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_STATUS_TYPE, &status, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_INPUT_OCTETS, &octets_down, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_INPUT_PACKETS, &packets_down, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_OUTPUT_OCTETS, &octets_up, -1, 0))) {
        goto end;
    }
    if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_OUTPUT_PACKETS, &packets_down, -1, 0))) {
        goto end;
    }
    if (unlikely(UINT32_MAX < traff_down)) {
        gigawords_down = (uint32_t) (traff_down / UINT32_MAX);
        if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_INPUT_GIGAWORDS, &gigawords_down, -1, 0))) {
            goto end;
        }
    }
    if (unlikely(UINT32_MAX < traff_up)) {
        gigawords_up = (uint32_t) (traff_up / UINT32_MAX);
        if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_OUTPUT_GIGAWORDS, &gigawords_up, -1, 0))) {
            goto end;
        }
    }

    ret = rc_acct(rh, 0, request_attrs);
    if (unlikely(OK_RC != ret)) {
        ZERO_LOG(LOG_ERR, "radius accounting failed %s (code:%d)", ip_str, ret);
        goto end;
    }

    atomic_fetch_sub_explicit(&sess->traff_down, traff_down, memory_order_release);
    atomic_fetch_sub_explicit(&sess->traff_up, traff_up, memory_order_release);
    atomic_fetch_sub_explicit(&sess->packets_down, packets_down, memory_order_release);
    atomic_fetch_sub_explicit(&sess->packets_up, packets_up, memory_order_release);

    end:
    if (request_attrs) {
        rc_avpair_free(request_attrs);
    }

    return ret;
}