Exemplo n.º 1
0
static void overlord_dns_attack_detect(struct zsession *sess)
{
    if (zcfg()->dns_attack_threshold) {
        uint64_t pps = spdm_calc(&sess->dns_speed);
        if (unlikely(pps >= zcfg()->dns_attack_threshold)) {
            if (!sess->is_dns_attack) {
                ZERO_LOG(LOG_WARNING, "DNS amplification attack begin detected: session %s, %" PRIu64 " pps",
                         ipv4_to_str(sess->ip), pps);
                sess->is_dns_attack = true;
            }
        } else if (unlikely(sess->is_dns_attack)) {
            ZERO_LOG(LOG_WARNING, "DNS amplification attack end: session %s", ipv4_to_str(sess->ip));
            sess->is_dns_attack = false;
        }
    }
}
Exemplo n.º 2
0
/**
 * Load uint16 array from config.
 * @param[in] cfg Configuration option.
 * @param[in] option Option name.
 * @param[in,out] array Resulting array.
 * @return Zero on success.
 */
static int load_uint16_list(const config_setting_t *cfg, const char *option, UT_array *array)
{
    config_setting_t *cfg_list = config_setting_get_member(cfg, option);

    if (!cfg_list) {
        ZERO_LOG(LOG_ERR, "config: missing %s entry", option);
        return 0;
    }

    if (config_setting_type(cfg_list) != CONFIG_TYPE_LIST) {
        ZERO_LOG(LOG_ERR, "config: invalid %s entry", option);
        return -1;
    }

    int count = config_setting_length(cfg_list);

    if (0 >= count) {
        return 0;
    }

    utarray_init(array, &ut_uint16_icd);

    for (int i = 0; i < count; i++) {
        int entry = config_setting_get_int_elem(cfg_list, i);

        if (!entry) {
            ZERO_LOG(LOG_ERR, "config: failed to get next %s record", option);
            continue;
        }

        if (entry < UINT16_MAX) {
            uint16_t port = entry;
            utarray_push_back(array, &port);
            continue;
        }

        // if we here, then entry is invalid
        ZERO_LOG(LOG_ERR, "config: invalid %s item: %d", option, entry);
        utarray_done(array);
        return -1;
    }

    utarray_sort(array, uint16_cmp);

    return 0;
}
Exemplo n.º 3
0
/**
 * Load configuration file.
 * @param[in] path Location of configuration file.
 * @param[in,out] zconf Loaded options will be stored here.
 * @return Zero on success.
 */
int zero_config_load(const char *path, struct zero_config *zconf)
{
    int ret = 0;
    config_t config;
    config_init(&config);

    if (NULL == path) {
        path = ZCFG_DEFAULT_PATH;
    }

     if (config_read_file(&config, path)) {
        const config_setting_t *root = config_root_setting(&config);

        ret = ret
            || load_interfaces(root, ZCFG_INTERFACES, &zconf->interfaces)
            || load_uint_req(root, ZCFG_IFACE_WAIT_TIME, &zconf->iface_wait_time)
            || load_uint_req(root, ZCFG_OVERLORD_THREADS, &zconf->overlord_threads)
            || load_kmgt(root, ZCFG_UNAUTH_BW_LIMIT_DOWN, &zconf->unauth_bw_limit[DIR_DOWN], 1024)
            || load_kmgt(root, ZCFG_UNAUTH_BW_LIMIT_UP, &zconf->unauth_bw_limit[DIR_UP], 1024)
            || load_string_req(root, ZCFG_RADIUS_CONFIG_FILE, &zconf->radius_config_file)
            || load_string_req(root, ZCFG_RADIUS_NAS_IDENTIFIER, &zconf->radius_nas_identifier)
            || load_uint64_req(root, ZCFG_SESSION_TIMEOUT, &zconf->session_timeout)
            || load_uint64_req(root, ZCFG_SESSION_ACCT_INTERVAL, &zconf->session_acct_interval)
            || load_uint64_req(root, ZCFG_SESSION_AUTH_INTERVAL, &zconf->session_auth_interval)
            || load_string_req(root, ZCFG_RC_LISTEN_ADDR, &zconf->rc_listen_addr)
            || load_kmgt(root, ZCFG_UPSTREAM_P2P_BW_DOWN, &zconf->upstream_p2p_bw[DIR_DOWN], 1024)
            || load_kmgt(root, ZCFG_UPSTREAM_P2P_BW_UP, &zconf->upstream_p2p_bw[DIR_UP], 1024)
            || load_ip_mask_list(root, ZCFG_IP_WHITELIST, &zconf->ip_whitelist)
            || load_uint16_list(root, ZCFG_P2P_PORTS_WHITELIST, &zconf->p2p_ports_whitelist)
            || load_uint16_list(root, ZCFG_P2P_PORTS_BLACKLIST, &zconf->p2p_ports_blacklist)
            || load_kmgt(root, ZCFG_NON_CLIENT_BW_DOWN, &zconf->non_client_bw[DIR_DOWN], 1024)
            || load_kmgt(root, ZCFG_NON_CLIENT_BW_UP, &zconf->non_client_bw[DIR_UP], 1024)
            || load_kmgt(root, ZCFG_INITIAL_CLIENT_BUCKET_SIZE, &zconf->initial_client_bucket_size, 1024)
        ;

        // convert from bits to bytes
        zconf->unauth_bw_limit[DIR_DOWN] /= 8;
        zconf->unauth_bw_limit[DIR_UP] /= 8;
        zconf->upstream_p2p_bw[DIR_DOWN] /= 8;
        zconf->upstream_p2p_bw[DIR_UP] /= 8;
        zconf->non_client_bw[DIR_DOWN] /= 8;
        zconf->non_client_bw[DIR_UP] /= 8;

        // convert from seconds to microseconds
        zconf->session_timeout *= 1000000;
        zconf->session_acct_interval *= 1000000;
        zconf->session_auth_interval *= 1000000;
    } else {
        ZERO_LOG(LOG_ERR, "config: failed to parse %s (error:%s at %d line)", path, config_error_text(&config), config_error_line(&config));
        ret = -1;
    }

    config_destroy(&config);

    return ret;
}
Exemplo n.º 4
0
/**
 * Load required int value from config.
 * @param[in] cfg Config section.
 * @param[in] opt Option name.
 * @param[out] val Value pointer.
 * @return Zero on success.
 */
static int load_int64_req(const config_setting_t *cfg, const char *opt, int64_t *val)
{
    long long int int64_val;
    if (config_setting_lookup_int64(cfg, opt, &int64_val)) {
        *val = int64_val;
        return 0;
    } else {
        ZERO_LOG(LOG_ERR, "config: '%s' missing", opt);
        return -1;
    }
}
Exemplo n.º 5
0
/**
 * Load required string value from config.
 * @param[in] cfg Config section.
 * @param[in] opt Option name.
 * @param[out] val Value pointer.
 * @return Zero on success.
 */
static int load_string_req(const config_setting_t *cfg, const char *opt, char **val)
{
    const char *str_val;
    if (config_setting_lookup_string(cfg, opt, &str_val)) {
        *val = strdup(str_val);
        return 0;
    } else {
        ZERO_LOG(LOG_ERR, "config: '%s' missing", opt);
        return -1;
    }
}
Exemplo n.º 6
0
/**
 * Load size with SI prefix.
 * @param cfg Config section.
 * @param opt Option name.
 * @param val Value pointer.
 * @param base Value base (e.g. 1000, 1024, etc.).
 * @return Zero on success.
 */
static int load_kmgt(const config_setting_t *cfg, const char *opt, uint64_t *val, u_int base)
{
    const char *str_val;
    if (config_setting_lookup_string(cfg, opt, &str_val)) {
        *val = strtoul(str_val, NULL, 10);
        char prefix = str_val[strlen(str_val)-1];
        if (!isdigit(prefix)) {
            switch (str_val[strlen(str_val)-1]) {
            // no prefix
            case 0:
                break;
            // tera
            case 'T':
            case 't':
                *val *= base;
            // giga
            case 'G':
            case 'g':
                *val *= base;
            // mega
            case 'M':
            case 'm':
                *val *= base;
            // kilo
            case 'K':
            case 'k':
                *val *= base;
                break;
            default:
                ZERO_LOG(LOG_ERR, "config: '%s' invalid value", opt);
                return -1;
            }
        }

        return 0;
    } else {
        ZERO_LOG(LOG_ERR, "config: '%s' missing", opt);
        return -1;
    }
}
Exemplo n.º 7
0
/**
 * Load required unsigned int value from config.
 * @param[in] cfg Config section.
 * @param[in] opt Option name.
 * @param[out] val Value pointer.
 * @return Zero on success.
 */
static int load_uint64_req(const config_setting_t *cfg, const char *opt, uint64_t *val)
{
    int64_t int64_val;

    if (!load_int64_req(cfg, opt, &int64_val)) {
        if (int64_val < 0) {
            ZERO_LOG(LOG_ERR, "config: '%s' must be greater than zero", opt);
        } else {
            *val = (u_int)int64_val;
            return 0;
        }
    }

    return -1;
}
Exemplo n.º 8
0
/**
 * Set BPF filter on monitor connection.
 * @param[in] conn Monitor connection.
 * @param[in] filter Filter string.
 * @return Zero on success.
 */
int zmonitor_conn_set_filter(struct zmonitor_conn *conn, const char *filter)
{
    assert(!conn->active);

    pcap_t *cap = pcap_open_dead(DLT_EN10MB, MONITOR_SNAPLEN);
    pcap_freecode(&conn->bpf);

    if (0 != pcap_compile(cap, &conn->bpf, filter, 1, PCAP_NETMASK_UNKNOWN)) {
        ZERO_LOG(LOG_INFO, "Invalid monitor filter \"%s\": %s", filter, pcap_geterr(cap));
        pcap_close(cap);
        return -1;
    }

    pcap_close(cap);
    return 0;
}
Exemplo n.º 9
0
/**
 * Open netmap ring.
 * @param[in,out] ring
 * @param[in] ringid Ring ID.
 * @param[in] cached_mmap_mem Pointer to already mmapped shared netmap memory.
 */
int znm_open(struct znm_ring *ring, const char *ifname, uint16_t ringid, void *cached_mmap_mem)
{
    struct nmreq req;

    ring->fd = open(ZNM_DEVICE, O_RDWR);
    if (ring->fd < 0) {
        ZERO_ELOG(LOG_ERR, "Unable to open %s", ZNM_DEVICE);
        return -1;
    }

    memset(&req, 0, sizeof(req));
    req.nr_version = NETMAP_API;
    strncpy(req.nr_name, ifname, sizeof(req.nr_name));
    req.nr_ringid = ringid;
    req.nr_flags = NR_REG_ONE_NIC;

    if (0 == ioctl(ring->fd, NIOCGINFO, &req)) {
        ring->memsize = req.nr_memsize;
        if (0 == ioctl(ring->fd, NIOCREGIF, &req)) {
            if (NULL != cached_mmap_mem) {
                ring->mem = cached_mmap_mem;
            } else {
                ring->mem = mmap(0, ring->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, ring->fd, 0);
                ring->own_mmap = 1;
            }

            if (MAP_FAILED != ring->mem) {
                ZERO_LOG(LOG_DEBUG, "Attached to %s HW ring %u", ifname, ringid);
                ring->nifp = NETMAP_IF(ring->mem, req.nr_offset);
                ring->tx = NETMAP_TXRING(ring->nifp, ringid);
                ring->rx = NETMAP_RXRING(ring->nifp, ringid);
                // Success.
                return 0;
            } else {
                ring->mem = NULL;
                ZERO_ELOG(LOG_ERR, "Unable to mmap netmap shared memory");
            }
        } else {
            ZERO_ELOG(LOG_ERR, "Unable to register %s with netmap", ifname);
        }
    } else {
        ZERO_ELOG(LOG_ERR, "Unable to query netmap for '%s' info", ifname);
    }

    close(ring->fd);
    return -1;
}
Exemplo n.º 10
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;
}
Exemplo n.º 11
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;
}
Exemplo n.º 12
0
/**
 * Preapre interface for operation in netmap mode.
 * @param[in] ifname Interface name.
 * @return Zero on success.
 */
int znm_prepare_if(const char *ifname)
{
    struct ifreq ifr;
    struct ethtool_value ethval;
    int fd, ret = -1;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        ZERO_ELOG(LOG_ERR, "Can not create device control socket");
        goto end;
    }

    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));

    // check and set interface flags
    if (0 != ioctl(fd, SIOCGIFFLAGS, &ifr)) {
        ZERO_ELOG(LOG_ERR, "Failed to get '%s' interface flags", ifname);
        goto end;
    }
    if (0 == (ifr.ifr_flags & IFF_UP)) {
        ZERO_LOG(LOG_INFO, "'%s' is down, bringing up...", ifname);
        ifr.ifr_flags |= IFF_UP;
    }
    if (0 == (ifr.ifr_flags & IFF_PROMISC)) {
        ZERO_LOG(LOG_DEBUG, "Set '%s' to promisc mode", ifname);
        ifr.ifr_flags |= IFF_PROMISC;
    }
    if (0 != ioctl(fd, SIOCSIFFLAGS, &ifr)) {
        ZERO_ELOG(LOG_ERR, "Failed to set '%s' interface flags", ifname);
        goto end;
    }

    ifr.ifr_data = (caddr_t) &ethval;

    // disable generic-segmentation-offload
    ethval.cmd = ETHTOOL_SGSO;
    ethval.data = 0;
    if (0 != ioctl(fd, SIOCETHTOOL, &ifr)) {
        ZERO_ELOG(LOG_ERR, "Failed to disable GSO feature on '%s' interface", ifname);
        goto end;
    }

    // disable generic-receive-offload
    ethval.cmd = ETHTOOL_SGRO;
    ethval.data = 0;
    if (0 != ioctl(fd, SIOCETHTOOL, &ifr)) {
        ZERO_ELOG(LOG_ERR, "Failed to disable GRO feature on '%s' interface", ifname);
        goto end;
    }

    // disable tcp-segmentation-offload
    ethval.cmd = ETHTOOL_STSO;
    ethval.data = 0;
    if (0 != ioctl(fd, SIOCETHTOOL, &ifr)) {
        ZERO_ELOG(LOG_ERR, "Failed to disable TSO feature on '%s' interface", ifname);
        goto end;
    }

    // disable hw rx-checksumming
    ethval.cmd = ETHTOOL_SRXCSUM;
    ethval.data = 0;
    if (0 != ioctl(fd, SIOCETHTOOL, &ifr)) {
        ZERO_ELOG(LOG_ERR, "Failed to disable rx-checksum feature on '%s' interface", ifname);
        goto end;
    }

    // disable hw tx-checksumming
    ethval.cmd = ETHTOOL_STXCSUM;
    ethval.data = 0;
    if (0 != ioctl(fd, SIOCETHTOOL, &ifr)) {
        ZERO_ELOG(LOG_ERR, "Failed to disable tx-checksum feature on '%s' interface", ifname);
        goto end;
    }

    // disable ntuple, rx/tx VLAN offload, large-receive-offload
    ethval.cmd = ETHTOOL_SFLAGS;
    ethval.data = 0;
    if (0 != ioctl(fd, SIOCETHTOOL, &ifr)) {
        ZERO_ELOG(LOG_ERR, "Failed to disable ntuple, VLAN offload, LRO features on '%s' interface", ifname);
        goto end;
    }

    ret = 0;

    end:
    if (fd >= 0) close(fd);
    return ret;
}
Exemplo n.º 13
0
/**
   Load interfaces section.
 * @param[in] cfg Config section.
 * @param[in] option Option name.
 * @param[in,out] array Resulting array.
 * @return Zero on success.
 */
int load_interfaces(const config_setting_t *cfg, const char *option, UT_array *array)
{
    config_setting_t *cfg_list = config_setting_get_member(cfg, option);

    if (!cfg_list) {
        ZERO_LOG(LOG_ERR, "config: missing %s entry", option);
        return -1;
    }

    if (config_setting_type(cfg_list) != CONFIG_TYPE_LIST) {
        ZERO_LOG(LOG_ERR, "config: invalid %s entry", option);
        return -1;
    }

    int count = config_setting_length(cfg_list);

    if (0 >= count) {
        ZERO_LOG(LOG_ERR, "config: empty %s entry", option);
        return -1;
    }

    utarray_init(array, &ut_zif_pair_icd);

    for (int i = 0; i < count; i++) {
        struct zif_pair if_pair;
        const char *str;
        config_setting_t *entry = config_setting_get_elem(cfg_list, i);

        if (NULL == entry) {
            ZERO_LOG(LOG_ERR, "config: failed to read %u-th group of %s entry", i, option);
            goto fail;
        }

        if (!config_setting_lookup_string(entry, ZCFG_LAN, &str)) {
            ZERO_LOG(LOG_ERR, "config: failed to read '%s' property of %u-th group of %s entry", ZCFG_LAN, i, option);
            goto fail;
        }
        strncpy(if_pair.lan, str, sizeof(if_pair.lan));

        if (!config_setting_lookup_string(entry, ZCFG_WAN, &str)) {
            ZERO_LOG(LOG_ERR, "config: failed to read '%s' property of %u-th group of %s entry", ZCFG_WAN, i, option);
            goto fail;
        }
        strncpy(if_pair.wan, str, sizeof(if_pair.wan));

        int affinity = 0;
        if (!config_setting_lookup_int(entry, ZCFG_AFFINITY, &affinity)) {
            ZERO_LOG(LOG_ERR, "config: failed to read '%s' property of %u-th group of %s entry", ZCFG_AFFINITY, i, option);
            goto fail;
        }
        if ((affinity < 0) || affinity >= UINT16_MAX) {
            ZERO_LOG(LOG_ERR, "config: invalid value in '%s' property of %u-th group of %s entry", ZCFG_AFFINITY, i, option);
            goto fail;
        }
        if_pair.affinity = (uint16_t)affinity;

        utarray_push_back(array, &if_pair);
    }

    return 0;

fail:
    utarray_done(array);
    return -1;
}
Exemplo n.º 14
0
/**
 * Load ip-mask array.
 * @param[in] cfg Config section.
 * @param[in] option Option name.
 * @param[in,out] array Resulting array.
 * @return Zero on success.
 */
static int load_ip_mask_list(const config_setting_t *cfg, const char *option, UT_array *array)
{
    config_setting_t *cfg_list = config_setting_get_member(cfg, option);

    if (!cfg_list) {
        ZERO_LOG(LOG_ERR, "config: missing %s entry", option);
        return 0;
    }

    if (config_setting_type(cfg_list) != CONFIG_TYPE_LIST) {
        ZERO_LOG(LOG_ERR, "config: invalid %s entry", option);
        return -1;
    }

    int count = config_setting_length(cfg_list);

    if (0 >= count) {
        return 0;
    }

    utarray_init(array, &ut_ip_range_icd);

    for (int i = 0; i < count; i++) {
        struct ip_range range;
        const char *entry = config_setting_get_string_elem(cfg_list, i);

        if (!entry) {
            ZERO_LOG(LOG_ERR, "config: failed to get next %s record", option);
            continue;
        }

        char ip_str[INET_ADDRSTRLEN];
        const char *cidr_pos = strchr(entry, '/');

        // we search for CIDR, and make sure, that ip part is not bigger than allowed size
        if (cidr_pos && ((size_t)(cidr_pos - entry) < sizeof(ip_str))) {
            strncpy(ip_str, entry, cidr_pos - entry);
            ip_str[cidr_pos - entry] = '\0';

            struct in_addr ip_addr;
            if (0 < inet_pton(AF_INET, ip_str, &ip_addr)) {
                u_long cidr = strtoul(cidr_pos + 1, NULL, 10);
                if (cidr != ULONG_MAX && cidr <= 32) {
                    range.ip_start = ntohl(ip_addr.s_addr);
                    range.ip_end = IP_RANGE_END(range.ip_start, cidr);
                    utarray_push_back(array, &range);
                    continue;
                }
            }
        }

        // if we here, then entry is invalid
        ZERO_LOG(LOG_ERR, "config: invalid %s item: %s", option, entry);
        utarray_done(array);
        return -1;
    }

    utarray_sort(array, ip_range_cmp);

    return 0;
}