📄 130-netfilter_ipset.patch
字号:
+ strcpy(modulename, "ip_set_");+ strcat(modulename, typename);+ DP("try to load %s", modulename);+ request_module(modulename);+ set->type = find_set_type_rlock(typename);+ }+ if (set->type == NULL) {+ ip_set_printk("no set type '%s', set '%s' not created",+ typename, name);+ res = -ENOENT;+ goto out;+ }+ if (!try_module_get(set->type->me)) {+ read_unlock_bh(&ip_set_lock);+ res = -EFAULT;+ goto out;+ }+ read_unlock_bh(&ip_set_lock);++ /*+ * Without holding any locks, create private part.+ */+ res = set->type->create(set, data, size);+ if (res != 0)+ goto put_out;++ /* BTW, res==0 here. */++ /*+ * Here, we have a valid, constructed set. &ip_set_lock again,+ * find free id/index and check that it is not already in + * ip_set_list.+ */+ write_lock_bh(&ip_set_lock);+ if ((res = find_free_id(set->name, &index, &id)) != 0) {+ DP("no free id!");+ goto cleanup;+ }++ /* Make sure restore gets the same index */+ if (restore != IP_SET_INVALID_ID && index != restore) {+ DP("Can't restore, sets are screwed up");+ res = -ERANGE;+ goto cleanup;+ }+ + /*+ * Finally! Add our shiny new set to the list, and be done.+ */+ DP("create: '%s' created with index %u, id %u!", set->name, index, id);+ set->id = id;+ ip_set_list[index] = set;+ write_unlock_bh(&ip_set_lock);+ return res;+ + cleanup:+ write_unlock_bh(&ip_set_lock);+ set->type->destroy(set);+ put_out:+ module_put(set->type->me);+ out:+ kfree(set);+ return res;+}++/*+ * Destroy a given existing set+ */+static void+ip_set_destroy_set(ip_set_id_t index)+{+ struct ip_set *set = ip_set_list[index];++ IP_SET_ASSERT(set);+ DP("set: %s", set->name);+ write_lock_bh(&ip_set_lock);+ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);+ if (set->binding != IP_SET_INVALID_ID)+ __ip_set_put(set->binding);+ ip_set_list[index] = NULL;+ write_unlock_bh(&ip_set_lock);++ /* Must call it without holding any lock */+ set->type->destroy(set);+ module_put(set->type->me);+ kfree(set);+}++/*+ * Destroy a set - or all sets+ * Sets must not be referenced/used.+ */+static int+ip_set_destroy(ip_set_id_t index)+{+ ip_set_id_t i;++ /* ref modification always protected by the mutex */+ if (index != IP_SET_INVALID_ID) {+ if (atomic_read(&ip_set_list[index]->ref))+ return -EBUSY;+ ip_set_destroy_set(index);+ } else {+ for (i = 0; i < ip_set_max; i++) {+ if (ip_set_list[i] != NULL + && (atomic_read(&ip_set_list[i]->ref)))+ return -EBUSY;+ }++ for (i = 0; i < ip_set_max; i++) {+ if (ip_set_list[i] != NULL)+ ip_set_destroy_set(i);+ }+ }+ return 0;+}++static void+ip_set_flush_set(struct ip_set *set)+{+ DP("set: %s %u", set->name, set->id);++ write_lock_bh(&set->lock);+ set->type->flush(set);+ write_unlock_bh(&set->lock);+}++/* + * Flush data in a set - or in all sets+ */+static int+ip_set_flush(ip_set_id_t index)+{+ if (index != IP_SET_INVALID_ID) {+ IP_SET_ASSERT(ip_set_list[index]);+ ip_set_flush_set(ip_set_list[index]);+ } else+ FOREACH_SET_DO(ip_set_flush_set);++ return 0;+}++/* Rename a set */+static int+ip_set_rename(ip_set_id_t index, const char *name)+{+ struct ip_set *set = ip_set_list[index];+ ip_set_id_t i;+ int res = 0;++ DP("set: %s to %s", set->name, name);+ write_lock_bh(&ip_set_lock);+ for (i = 0; i < ip_set_max; i++) {+ if (ip_set_list[i] != NULL+ && strncmp(ip_set_list[i]->name, + name,+ IP_SET_MAXNAMELEN - 1) == 0) {+ res = -EEXIST;+ goto unlock;+ }+ }+ strncpy(set->name, name, IP_SET_MAXNAMELEN);+ unlock:+ write_unlock_bh(&ip_set_lock);+ return res;+}++/*+ * Swap two sets so that name/index points to the other.+ * References are also swapped.+ */+static int+ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index)+{+ struct ip_set *from = ip_set_list[from_index];+ struct ip_set *to = ip_set_list[to_index];+ char from_name[IP_SET_MAXNAMELEN];+ u_int32_t from_ref;++ DP("set: %s to %s", from->name, to->name);+ /* Features must not change. Artifical restriction. */+ if (from->type->features != to->type->features)+ return -ENOEXEC;++ /* No magic here: ref munging protected by the mutex */ + write_lock_bh(&ip_set_lock);+ strncpy(from_name, from->name, IP_SET_MAXNAMELEN);+ from_ref = atomic_read(&from->ref);++ strncpy(from->name, to->name, IP_SET_MAXNAMELEN);+ atomic_set(&from->ref, atomic_read(&to->ref));+ strncpy(to->name, from_name, IP_SET_MAXNAMELEN);+ atomic_set(&to->ref, from_ref);+ + ip_set_list[from_index] = to;+ ip_set_list[to_index] = from;+ + write_unlock_bh(&ip_set_lock);+ return 0;+}++/*+ * List set data+ */++static inline void+__set_hash_bindings_size_list(struct ip_set_hash *set_hash,+ ip_set_id_t id, size_t *size)+{+ if (set_hash->id == id)+ *size += sizeof(struct ip_set_hash_list);+}++static inline void+__set_hash_bindings_size_save(struct ip_set_hash *set_hash,+ ip_set_id_t id, size_t *size)+{+ if (set_hash->id == id)+ *size += sizeof(struct ip_set_hash_save);+}++static inline void+__set_hash_bindings(struct ip_set_hash *set_hash,+ ip_set_id_t id, void *data, int *used)+{+ if (set_hash->id == id) {+ struct ip_set_hash_list *hash_list = + (struct ip_set_hash_list *)(data + *used);++ hash_list->ip = set_hash->ip;+ hash_list->binding = set_hash->binding;+ *used += sizeof(struct ip_set_hash_list);+ }+}++static int ip_set_list_set(ip_set_id_t index,+ void *data,+ int *used,+ int len)+{+ struct ip_set *set = ip_set_list[index];+ struct ip_set_list *set_list;++ /* Pointer to our header */+ set_list = (struct ip_set_list *) (data + *used);++ DP("set: %s, used: %d %p %p", set->name, *used, data, data + *used);++ /* Get and ensure header size */+ if (*used + sizeof(struct ip_set_list) > len)+ goto not_enough_mem;+ *used += sizeof(struct ip_set_list);++ read_lock_bh(&set->lock);+ /* Get and ensure set specific header size */+ set_list->header_size = set->type->header_size;+ if (*used + set_list->header_size > len)+ goto unlock_set;++ /* Fill in the header */+ set_list->index = index;+ set_list->binding = set->binding;+ set_list->ref = atomic_read(&set->ref);++ /* Fill in set spefific header data */+ set->type->list_header(set, data + *used);+ *used += set_list->header_size;++ /* Get and ensure set specific members size */+ set_list->members_size = set->type->list_members_size(set);+ if (*used + set_list->members_size > len)+ goto unlock_set;++ /* Fill in set spefific members data */+ set->type->list_members(set, data + *used);+ *used += set_list->members_size;+ read_unlock_bh(&set->lock);++ /* Bindings */++ /* Get and ensure set specific bindings size */+ set_list->bindings_size = 0;+ FOREACH_HASH_DO(__set_hash_bindings_size_list,+ set->id, &set_list->bindings_size);+ if (*used + set_list->bindings_size > len)+ goto not_enough_mem;++ /* Fill in set spefific bindings data */+ FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used);+ + return 0;++ unlock_set:+ read_unlock_bh(&set->lock);+ not_enough_mem:+ DP("not enough mem, try again");+ return -EAGAIN;+}++/*+ * Save sets+ */+static int ip_set_save_set(ip_set_id_t index,+ void *data,+ int *used,+ int len)+{+ struct ip_set *set;+ struct ip_set_save *set_save;++ /* Pointer to our header */+ set_save = (struct ip_set_save *) (data + *used);++ /* Get and ensure header size */+ if (*used + sizeof(struct ip_set_save) > len)+ goto not_enough_mem;+ *used += sizeof(struct ip_set_save);++ set = ip_set_list[index];+ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len, + data, data + *used);++ read_lock_bh(&set->lock);+ /* Get and ensure set specific header size */+ set_save->header_size = set->type->header_size;+ if (*used + set_save->header_size > len)+ goto unlock_set;++ /* Fill in the header */+ set_save->index = index;+ set_save->binding = set->binding;++ /* Fill in set spefific header data */+ set->type->list_header(set, data + *used);+ *used += set_save->header_size;++ DP("set header filled: %s, used: %u(%u) %p %p", set->name, *used,+ set_save->header_size, data, data + *used);+ /* Get and ensure set specific members size */+ set_save->members_size = set->type->list_members_size(set);+ if (*used + set_save->members_size > len)+ goto unlock_set;++ /* Fill in set spefific members data */+ set->type->list_members(set, data + *used);+ *used += set_save->members_size;+ read_unlock_bh(&set->lock);+ DP("set members filled: %s, used: %u(%u) %p %p", set->name, *used,+ set_save->members_size, data, data + *used);+ return 0;++ unlock_set:+ read_unlock_bh(&set->lock);+ not_enough_mem:+ DP("not enough mem, try again");+ return -EAGAIN;+}++static inline void+__set_hash_save_bindings(struct ip_set_hash *set_hash,+ ip_set_id_t id,+ void *data,+ int *used,+ int len,+ int *res)+{+ if (*res == 0+ && (id == IP_SET_INVALID_ID || set_hash->id == id)) {+ struct ip_set_hash_save *hash_save = + (struct ip_set_hash_save *)(data + *used);+ /* Ensure bindings size */+ if (*used + sizeof(struct ip_set_hash_save) > len) {+ *res = -ENOMEM;+ return;+ }+ hash_save->id = set_hash->id;+ hash_save->ip = set_hash->ip;+ hash_save->binding = set_hash->binding;+ *used += sizeof(struct ip_set_hash_save);+ }+}++static int ip_set_save_bindings(ip_set_id_t index,+ void *data,+ int *used,+ int len)+{+ int res = 0;+ struct ip_set_save *set_save;++ DP("used %u, len %u", *used, len);+ /* Get and ensure header size */+ if (*used + sizeof(struct ip_set_save) > len)+ return -ENOMEM;++ /* Marker */+ set_save = (struct ip_set_save *) (data + *used);+ set_save->index = IP_SET_INVALID_ID;+ set_save->header_size = 0;+ set_save->members_size = 0;+ *used += sizeof(struct ip_set_save);++ DP("marker added used %u, len %u", *used, len);+ /* Fill in bindings data */+ if (index != IP_SET_INVALID_ID)+ /* Sets are identified by id in hash */+ index = ip_set_list[index]->id;+ FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res);++ return res; +}++/*+ * Restore sets+ */+static int ip_set_restore(void *data,+ int len)+{+ int res = 0;+ int line = 0, used = 0, members_size;+ struct ip_set *set;+ struct ip_set_hash_save *hash_save;+ struct ip_set_restore *set_restore;+ ip_set_id_t index;++ /* Loop to restore sets */+ while (1) {+ line++;+ + DP("%u %u %u", used, sizeof(struct ip_set_restore), len);+ /* Get and ensure header size */+ if (used + sizeof(struct ip_set_restore) > len)+ return line;+ set_restore = (struct ip_set_restore *) (data + used);+ used += sizeof(struct ip_set_restore);++ /* Ensure data size */+ if (used + + set_restore->header_size + + set_restore->members_size > len)+ return line;++ /* Check marker */+ if (set_restore->index == IP_SET_INVALID_ID) {+ line--;+ goto bindings;+ }+ + /* Try to create the set */+ DP("restore %s %s", set_restore->name, set_restore->typename);+ res = ip_set_create(set_restore->name,+ set_restore->typename,+ set_restore->index,+ data + used,+ set_restore->header_size);+ + if (res != 0)+ return line;+ used += set_restore->header_size;++ index = ip_set_find_byindex(set_restore->index);+ DP("index %u, restore_index %u", index, set_restore->index);+ if (index != set_restore->index)+ return line;+ /* Try to restore members data */+ set = ip_set_list[index];+ members_size = 0;+ DP("members_size %u reqsize %u",+ set_restore->members_size, set->type->reqsize);+ while (members_size + set->type->reqsize <=+ set_restore->members_size) {+ line++;+ DP("members: %u, line %u", members_size, line);+ res = __ip_set_addip(index,+ data + used + members_size,+ set->type->reqsize);+ if (!(res == 0 || res == -EEXIST)) + return line;+ members_size += set->type->reqsize;+ }++ DP("members_size %u %u",+ set_restore->members_size, members_size);+ if (members_size != set_restore->members_size)+ return line++;+ used += set_restore->members_size; + }+ + bindings:+ /* Loop to restore bindings */+ while (used < len) {+ line++;++ DP("restore binding, line %u", line); + /* Get and ensure size */+ if (used + sizeof(struct ip_set_hash_save) > len)+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -