📄 x_tables.c
字号:
/* * x_tables core - Backend for {ip,ip6,arp}_tables * * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org> * * Based on existing ip_tables code which is * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#include <linux/kernel.h>#include <linux/socket.h>#include <linux/net.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/string.h>#include <linux/vmalloc.h>#include <linux/mutex.h>#include <linux/mm.h>#include <net/net_namespace.h>#include <linux/netfilter/x_tables.h>#include <linux/netfilter_arp.h>MODULE_LICENSE("GPL");MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))struct xt_af { struct mutex mutex; struct list_head match; struct list_head target; struct list_head tables; struct mutex compat_mutex;};static struct xt_af *xt;#ifdef DEBUG_IP_FIREWALL_USER#define duprintf(format, args...) printk(format , ## args)#else#define duprintf(format, args...)#endifenum { TABLE, TARGET, MATCH,};static const char *xt_prefix[NPROTO] = { [AF_INET] = "ip", [AF_INET6] = "ip6", [NF_ARP] = "arp",};/* Registration hooks for targets. */intxt_register_target(struct xt_target *target){ int ret, af = target->family; ret = mutex_lock_interruptible(&xt[af].mutex); if (ret != 0) return ret; list_add(&target->list, &xt[af].target); mutex_unlock(&xt[af].mutex); return ret;}EXPORT_SYMBOL(xt_register_target);voidxt_unregister_target(struct xt_target *target){ int af = target->family; mutex_lock(&xt[af].mutex); list_del(&target->list); mutex_unlock(&xt[af].mutex);}EXPORT_SYMBOL(xt_unregister_target);intxt_register_targets(struct xt_target *target, unsigned int n){ unsigned int i; int err = 0; for (i = 0; i < n; i++) { err = xt_register_target(&target[i]); if (err) goto err; } return err;err: if (i > 0) xt_unregister_targets(target, i); return err;}EXPORT_SYMBOL(xt_register_targets);voidxt_unregister_targets(struct xt_target *target, unsigned int n){ unsigned int i; for (i = 0; i < n; i++) xt_unregister_target(&target[i]);}EXPORT_SYMBOL(xt_unregister_targets);intxt_register_match(struct xt_match *match){ int ret, af = match->family; ret = mutex_lock_interruptible(&xt[af].mutex); if (ret != 0) return ret; list_add(&match->list, &xt[af].match); mutex_unlock(&xt[af].mutex); return ret;}EXPORT_SYMBOL(xt_register_match);voidxt_unregister_match(struct xt_match *match){ int af = match->family; mutex_lock(&xt[af].mutex); list_del(&match->list); mutex_unlock(&xt[af].mutex);}EXPORT_SYMBOL(xt_unregister_match);intxt_register_matches(struct xt_match *match, unsigned int n){ unsigned int i; int err = 0; for (i = 0; i < n; i++) { err = xt_register_match(&match[i]); if (err) goto err; } return err;err: if (i > 0) xt_unregister_matches(match, i); return err;}EXPORT_SYMBOL(xt_register_matches);voidxt_unregister_matches(struct xt_match *match, unsigned int n){ unsigned int i; for (i = 0; i < n; i++) xt_unregister_match(&match[i]);}EXPORT_SYMBOL(xt_unregister_matches);/* * These are weird, but module loading must not be done with mutex * held (since they will register), and we have to have a single * function to use try_then_request_module(). *//* Find match, grabs ref. Returns ERR_PTR() on error. */struct xt_match *xt_find_match(int af, const char *name, u8 revision){ struct xt_match *m; int err = 0; if (mutex_lock_interruptible(&xt[af].mutex) != 0) return ERR_PTR(-EINTR); list_for_each_entry(m, &xt[af].match, list) { if (strcmp(m->name, name) == 0) { if (m->revision == revision) { if (try_module_get(m->me)) { mutex_unlock(&xt[af].mutex); return m; } } else err = -EPROTOTYPE; /* Found something. */ } } mutex_unlock(&xt[af].mutex); return ERR_PTR(err);}EXPORT_SYMBOL(xt_find_match);/* Find target, grabs ref. Returns ERR_PTR() on error. */struct xt_target *xt_find_target(int af, const char *name, u8 revision){ struct xt_target *t; int err = 0; if (mutex_lock_interruptible(&xt[af].mutex) != 0) return ERR_PTR(-EINTR); list_for_each_entry(t, &xt[af].target, list) { if (strcmp(t->name, name) == 0) { if (t->revision == revision) { if (try_module_get(t->me)) { mutex_unlock(&xt[af].mutex); return t; } } else err = -EPROTOTYPE; /* Found something. */ } } mutex_unlock(&xt[af].mutex); return ERR_PTR(err);}EXPORT_SYMBOL(xt_find_target);struct xt_target *xt_request_find_target(int af, const char *name, u8 revision){ struct xt_target *target; target = try_then_request_module(xt_find_target(af, name, revision), "%st_%s", xt_prefix[af], name); if (IS_ERR(target) || !target) return NULL; return target;}EXPORT_SYMBOL_GPL(xt_request_find_target);static int match_revfn(int af, const char *name, u8 revision, int *bestp){ struct xt_match *m; int have_rev = 0; list_for_each_entry(m, &xt[af].match, list) { if (strcmp(m->name, name) == 0) { if (m->revision > *bestp) *bestp = m->revision; if (m->revision == revision) have_rev = 1; } } return have_rev;}static int target_revfn(int af, const char *name, u8 revision, int *bestp){ struct xt_target *t; int have_rev = 0; list_for_each_entry(t, &xt[af].target, list) { if (strcmp(t->name, name) == 0) { if (t->revision > *bestp) *bestp = t->revision; if (t->revision == revision) have_rev = 1; } } return have_rev;}/* Returns true or false (if no such extension at all) */int xt_find_revision(int af, const char *name, u8 revision, int target, int *err){ int have_rev, best = -1; if (mutex_lock_interruptible(&xt[af].mutex) != 0) { *err = -EINTR; return 1; } if (target == 1) have_rev = target_revfn(af, name, revision, &best); else have_rev = match_revfn(af, name, revision, &best); mutex_unlock(&xt[af].mutex); /* Nothing at all? Return 0 to try loading module. */ if (best == -1) { *err = -ENOENT; return 0; } *err = best; if (!have_rev) *err = -EPROTONOSUPPORT; return 1;}EXPORT_SYMBOL_GPL(xt_find_revision);int xt_check_match(const struct xt_match *match, unsigned short family, unsigned int size, const char *table, unsigned int hook_mask, unsigned short proto, int inv_proto){ if (XT_ALIGN(match->matchsize) != size) { printk("%s_tables: %s match: invalid size %Zu != %u\n", xt_prefix[family], match->name, XT_ALIGN(match->matchsize), size); return -EINVAL; } if (match->table && strcmp(match->table, table)) { printk("%s_tables: %s match: only valid in %s table, not %s\n", xt_prefix[family], match->name, match->table, table); return -EINVAL; } if (match->hooks && (hook_mask & ~match->hooks) != 0) { printk("%s_tables: %s match: bad hook_mask %u/%u\n", xt_prefix[family], match->name, hook_mask, match->hooks); return -EINVAL; } if (match->proto && (match->proto != proto || inv_proto)) { printk("%s_tables: %s match: only valid for protocol %u\n", xt_prefix[family], match->name, match->proto); return -EINVAL; } return 0;}EXPORT_SYMBOL_GPL(xt_check_match);#ifdef CONFIG_COMPATint xt_compat_match_offset(struct xt_match *match){ u_int16_t csize = match->compatsize ? : match->matchsize; return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);}EXPORT_SYMBOL_GPL(xt_compat_match_offset);void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, int *size){ struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; int pad, off = xt_compat_match_offset(match); u_int16_t msize = cm->u.user.match_size; m = *dstptr; memcpy(m, cm, sizeof(*cm)); if (match->compat_from_user) match->compat_from_user(m->data, cm->data); else memcpy(m->data, cm->data, msize - sizeof(*cm)); pad = XT_ALIGN(match->matchsize) - match->matchsize; if (pad > 0) memset(m->data + match->matchsize, 0, pad); msize += off; m->u.user.match_size = msize; *size += off; *dstptr += msize;}EXPORT_SYMBOL_GPL(xt_compat_match_from_user);int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr, int *size){ struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match __user *cm = *dstptr; int off = xt_compat_match_offset(match); u_int16_t msize = m->u.user.match_size - off; if (copy_to_user(cm, m, sizeof(*cm)) || put_user(msize, &cm->u.user.match_size) || copy_to_user(cm->u.user.name, m->u.kernel.match->name, strlen(m->u.kernel.match->name) + 1)) return -EFAULT; if (match->compat_to_user) { if (match->compat_to_user((void __user *)cm->data, m->data)) return -EFAULT; } else { if (copy_to_user(cm->data, m->data, msize - sizeof(*cm))) return -EFAULT; } *size -= off; *dstptr += msize; return 0;}EXPORT_SYMBOL_GPL(xt_compat_match_to_user);#endif /* CONFIG_COMPAT */int xt_check_target(const struct xt_target *target, unsigned short family, unsigned int size, const char *table, unsigned int hook_mask, unsigned short proto, int inv_proto){ if (XT_ALIGN(target->targetsize) != size) { printk("%s_tables: %s target: invalid size %Zu != %u\n", xt_prefix[family], target->name, XT_ALIGN(target->targetsize), size); return -EINVAL; } if (target->table && strcmp(target->table, table)) { printk("%s_tables: %s target: only valid in %s table, not %s\n", xt_prefix[family], target->name, target->table, table); return -EINVAL; } if (target->hooks && (hook_mask & ~target->hooks) != 0) { printk("%s_tables: %s target: bad hook_mask %u/%u\n", xt_prefix[family], target->name, hook_mask, target->hooks); return -EINVAL; } if (target->proto && (target->proto != proto || inv_proto)) { printk("%s_tables: %s target: only valid for protocol %u\n", xt_prefix[family], target->name, target->proto); return -EINVAL; } return 0;}EXPORT_SYMBOL_GPL(xt_check_target);#ifdef CONFIG_COMPATint xt_compat_target_offset(struct xt_target *target){ u_int16_t csize = target->compatsize ? : target->targetsize; return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);}EXPORT_SYMBOL_GPL(xt_compat_target_offset);void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, int *size){ struct xt_target *target = t->u.kernel.target; struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; int pad, off = xt_compat_target_offset(target); u_int16_t tsize = ct->u.user.target_size; t = *dstptr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -