日期:2014-05-16 浏览次数:20794 次
8.7 ipt动作操作结构 ipt是借用了netfilter的目标操作, 根据netfilter的target结果作为是否接受还是丢弃数据包, 不过感觉意义不大, 因为这破坏了协议栈的分层处理, 要丢包的话直接在上层就丢了就算了。代码在net/sched/act_ipt.c中定义。 8.7.1 数据结构和动作操作结构 /* include/net/tc_act/tc_ipt.h */ // ipt动作结构 struct tcf_ipt { // 通用结构 struct tcf_common common; // hook点 u32 tcfi_hook; // target名称 char *tcfi_tname; // target指针 struct xt_entry_target *tcfi_t; }; #define to_ipt(pc) \ container_of(pc, struct tcf_ipt, common) /* net/sched/act_ipt.c */ static struct tcf_hashinfo ipt_hash_info = { .htab = tcf_ipt_ht, .hmask = IPT_TAB_MASK, .lock = &ipt_lock, }; // ipt动作操作结构 static struct tc_action_ops act_ipt_ops = { // 名称 .kind = "ipt", .hinfo = &ipt_hash_info, // 类型 .type = TCA_ACT_IPT, .capab = TCA_CAP_NONE, .owner = THIS_MODULE, .act = tcf_ipt, .dump = tcf_ipt_dump, .cleanup = tcf_ipt_cleanup, // 查找, 通用函数 .lookup = tcf_hash_search, .init = tcf_ipt_init, // 遍历, 通用函数 .walk = tcf_generic_walker }; 8.7.2 初始化 static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct rtattr *tb[TCA_IPT_MAX]; struct tcf_ipt *ipt; struct tcf_common *pc; struct ipt_entry_target *td, *t; char *tname; int ret = 0, err; u32 hook = 0; u32 index = 0; // 解析输入参数 if (rta == NULL || rtattr_parse_nested(tb, TCA_IPT_MAX, rta) < 0) return -EINVAL; // 需要有hook参数 if (tb[TCA_IPT_HOOK-1] == NULL || RTA_PAYLOAD(tb[TCA_IPT_HOOK-1]) < sizeof(u32)) return -EINVAL; // 需要有target参数 if (tb[TCA_IPT_TARG-1] == NULL || RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < sizeof(*t)) return -EINVAL; // netfilter目标 td = (struct ipt_entry_target *)RTA_DATA(tb[TCA_IPT_TARG-1]); // 检查target参数大小是否合法 if (RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < td->u.target_size) return -EINVAL; // 索引号 if (tb[TCA_IPT_INDEX-1] != NULL && RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32)) index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]); // 根据索引号查找common节点, 绑定到a节点(priv) pc = tcf_hash_check(index, a, bind, &ipt_hash_info); if (!pc) { // 如果为空, 创建新的common节点 pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind, &ipt_idx_gen, &ipt_hash_info); if (unlikely(!pc)) return -ENOMEM; ret = ACT_P_CREATED; } else { // ovr是替代标志, 如果不是替代操作, 对象已经存在, 操作失败 if (!ovr) { // 释放 tcf_ipt_release(to_ipt(pc), bind); return -EEXIST; } } // ipt = to_ipt(pc); // hook点 hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]); err = -ENOMEM; // 分配缓冲区保存目标名称 tname = kmalloc(IFNAMSIZ, GFP_KERNEL); if (unlikely(!tname)) goto err1; // 解析iptables表的名称, 缺省为mangle表 if (tb[TCA_IPT_TABLE - 1] == NULL || rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ) strcpy(tname, "mangle"); // 分配目标空间 t = kmalloc(td->u.target_size, GFP_KERNEL); if (unlikely(!t)) goto err2; // 复制目标结构相关参数 memcpy(t, td, td->u.target_size); // 初始化目标 if ((err = ipt_init_target(t, tname, hook)) < 0) goto err3; spin_lock_bh(&ipt->tcf_lock); if (ret != ACT_P_CREATED) { // 如果不是新建, 释放老节点参数 ipt_destroy_target(ipt->tcfi_t); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); } // 参数赋值 ipt->tcfi_tname = tname; ipt->tcfi_t = t; ipt->tcfi_hook = hook; spin_unlock_bh(&ipt->tcf_lock); // 新建节点, 插入哈希表 if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &ipt_hash_info); return ret; 错误处理, 释放各种动态分配的参数 err3: kfree(t); err2: kfree(tname); err1: kfree(pc); return err; } // 初始化目标 static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) { struct ipt_target *target; int ret = 0; // 根据名称查找target target = xt_find_target(AF_INET, t->u.user.name, t->u.user.revision); // 找不到则失败 if (!target) return -ENOENT; t->u.kernel.target = target; // target通用检查, 检查合适的大小, 表名, hook, 协议等信息 ret = xt_check_target(target, AF_INET, t-&g