コード例 #1
0
ファイル: net_ipv4_addr.c プロジェクト: AmVPN/badvpn
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef ifname_arg;
    NCDValRef addr_arg;
    NCDValRef prefix_arg = NCDVal_NewInvalid();
    if (!NCDVal_ListRead(params->args, 2, &ifname_arg, &addr_arg) &&
        !NCDVal_ListRead(params->args, 3, &ifname_arg, &addr_arg, &prefix_arg)
    ) {
        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsString(addr_arg) ||
        (!NCDVal_IsInvalid(prefix_arg) && !NCDVal_IsString(prefix_arg))
    ) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // null terminate ifname
    if (!NCDVal_StringNullTerminate(ifname_arg, &o->ifname_nts)) {
        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
        goto fail0;
    }
    
    if (NCDVal_IsInvalid(prefix_arg)) {
        if (!ipaddr_parse_ipv4_ifaddr(NCDVal_StringMemRef(addr_arg), &o->ifaddr)) {
            ModuleLog(o->i, BLOG_ERROR, "wrong CIDR notation address");
            goto fail1;
        }
    } else {
        if (!ipaddr_parse_ipv4_addr(NCDVal_StringMemRef(addr_arg), &o->ifaddr.addr)) {
            ModuleLog(o->i, BLOG_ERROR, "wrong address");
            goto fail1;
        }
        
        if (!ipaddr_parse_ipv4_prefix(NCDVal_StringMemRef(prefix_arg), &o->ifaddr.prefix)) {
            ModuleLog(o->i, BLOG_ERROR, "wrong prefix");
            goto fail1;
        }
    }
    
    // add address
    if (!NCDIfConfig_add_ipv4_addr(o->ifname_nts.data, o->ifaddr)) {
        ModuleLog(o->i, BLOG_ERROR, "failed to add IP address");
        goto fail1;
    }
    
    // signal up
    NCDModuleInst_Backend_Up(o->i);
    return;
    
fail1:
    NCDValNullTermString_Free(&o->ifname_nts);
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #2
0
ファイル: strcmp.c プロジェクト: 0wsqqsw/lantern
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // check arguments
    NCDValRef str1_arg;
    NCDValRef str2_arg;
    if (!NCDVal_ListRead(params->args, 2, &str1_arg, &str2_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(str1_arg) || !NCDVal_IsString(str2_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // compare
    o->result = (NCDVal_Compare(str1_arg, str2_arg) == 0);
    
    // signal up
    NCDModuleInst_Backend_Up(i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #3
0
ファイル: sleep.c プロジェクト: AmVPN/badvpn
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // check arguments
    NCDValRef ms_start_arg;
    NCDValRef ms_stop_arg = NCDVal_NewInvalid();
    if (!NCDVal_ListRead(params->args, 1, &ms_start_arg) &&
        !NCDVal_ListRead(params->args, 2, &ms_start_arg, &ms_stop_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    
    uintmax_t ms;
    btime_t ms_start;
    
    if (NCDVal_IsString(ms_start_arg) && NCDVal_StringEqualsId(ms_start_arg, NCD_STRING_EMPTY)) {
        ms_start = -1;
    } else {
        if (!ncd_read_uintmax(ms_start_arg, &ms) || ms > INT64_MAX) {
            ModuleLog(o->i, BLOG_ERROR, "wrong start time");
            goto fail0;
        }
        ms_start = ms;
    }
    
    if (NCDVal_IsInvalid(ms_stop_arg) || (NCDVal_IsString(ms_stop_arg) && NCDVal_StringEqualsId(ms_stop_arg, NCD_STRING_EMPTY))) {
        o->ms_stop = -1;
    } else {
        if (!ncd_read_uintmax(ms_stop_arg, &ms) || ms > INT64_MAX) {
            ModuleLog(o->i, BLOG_ERROR, "wrong stop time");
            goto fail0;
        }
        o->ms_stop = ms;
    }
    
    // init timer
    BTimer_Init(&o->timer, 0, timer_handler, o);
    
    // set not dying
    o->dying = 0;
    
    if (ms_start < 0) {
        // go up
        NCDModuleInst_Backend_Up(i);
    } else {
        // set timer
        BReactor_SetTimerAfter(o->i->params->iparams->reactor, &o->timer, ms_start);
    }
    
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #4
0
ファイル: netmask.c プロジェクト: AmVPN/badvpn
static void prefix_to_mask_func_init (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    // read arguments
    NCDValRef prefix_arg;
    if (!NCDVal_ListRead(params->args, 1, &prefix_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(prefix_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // parse prefix
    int prefix;
    if (!ipaddr_parse_ipv4_prefix(NCDVal_StringMemRef(prefix_arg), &prefix)) {
        ModuleLog(i, BLOG_ERROR, "bad prefix");
        goto fail0;
    }
    
    // make mask
    uint32_t mask = ipaddr_ipv4_mask_from_prefix(prefix);
    
    addr_func_init_templ(vo, i, mask);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #5
0
ファイル: choose.c プロジェクト: 0wsqqsw/lantern
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef arg_choices;
    NCDValRef arg_default_result;
    if (!NCDVal_ListRead(params->args, 2, &arg_choices, &arg_default_result)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsList(arg_choices)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // iterate choices
    int have_result = 0;
    size_t count = NCDVal_ListCount(arg_choices);
    for (size_t j = 0; j < count; j++) {
        NCDValRef c = NCDVal_ListGet(arg_choices, j);
        
        // check choice type
        if (!NCDVal_IsList(c)) {
            ModuleLog(i, BLOG_ERROR, "wrong choice type");
            goto fail0;
        }
        
        // read choice
        NCDValRef c_cond;
        NCDValRef c_result;
        if (!NCDVal_ListRead(c, 2, &c_cond, &c_result)) {
            ModuleLog(i, BLOG_ERROR, "wrong choice contents arity");
            goto fail0;
        }
        if (!NCDVal_IsString(c_cond)) {
            ModuleLog(i, BLOG_ERROR, "wrong choice condition type");
            goto fail0;
        }
        
        // update result
        if (!have_result && ncd_read_boolean(c_cond)) {
            o->result = c_result;
            have_result = 1;
        }
    }
    
    // default?
    if (!have_result) {
        o->result = arg_default_result;
    }
    
    // signal up
    NCDModuleInst_Backend_Up(o->i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #6
0
ファイル: basic_functions.c プロジェクト: AmVPN/badvpn
static void decode_value_eval (NCDCall call)
{
    if (NCDCall_ArgCount(&call) != 1) {
        return FunctionLog(&call, BLOG_ERROR, "decode_value: need one argument");
    }
    // Evaluate the string to a temporary mem, not ResMem.
    // Otherwise the ResMem could get resized while we're
    // parsing a string within it, and boom.
    NCDValMem temp_mem;
    NCDValMem_Init(&temp_mem, NCDCall_Iparams(&call)->string_index);
    NCDValRef arg = NCDCall_EvalArg(&call, 0, &temp_mem);
    if (NCDVal_IsInvalid(arg)) {
        goto fail1;
    }
    if (!NCDVal_IsString(arg)) {
        FunctionLog(&call, BLOG_ERROR, "decode_value: argument not a string");
        goto fail1;
    }
    NCDValRef value;
    int res = NCDValParser_Parse(NCDVal_StringMemRef(arg), NCDCall_ResMem(&call), &value);
    if (!res) {
        FunctionLog(&call, BLOG_ERROR, "decode_value: NCDValParser_Parse failed");
        goto fail1;
    }
    NCDCall_SetResult(&call, value);
fail1:
    NCDValMem_Free(&temp_mem);
}
コード例 #7
0
ファイル: index.c プロジェクト: Christeefym/lantern
static void func_new_from_value (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    // read arguments
    NCDValRef arg_value;
    if (!NCDVal_ListRead(params->args, 1, &arg_value)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(arg_value)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }

    // parse value
    uintmax_t value;
    if (!ncd_read_uintmax(arg_value, &value)) {
        ModuleLog(i, BLOG_ERROR, "wrong value");
        goto fail0;
    }

    // check overflow
    if (value > SIZE_MAX) {
        ModuleLog(i, BLOG_ERROR, "value too large");
        goto fail0;
    }

    func_new_templ(vo, i, value);
    return;

fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #8
0
ファイル: exit.c プロジェクト: 2722/lantern
static void func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    // check arguments
    NCDValRef exit_code_arg;
    if (!NCDVal_ListRead(params->args, 1, &exit_code_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(exit_code_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }

    // parse exit code
    uintmax_t exit_code;
    if (!ncd_read_uintmax(exit_code_arg, &exit_code) || exit_code >= INT_MAX) {
        ModuleLog(i, BLOG_ERROR, "wrong exit code value");
        goto fail0;
    }

    // signal up
    NCDModuleInst_Backend_Up(i);

    // initiate exit (before up!)
    NCDModuleInst_Backend_InterpExit(i, exit_code);
    return;

fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #9
0
ファイル: parse.c プロジェクト: jamiesonbecker/badvpn
static void new_templ (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, parse_func pfunc)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef str_arg;
    if (!NCDVal_ListRead(params->args, 1, &str_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(str_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // init mem
    NCDValMem_Init(&o->mem);
    
    // parse
    o->succeeded = pfunc(i, NCDVal_StringMemRef(str_arg), &o->mem, &o->value);
    
    // signal up
    NCDModuleInst_Backend_Up(i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #10
0
ファイル: alias.c プロジェクト: mikalv/badvpn
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef target_arg;
    if (!NCDVal_ListRead(params->args, 1, &target_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(target_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // parse name string
    if (!AliasNames_InitNames(o, i->params->iparams->string_index, NCDVal_StringData(target_arg), NCDVal_StringLength(target_arg))) {
        ModuleLog(i, BLOG_ERROR, "make_names failed");
        goto fail0;
    }
    
    // signal up
    NCDModuleInst_Backend_Up(o->i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #11
0
ファイル: print.c プロジェクト: AmVPN/badvpn
static void do_print (NCDModuleInst *i, NCDValRef args, int ln)
{
    size_t num_args = NCDVal_ListCount(args);
    
    for (size_t j = 0; j < num_args; j++) {
        NCDValRef arg = NCDVal_ListGet(args, j);
        ASSERT(NCDVal_IsString(arg))
        
        MemRef arg_mr = NCDVal_StringMemRef(arg);
        
        size_t pos = 0;
        while (pos < arg_mr.len) {
            ssize_t res = fwrite(arg_mr.ptr + pos, 1, arg_mr.len - pos, stdout);
            if (res <= 0) {
                goto out;
            }
            pos += res;
        }
    }
    
out:
    if (ln) {
        printf("\n");
    }
}
コード例 #12
0
ファイル: net_backend_rfkill.c プロジェクト: AmVPN/badvpn
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // check arguments
    NCDValRef type_arg;
    NCDValRef name_arg;
    if (!NCDVal_ListRead(params->args, 2, &type_arg, &name_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(type_arg) || !NCDVal_IsStringNoNulls(name_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // null terminate name
    NCDValNullTermString name_nts;
    if (!NCDVal_StringNullTerminate(name_arg, &name_nts)) {
        ModuleLog(o->i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
        goto fail0;
    }
    
    if (NCDVal_StringEquals(type_arg, "index")) {
        if (sscanf(name_nts.data, "%"SCNu32, &o->index) != 1) {
            ModuleLog(o->i, BLOG_ERROR, "wrong index argument");
            goto fail1;
        }
    }
    else if (NCDVal_StringEquals(type_arg, "wlan")) {
        if (!find_wlan_rfill(name_nts.data, &o->index)) {
            ModuleLog(o->i, BLOG_ERROR, "failed to find rfkill for wlan interface");
            goto fail1;
        }
    }
    else {
        ModuleLog(o->i, BLOG_ERROR, "unknown type argument");
        goto fail1;
    }
    
    // init monitor
    if (!NCDRfkillMonitor_Init(&o->monitor, o->i->params->iparams->reactor, (NCDRfkillMonitor_handler)monitor_handler, o)) {
        ModuleLog(o->i, BLOG_ERROR, "monitor failed");
        goto fail1;
    }
    
    // set not up
    o->up = 0;
    
    // free name nts
    NCDValNullTermString_Free(&name_nts);
    return;
    
fail1:
    NCDValNullTermString_Free(&name_nts);
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #13
0
ファイル: regex_match.c プロジェクト: jamiesonbecker/badvpn
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef input_arg;
    NCDValRef regex_arg;
    if (!NCDVal_ListRead(params->args, 2, &input_arg, &regex_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(input_arg) || !NCDVal_IsStringNoNulls(regex_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    o->input = NCDVal_StringMemRef(input_arg);
    
    // make sure we don't overflow regoff_t
    if (o->input.len > INT_MAX) {
        ModuleLog(o->i, BLOG_ERROR, "input string too long");
        goto fail0;
    }
    
    // null terminate regex
    NCDValNullTermString regex_nts;
    if (!NCDVal_StringNullTerminate(regex_arg, &regex_nts)) {
        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
        goto fail0;
    }
    
    // compile regex
    regex_t preg;
    int ret = regcomp(&preg, regex_nts.data, REG_EXTENDED);
    NCDValNullTermString_Free(&regex_nts);
    if (ret != 0) {
        ModuleLog(o->i, BLOG_ERROR, "regcomp failed (error=%d)", ret);
        goto fail0;
    }
    
    // execute match
    o->matches[0].rm_so = 0;
    o->matches[0].rm_eo = o->input.len;
    o->succeeded = (regexec(&preg, o->input.ptr, MAX_MATCHES, o->matches, REG_STARTEND) == 0);
    
    // free regex
    regfree(&preg);
    
    // signal up
    NCDModuleInst_Backend_Up(o->i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #14
0
ファイル: arithmetic.c プロジェクト: 0wsqqsw/lantern
static void new_number_templ (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, number_compute_func cfunc)
{
    struct number_instance *o = vo;
    o->i = i;
    
    NCDValRef n1_arg;
    NCDValRef n2_arg;
    if (!NCDVal_ListRead(params->args, 2, &n1_arg, &n2_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(n1_arg) || !NCDVal_IsString(n2_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    uintmax_t n1;
    if (!ncd_read_uintmax(n1_arg, &n1)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong first argument");
        goto fail0;
    }
    
    uintmax_t n2;
    if (!ncd_read_uintmax(n2_arg, &n2)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong second argument");
        goto fail0;
    }
    
    if (!cfunc(i, n1, n2, &o->value)) {
        goto fail0;
    }
    
    NCDModuleInst_Backend_Up(i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #15
0
ファイル: print.c プロジェクト: AmVPN/badvpn
static int check_args (NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    size_t num_args = NCDVal_ListCount(params->args);
    
    for (size_t j = 0; j < num_args; j++) {
        NCDValRef arg = NCDVal_ListGet(params->args, j);
        if (!NCDVal_IsString(arg)) {
            ModuleLog(i, BLOG_ERROR, "wrong type");
            return 0;
        }
    }
    
    return 1;
}
コード例 #16
0
ファイル: netmask.c プロジェクト: AmVPN/badvpn
static void ipv4_net_from_addr_and_prefix_func_init (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    // read arguments
    NCDValRef addr_arg;
    NCDValRef prefix_arg;
    if (!NCDVal_ListRead(params->args, 2, &addr_arg, &prefix_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(addr_arg) || !NCDVal_IsString(prefix_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // parse addr
    uint32_t addr;
    if (!ipaddr_parse_ipv4_addr(NCDVal_StringMemRef(addr_arg), &addr)) {
        ModuleLog(i, BLOG_ERROR, "bad addr");
        goto fail0;
    }
    
    // parse prefix
    int prefix;
    if (!ipaddr_parse_ipv4_prefix(NCDVal_StringMemRef(prefix_arg), &prefix)) {
        ModuleLog(i, BLOG_ERROR, "bad prefix");
        goto fail0;
    }
    
    // make network
    uint32_t network = (addr & ipaddr_ipv4_mask_from_prefix(prefix));
    
    addr_func_init_templ(vo, i, network);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #17
0
ファイル: file.c プロジェクト: jamiesonbecker/badvpn
static void stat_func_new_common (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, int is_lstat)
{
    struct stat_instance *o = vo;
    o->i = i;
    
    NCDValRef filename_arg;
    if (!NCDVal_ListRead(params->args, 1, &filename_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(filename_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    o->succeeded = 0;
    
    if (!NCDVal_IsStringNoNulls(filename_arg)) {
        goto out;
    }
    
    // null terminate filename
    NCDValNullTermString filename_nts;
    if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
        goto fail0;
    }
    
    int res;
    if (is_lstat) {
        res = lstat(filename_nts.data, &o->result);
    } else {
        res = stat(filename_nts.data, &o->result);
    }
    NCDValNullTermString_Free(&filename_nts);
    
    if (res < 0) {
        goto out;
    }
    
    o->succeeded = 1;
    
out:
    NCDModuleInst_Backend_Up(i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #18
0
ファイル: net_ipv4_arp_probe.c プロジェクト: mikalv/badvpn
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef arg_ifname;
    NCDValRef arg_addr;
    if (!NCDVal_ListRead(params->args, 2, &arg_ifname, &arg_addr)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsStringNoNulls(arg_ifname) || !NCDVal_IsString(arg_addr)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // parse address
    uint32_t addr;
    if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringData(arg_addr), NCDVal_StringLength(arg_addr), &addr)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong address");
        goto fail0;
    }
    
    // null terminate ifname
    NCDValNullTermString ifname_nts;
    if (!NCDVal_StringNullTerminate(arg_ifname, &ifname_nts)) {
        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
        goto fail0;
    }
    
    // init arpprobe
    int res = BArpProbe_Init(&o->arpprobe, ifname_nts.data, addr, i->params->iparams->reactor, o, (BArpProbe_handler)arpprobe_handler);
    NCDValNullTermString_Free(&ifname_nts);
    if (!res) {
        ModuleLog(o->i, BLOG_ERROR, "BArpProbe_Init failed");
        goto fail0;
    }
    
    // set state unknown
    o->state = STATE_UNKNOWN;
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #19
0
ファイル: basic_functions.c プロジェクト: AmVPN/badvpn
static void perchar_eval (NCDCall call, perchar_func func)
{
    if (NCDCall_ArgCount(&call) != 1) {
        return FunctionLog(&call, BLOG_ERROR, "tolower: need one argument");
    }
    NCDValRef arg = NCDCall_EvalArg(&call, 0, NCDCall_ResMem(&call));
    if (NCDVal_IsInvalid(arg)) {
        return;
    }
    if (!NCDVal_IsString(arg)) {
        return FunctionLog(&call, BLOG_ERROR, "tolower: argument not a string");
    }
    NCDValRef value = NCDVal_NewStringUninitialized(NCDCall_ResMem(&call), NCDVal_StringLength(arg));
    if (NCDVal_IsInvalid(value)) {
        return;
    }
    char *out_data = (char *)NCDVal_StringData(value);
    MEMREF_LOOP_CHARS(NCDVal_StringMemRef(arg), i, ch, {
        out_data[i] = func(ch);
    })
コード例 #20
0
ファイル: basic_functions.c プロジェクト: AmVPN/badvpn
static int concat_recurser (ExpString *estr, NCDValRef arg, NCDCall const *call)
{
    if (NCDVal_IsString(arg)) {
        if (!ExpString_AppendBinaryMr(estr, NCDVal_StringMemRef(arg))) {
            FunctionLog(call, BLOG_ERROR, "ExpString_AppendBinaryMr failed");
            return 0;
        }
    } else if (NCDVal_IsList(arg)) {
        size_t count = NCDVal_ListCount(arg);
        for (size_t i = 0; i < count; i++) {
            if (!concat_recurser(estr, NCDVal_ListGet(arg, i), call)) {
                return 0;
            }
        }
    } else {
        FunctionLog(call, BLOG_ERROR, "concat: value is not a string or list");
        return 0;
    }
    return 1;
}
コード例 #21
0
ファイル: print.c プロジェクト: mikalv/badvpn
static void do_print (NCDModuleInst *i, NCDValRef args, int ln)
{
    size_t num_args = NCDVal_ListCount(args);
    
    for (size_t j = 0; j < num_args; j++) {
        NCDValRef arg = NCDVal_ListGet(args, j);
        ASSERT(NCDVal_IsString(arg))
        
        b_cstring arg_cstr = NCDVal_StringCstring(arg);
        
        B_CSTRING_LOOP_RANGE(arg_cstr, 0, arg_cstr.length, pos, chunk_data, chunk_length, {
            size_t chunk_pos = 0;
            while (chunk_pos < chunk_length) {
                ssize_t res = fwrite(chunk_data + chunk_pos, 1, chunk_length - chunk_pos, stdout);
                if (res <= 0) {
                    goto out;
                }
                chunk_pos += res;
            }
        })
    }
コード例 #22
0
ファイル: parse.c プロジェクト: jamiesonbecker/badvpn
static void ipv6_cidr_addr_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct ipv6_cidr_instance *o = vo;
    o->i = i;
    
    NCDValRef str_arg;
    if (!NCDVal_ListRead(params->args, 1, &str_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(str_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    o->succeeded = ipaddr6_parse_ipv6_ifaddr(NCDVal_StringMemRef(str_arg), &o->ifaddr);
    
    NCDModuleInst_Backend_Up(i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #23
0
ファイル: netmask.c プロジェクト: AmVPN/badvpn
static void mask_to_prefix_func_init (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct prefix_instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef mask_arg;
    if (!NCDVal_ListRead(params->args, 1, &mask_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(mask_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // parse mask
    uint32_t mask;
    if (!ipaddr_parse_ipv4_addr(NCDVal_StringMemRef(mask_arg), &mask)) {
        ModuleLog(i, BLOG_ERROR, "bad mask");
        goto fail0;
    }
    
    // build prefix
    if (!ipaddr_ipv4_prefix_from_mask(mask, &o->prefix)) {
        ModuleLog(i, BLOG_ERROR, "bad mask");
        goto fail0;
    }
    
    // signal up
    NCDModuleInst_Backend_Up(i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #24
0
ファイル: file.c プロジェクト: jamiesonbecker/badvpn
static void write_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    // read arguments
    NCDValRef filename_arg;
    NCDValRef contents_arg;
    if (!NCDVal_ListRead(params->args, 2, &filename_arg, &contents_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsStringNoNulls(filename_arg) || !NCDVal_IsString(contents_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // get null terminated name
    NCDValNullTermString filename_nts;
    if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
        goto fail0;
    }
    
    // write file
    int res = write_file(filename_nts.data, NCDVal_StringMemRef(contents_arg));
    NCDValNullTermString_Free(&filename_nts);
    if (!res) {
        ModuleLog(i, BLOG_ERROR, "failed to write file");
        goto fail0;
    }
    
    // signal up
    NCDModuleInst_Backend_Up(i);
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #25
0
ファイル: explode.c プロジェクト: 0wsqqsw/lantern
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef delimiter_arg;
    NCDValRef input_arg;
    NCDValRef limit_arg = NCDVal_NewInvalid();
    if (!NCDVal_ListRead(params->args, 2, &delimiter_arg, &input_arg) && !NCDVal_ListRead(params->args, 3, &delimiter_arg, &input_arg, &limit_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(delimiter_arg) || !NCDVal_IsString(input_arg) || (!NCDVal_IsInvalid(limit_arg) && !NCDVal_IsString(limit_arg))) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    size_t limit = SIZE_MAX;
    if (!NCDVal_IsInvalid(limit_arg)) {
        uintmax_t n;
        if (!ncd_read_uintmax(limit_arg, &n) || n == 0) {
            ModuleLog(i, BLOG_ERROR, "bad limit argument");
            goto fail0;
        }
        n--;
        limit = (n <= SIZE_MAX ? n : SIZE_MAX);
    }
    
    const char *del_data = NCDVal_StringData(delimiter_arg);
    size_t del_len = NCDVal_StringLength(delimiter_arg);
    
    if (del_len == 0) {
        ModuleLog(i, BLOG_ERROR, "delimiter must be nonempty");
        goto fail0;
    }
    
    size_t *table = BAllocArray(del_len, sizeof(table[0]));
    if (!table) {
        ModuleLog(i, BLOG_ERROR, "ExpArray_init failed");
        goto fail0;
    }
    
    build_substring_backtrack_table(del_data, del_len, table);
    
    if (!ExpArray_init(&o->arr, sizeof(struct substring), 8)) {
        ModuleLog(i, BLOG_ERROR, "ExpArray_init failed");
        goto fail1;
    }
    o->num = 0;
    
    const char *data = NCDVal_StringData(input_arg);
    size_t len = NCDVal_StringLength(input_arg);
    
    while (1) {
        size_t start;
        int is_end = 0;
        if (limit == 0 || !find_substring(data, len, del_data, del_len, table, &start)) {
            start = len;
            is_end = 1;
        }
        
        if (!ExpArray_resize(&o->arr, o->num + 1)) {
            ModuleLog(i, BLOG_ERROR, "ExpArray_init failed");
            goto fail2;
        }
        
        struct substring *elem = &((struct substring *)o->arr.v)[o->num];
        
        if (!(elem->data = BAlloc(start))) {
            ModuleLog(i, BLOG_ERROR, "BAlloc failed");
            goto fail2;
        }
        
        memcpy(elem->data, data, start);
        elem->len = start;
        o->num++;
        
        if (is_end) {
            break;
        }
        
        data += start + del_len;
        len -= start + del_len;
        limit--;
    }
    
    BFree(table);
    
    // signal up
    NCDModuleInst_Backend_Up(i);
    return;

fail2:
    while (o->num-- > 0) {
        BFree(((struct substring *)o->arr.v)[o->num].data);
    }
    free(o->arr.v);
fail1:
    BFree(table);
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #26
0
ファイル: implode.c プロジェクト: 0wsqqsw/lantern
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef glue_arg;
    NCDValRef pieces_arg;
    if (!NCDVal_ListRead(params->args, 2, &glue_arg, &pieces_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(glue_arg) || !NCDVal_IsList(pieces_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // init result string
    ExpString str;
    if (!ExpString_Init(&str)) {
        ModuleLog(i, BLOG_ERROR, "ExpString_Init failed");
        goto fail0;
    }
    
    size_t count = NCDVal_ListCount(pieces_arg);
    for (size_t j = 0; j < count; j++) {
        NCDValRef piece = NCDVal_ListGet(pieces_arg, j);
        
        // check piece type
        if (!NCDVal_IsString(piece)) {
            ModuleLog(i, BLOG_ERROR, "wrong piece type");
            goto fail1;
        }
        
        // append glue
        if (j > 0) {
            if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDVal_StringData(glue_arg), NCDVal_StringLength(glue_arg))) {
                ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinary failed");
                goto fail1;
            }
        }
        
        // append piece
        if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDVal_StringData(piece), NCDVal_StringLength(piece))) {
            ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinary failed");
            goto fail1;
        }
    }
    
    // store result
    o->result = ExpString_Get(&str);
    o->result_len = ExpString_Length(&str);
    
    // signal up
    NCDModuleInst_Backend_Up(i);
    return;
    
fail1:
    ExpString_Free(&str);
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #27
0
static void func_new_common (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, int is_ifnot)
{
    struct instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef arg_addr;
    NCDValRef arg_net_addr;
    NCDValRef arg_net_prefix = NCDVal_NewInvalid();
    if (!NCDVal_ListRead(params->args, 2, &arg_addr, &arg_net_addr) &&
        !NCDVal_ListRead(params->args, 3, &arg_addr, &arg_net_addr, &arg_net_prefix) 
    ) {
        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsString(arg_addr) || !NCDVal_IsString(arg_net_addr) ||
        (!NCDVal_IsInvalid(arg_net_prefix) && !NCDVal_IsString(arg_net_prefix))
    ) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    // parse addr
    struct ipv6_addr addr;
    if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringData(arg_addr), NCDVal_StringLength(arg_addr), &addr)) {
        ModuleLog(o->i, BLOG_ERROR, "bad address");
        goto fail0;
    }
    
    // parse network
    struct ipv6_ifaddr network;
    if (NCDVal_IsInvalid(arg_net_prefix)) {
        if (!ipaddr6_parse_ipv6_ifaddr_bin(NCDVal_StringData(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network)) {
            ModuleLog(o->i, BLOG_ERROR, "bad network in CIDR notation");
            goto fail0;
        }
    } else {
        if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringData(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network.addr)) {
            ModuleLog(o->i, BLOG_ERROR, "bad network address");
            goto fail0;
        }
        if (!ipaddr6_parse_ipv6_prefix_bin(NCDVal_StringData(arg_net_prefix), NCDVal_StringLength(arg_net_prefix), &network.prefix)) {
            ModuleLog(o->i, BLOG_ERROR, "bad network prefix");
            goto fail0;
        }
    }
    
    // test
    o->value = ipaddr6_ipv6_addrs_in_network(addr, network.addr, network.prefix);
    
    if (is_ifnot && o->value) {
        ModuleLog(o->i, BLOG_ERROR, "addresses belong to same subnet, not proceeding");
    }
    
    // signal up
    if (!is_ifnot || !o->value) {
        NCDModuleInst_Backend_Up(o->i);
    }
    
    return;
    
fail0:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #28
0
ファイル: regex_match.c プロジェクト: jamiesonbecker/badvpn
static void replace_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct replace_instance *o = vo;
    o->i = i;
    
    // read arguments
    NCDValRef input_arg;
    NCDValRef regex_arg;
    NCDValRef replace_arg;
    if (!NCDVal_ListRead(params->args, 3, &input_arg, &regex_arg, &replace_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong arity");
        goto fail1;
    }
    if (!NCDVal_IsString(input_arg) || !NCDVal_IsList(regex_arg) || !NCDVal_IsList(replace_arg)) {
        ModuleLog(i, BLOG_ERROR, "wrong type");
        goto fail1;
    }
    
    // check number of regex/replace
    if (NCDVal_ListCount(regex_arg) != NCDVal_ListCount(replace_arg)) {
        ModuleLog(i, BLOG_ERROR, "number of regex's is not the same as number of replacements");
        goto fail1;
    }
    size_t num_regex = NCDVal_ListCount(regex_arg);
    
    // allocate array for compiled regex's
    regex_t *regs = BAllocArray(num_regex, sizeof(regs[0]));
    if (!regs) {
        ModuleLog(i, BLOG_ERROR, "BAllocArray failed");
        goto fail1;
    }
    size_t num_done_regex = 0;
    
    // compile regex's, check arguments
    while (num_done_regex < num_regex) {
        NCDValRef regex = NCDVal_ListGet(regex_arg, num_done_regex);
        NCDValRef replace = NCDVal_ListGet(replace_arg, num_done_regex);
        
        if (!NCDVal_IsStringNoNulls(regex) || !NCDVal_IsString(replace)) {
            ModuleLog(i, BLOG_ERROR, "wrong regex/replace type for pair %zu", num_done_regex);
            goto fail2;
        }
        
        // null terminate regex
        NCDValNullTermString regex_nts;
        if (!NCDVal_StringNullTerminate(regex, &regex_nts)) {
            ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
            goto fail2;
        }
        
        int res = regcomp(&regs[num_done_regex], regex_nts.data, REG_EXTENDED);
        NCDValNullTermString_Free(&regex_nts);
        if (res != 0) {
            ModuleLog(i, BLOG_ERROR, "regcomp failed for pair %zu (error=%d)", num_done_regex, res);
            goto fail2;
        }
        
        num_done_regex++;
    }
    
    // init output string
    ExpString out;
    if (!ExpString_Init(&out)) {
        ModuleLog(i, BLOG_ERROR, "ExpString_Init failed");
        goto fail2;
    }
    
    // input state
    MemRef in = NCDVal_StringMemRef(input_arg);
    size_t in_pos = 0;
    
    // process input
    while (in_pos < in.len) {
        // find first match
        int have_match = 0;
        size_t match_regex = 0; // to remove warning
        regmatch_t match = {0, 0}; // to remove warning
        for (size_t j = 0; j < num_regex; j++) {
            regmatch_t this_match;
            this_match.rm_so = 0;
            this_match.rm_eo = in.len - in_pos;
            if (regexec(&regs[j], in.ptr + in_pos, 1, &this_match, REG_STARTEND) == 0 && (!have_match || this_match.rm_so < match.rm_so)) {
                have_match = 1;
                match_regex = j;
                match = this_match;
            }
        }
        
        // if no match, append remaining data and finish
        if (!have_match) {
            if (!ExpString_AppendBinaryMr(&out, MemRef_SubFrom(in, in_pos))) {
                ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinaryMr failed");
                goto fail3;
            }
            break;
        }
        
        // append data before match
        if (!ExpString_AppendBinaryMr(&out, MemRef_Sub(in, in_pos, match.rm_so))) {
            ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinaryMr failed");
            goto fail3;
        }
        
        // append replacement data
        NCDValRef replace = NCDVal_ListGet(replace_arg, match_regex);
        if (!ExpString_AppendBinaryMr(&out, NCDVal_StringMemRef(replace))) {
            ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinaryMr failed");
            goto fail3;
        }
        
        in_pos += match.rm_eo;
    }
    
    // set output
    o->output = ExpString_GetMr(&out);
    
    // free compiled regex's
    while (num_done_regex-- > 0) {
        regfree(&regs[num_done_regex]);
    }
    
    // free array
    BFree(regs);
    
    // signal up
    NCDModuleInst_Backend_Up(i);
    return;
    
fail3:
    ExpString_Free(&out);
fail2:
    while (num_done_regex-- > 0) {
        regfree(&regs[num_done_regex]);
    }
    BFree(regs);
fail1:
    NCDModuleInst_Backend_DeadError(i);
}
コード例 #29
0
ファイル: NCDBProcessOpts.c プロジェクト: 0wsqqsw/lantern
int NCDBProcessOpts_Init2 (NCDBProcessOpts *o, NCDValRef opts_arg, NCDBProcessOpts_func_unknown func_unknown, void *func_unknown_user, NCDModuleInst *i, int blog_channel,
                           int *out_keep_stdout, int *out_keep_stderr)
{
    if (!NCDVal_IsInvalid(opts_arg) && !NCDVal_IsMap(opts_arg)) {
        NCDModuleInst_Backend_Log(i, blog_channel, BLOG_ERROR, "options must be a map");
        goto fail0;
    }
    
    o->username = NULL;
    o->do_setsid = 0;
    
    int keep_stdout = 0;
    int keep_stderr = 0;
    
    if (!NCDVal_IsInvalid(opts_arg)) {
        for (NCDValMapElem me = NCDVal_MapFirst(opts_arg); !NCDVal_MapElemInvalid(me); me = NCDVal_MapNext(opts_arg, me)) {
            NCDValRef key = NCDVal_MapElemKey(opts_arg, me);
            NCDValRef val = NCDVal_MapElemVal(opts_arg, me);
            
            if (NCDVal_IsString(key) && NCDVal_StringEquals(key, "keep_stdout")) {
                keep_stdout = ncd_read_boolean(val);
            }
            else if (NCDVal_IsString(key) && NCDVal_StringEquals(key, "keep_stderr")) {
                keep_stderr = ncd_read_boolean(val);
            }
            else if (NCDVal_IsString(key) && NCDVal_StringEquals(key, "do_setsid")) {
                o->do_setsid = ncd_read_boolean(val);
            }
            else if (NCDVal_IsString(key) && NCDVal_StringEquals(key, "username")) {
                if (!NCDVal_IsStringNoNulls(val)) {
                    NCDModuleInst_Backend_Log(i, blog_channel, BLOG_ERROR, "username must be a string without nulls");
                    goto fail1;
                }
                b_cstring cstr = NCDVal_StringCstring(val);
                o->username = b_cstring_strdup(cstr, 0, cstr.length);
                if (!o->username) {
                    NCDModuleInst_Backend_Log(i, blog_channel, BLOG_ERROR, "b_cstring_strdup failed");
                    goto fail1;
                }
            }
            else {
                if (!func_unknown || !func_unknown(func_unknown_user, key, val)) {
                    NCDModuleInst_Backend_Log(i, blog_channel, BLOG_ERROR, "unknown option");
                    goto fail1;
                }
            }
        }
    }
    
    o->nfds = 0;
    if (keep_stdout) {
        o->fds[o->nfds] = 1;
        o->fds_map[o->nfds++] = 1;
    }
    if (keep_stderr) {
        o->fds[o->nfds] = 2;
        o->fds_map[o->nfds++] = 2;
    }
    o->fds[o->nfds] = -1;
    
    if (out_keep_stdout) {
        *out_keep_stdout = keep_stdout;
    }
    if (out_keep_stderr) {
        *out_keep_stderr = keep_stderr;
    }
    
    return 1;
    
fail1:
    if (o->username) {
        BFree(o->username);
    }
fail0:
    return 0;
}
コード例 #30
0
ファイル: net_ipv4_dhcp.c プロジェクト: 0wsqqsw/lantern
static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
{
    struct instance *o = vo;
    o->i = i;
    
    // check arguments
    NCDValRef ifname_arg;
    NCDValRef opts_arg = NCDVal_NewInvalid();
    if (!NCDVal_ListRead(params->args, 1, &ifname_arg) && !NCDVal_ListRead(params->args, 2, &ifname_arg, &opts_arg)) {
        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
        goto fail0;
    }
    if (!NCDVal_IsStringNoNulls(ifname_arg) || (!NCDVal_IsInvalid(opts_arg) && !NCDVal_IsList(opts_arg))) {
        ModuleLog(o->i, BLOG_ERROR, "wrong type");
        goto fail0;
    }
    
    NCDValNullTermString hostname_nts = NCDValNullTermString_NewDummy();
    NCDValNullTermString vendorclassid_nts = NCDValNullTermString_NewDummy();
    
    struct BDHCPClient_opts opts = {};
    
    // read options
    size_t count = NCDVal_IsInvalid(opts_arg) ? 0 : NCDVal_ListCount(opts_arg);
    for (size_t j = 0; j < count; j++) {
        NCDValRef opt = NCDVal_ListGet(opts_arg, j);
        
        // read name
        if (!NCDVal_IsString(opt)) {
            ModuleLog(o->i, BLOG_ERROR, "wrong option name type");
            goto fail1;
        }
        
        if (NCDVal_StringEquals(opt, "hostname") || NCDVal_StringEquals(opt, "vendorclassid")) {
            int is_hostname = NCDVal_StringEquals(opt, "hostname");
            
            // read value
            if (j == count) {
                ModuleLog(o->i, BLOG_ERROR, "option value missing");
                goto fail1;
            }
            NCDValRef val = NCDVal_ListGet(opts_arg, j + 1);
            if (!NCDVal_IsStringNoNulls(val)) {
                ModuleLog(o->i, BLOG_ERROR, "wrong option value type");
                goto fail1;
            }
            
            // null terminate
            NCDValNullTermString nts;
            if (!NCDVal_StringNullTerminate(val, &nts)) {
                ModuleLog(o->i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
                goto fail1;
            }
            NCDValNullTermString *nts_ptr = (is_hostname ? &hostname_nts : &vendorclassid_nts);
            NCDValNullTermString_Free(nts_ptr);
            *nts_ptr = nts;
            
            if (is_hostname) {
                opts.hostname = nts.data;
            } else {
                opts.vendorclassid = nts.data;
            }
            
            j++;
        }
        else if (NCDVal_StringEquals(opt, "auto_clientid")) {
            opts.auto_clientid = 1;
        }
        else {
            ModuleLog(o->i, BLOG_ERROR, "unknown option name");
            goto fail1;
        }
    }
    
    // null terminate ifname
    NCDValNullTermString ifname_nts;
    if (!NCDVal_StringNullTerminate(ifname_arg, &ifname_nts)) {
        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
        goto fail1;
    }
    
    // init DHCP
    int res = BDHCPClient_Init(&o->dhcp, ifname_nts.data, opts, o->i->params->iparams->reactor, o->i->params->iparams->random2, (BDHCPClient_handler)dhcp_handler, o);
    NCDValNullTermString_Free(&ifname_nts);
    if (!res) {
        ModuleLog(o->i, BLOG_ERROR, "BDHCPClient_Init failed");
        goto fail1;
    }
    
    // set not up
    o->up = 0;
    
    // free options nts's
    NCDValNullTermString_Free(&hostname_nts);
    NCDValNullTermString_Free(&vendorclassid_nts);
    return;
    
fail1:
    NCDValNullTermString_Free(&hostname_nts);
    NCDValNullTermString_Free(&vendorclassid_nts);
fail0:
    NCDModuleInst_Backend_DeadError(i);
}