msn: [email protected]
来源:http://yfydz.cublog.cn
1. 5个挂接点 以下内核代码版本2.6.17.11。 1.1 PREROTING /* net/ipv4/ip_input.c */ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { ...... return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish); ...... } 1.2 INPUT /* net/ipv4/ip_input.c */ int ip_local_deliver(struct sk_buff *skb) { ...... return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, ip_local_deliver_finish); } 1.3 FORWARD /* net/ipv4/ip_forward.c */ int ip_forward(struct sk_buff *skb) { ...... return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev, ip_forward_finish); ...... } 1.4 OUTPUT /* net/ipv4/ip_output.c */ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, u32 saddr, u32 daddr, struct ip_options *opt) { ...... return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); } int ip_queue_xmit(struct sk_buff *skb, int ipfragok) { ...... return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); ...... } int ip_push_pending_frames(struct sock *sk) { ...... /* Netfilter gets whole the not fragmented skb. */ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); ...... } 1.5 POSTROUTING /* net/ipv4/ip_output.c */ int ip_output(struct sk_buff *skb) { struct net_device *dev = skb->dst->dev; IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); skb->dev = dev; skb->protocol = htons(ETH_P_IP); return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev, ip_finish_output, !(IPCB(skb)->flags & IPSKB_REROUTED)); } 2. 每个挂接点所挂接的hook操作 只考虑是AF_INET协议族的挂接点,以下各点的hook操作按执行顺序排序,优先级数值越小,级别越高,执行顺序越靠前。 如果用户可以通过iptables规则进行控制的处理点称为用户可控,否则为不可控。 2.1 PREREOUTING /* net/bridge/br_netfilter.c */ // 这个hook点只丢弃skb结构中设置桥参数但没有相关桥标志的包 // 用户不可控 { .hook = ip_sabotage_in, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_PRE_ROUTING, // 优先级最高 .priority = NF_IP_PRI_FIRST, }, /* net/ipv4/netfilter/ip_conntrack_standalone.c */ // 这个hook点完成分片重组,以后处理过程中的包都是非分片包 // 直到发送出去重新分片。注意2.6重组后的分片包并不进行线性 // 化,所以逻辑上应该连在一起的两字节数据可能分属不同的页, // 存储是不连续的 // 该点操作用户不可控 { .hook = ip_conntrack_defrag, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_PRE_ROUTING, // 优先级为-400 .priority = NF_IP_PRI_CONNTRACK_DEFRAG, }, /* net/ipv4/netfilter/iptable_raw.c */ // 这个hook点为raw表,提供对收到的数据包在连接跟踪前进行处理的手段 // 该点用户可加载iptables规则进行控制 { .hook = ipt_hook, .pf = PF_INET, .hooknum = NF_IP_PRE_ROUTING, // 优先级为-300 .priority = NF_IP_PRI_RAW, .owner = THIS_MODULE, }, /* net/ipv4/netfilter/ip_conntrack_standalone.c */ // 这个hook点完成连接跟踪,为每个skb找到所属连接(ESTABLISHED, REPLY) // 或新建连接(NEW, RELATED) // 该点操作用户不可控 { .hook = ip_conntrack_in, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_PRE_ROUTING, // 优先级为-200 .priority = NF_IP_PRI_CONNTRACK, }, /* net/ipv4/netfilter/iptable_mangle.c */ // 这个hook点为mangle表,提供对收到的数据包进行修改的处理 // 该点用户可加载iptables规则进行控制 { .hook = ipt_route_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_PRE_ROUTING, // 优先级为-150 .priority = NF_IP_PRI_MANGLE, }, /* net/ipv4/netfilter/ip_nat_standalone.c */ // 该hook点对刚收到本机的skb包进行目的NAT操作 // 用户规则可控,nat表,但规则只对NEW包进行处理,后续包自动处理 { .hook = ip_nat_in, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_PRE_ROUTING, // 优先级为-100 .priority = NF_IP_PRI_NAT_DST, }, /* net/sched/sch_ingress.c */ // 该hook点对j进入本机的skb包进行排队处理,QoS操作 // 用户不可控 static struct nf_hook_ops ing_ops = { .hook = ing_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_PRE_ROUTING, // 优先级为1 .priority = NF_IP_PRI_FILTER + 1, }; 2.2 INPUT /* net/ipv4/netfilter/iptable_mangle.c */ // 这个hook点为mangle表,提供对收到的数据包进行修改的处理 // 该点用户可加载iptables规则进行控制 { .hook = ipt_route_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, // 优先级为-150 .priority = NF_IP_PRI_MANGLE, }, /* net/ipv4/netfilter/iptable_filter.c */ // 这个hook点为filter表,提供对进入本机的数据包进行过滤的处理 // 该点用户可加载iptables规则进行控制 { .hook = ipt_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, // 优先级为0 .priority = NF_IP_PRI_FILTER, }, /* net/ipv4/netfilter/ip_nat_standalone.c */ // 对进入本机的skb包进行源NAT操作 // 用户规则可控,nat表,但规则只对NEW包进行处理,后续包自动处理 { .hook = ip_nat_fn, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, // 优先级为100 .priority = NF_IP_PRI_NAT_SRC, }, /* net/ipv4/ipvs/ip_vs_core.c */ // 该hook点对进入本机的skb包均衡分配 // 用户不可控 static struct nf_hook_ops ip_vs_in_ops = { .hook = ip_vs_in, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, .priority = 100, }; /* net/ipv4/netfilter/ip_conntrack_standalone.c */ // 该hook点对进入本机的skb包完成对连接跟踪的help,也就是 // 多连接协议中对子连接的处理 // 用户不可控 { .hook = ip_conntrack_help, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, // 优先级为INT_MAX-2,相当低 .priority = NF_IP_PRI_CONNTRACK_HELPER, }, /* net/ipv4/netfilter/ip_nat_standalone.c */ // 对进入本机的skb包进行TCP序列号调整操作,主要是因为跟踪多连接协议时 // 修改了数据包内容可能导致数据包长度发生变化,相应序列号和确认号需要 // 自动调整 // 用户规则不可控 { .hook = ip_nat_adjust, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, // 优先级为INR_MAX-1,相当低 .priority = NF_IP_PRI_NAT_SEQ_ADJUST, }, /* net/ipv4/netfilter/ip_conntrack_standalone.c */ // 该hook点对进入本机的skb包完成最后的确认,只对NEW包处理 // 确认NEW的连接信息在当前的连接表中是不存在的 // 用户不可控 { .hook = ip_confirm, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, // 优先级为INT_MAX,最低 .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }, 2.3 FORWARD /* net/bridge/br_netfilter.c */ // 这个hook点对由桥网卡转发的skb包设置桥信息和物理网卡等信息 // 该函数可能会返回NF_STOP不进行后续hook点的处理 // 用户不可控 { .hook = ip_sabotage_out, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_FORWARD, // 优先级为-175 .priority = NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD, }, /* net/ipv4/netfilter/iptable_mangle.c */ // 这个hook点为mangle表,提供对收到的数据包进行修改的处理 // 该点用户可加载iptables规则进行控制 { .hook = ipt_route_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_FORWARD, // 优先级为-150 .priority = NF_IP_PRI_MANGLE, }, /* net/ipv4/netfilter/iptable_filter.c */ // 这个hook点为filter表,提供对转发的数据包进行过滤的处理 // 该点用户可加载iptables规则进行控制 { .hook = ipt_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_FORWARD, // 优先级为0 .priority = NF_IP_PRI_FILTER, }, /* net/ipv4/ipvs/ip_vs_core.c */ // 该hook点对转发的skb包均衡分配前处理ICMP异常 // 用户不可控 static struct nf_hook_ops ip_vs_forward_icmp_ops = { .hook = ip_vs_forward_icmp, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_FORWARD, .priority = 99, }; /* net/ipv4/ipvs/ip_vs_core.c */ // 该hook点对转发的skb包均衡分配 // 用户不可控 static struct nf_hook_ops ip_vs_out_ops = { .hook = ip_vs_out, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_FORWARD, .priority = 100, }; 3.4 OUTPUT /* net/ipv4/netfilter/ip_conntrack_standalone.c */ // 这个hook点对自身发出的包完成分片重组,以后处理过程中的包都是非分片包 // 直到最后发送出去重新分片。注意2.6重组后的分片包并不进行线性 // 化,所以逻辑上应该连在一起的两字节数据可能分属不同的页, // 存储是不连续的 // 该点操作用户不可控 { .hook = ip_conntrack_defrag, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_OUT, // 优先级为-400 .priority = NF_IP_PRI_CONNTRACK_DEFRAG, }, /* net/ipv4/netfilter/iptable_raw.c */ // 这个hook点为raw表,提供对本机发出数据包在连接跟踪前进行处理的手段 // 该点用户可加载iptables规则进行控制 { .hook = ipt_hook, .pf = PF_INET, .hooknum = NF_IP_LOCAL_OUT, // 优先级为-300 .priority = NF_IP_PRI_RAW, .owner = THIS_MODULE, }, /* net/ipv4/netfilter/ip_conntrack_standalone.c */ // 这个hook点对自身发出的包完成连接跟踪,为每个skb找到所属连接 // (ESTABLISHED, REPLY)或新建连接(NEW, RELATED) // 该点操作用户不可控 { .hook = ip_conntrack_local, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_OUT, // 优先级为-200 .priority = NF_IP_PRI_CONNTRACK, }, /* net/ipv4/netfilter/iptable_mangle.c */ // 这个hook点为mangle表,提供对收到的数据包进行修改的处理 // 该点用户可加载iptables规则进行控制 { .hook = ipt_local_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_OUT, // 优先级为-150 .priority = NF_IP_PRI_MANGLE, }, /* net/ipv4/netfilter/ip_nat_standalone.c */ // 对本机发出的skb包进行目的NAT操作 // 用户规则可控,nat表,但规则只对NEW包进行处理,后续包自动处理 { .hook = ip_nat_local_fn, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_OUT, // 优先级为-100 .priority = NF_IP_PRI_NAT_DST, }, /* net/bridge/br_netfilter.c */ // 这个hook点对由桥网卡发出的skb包设置桥信息和物理网卡等信息 // 该函数会返回NF_STOP,提前终止检查而返回 // 用户不可控 { .hook = ip_sabotage_out, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_OUT, // 优先级为-50 .priority = NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, }, /* net/ipv4/netfilter/iptable_filter.c */ // 这个hook点为filter表,提供对本机发出的数据包进行过滤的处理 // 该点用户可加载iptables规则进行控制 { .hook = ipt_local_out_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_OUT, // 优先级为0 .priority = NF_IP_PRI_FILTER, }, 2.5 POSTROUTING /* net/bridge/br_netfilter.c */ // 这个hook点对由桥网卡发出的skb包设置桥信息和物理网卡等信息 // 该函数会返回NF_STOP,提前终止检查而返回 // 用户不可控 { .hook = ip_sabotage_out, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_POST_ROUTING, // 优先级最高 .priority = NF_IP_PRI_FIRST, }, /* net/ipv4/netfilter/iptable_mangle.c */ // 这个hook点为mangle表,提供对收到的数据包进行修改的处理 // 该点用户可加载iptables规则进行控制 { .hook = ipt_route_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_POST_ROUTING, // 优先级为-150 .priority = NF_IP_PRI_MANGLE, }, /* net/ipv4/ipvs/ip_vs_core.c */ // 该hook点对IPVS本身的控制包直接返回NF_STOP不进行后续hook点处理 // 用户不可控 static struct nf_hook_ops ip_vs_post_routing_ops = { .hook = ip_vs_post_routing, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_POST_ROUTING, // 优先级为99 .priority = NF_IP_PRI_NAT_SRC-1, }; /* net/ipv4/netfilter/ip_nat_standalone.c */ // 对本机发出的skb包进行源NAT操作 // 用户规则可控,nat表,但规则只对NEW包进行处理,后续包自动处理 { .hook = ip_nat_out, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_POST_ROUTING, // 优先级为100 .priority = NF_IP_PRI_NAT_SRC, }, /* net/ipv4/netfilter/ip_conntrack_standalone.c */ // 该hook点对转发的skb包完成对连接跟踪的help,也就是 // 多连接协议中对子连接的处理 // 用户不可控 { .hook = ip_conntrack_help, .owner = THIS_MODULE, .pf = PF_INET, // 优先级为INT_MAX-2,相当低 .hooknum = NF_IP_POST_ROUTING, .priority = NF_IP_PRI_CONNTRACK_HELPER, }, /* net/ipv4/netfilter/ip_nat_standalone.c */ // 对发出本机的skb包进行TCP序列号调整操作,主要是因为跟踪多连接协议时 // 修改了数据包内容可能导致数据包长度发生变化,相应序列号和确认号需要 // 自动调整 // 用户规则不可控 { .hook = ip_nat_adjust, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_POST_ROUTING, // 优先级为INR_MAX-1,相当低 .priority = NF_IP_PRI_NAT_SEQ_ADJUST, }, /* net/ipv4/netfilter/ip_conntrack_standalone.c */ // 该hook点对进入本机的skb包完成最后的确认,只对NEW包处理 // 确认NEW的新连接信息在当前的连接表中是不存在的 // 用户不可控 { .hook = ip_confirm, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_POST_ROUTING, // 优先级为INT_MAX,最低 .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }, 3. 结论 由此可见,即使内核不支持bridge, ipvs和sched,一个转发包通过netfilter时也会经过12个处理点的处理,任何一点的拒绝都会使该包丢弃,在各点的控制处理功能可以高度集中,象流水线的各个环节一样。如果能用多核处理器能让比较费资源的点单独跑一个核,各个核的处理结果进行流水线,系统效率的提升肯定会很高,可惜这种 AMP处理还是"Mission impossible",当前的SMP处理方式只会使netfilter架构效率很低,什么时候可以把“im”去掉还要等待。