初始化

iptable_mangle_table_init函数通过调用ipt_register_table完成mangle表注册和钩子函数注册的功能;该流程与iptable_filter的函数调用的函数一致,此处不再重复分析,详情请移步<iptable_filter分析>;

 static int __net_init iptable_mangle_table_init(struct net *net)
{
struct ipt_replace *repl;
int ret; /* 已经初始化 */
if (net->ipv4.iptable_mangle)
return ; /* 分配初始化用于下面注册的结构 */
repl = ipt_alloc_initial_table(&packet_mangler);
if (repl == NULL)
return -ENOMEM;
/* 注册表和钩子函数 */
ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops,
&net->ipv4.iptable_mangle);
kfree(repl);
return ret;
}
钩子函数

从下面的钩子函数可以看到其分布于全部5个钩子点;

 #define MANGLE_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
( << NF_INET_LOCAL_IN) | \
( << NF_INET_FORWARD) | \
( << NF_INET_LOCAL_OUT) | \
( << NF_INET_POST_ROUTING))
 static const struct xt_table packet_mangler = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_MANGLE,
.table_init = iptable_mangle_table_init,
};

iptable_mangle_hook为mangle钩子函数,如果当前是处于LOCAL_OUT钩子点,则需要调用ip_mangle_out函数,其他店则调用ipt_do_table进行规则匹配;ipt_do_table函数此处不再重复分析,详情请移步<iptable_filter分析>;

 static unsigned int
iptable_mangle_hook(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
/* LOCAL_OUT钩子点,调用mangle_out */
if (state->hook == NF_INET_LOCAL_OUT)
return ipt_mangle_out(skb, state);
/* 规则匹配 */
return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
}

ipt_mangle_out首先保存ip头部的一些信息,然后调用ipt_do_table进行规则匹配,规则之后检查ip头中的保存字段是否发生变化,如果发生变化,则需要重新查路由;

 static unsigned int
ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
{
unsigned int ret;
const struct iphdr *iph;
u_int8_t tos;
__be32 saddr, daddr;
u_int32_t mark;
int err; /* root is playing with raw sockets. */
/* 原始套接字 */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT; /* Save things which could affect route */ mark = skb->mark;
iph = ip_hdr(skb);
saddr = iph->saddr;
daddr = iph->daddr;
tos = iph->tos; /* 进行规则匹配 */
ret = ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
/* Reroute for ANY change. */
/* 经过规则后 */
if (ret != NF_DROP && ret != NF_STOLEN) {
iph = ip_hdr(skb); /* 判断ip头中的字段是否有改变 */
if (iph->saddr != saddr ||
iph->daddr != daddr ||
skb->mark != mark ||
iph->tos != tos) {
/* 重新查路由 */
err = ip_route_me_harder(state->net, skb, RTN_UNSPEC);
if (err < )
ret = NF_DROP_ERR(err);
}
} return ret;
}

最新文章

  1. 关于ubuntu16.04中mysql root登陆不了的情况下(大多是未设置密码的情况)
  2. [WCF编程]12.事务:事务协议与管理器
  3. js 阻止事件冒泡和默认行为 preventDefault、stopPropagation、return false
  4. 冲刺阶段 day 9
  5. 单击HighCharts柱形体弹框显示详细信息
  6. Field+offset(len)
  7. 线程中CreateEvent和SetEvent及WaitForSingleObject的用法
  8. zencart安装第三步出现空白
  9. IOS 7 Study - UIDatePicker
  10. Comparison method violates its general contract
  11. xml的生成与解析_老师笔记
  12. CSS3中的选择器
  13. Qt之QNetworkInterface(查询网络接口),QHostInfo(查询主机IP)
  14. highstock
  15. null transform hack 强制使用硬件加速
  16. render函数(转)
  17. Spring的Aspect切面类不能拦截Controller中的方法
  18. 如何在VS Code中进行golang编程
  19. Unbuntu18.04通过apt源方式安装mysql5.7.22
  20. runloop timer

热门文章

  1. 深入JavaScript对象(Object)与类(class),详细了解类、原型
  2. jQuery实现购物车效果
  3. JS-上下文练习
  4. 内核开机logo
  5. 使用pycharm 编写代码 并在远程主机上运行
  6. linux后台启动项目命令
  7. Computer Vision_1_Active Appearance Models:Active Appearance Models——2001
  8. redis系列一: windows下安装redis
  9. (备忘)Nodepad++常用快捷键
  10. MinGW-W64 编译 LLVM 与 Clang