本节中,我们分析MASQUERADE在内核空间的实现。详细分析在代码中以注释的形式说明。

#####1.ipt_MASQUERADE.c源码分析
  iptables 命令行在用户空间配置之后,会激活相应的内核空间的钩子函数。此源码即为钩子函数的注册。

/* Masquerade.  Simple mapping which alters range to a local IP address(depending on route). *//* (C) 1999-2001 Paul `Rusty' Russell* (C) 2002-2006 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.*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/inetdevice.h>
#include <linux/ip.h>
#include <linux/timer.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/checksum.h>
#include <net/route.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/ipv4/nf_nat_masquerade.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("Xtables: automatic-address SNAT");/* * FIXME: Multiple targets. --RR * 对iptables命令行传入内和空间的数据输入的检测*/
static int masquerade_tg_check(const struct xt_tgchk_param *par)
{const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;if (mr->range[0].flags & NF_NAT_RANGE_MAP_IPS) {pr_debug("bad MAP_IPS.\n");return -EINVAL;}if (mr->rangesize != 1) {pr_debug("bad rangesize %u\n", mr->rangesize);return -EINVAL;}return nf_ct_netns_get(par->net, par->family);
}static unsigned int
masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
{struct nf_nat_range range;const struct nf_nat_ipv4_multi_range_compat *mr;mr = par->targinfo;range.flags = mr->range[0].flags;range.min_proto = mr->range[0].min;range.max_proto = mr->range[0].max;/* 调用函数nf_nat_masquerade_ipv4()将命令行输入的数值传入Netfilter中以实现钩子函数功能*/return nf_nat_masquerade_ipv4(skb, xt_hooknum(par), &range,xt_out(par));
}static void masquerade_tg_destroy(const struct xt_tgdtor_param *par)
{nf_ct_netns_put(par->net, par->family);
}/** 钩子函数的注册* 一定要注意,这里的名字必须和用户空间的libipt_masquerade.c中注册的对应* 这里我们可以看到masquerade的位置是POSTROUTING,即针对内部tuple转化为外部tuple和目标通信*/
static struct xt_target masquerade_tg_reg __read_mostly = {.name       = "MASQUERADE",.family       = NFPROTO_IPV4,.target     = masquerade_tg,.targetsize    = sizeof(struct nf_nat_ipv4_multi_range_compat),.table     = "nat",.hooks       = 1 << NF_INET_POST_ROUTING,.checkentry  = masquerade_tg_check,.destroy = masquerade_tg_destroy,.me        = THIS_MODULE,
};static int __init masquerade_tg_init(void)
{int ret;ret = xt_register_target(&masquerade_tg_reg);if (ret == 0)nf_nat_masquerade_ipv4_register_notifier();return ret;
}static void __exit masquerade_tg_exit(void)
{xt_unregister_target(&masquerade_tg_reg);nf_nat_masquerade_ipv4_unregister_notifier();
}module_init(masquerade_tg_init);
module_exit(masquerade_tg_exit);

#####2.nf_nat_masquerade_ipv4.c源码分析

  这里是对上文中调用函数的具体实现。

/* (C) 1999-2001 Paul `Rusty' Russell* (C) 2002-2006 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/types.h>
#include <linux/module.h>
#include <linux/atomic.h>
#include <linux/inetdevice.h>
#include <linux/ip.h>
#include <linux/timer.h>
#include <linux/netfilter.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/checksum.h>
#include <net/route.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/ipv4/nf_nat_masquerade.h>/* masquerade_tg()中引用的函数的具体实现*/
unsigned int
nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,const struct nf_nat_range *range,const struct net_device *out)
{struct nf_conn *ct;struct nf_conn_nat *nat;enum ip_conntrack_info ctinfo;struct nf_nat_range newrange;const struct rtable *rt;__be32 newsrc, nh;WARN_ON(hooknum != NF_INET_POST_ROUTING);ct = nf_ct_get(skb, &ctinfo);/*仅针对新的通信连接进行该转换,已有的可以在by_source表中查到,详情见下一讲*/WARN_ON(!(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||ctinfo == IP_CT_RELATED_REPLY)));/* Source address is 0.0.0.0 - locally generated packet that is* probably not supposed to be masqueraded.*/if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)return NF_ACCEPT;rt = skb_rtable(skb);nh = rt_nexthop(rt, ip_hdr(skb)->daddr);/** 注意看这里,这里的inet_select_addr()功能是在当前可用的外部IP中随机选择一个* 由此,实现了对内部IP转化为外部IP的过程* 由于是随机转化,因此取名为masquerade*/newsrc = inet_select_addr(out, nh, RT_SCOPE_UNIVERSE);if (!newsrc) {pr_info("%s ate my IP address\n", out->name);return NF_DROP;}nat = nf_ct_nat_ext_add(ct);if (nat)nat->masq_index = out->ifindex;/* Transfer from original range. */memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));newrange.flags       = range->flags | NF_NAT_RANGE_MAP_IPS;newrange.min_addr.ip = newsrc;newrange.max_addr.ip = newsrc;newrange.min_proto   = range->min_proto;newrange.max_proto   = range->max_proto;/* Hand modified range to generic setup. */return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
}
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4);static int device_cmp(struct nf_conn *i, void *ifindex)
{const struct nf_conn_nat *nat = nfct_nat(i);if (!nat)return 0;if (nf_ct_l3num(i) != NFPROTO_IPV4)return 0;return nat->masq_index == (int)(long)ifindex;
}static int masq_device_event(struct notifier_block *this,unsigned long event,void *ptr)
{const struct net_device *dev = netdev_notifier_info_to_dev(ptr);struct net *net = dev_net(dev);if (event == NETDEV_DOWN) {/* Device was downed.  Search entire table for* conntracks which were associated with that device,* and forget them.*/WARN_ON(dev->ifindex == 0);nf_ct_iterate_cleanup_net(net, device_cmp,(void *)(long)dev->ifindex, 0, 0);}return NOTIFY_DONE;
}static int masq_inet_event(struct notifier_block *this,unsigned long event,void *ptr)
{struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev;struct netdev_notifier_info info;/* The masq_dev_notifier will catch the case of the device going* down.  So if the inetdev is dead and being destroyed we have* no work to do.  Otherwise this is an individual address removal* and we have to perform the flush.*/if (idev->dead)return NOTIFY_DONE;netdev_notifier_info_init(&info, idev->dev);return masq_device_event(this, event, &info);
}static struct notifier_block masq_dev_notifier = {.notifier_call  = masq_device_event,
};static struct notifier_block masq_inet_notifier = {.notifier_call    = masq_inet_event,
};static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0);void nf_nat_masquerade_ipv4_register_notifier(void)
{/* check if the notifier was already set */if (atomic_inc_return(&masquerade_notifier_refcount) > 1)return;/* Register for device down reports */register_netdevice_notifier(&masq_dev_notifier);/* Register IP address change reports */register_inetaddr_notifier(&masq_inet_notifier);
}
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_register_notifier);void nf_nat_masquerade_ipv4_unregister_notifier(void)
{/* check if the notifier still has clients */if (atomic_dec_return(&masquerade_notifier_refcount) > 0)return;unregister_netdevice_notifier(&masq_dev_notifier);unregister_inetaddr_notifier(&masq_inet_notifier);
}
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_unregister_notifier);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");

#####3.小结
  通过以上分析,我们可以了解了iptables命令行激活的内核中钩子函数是如何定义和实现的。但是依然有着许多的疑问,比如,钩子函数如何实现了NAT的类型转化?具体函数如何起作用的等等。这些问题是解决不同类型NAT实现的关键所在,将在下面几节中分析。

  本文结束。

Netfilter学习之NAT类型动态配置(三)MASQUERADE内核空间的实现相关推荐

  1. Windows驱动开发学习笔记(三)—— 内核空间内核模块

    Windows驱动开发学习笔记(三)-- 内核空间&内核模块 内核空间 实验 第一步:编译如下代码 第二步:将 .sys 文件拷贝到虚拟机中 第三步:部署 .sys 文件并运行 第四步:创建一 ...

  2. 华为防火墙:五种NAT类型以及配置NAT策略。

    NAT类型: 1. NAT NO-PAT .将源IP地址映射到公网IP地址上. .属于多对多的映射关系. .不会节约公网IP地址,但会保护内网IP地址. 2. NAPT . 将源IP地址和端口号映射到 ...

  3. 华为防火墙的NAT介绍及配置详解

    一.华为防火墙NAT的六个分类 华为防火墙的NAT分类: NAT No-PAT:类似于Cisco的动态转换,只转换源IP地址,不转换端口,属于多对多转换,不能节约公网IP地址,使用情况较少. NAPT ...

  4. kafka原理_Kafka动态配置实现原理解析

    总 第19篇 2019年 第15篇 一.问题导读Apache Kafka在全球各个领域各大公司获得广泛使用,得益于它强大的功能和不断完善的生态.其中Kafka动态配置是一个比较高频好用的功能,下面我们 ...

  5. 操作篇 了解学习NAT实验(关于静态NAT、动态NAT、EasyIP、端口映射的配置方法))

    文章目录 前言 NAT工作原理 NAT分类 一:实验环境 1.1:实验原理 1.2实验目的 1.3华为NAT实验拓扑图 二:实验过程 配置SW1 配置AR1: 配置AR2: 前言 随着Internet ...

  6. 动态NAT地址转换配置实验(中兴)

    动态NAT地址转换配置实验 一.实验目的 二.实验内容 三.实验流程 四.查看和验证 五.实验总结 一.实验目的 1.掌握中兴动态NAT技术的基本原理和作用,及其数据的转发过程: 2.掌握动态NAT技 ...

  7. [网络安全学习篇19]:NAT、动态路由及实验(千峰网络安全视频笔记 19 day)

    引言:我的系列博客[网络安全学习篇]上线了,小编也是初次创作博客,经验不足:对千峰网络信息安全开源的视频公开课程的学习整理的笔记整理的也比较粗糙,其实看到目录有300多集的时候,讲道理,有点怂了,所以 ...

  8. NAT的原理与类型,静态NAT、动态NAT

    目录 NAT产生背景 NAT概述 NAT工作原理 NAT类型 静态NAT配置 动态NAT 端口NAT(PAT) EasyIP-最简单的PAT NAT Server 外网访问内网WEB服务 外网访问内网 ...

  9. 【有图有真相】静态NAT、动态NAT、PAT、端口映射的详细配置过程

    实验要求:使用宿主机利用NAT地址转换技术访问虚拟机的Web80端口.全是***实弹的操作步骤. 实验前提:开启server 2008虚拟机并且搭建一个简单web服务.打开GNS3连接拓扑图的线路,一 ...

  10. 三张图解释静态NAT、动态NAT、PAT

    介绍 定义:NAT是网络地址转换,Network Address Translations. IPv4地址分类: IP地址分为公网IP和私网IP 公网IP只能在公网上使用 私网IP只能在内网中使用 公 ...

最新文章

  1. 关于BIO | NIO | AIO的讨论
  2. zoomImg相册大图预览插件
  3. cdn对加速效果明显吗
  4. .NET微服务架构及API网关
  5. Cobaltstrike4.0系列教程(一)----简介与安装
  6. 1092. To Buy or Not to Buy (20)
  7. java implements t_Java泛型——為什么“擴展T”允許而不是“實現T”?
  8. Vue + Spring Boot 项目实战(二):使用 CLI 搭建 Vue.js 项目
  9. 此电脑怎么放在桌面上_window10桌面美化,真的是美爆了,高效整理电脑桌面
  10. CentOS7下php安装mcrypt扩展
  11. 案例:ORA-04031 12.1.0.2 on exadata x7
  12. 玩转 Springboot 2 之热部署(DevTools)
  13. Vue安装及环境配置、开发工具
  14. python实现pdf阅读器_PyQt5 从零开始制作 PDF 阅读器(一)
  15. linux开机自动执行脚本、运行程序
  16. 无损音乐刻录成cd有意义吗_无损和CD不一样?无损音乐的“玄学”知多少?
  17. 阿里正式开源通用算法平台Alink,“双11”将天猫推荐点击率提升4%
  18. debian安装docker
  19. 计算机流水线生产管理知识,生产流水线管理应注意的六个方面
  20. 太子家居:引领家居风尚,不容错过的橱柜定制名牌

热门文章

  1. 如何快速给多张图片添加边框,这招你一定要会
  2. 计算机平面设计是计算机类吗,计算机平面设计是什么?平面设计就业前景怎么样?...
  3. 2、Docker部署的Onlyoffice中文字体修改
  4. Java爬虫(三)后台发请求获取页面解析数据
  5. 思科视频会议系统+服务器,Cisco思科MCU5310视频会议系统服务器
  6. 相见恨晚,真的很喜欢Udacity
  7. 快速幂计算x的n次幂,递归版本、迭代版本、python实现
  8. 电源 PFC(功率因数校正)电路拓扑,共计100多份,内含A PFC,连续断续,交错,维也纳,各功率段的PFC电路,还有电感 设计选型
  9. C#桌面办公应用-工资管理系统系列二
  10. 青出于蓝而胜于蓝 — Vue.js对Angular.js的那些进步