📄 130-netfilter_ipset.patch
字号:
+ DP("'%s' registered.", set_type->typename);+ unlock:+ write_unlock_bh(&ip_set_lock);+ return ret;+}++void+ip_set_unregister_set_type(struct ip_set_type *set_type)+{+ write_lock_bh(&ip_set_lock);+ if (!find_set_type(set_type->typename)) {+ ip_set_printk("'%s' not registered?",+ set_type->typename);+ goto unlock;+ }+ list_del(&set_type->list);+ module_put(THIS_MODULE);+ DP("'%s' unregistered.", set_type->typename);+ unlock:+ write_unlock_bh(&ip_set_lock);++}++/*+ * Userspace routines+ */++/*+ * Find set by name, reference it once. The reference makes sure the+ * thing pointed to, does not go away under our feet. Drop the reference+ * later, using ip_set_put().+ */+ip_set_id_t+ip_set_get_byname(const char *name)+{+ ip_set_id_t i, index = IP_SET_INVALID_ID;+ + down(&ip_set_app_mutex);+ for (i = 0; i < ip_set_max; i++) {+ if (ip_set_list[i] != NULL+ && strcmp(ip_set_list[i]->name, name) == 0) {+ __ip_set_get(i);+ index = i;+ break;+ }+ }+ up(&ip_set_app_mutex);+ return index;+}++/*+ * Find set by index, reference it once. The reference makes sure the+ * thing pointed to, does not go away under our feet. Drop the reference+ * later, using ip_set_put().+ */+ip_set_id_t+ip_set_get_byindex(ip_set_id_t index)+{+ down(&ip_set_app_mutex);++ if (index >= ip_set_max)+ return IP_SET_INVALID_ID;+ + if (ip_set_list[index])+ __ip_set_get(index);+ else+ index = IP_SET_INVALID_ID;+ + up(&ip_set_app_mutex);+ return index;+}++/*+ * If the given set pointer points to a valid set, decrement+ * reference count by 1. The caller shall not assume the index+ * to be valid, after calling this function.+ */+void ip_set_put(ip_set_id_t index)+{+ down(&ip_set_app_mutex);+ if (ip_set_list[index])+ __ip_set_put(index);+ up(&ip_set_app_mutex);+}++/* Find a set by name or index */+static ip_set_id_t+ip_set_find_byname(const char *name)+{+ ip_set_id_t i, index = IP_SET_INVALID_ID;+ + for (i = 0; i < ip_set_max; i++) {+ if (ip_set_list[i] != NULL+ && strcmp(ip_set_list[i]->name, name) == 0) {+ index = i;+ break;+ }+ }+ return index;+}++static ip_set_id_t+ip_set_find_byindex(ip_set_id_t index)+{+ if (index >= ip_set_max || ip_set_list[index] == NULL)+ index = IP_SET_INVALID_ID;+ + return index;+}++/*+ * Add, del, test, bind and unbind+ */++static inline int+__ip_set_testip(struct ip_set *set,+ const void *data,+ size_t size,+ ip_set_ip_t *ip)+{+ int res;++ read_lock_bh(&set->lock);+ res = set->type->testip(set, data, size, ip);+ read_unlock_bh(&set->lock);++ return res;+}++static int+__ip_set_addip(ip_set_id_t index,+ const void *data,+ size_t size)+{+ struct ip_set *set = ip_set_list[index];+ ip_set_ip_t ip;+ int res;+ + IP_SET_ASSERT(set);+ do {+ write_lock_bh(&set->lock);+ res = set->type->addip(set, data, size, &ip);+ write_unlock_bh(&set->lock);+ } while (res == -EAGAIN+ && set->type->retry+ && (res = set->type->retry(set)) == 0);++ return res;+}++static int+ip_set_addip(ip_set_id_t index,+ const void *data,+ size_t size)+{++ return __ip_set_addip(index,+ data + sizeof(struct ip_set_req_adt),+ size - sizeof(struct ip_set_req_adt));+}++static int+ip_set_delip(ip_set_id_t index,+ const void *data,+ size_t size)+{+ struct ip_set *set = ip_set_list[index];+ ip_set_ip_t ip;+ int res;+ + IP_SET_ASSERT(set);+ write_lock_bh(&set->lock);+ res = set->type->delip(set,+ data + sizeof(struct ip_set_req_adt),+ size - sizeof(struct ip_set_req_adt),+ &ip);+ write_unlock_bh(&set->lock);++ return res;+}++static int+ip_set_testip(ip_set_id_t index,+ const void *data,+ size_t size)+{+ struct ip_set *set = ip_set_list[index];+ ip_set_ip_t ip;+ int res;++ IP_SET_ASSERT(set);+ res = __ip_set_testip(set,+ data + sizeof(struct ip_set_req_adt),+ size - sizeof(struct ip_set_req_adt),+ &ip);++ return (res > 0 ? -EEXIST : res);+}++static int+ip_set_bindip(ip_set_id_t index,+ const void *data,+ size_t size)+{+ struct ip_set *set = ip_set_list[index];+ struct ip_set_req_bind *req_bind;+ ip_set_id_t binding;+ ip_set_ip_t ip;+ int res;++ IP_SET_ASSERT(set);+ if (size < sizeof(struct ip_set_req_bind))+ return -EINVAL;+ + req_bind = (struct ip_set_req_bind *) data;+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {+ /* Default binding of a set */+ char *binding_name;+ + if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)+ return -EINVAL;++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind)); + binding_name[IP_SET_MAXNAMELEN - 1] = '\0';++ binding = ip_set_find_byname(binding_name);+ if (binding == IP_SET_INVALID_ID)+ return -ENOENT;++ write_lock_bh(&ip_set_lock);+ /* Sets as binding values are referenced */+ if (set->binding != IP_SET_INVALID_ID)+ __ip_set_put(set->binding);+ set->binding = binding;+ __ip_set_get(set->binding);+ write_unlock_bh(&ip_set_lock);++ return 0;+ }+ binding = ip_set_find_byname(req_bind->binding);+ if (binding == IP_SET_INVALID_ID)+ return -ENOENT;++ res = __ip_set_testip(set,+ data + sizeof(struct ip_set_req_bind),+ size - sizeof(struct ip_set_req_bind),+ &ip);+ DP("set %s, ip: %u.%u.%u.%u, binding %s",+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);+ + if (res >= 0)+ res = ip_set_hash_add(set->id, ip, binding);++ return res;+}++#define FOREACH_SET_DO(fn, args...) \+({ \+ ip_set_id_t __i; \+ struct ip_set *__set; \+ \+ for (__i = 0; __i < ip_set_max; __i++) { \+ __set = ip_set_list[__i]; \+ if (__set != NULL) \+ fn(__set , ##args); \+ } \+})++static inline void+__set_hash_del_byid(struct ip_set_hash *set_hash, ip_set_id_t id)+{+ if (set_hash->id == id)+ __set_hash_del(set_hash);+}++static inline void+__unbind_default(struct ip_set *set)+{+ if (set->binding != IP_SET_INVALID_ID) {+ /* Sets as binding values are referenced */+ __ip_set_put(set->binding);+ set->binding = IP_SET_INVALID_ID;+ }+}++static int+ip_set_unbindip(ip_set_id_t index,+ const void *data,+ size_t size)+{+ struct ip_set *set;+ struct ip_set_req_bind *req_bind;+ ip_set_ip_t ip;+ int res;++ DP("");+ if (size < sizeof(struct ip_set_req_bind))+ return -EINVAL;+ + req_bind = (struct ip_set_req_bind *) data;+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';+ + DP("%u %s", index, req_bind->binding);+ if (index == IP_SET_INVALID_ID) {+ /* unbind :all: */+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {+ /* Default binding of sets */+ write_lock_bh(&ip_set_lock);+ FOREACH_SET_DO(__unbind_default);+ write_unlock_bh(&ip_set_lock);+ return 0;+ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) {+ /* Flush all bindings of all sets*/+ write_lock_bh(&ip_set_lock);+ FOREACH_HASH_RW_DO(__set_hash_del);+ write_unlock_bh(&ip_set_lock);+ return 0;+ }+ DP("unreachable reached!");+ return -EINVAL;+ }+ + set = ip_set_list[index];+ IP_SET_ASSERT(set);+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {+ /* Default binding of set */+ ip_set_id_t binding = ip_set_find_byindex(set->binding);++ if (binding == IP_SET_INVALID_ID)+ return -ENOENT;+ + write_lock_bh(&ip_set_lock);+ /* Sets in hash values are referenced */+ __ip_set_put(set->binding);+ set->binding = IP_SET_INVALID_ID;+ write_unlock_bh(&ip_set_lock);++ return 0;+ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) {+ /* Flush all bindings */++ write_lock_bh(&ip_set_lock);+ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);+ write_unlock_bh(&ip_set_lock);+ return 0;+ }+ + res = __ip_set_testip(set,+ data + sizeof(struct ip_set_req_bind),+ size - sizeof(struct ip_set_req_bind),+ &ip);++ DP("set %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));+ if (res >= 0)+ res = ip_set_hash_del(set->id, ip);++ return res;+}++static int+ip_set_testbind(ip_set_id_t index,+ const void *data,+ size_t size)+{+ struct ip_set *set = ip_set_list[index];+ struct ip_set_req_bind *req_bind;+ ip_set_id_t binding;+ ip_set_ip_t ip;+ int res;++ IP_SET_ASSERT(set);+ if (size < sizeof(struct ip_set_req_bind))+ return -EINVAL;+ + req_bind = (struct ip_set_req_bind *) data;+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {+ /* Default binding of set */+ char *binding_name;+ + if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)+ return -EINVAL;++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind)); + binding_name[IP_SET_MAXNAMELEN - 1] = '\0';++ binding = ip_set_find_byname(binding_name);+ if (binding == IP_SET_INVALID_ID)+ return -ENOENT;+ + res = (set->binding == binding) ? -EEXIST : 0;++ return res;+ }+ binding = ip_set_find_byname(req_bind->binding);+ if (binding == IP_SET_INVALID_ID)+ return -ENOENT;+ + + res = __ip_set_testip(set,+ data + sizeof(struct ip_set_req_bind),+ size - sizeof(struct ip_set_req_bind),+ &ip);+ DP("set %s, ip: %u.%u.%u.%u, binding %s",+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);+ + if (res >= 0)+ res = (ip_set_find_in_hash(set->id, ip) == binding)+ ? -EEXIST : 0;++ return res;+}++static struct ip_set_type *+find_set_type_rlock(const char *typename)+{+ struct ip_set_type *type;+ + read_lock_bh(&ip_set_lock);+ type = find_set_type(typename);+ if (type == NULL)+ read_unlock_bh(&ip_set_lock);++ return type;+}++static int+find_free_id(const char *name,+ ip_set_id_t *index,+ ip_set_id_t *id)+{+ ip_set_id_t i;++ *id = IP_SET_INVALID_ID;+ for (i = 0; i < ip_set_max; i++) {+ if (ip_set_list[i] == NULL) {+ if (*id == IP_SET_INVALID_ID)+ *id = *index = i;+ } else if (strcmp(name, ip_set_list[i]->name) == 0)+ /* Name clash */+ return -EEXIST;+ }+ if (*id == IP_SET_INVALID_ID)+ /* No free slot remained */+ return -ERANGE;+ /* Check that index is usable as id (swapping) */+ check: + for (i = 0; i < ip_set_max; i++) {+ if (ip_set_list[i] != NULL+ && ip_set_list[i]->id == *id) {+ *id = i;+ goto check;+ }+ }+ return 0;+}++/*+ * Create a set+ */+static int+ip_set_create(const char *name,+ const char *typename,+ ip_set_id_t restore,+ const void *data,+ size_t size)+{+ struct ip_set *set;+ ip_set_id_t index = 0, id;+ int res = 0;++ DP("setname: %s, typename: %s, id: %u", name, typename, restore);+ /*+ * First, and without any locks, allocate and initialize+ * a normal base set structure.+ */+ set = kmalloc(sizeof(struct ip_set), GFP_KERNEL);+ if (!set)+ return -ENOMEM;+ set->lock = RW_LOCK_UNLOCKED;+ strncpy(set->name, name, IP_SET_MAXNAMELEN);+ set->binding = IP_SET_INVALID_ID;+ atomic_set(&set->ref, 0);++ /*+ * Next, take the &ip_set_lock, check that we know the type,+ * and take a reference on the type, to make sure it+ * stays available while constructing our new set.+ *+ * After referencing the type, we drop the &ip_set_lock,+ * and let the new set construction run without locks.+ */+ set->type = find_set_type_rlock(typename);+ if (set->type == NULL) {+ /* Try loading the module */+ char modulename[IP_SET_MAXNAMELEN + strlen("ip_set_") + 1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -