void rpc_ip_set_commit(rpc_t* rpc, void* ctx) { str name; struct ip_set_list_item *p; struct ip_set_ref *new_ip_set; if (rpc->scan(ctx, "S", &name) < 1) { return; } p = ip_set_list_find_by_name(name); if (!p) { rpc->fault(ctx, 400, "Ip set not found"); return; } lock_get(&p->write_lock); lock_get(&p->read_lock); new_ip_set = shm_malloc(sizeof(*new_ip_set)); if (!new_ip_set) { rpc->fault(ctx, 500, "Not enough memory"); goto err; } if (p->ip_set) { if (atomic_dec_and_test(&p->ip_set->refcnt)) { ip_set_destroy(&p->ip_set->ip_set); /* not used in local copy */ shm_free(p->ip_set); } } new_ip_set->ip_set = p->ip_set_pending; atomic_set(&new_ip_set->refcnt, 1); p->ip_set = new_ip_set; ip_set_init(&p->ip_set_pending, 1); err: lock_release(&p->read_lock); lock_release(&p->write_lock); }
void rpc_ip_set_print(rpc_t* rpc, void* ctx) { struct ip_set_list_item *p; struct ip_set *ip_set, ip_set2; void *c; str name; int pending; if (rpc->scan(ctx, "Sd", &name, &pending) < 1) { return; } p = ip_set_list_find_by_name(name); if (!p) { rpc->fault(ctx, 400, "Ip set not found"); return; } if (pending) { lock_get(&p->write_lock); ip_set = &p->ip_set_pending; } else { lock_get(&p->read_lock); if (!p->ip_set) { ip_set_init(&ip_set2, 1); /* dummy to return empty ip set */ ip_set = &ip_set2; } else ip_set = &p->ip_set->ip_set; } /* nested array/struct not supported */ rpc->add(ctx, "{", &c); if (rpc->struct_add(c, "s", "IPv", "4") < 0) goto err; if (rpc_ip_tree_print(rpc, c, "", ip_set->ipv4_tree, 0) < 0) goto err; rpc->add(ctx, "{", &c); if (rpc->struct_add(c, "s", "IPv", "6") < 0) goto err; #ifdef USE_IPV6 if (rpc_ip_tree_print(rpc, c, "", ip_set->ipv6_tree, 0) < 0) goto err; #endif err: if (pending) lock_release(&p->write_lock); else lock_release(&p->read_lock); }
void rpc_ip_set_clean(rpc_t* rpc, void* ctx) { str name; struct ip_set_list_item *p; if (rpc->scan(ctx, "S", &name) < 1) { return; } p = ip_set_list_find_by_name(name); if (!p) { rpc->fault(ctx, 400, "Ip set not found"); return; } lock_get(&p->write_lock); ip_set_destroy(&p->ip_set_pending); ip_set_init(&p->ip_set_pending, 1); lock_release(&p->write_lock); }
void rpc_ip_set_add(rpc_t* rpc, void* ctx) { str name, ip, mask; struct ip_set_list_item* p; if (rpc->scan(ctx, "SSS", &name, &ip, &mask) < 1) { return; } while (mask.len && mask.s[0]=='/') { /* rpc cannot read plain number as string, adding '/' helps */ mask.s++; mask.len--; } p = ip_set_list_find_by_name(name); if (!p) { rpc->fault(ctx, 400, "Ip set not found"); return; } lock_get(&p->write_lock); if (ip_set_add_ip_s(&p->ip_set_pending, ip, mask) < 0) { lock_release(&p->write_lock); rpc->fault(ctx, 400, "Cannot add ip/mask into ip set"); return; } lock_release(&p->write_lock); }
static int fixup_ip_is_trusted(void** param, int param_no) { int ret = E_CFG; struct ip_set_param *p; str s; if (param_no == 1) { p = pkg_malloc(sizeof(*p)); if (!p) return E_OUT_OF_MEM; memset(p, 0, sizeof(*p)); s.s = *param; s.len = strlen(s.s); if (is_ip_set_name(&s)) { p->u.global.ip_set = ip_set_list_find_by_name(s); if (!p->u.global.ip_set) { ERR(MODULE_NAME": fixup_ip_is_trusted: ip set '%.*s' is not declared\n", s.len, s.s); goto err; } p->kind = IP_SET_PARAM_KIND_GLOBAL; } else { ret = fixup_var_str_12(param, param_no); if (ret < 0) goto err; ip_set_init(&p->u.local.ip_set, 0); p->u.local.fparam = *param; *param = p; p->kind = IP_SET_PARAM_KIND_LOCAL; } } else { return fixup_var_str_12(param, param_no); } return E_OK; err: pkg_free(p); return ret; }
static int w_ip_is_trusted(struct sip_msg* msg, char* _ip_set, char* _ip) { str ip_set_s, ip_s; struct ip_addr *ip, ip_buf; struct ip_set new_ip_set, *ip_set; struct ip_set_list_item *isli = NULL; int kind; kind = ((struct ip_set_param*)_ip_set)->kind; if (kind == IP_SET_PARAM_KIND_LOCAL) { if (get_str_fparam(&ip_set_s, msg, ((struct ip_set_param*)_ip_set)->u.local.fparam) < 0) { ERR(MODULE_NAME": ip_is_trusted: Error while obtaining ip_set parameter value\n"); return -1; } if (is_ip_set_name(&ip_set_s)) { isli = ip_set_list_find_by_name(ip_set_s); if (!isli) { ERR(MODULE_NAME": ip_is_trusted: ip set '%.*s' is not declared\n", ip_set_s.len, ip_set_s.s); return -1; } kind = IP_SET_PARAM_KIND_GLOBAL; goto force_global; } ip_set = &((struct ip_set_param*)_ip_set)->u.local.ip_set; } else { isli = ((struct ip_set_param*)_ip_set)->u.global.ip_set; force_global: if (!isli->ip_set) return -1; /* empty ip set */ if (unlikely(isli->ip_set != ip_set_list_local[isli->idx])) { /* global ip set has changed ? */ if (ip_set_list_local[isli->idx]) { if (atomic_dec_and_test(&ip_set_list_local[isli->idx]->refcnt)) { ip_set_destroy(&ip_set_list_local[isli->idx]->ip_set); shm_free(ip_set_list_local[isli->idx]); ip_set_list_local[isli->idx] = NULL; } } lock_get(&isli->read_lock); atomic_inc(&isli->ip_set->refcnt); ip_set_list_local[isli->idx] = isli->ip_set; lock_release(&isli->read_lock); } ip_set = &ip_set_list_local[isli->idx]->ip_set; } if (get_str_fparam(&ip_s, msg, (fparam_t*)_ip) < 0) { ERR(MODULE_NAME": ip_is_trusted: Error while obtaining ip parameter value\n"); return -1; } if (!ip_s.len || !ip_set_s.len) return -1; switch (ip_s.s[0]) { case 's': /* src */ case 'S': ip = &msg->rcv.src_ip; break; case 'd': /* dst */ case 'D': ip = &msg->rcv.dst_ip; break; case 'r': /* rcv */ case 'R': ip = &msg->rcv.bind_address->address; break; default: /* string -> ip */ if ( ((ip = str2ip(&ip_s))==0) && ((ip = str2ip6(&ip_s))==0) ){ ERR(MODULE_NAME": ip_is_trusted: string to ip conversion error '%.*s'\n", ip_s.len, ip_s.s); return -1; } ip_buf = *ip; ip = &ip_buf; /* value has been in static buffer */ break; } /* test if ip_set string has changed since last call */ if (kind == IP_SET_PARAM_KIND_LOCAL) { if (((struct ip_set_param*)_ip_set)->u.local.s.len != ip_set_s.len || memcmp(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.s, ip_set_s.len) != 0) { ip_set_init(&new_ip_set, 0); if (ip_set_add_list(&new_ip_set, ip_set_s) < 0) { ip_set_destroy(&new_ip_set); return -1; }; if (((struct ip_set_param*)_ip_set)->u.local.sz < ip_set_s.len) { void *p; p = pkg_realloc(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.len); if (!p) { ip_set_destroy(&new_ip_set); return E_OUT_OF_MEM; } ((struct ip_set_param*)_ip_set)->u.local.s.s = p; ((struct ip_set_param*)_ip_set)->u.local.sz = ip_set_s.len; } memcpy(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.s, ip_set_s.len); ((struct ip_set_param*)_ip_set)->u.local.s.len = ip_set_s.len; ip_set_destroy(&((struct ip_set_param*)_ip_set)->u.local.ip_set); ((struct ip_set_param*)_ip_set)->u.local.ip_set = new_ip_set; } } /* ip_set_print(stderr, &ip_set); */ switch (ip_set_ip_exists(ip_set, ip)) { case IP_TREE_FIND_FOUND: case IP_TREE_FIND_FOUND_UPPER_SET: return 1; default: return -1; } }