📄 ebtables.c
字号:
else ret = 0; /* decrease module count and free resources */ EBT_ENTRY_ITERATE(table->entries, table->entries_size, ebt_cleanup_entry, NULL); vfree(table->entries); if (table->chainstack) { for_each_possible_cpu(i) vfree(table->chainstack[i]); vfree(table->chainstack); } vfree(table); vfree(counterstmp); return ret;free_unlock: mutex_unlock(&ebt_mutex);free_iterate: EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ebt_cleanup_entry, NULL);free_counterstmp: vfree(counterstmp); /* can be initialized in translate_table() */ if (newinfo->chainstack) { for_each_possible_cpu(i) vfree(newinfo->chainstack[i]); vfree(newinfo->chainstack); }free_entries: vfree(newinfo->entries);free_newinfo: vfree(newinfo); return ret;}int ebt_register_target(struct ebt_target *target){ struct ebt_target *t; int ret; ret = mutex_lock_interruptible(&ebt_mutex); if (ret != 0) return ret; list_for_each_entry(t, &ebt_targets, list) { if (strcmp(t->name, target->name) == 0) { mutex_unlock(&ebt_mutex); return -EEXIST; } } list_add(&target->list, &ebt_targets); mutex_unlock(&ebt_mutex); return 0;}void ebt_unregister_target(struct ebt_target *target){ mutex_lock(&ebt_mutex); list_del(&target->list); mutex_unlock(&ebt_mutex);}int ebt_register_match(struct ebt_match *match){ struct ebt_match *m; int ret; ret = mutex_lock_interruptible(&ebt_mutex); if (ret != 0) return ret; list_for_each_entry(m, &ebt_matches, list) { if (strcmp(m->name, match->name) == 0) { mutex_unlock(&ebt_mutex); return -EEXIST; } } list_add(&match->list, &ebt_matches); mutex_unlock(&ebt_mutex); return 0;}void ebt_unregister_match(struct ebt_match *match){ mutex_lock(&ebt_mutex); list_del(&match->list); mutex_unlock(&ebt_mutex);}int ebt_register_watcher(struct ebt_watcher *watcher){ struct ebt_watcher *w; int ret; ret = mutex_lock_interruptible(&ebt_mutex); if (ret != 0) return ret; list_for_each_entry(w, &ebt_watchers, list) { if (strcmp(w->name, watcher->name) == 0) { mutex_unlock(&ebt_mutex); return -EEXIST; } } list_add(&watcher->list, &ebt_watchers); mutex_unlock(&ebt_mutex); return 0;}void ebt_unregister_watcher(struct ebt_watcher *watcher){ mutex_lock(&ebt_mutex); list_del(&watcher->list); mutex_unlock(&ebt_mutex);}int ebt_register_table(struct ebt_table *table){ struct ebt_table_info *newinfo; struct ebt_table *t; struct ebt_replace_kernel *repl; int ret, i, countersize; void *p; if (!table || !(repl = table->table) || !repl->entries || repl->entries_size == 0 || repl->counters || table->private) { BUGPRINT("Bad table data for ebt_register_table!!!\n"); return -EINVAL; } countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids; newinfo = vmalloc(sizeof(*newinfo) + countersize); ret = -ENOMEM; if (!newinfo) return -ENOMEM; p = vmalloc(repl->entries_size); if (!p) goto free_newinfo; memcpy(p, repl->entries, repl->entries_size); newinfo->entries = p; newinfo->entries_size = repl->entries_size; newinfo->nentries = repl->nentries; if (countersize) memset(newinfo->counters, 0, countersize); /* fill in newinfo and parse the entries */ newinfo->chainstack = NULL; for (i = 0; i < NF_BR_NUMHOOKS; i++) { if ((repl->valid_hooks & (1 << i)) == 0) newinfo->hook_entry[i] = NULL; else newinfo->hook_entry[i] = p + ((char *)repl->hook_entry[i] - repl->entries); } ret = translate_table(repl->name, newinfo); if (ret != 0) { BUGPRINT("Translate_table failed\n"); goto free_chainstack; } if (table->check && table->check(newinfo, table->valid_hooks)) { BUGPRINT("The table doesn't like its own initial data, lol\n"); return -EINVAL; } table->private = newinfo; rwlock_init(&table->lock); ret = mutex_lock_interruptible(&ebt_mutex); if (ret != 0) goto free_chainstack; list_for_each_entry(t, &ebt_tables, list) { if (strcmp(t->name, table->name) == 0) { ret = -EEXIST; BUGPRINT("Table name already exists\n"); goto free_unlock; } } /* Hold a reference count if the chains aren't empty */ if (newinfo->nentries && !try_module_get(table->me)) { ret = -ENOENT; goto free_unlock; } list_add(&table->list, &ebt_tables); mutex_unlock(&ebt_mutex); return 0;free_unlock: mutex_unlock(&ebt_mutex);free_chainstack: if (newinfo->chainstack) { for_each_possible_cpu(i) vfree(newinfo->chainstack[i]); vfree(newinfo->chainstack); } vfree(newinfo->entries);free_newinfo: vfree(newinfo); return ret;}void ebt_unregister_table(struct ebt_table *table){ int i; if (!table) { BUGPRINT("Request to unregister NULL table!!!\n"); return; } mutex_lock(&ebt_mutex); list_del(&table->list); mutex_unlock(&ebt_mutex); vfree(table->private->entries); if (table->private->chainstack) { for_each_possible_cpu(i) vfree(table->private->chainstack[i]); vfree(table->private->chainstack); } vfree(table->private);}/* userspace just supplied us with counters */static int update_counters(void __user *user, unsigned int len){ int i, ret; struct ebt_counter *tmp; struct ebt_replace hlp; struct ebt_table *t; if (copy_from_user(&hlp, user, sizeof(hlp))) return -EFAULT; if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) return -EINVAL; if (hlp.num_counters == 0) return -EINVAL; if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) { MEMPRINT("Update_counters && nomemory\n"); return -ENOMEM; } t = find_table_lock(hlp.name, &ret, &ebt_mutex); if (!t) goto free_tmp; if (hlp.num_counters != t->private->nentries) { BUGPRINT("Wrong nr of counters\n"); ret = -EINVAL; goto unlock_mutex; } if ( copy_from_user(tmp, hlp.counters, hlp.num_counters * sizeof(struct ebt_counter)) ) { BUGPRINT("Updata_counters && !cfu\n"); ret = -EFAULT; goto unlock_mutex; } /* we want an atomic add of the counters */ write_lock_bh(&t->lock); /* we add to the counters of the first cpu */ for (i = 0; i < hlp.num_counters; i++) { t->private->counters[i].pcnt += tmp[i].pcnt; t->private->counters[i].bcnt += tmp[i].bcnt; } write_unlock_bh(&t->lock); ret = 0;unlock_mutex: mutex_unlock(&ebt_mutex);free_tmp: vfree(tmp); return ret;}static inline int ebt_make_matchname(struct ebt_entry_match *m, char *base, char __user *ubase){ char __user *hlp = ubase + ((char *)m - base); if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0;}static inline int ebt_make_watchername(struct ebt_entry_watcher *w, char *base, char __user *ubase){ char __user *hlp = ubase + ((char *)w - base); if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0;}static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase){ int ret; char __user *hlp; struct ebt_entry_target *t; if (e->bitmask == 0) return 0; hlp = ubase + (((char *)e + e->target_offset) - base); t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase); if (ret != 0) return ret; ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase); if (ret != 0) return ret; if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0;}/* called with ebt_mutex locked */static int copy_everything_to_user(struct ebt_table *t, void __user *user, int *len, int cmd){ struct ebt_replace tmp; struct ebt_counter *counterstmp, *oldcounters; unsigned int entries_size, nentries; char *entries; if (cmd == EBT_SO_GET_ENTRIES) { entries_size = t->private->entries_size; nentries = t->private->nentries; entries = t->private->entries; oldcounters = t->private->counters; } else { entries_size = t->table->entries_size; nentries = t->table->nentries; entries = t->table->entries; oldcounters = t->table->counters; } if (copy_from_user(&tmp, user, sizeof(tmp))) { BUGPRINT("Cfu didn't work\n"); return -EFAULT; } if (*len != sizeof(struct ebt_replace) + entries_size + (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) { BUGPRINT("Wrong size\n"); return -EINVAL; } if (tmp.nentries != nentries) { BUGPRINT("Nentries wrong\n"); return -EINVAL; } if (tmp.entries_size != entries_size) { BUGPRINT("Wrong size\n"); return -EINVAL; } /* userspace might not need the counters */ if (tmp.num_counters) { if (tmp.num_counters != nentries) { BUGPRINT("Num_counters wrong\n"); return -EINVAL; } counterstmp = vmalloc(nentries * sizeof(*counterstmp)); if (!counterstmp) { MEMPRINT("Couldn't copy counters, out of memory\n"); return -ENOMEM; } write_lock_bh(&t->lock); get_counters(oldcounters, counterstmp, nentries); write_unlock_bh(&t->lock); if (copy_to_user(tmp.counters, counterstmp, nentries * sizeof(struct ebt_counter))) { BUGPRINT("Couldn't copy counters to userspace\n"); vfree(counterstmp); return -EFAULT; } vfree(counterstmp); } if (copy_to_user(tmp.entries, entries, entries_size)) { BUGPRINT("Couldn't copy entries to userspace\n"); return -EFAULT; } /* set the match/watcher/target names right */ return EBT_ENTRY_ITERATE(entries, entries_size, ebt_make_names, entries, tmp.entries);}static int do_ebt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len){ int ret; switch(cmd) { case EBT_SO_SET_ENTRIES: ret = do_replace(user, len); break; case EBT_SO_SET_COUNTERS: ret = update_counters(user, len); break; default: ret = -EINVAL; } return ret;}static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len){ int ret; struct ebt_replace tmp; struct ebt_table *t; if (copy_from_user(&tmp, user, sizeof(tmp))) return -EFAULT; t = find_table_lock(tmp.name, &ret, &ebt_mutex); if (!t) return ret; switch(cmd) { case EBT_SO_GET_INFO: case EBT_SO_GET_INIT_INFO: if (*len != sizeof(struct ebt_replace)){ ret = -EINVAL; mutex_unlock(&ebt_mutex); break; } if (cmd == EBT_SO_GET_INFO) { tmp.nentries = t->private->nentries; tmp.entries_size = t->private->entries_size; tmp.valid_hooks = t->valid_hooks; } else { tmp.nentries = t->table->nentries; tmp.entries_size = t->table->entries_size; tmp.valid_hooks = t->table->valid_hooks; } mutex_unlock(&ebt_mutex); if (copy_to_user(user, &tmp, *len) != 0){ BUGPRINT("c2u Didn't work\n"); ret = -EFAULT; break; } ret = 0; break; case EBT_SO_GET_ENTRIES: case EBT_SO_GET_INIT_ENTRIES: ret = copy_everything_to_user(t, user, len, cmd); mutex_unlock(&ebt_mutex); break; default: mutex_unlock(&ebt_mutex); ret = -EINVAL; } return ret;}static struct nf_sockopt_ops ebt_sockopts ={ .pf = PF_INET, .set_optmin = EBT_BASE_CTL, .set_optmax = EBT_SO_SET_MAX + 1, .set = do_ebt_set_ctl, .get_optmin = EBT_BASE_CTL, .get_optmax = EBT_SO_GET_MAX + 1, .get = do_ebt_get_ctl, .owner = THIS_MODULE,};static int __init ebtables_init(void){ int ret; mutex_lock(&ebt_mutex); list_add(&ebt_standard_target.list, &ebt_targets); mutex_unlock(&ebt_mutex); if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) return ret; printk(KERN_INFO "Ebtables v2.0 registered\n"); return 0;}static void __exit ebtables_fini(void){ nf_unregister_sockopt(&ebt_sockopts); printk(KERN_INFO "Ebtables v2.0 unregistered\n");}EXPORT_SYMBOL(ebt_register_table);EXPORT_SYMBOL(ebt_unregister_table);EXPORT_SYMBOL(ebt_register_match);EXPORT_SYMBOL(ebt_unregister_match);EXPORT_SYMBOL(ebt_register_watcher);EXPORT_SYMBOL(ebt_unregister_watcher);EXPORT_SYMBOL(ebt_register_target);EXPORT_SYMBOL(ebt_unregister_target);EXPORT_SYMBOL(ebt_do_table);module_init(ebtables_init);module_exit(ebtables_fini);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -