Linux netfilter 学习笔记 之十一 ip层netfilter的NAT模块初始化以及NAT原理

1.NAT的原理

NAT会修改数据包的ip层的源或者目的ip地址。在实际应用中,NAT 主要用于实现私有网络访问公共网络的功能。

1.1 SNAT

源目的地址转换,即对ip数据包的源ip地址进行转换操作,典型的应用即是网关,网关的lan侧会下挂至少两台设备,而这两台设备的ip地址都是lan侧地址,而lan侧设备又要访问公网,这就需要SNAT大展身手了,通过将lan侧发送的ip数据包的源ip地址转换成公网地址即可以访问公网了。

1.2 DNAT

目的地址转换主要是将ip数据包的目的ip地址进行修改。典型的应用就是lan侧的设备需要作为服务器使用,比如网关的lan侧有一个设备用作ftp服务器,而作为服务器就需要一个公网地址。而对于服务器来说,只有客户端先向服务器发送请求后,服务器才会应答,这样的话,客户端发送的请求会首先到达网关,而此时的目的地址为公网地址,这就需要网关将目的ip地址修改成lan侧ftp的lan侧ip地址后才能发送给lan侧ftp服务器,这就需要使用DNAT操作,即DNAT的工作场景

本节我们分析nat表的创建及其hook函数分析,同样的 需要实例化xt_table与ipt_replace这两个结构体。创建filter表时同样需要这样做。

2.NAT模块的初始化

对于NAT模块的初始化,可以分为如下几个方面:

a)NAT表的初始化

b)NAT模块的SNAT与DNAT的target的注册

c)NAT的hook回调函数的初始化

d)四层协议中NAT模块相关的协议变量初始化

下面我们就从这几个方面进行分析

2. 1nat表的注册

首先是nat表的初始化,nat表的初始化与filter表的初始化大致相同,都是

下面是nat表实例化的这两个结构体

[cpp] view plain copy

print?

  1. #define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT))
  2. static struct
  3. {
  4. struct ipt_replace repl;
  5. struct ipt_standard entries[3];
  6. struct ipt_error term;
  7. } nat_initial_table __initdata = {
  8. .repl = {
  9. .name = "nat",
  10. .valid_hooks = NAT_VALID_HOOKS,
  11. .num_entries = 4,
  12. .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
  13. .hook_entry = {
  14. [NF_IP_PRE_ROUTING] = 0,
  15. [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
  16. [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
  17. .underflow = {
  18. [NF_IP_PRE_ROUTING] = 0,
  19. [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
  20. [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
  21. },
  22. .entries = {
  23. /* PRE_ROUTING */
  24. {
  25. .entry = {
  26. .target_offset = sizeof(struct ipt_entry),
  27. .next_offset = sizeof(struct ipt_standard),
  28. },
  29. .target = {
  30. .target = {
  31. .u = {
  32. .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
  33. },
  34. },
  35. .verdict = -NF_ACCEPT - 1,
  36. },
  37. },
  38. /* POST_ROUTING */
  39. {
  40. .entry = {
  41. .target_offset = sizeof(struct ipt_entry),
  42. .next_offset = sizeof(struct ipt_standard),
  43. },
  44. .target = {
  45. .target = {
  46. .u = {
  47. .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
  48. },
  49. },
  50. .verdict = -NF_ACCEPT - 1,
  51. },
  52. },
  53. /* LOCAL_OUT */
  54. {
  55. .entry = {
  56. .target_offset = sizeof(struct ipt_entry),
  57. .next_offset = sizeof(struct ipt_standard),
  58. },
  59. .target = {
  60. .target = {
  61. .u = {
  62. .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
  63. },
  64. },
  65. .verdict = -NF_ACCEPT - 1,
  66. },
  67. },
  68. },
  69. /* ERROR */
  70. .term = {
  71. .entry = {
  72. .target_offset = sizeof(struct ipt_entry),
  73. .next_offset = sizeof(struct ipt_error),
  74. },
  75. .target = {
  76. .target = {
  77. .u = {
  78. .user = {
  79. .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
  80. .name = IPT_ERROR_TARGET,
  81. },
  82. },
  83. },
  84. .errorname = "ERROR",
  85. },
  86. }
  87. };
  88. static struct xt_table nat_table = {
  89. .name = "nat",
  90. .valid_hooks = NAT_VALID_HOOKS,
  91. .lock = RW_LOCK_UNLOCKED,
  92. .me = THIS_MODULE,
  93. .af = AF_INET,
  94. };

对于这两个结构体,我们已经非常熟悉了,即创建了一个名字为nat的xt_table表,且只在NF_IP_PRE_ROUTING、NF_IP_POST_ROUTING、NF_IP_LOCAL_OUT这3个hook点进行nat操作。且为该表创建了NF_IP_PRE_ROUTING、NF_IP_POST_ROUTING、NF_IP_LOCAL_OUT等3个链,且为每一条链创建了一条target为accept的默认规则。

然后通过调用ipt_register_table即实现了nat表的初始化。

2.2 NAT模块的target注册

对于NAT模块来说,最主要的就是实现地址转换,而iptables中是通过-j实现地址转换的,这就说明NAT模块的注册的target模块一定很重要,那我们现在就分析一下这两个模块

2.2.1 SNAT target的注册

SNAT target的定义如下:

其中target的名称为SNAT,target函数ipt_snat_target,通过这个函数我们能够实现对连接跟踪项的SNAT操作。

[cpp] view plain copy

print?

  1. static struct xt_target ipt_snat_reg = {
  2. .name = "SNAT",
  3. .target = ipt_snat_target,
  4. .targetsize = sizeof(struct nf_nat_multi_range_compat),
  5. .table = "nat",
  6. .hooks = 1 << NF_IP_POST_ROUTING,
  7. .checkentry = ipt_snat_checkentry,
  8. .family = AF_INET,
  9. };

通过模块名称,我们可以知道怎样通过iptables添加SNAT,如下:

iptables -t nat -A POSTROUTING -s 192.168.1.123 -j SNAT --to-source 25.29.1.23

而ipt_snat_target是实现SNAT的重要函数,我们看下这个函数的定义:

功能:实现SNAT功能

1.调用nf_ct_get,获取传入数据包关联的nf_conn变量

2.此处进行SNAT只是设置连接跟踪项中的reply方向的nf_conntrack_tuple变量,

因此,

对于主连接,仅设置连接跟踪项的状态为NEW的SNAT操作,因为对于状态不为NEW的连接跟踪项,其reply方向的nf_conntrack_tuple结构的变量的目的地址和 端口号已经修改过了,不需要再次修改了;

对于期望连接来说,当期望连接刚建立时,其状态仅为IP_CT_RELATED或者IP_CT_RELATED+IP_CT_IS_REPLY,所以

也只对这两种情况的期望连接,进行SNAT操作。

3.调用nf_nat_setup_info,根据targinfo中的地址范围与端口值修改连接跟踪项的reply方向的nf_conntrack_tuple变量中的值。

执行这个target只是修改了数据包对应的连接跟踪项的reply方向的tuple变量,并没有修改数据包的ip地址,

而修改数据包的ip地址是nat模块的hook函数中执行的(在执行了target操作后才会执行)。

(疑问:为什么是期望连接时,状态为IP_CT_RELATED或者IP_CT_RELATED+IP_CT_IS_REPLY都认为是起始状态呢?

状态为IP_CT_RELATED时,认为是新创建的连接跟踪项,我是能理解的,但是IP_CT_RELATED+IP_CT_IS_REPLY也

做为新创建的连接跟踪项的依据,我没有搞懂? 而且我感觉不会出现状态为IP_CT_RELATED+IP_CT_IS_REPLY的

连接跟踪项

)

[cpp] view plain copy

print?

  1. static unsigned int ipt_snat_target(struct sk_buff **pskb,
  2. const struct net_device *in,
  3. const struct net_device *out,
  4. unsigned int hooknum,
  5. const struct xt_target *target,
  6. const void *targinfo)
  7. {
  8. struct nf_conn *ct;
  9. enum ip_conntrack_info ctinfo;
  10. const struct nf_nat_multi_range_compat *mr = targinfo;
  11. NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING);
  12. ct = nf_ct_get(*pskb, &ctinfo);
  13. /* Connection must be valid and new. */
  14. NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
  15. ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
  16. NF_CT_ASSERT(out);
  17. return nf_nat_setup_info(ct, &mr->range[0], hooknum);
  18. }

这个函数主要是通过调用nf_nat_setup_info实现SNAT操作,而对于该函数的分析,我准备放到下一节里分析。

最后通过调用函数xt_register_target,将该target添加到xt[AF_INET].target链表中

2.2.2 DNAT target的注册

[cpp] view plain copy

print?

  1. static struct xt_target ipt_dnat_reg = {
  2. .name = "DNAT",
  3. .target = ipt_dnat_target,
  4. .targetsize = sizeof(struct nf_nat_multi_range_compat),
  5. .table = "nat",
  6. .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
  7. .checkentry = ipt_dnat_checkentry,
  8. .family = AF_INET,
  9. };

该target的名称为DNAT,要使用该target,则在iptables命令中需要增加-j DNAT,下面是一个DNAT的命令:

iptables -t nat -A PREROUTING -i wan0 -j DNAT --to-destination 192.168.1.183

该target的处理函数为ipt_dnat_target,该函数的定义如下,与SNAT的处理函数的定义类似,最终都是通过调用函数nf_nat_setup_info实现DNAT转换。

[cpp] view plain copy

print?

  1. static unsigned int ipt_dnat_target(struct sk_buff **pskb,
  2. const struct net_device *in,
  3. const struct net_device *out,
  4. unsigned int hooknum,
  5. const struct xt_target *target,
  6. const void *targinfo)
  7. {
  8. struct nf_conn *ct;
  9. enum ip_conntrack_info ctinfo;
  10. const struct nf_nat_multi_range_compat *mr = targinfo;
  11. NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
  12. hooknum == NF_IP_LOCAL_OUT);
  13. ct = nf_ct_get(*pskb, &ctinfo);
  14. /* Connection must be valid and new. */
  15. NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
  16. if (hooknum == NF_IP_LOCAL_OUT &&
  17. mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
  18. warn_if_extra_mangle((*pskb)->nh.iph->daddr,
  19. mr->range[0].min_ip);
  20. return nf_nat_setup_info(ct, &mr->range[0], hooknum);
  21. }

在初始化函数里通过调用函数xt_register_target,将该target添加到xt[AF_INET].target链表中

2.3 NAT模块的hook函数的注册

Nat表主要对NF_IP_PRE_ROUTING、NF_IP_POST_ROUTING、NF_IP_LOCAL_OUT、NF_IP_LOCAL_IN这4条hook点感兴趣, 那nat的hook函数同样也是注册在这4个hook点上的。下面分析下nat表的hook函数注册情况。

通过ip_nat_in_ops的定义,我发现其在NF_IP_LOCAL_IN这个hook点上也定义了nf_hook_ops,但是我们在nat表的valid_hooks中并没有发现NF_IP_LOCAL_IN呢。

我们知道nat表上是没有NF_IP_LOCAL_IN链的,即在NF_IP_LOCAL_IN点根本不存在任何规则,那即使在NF_IP_LOCAL_IN hook点注册了hook函数,也不会匹配任何规则,那除非其hook函数并不是遍历nat表,而是进行其他的操作。

/* We must be after connection tracking and before packet filtering. */

/*注册在NF_IP_PRE_ROUTING链上,实现DNAT转换的功能(或者对于SNAT时,对reply的数据包实现De-SNAT功能)*/

[cpp] view plain copy

print?

  1. static struct nf_hook_ops nf_nat_ops[] = {
  2. /*注册在NF_IP_PRE_ROUTING链上,实现DNAT转换的功能(或者对于SNAT时,对reply的
  3. 数据包实现De-SNAT功能)*/
  4. {
  5. .hook = nf_nat_in,
  6. .owner = THIS_MODULE,
  7. .pf = PF_INET,
  8. .hooknum = NF_IP_PRE_ROUTING,
  9. .priority = NF_IP_PRI_NAT_DST,
  10. },
  11. /* After packet filtering, change source */
  12. /*注册在NF_IP_POST_ROUTING实现SNAT转换的功能(或者对于开启DNAT时,在此处
  13. 会对数据包实现De-DNAT功能)*/
  14. {
  15. .hook = nf_nat_out,
  16. .owner = THIS_MODULE,
  17. .pf = PF_INET,
  18. .hooknum = NF_IP_POST_ROUTING,
  19. .priority = NF_IP_PRI_NAT_SRC,
  20. },
  21. /* After conntrack, adjust sequence number */
  22. {
  23. .hook = nf_nat_adjust,
  24. .owner = THIS_MODULE,
  25. .pf = PF_INET,
  26. .hooknum = NF_IP_POST_ROUTING,
  27. .priority = NF_IP_PRI_NAT_SEQ_ADJUST,
  28. },
  29. /* Before packet filtering, change destination */
  30. /*
  31. 注册在NF_IP_LOCAL_OUT链,实现DNAT转换功能
  32. */
  33. {
  34. .hook = nf_nat_local_fn,
  35. .owner = THIS_MODULE,
  36. .pf = PF_INET,
  37. .hooknum = NF_IP_LOCAL_OUT,
  38. .priority = NF_IP_PRI_NAT_DST,
  39. },
  40. /* After packet filtering, change source */
  41. /*
  42. 注册在NF_IP_LOCAL_IN链上,实现SNAT转换功能
  43. */
  44. {
  45. .hook = nf_nat_fn,
  46. .owner = THIS_MODULE,
  47. .pf = PF_INET,
  48. .hooknum = NF_IP_LOCAL_IN,
  49. .priority = NF_IP_PRI_NAT_SRC,
  50. },
  51. /* After conntrack, adjust sequence number */
  52. {
  53. .hook = nf_nat_adjust,
  54. .owner = THIS_MODULE,
  55. .pf = PF_INET,
  56. .hooknum = NF_IP_LOCAL_IN,
  57. .priority = NF_IP_PRI_NAT_SEQ_ADJUST,
  58. },
  59. };

接着通过调用nf_register_hooks,即完成nat模块的hook点的注册。

2.4 NAT模块四层协议相关的结构注册

在NAT模块里,四层协议相关的函数与变量,抽象出了结构体nf_nat_protocol,该结构体的定义如下,主要包括四层协议号、转换数据包四层协议相关的关键字的函数、根据输入tuple通过修改四层协议相关的关键字返回一个唯一的未被使用的tuple变量的函数等。

[cpp] view plain copy

print?

  1. struct nf_nat_protocol
  2. {
  3. /* Protocol name */
  4. const char *name;
  5. /* Protocol number. */
  6. /*四层协议号*/
  7. unsigned int protonum;
  8. /*是否为模块*/
  9. struct module *me;
  10. /* Translate a packet to the target according to manip type.
  11. Return true if succeeded. */
  12. /*对数据包进行四层协议相关的关键字的NAT转换*/
  13. int (*manip_pkt)(struct sk_buff **pskb,
  14. unsigned int iphdroff,
  15. const struct nf_conntrack_tuple *tuple,
  16. enum nf_nat_manip_type maniptype);
  17. /* Is the manipable part of the tuple between min and max incl? */
  18. /*
  19. 判断一个连接跟踪的四层协议相关的关键字的值是否在合理的范围内
  20. */
  21. int (*in_range)(const struct nf_conntrack_tuple *tuple,
  22. enum nf_nat_manip_type maniptype,
  23. const union nf_conntrack_man_proto *min,
  24. const union nf_conntrack_man_proto *max);
  25. /* Alter the per-proto part of the tuple (depending on
  26. maniptype), to give a unique tuple in the given range if
  27. possible; return false if not.  Per-protocol part of tuple
  28. is initialized to the incoming packet. */
  29. /*
  30. 根据传递的tuple变量与range值,通过随机获取四层协议相关的关键字
  31. 找到一个唯一的未被其他连接跟踪项使用的tuple变量。
  32. */
  33. int (*unique_tuple)(struct nf_conntrack_tuple *tuple,
  34. const struct nf_nat_range *range,
  35. enum nf_nat_manip_type maniptype,
  36. const struct nf_conn *ct);
  37. /*netlink相关*/
  38. int (*range_to_nfattr)(struct sk_buff *skb,
  39. const struct nf_nat_range *range);
  40. int (*nfattr_to_range)(struct nfattr *tb[],
  41. struct nf_nat_range *range);
  42. };

因为不同的协议,其 nf_nat_protocol变量可能不一样,因此对不同的协议需要定义一个nf_nat_protocol变量。NAT模块用nf_nat_protos[MAX_IP_NAT_PROTO]数组存储不同协议的nf_nat_protocol变量,可以通过函数nf_nat_protocol_register将一个新的nf_nat_protocol变量添加到nf_nat_protos[]数组中。Tcp、udp、icmp的nf_nat_protocol变量的定义以及注册函数如下:

[cpp] view plain copy

print?

  1. struct nf_nat_protocol nf_nat_protocol_tcp = {
  2. .name = "TCP",
  3. .protonum = IPPROTO_TCP,
  4. .me = THIS_MODULE,
  5. .manip_pkt = tcp_manip_pkt,
  6. .in_range = tcp_in_range,
  7. .unique_tuple = tcp_unique_tuple,
  8. #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
  9. .range_to_nfattr = nf_nat_port_range_to_nfattr,
  10. .nfattr_to_range = nf_nat_port_nfattr_to_range,
  11. #endif
  12. };
  13. rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
  14. rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
  15. rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);

以上就是四个方面的初始化,下面讲一下这个四个方面分别在哪些初始化函数里被调用。

A)nf_nat_init

该函数主要是进行nat相关的nf_nat_protocol变量的初始化,不同四层协议相关的nf_nat_protocol变量的实现可能不一样,nf_nat_protocol变量主要是实现四层协议相关的NAT转换等操作,即上述2.4是在这个函数里初始化的

B)nf_nat_standalone_init

该函数实现如下三个功能:

1.调用函数nf_conntrack_register_cache创建nat模块相关的nf_conn_help 的slab缓存

2.调用nf_nat_rule_init进行nat表与nat转换相关的target的初始化

3.调用nf_register_hooks进行NAT模块相关的hook函数的注册。

即2.3 是在该函数里初始化的,而2.1与2.2则是通过调用nf_nat_rule_init初始化的

C)nf_nat_rule_init

该函数主要实现如下几个功能:

1.注册nat表

2.调用xt_register_target注册SNAT的target,根据该target变量里的target函数,能够 实现SNAT

3.调用xt_register_target注册DNAT的target,根据该target变量里的target函数,能够 实现DNAT功能

即2.1 2.2是在这个函数里进行初始化的。

以上就是本节的主要内容,本节主要是介绍了NAT模块的初始化,下一节就开始分析NAT模块相关的hook函数,以及NAT转换的实现等功能。

时间: 2024-11-25 09:34:18

Linux netfilter 学习笔记 之十一 ip层netfilter的NAT模块初始化以及NAT原理的相关文章

Linux netfilter 学习笔记 之十二 ip层netfilter的NAT模块代码分析

本节主要是分析NAT模块相关的hook函数与target函数,主要是理清NAT模块实现的原理等. 1.NAT相关的hook函数分析 NAT模块主要是在NF_IP_PREROUTING.NF_IP_POSTROUTING.NF_IP_LOCAL_OUT.NF_IP_LOCAL_IN四个节点上进行NAT操作,在上一节中我们知道nat表中只有PREROUTING.POSTROUTING.LOCAL_OUT三条链,而没有NF_IP_LOCAL_IN链,所以不能创建在LOCAL_IN hook点的SNAT

Linux程序设计学习笔记----Socket网络编程基础之TCP/IP协议簇

转载请注明出处: ,谢谢! 内容提要 本节主要学习网络通信基础,主要涉及的内容是: TCP/IP协议簇基础:两个模型 IPv4协议基础:IP地址分类与表示,子网掩码等 IP地址转换:点分十进制\二进制 TCP/IP协议簇基础 OSI模型 我们知道计算机网络之中,有各种各样的设备,那么如何实现这些设备的通信呢? 显然是通过标准的通讯协议,但是,整个网络连接的过程相当复杂,包括硬件.软件数据封包与应用程序的互相链接等等,如果想要写一支将联网全部功能都串连在一块的程序,那么当某个小环节出现问题时,整只

Linux程序设计学习笔记----网络通信编程API及其示例应用

转载请注明出处, http://blog.csdn.net/suool/article/details/38702855. BSD Socket 网络通信编程 BSD TCP 通信编程流程 图为面向连接的Socket通信的双方执行函数流程.使用TCP协议的通信双方实现数据通信的基本流程如下 建立连接的步骤 1.首先服务器端需要以下工作: (1)调用socket()函数,建立Socket对象,指定通信协议. (2)调用bind()函数,将创建的Socket对象与当前主机的某一个IP地址和TCP端口

Linux程序设计学习笔记----网络编程之网络数据包拆封包与字节顺序大小端

网络数据包的封包与拆包 过程如下: 将数据从一台计算机通过一定的路径发送到另一台计算机.应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装(Encapsulation),如下图所示: 不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据包(packet),在链路层叫做帧(frame).数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理. 上图对应两台计算机在同一网段中的情况,

Linux 程序设计学习笔记----POSIX 文件及目录管理

转载请注明:http://blog.csdn.net/suool/article/details/38141047 问题引入 文件流和文件描述符的区别 上节讲到ANSI C 库函数的实现在用户态,流的相应资源也在用户空间,但无论如何实现最终都需要通过内核实现对文件的读写控制.因此fopen函数必然调用了对OS的系统调用.这一调用在LINUX下即为open, close, read, write等函数.这些都遵循POSIX标准. so,在linux系统中是如何通过POSIX标准实现对文件的操作和目

linux kernel学习笔记-5内存管理(转)

http://blog.sina.com.cn/s/blog_65373f1401019dtz.htmllinux kernel学习笔记-5 内存管理1. 相关的数据结构 相比用户空间而言,在内核中分配内存往往受到更多的限制,比如内核中很多情况下不能睡眠,此外处理内存分配失败也不像用户空间那么容易.内核使用了页和区两种数据结构来管理内存: 1.1 页 内核把物理页作为内存管理的基本单位.尽管CPU的最小可寻址单位通常为字(甚至字节),但是MMU(内存管理单元,管理内存并把虚拟地址转换为物理地址的

Linux 操作系统学习笔记

一,unix 1.unix 特点 伸缩性强,开放性好, 2.基本原则 所有对象,硬件都是文件 配置数据以文本形式保存 短小的单目的程序构成 多个程序合作完成复杂任务 3.gnu 基本原则是共享,建立自由开放的unix系统 1984年 richard stallman 发起 基本体系是micro kernel 4.gpl Copyleft 原作者所有权 5.linux起源 Linustorvalds, 自由的类unix操作系统, 遵循gnu和gpl 6.linux 可以实现unix功能 遵循开源许

linux基础学习笔记——操作大全

作者:liaoyi 更新时间:2014-6-2 ****************基本操作***************** 关机 shutdown -h now    root用户               init 0              root用户halt      root+一般用户poweroff 重启shutdown -r now    root用户init6     root用户reboot            root+一般用户 注意:1.shutdown 比较灵活,可

学习笔记之TCP/IP协议分层与OSI参考模型

1.协议的分层      ISO在制定标准化OSI之前,对网络体系结构相关的问题进行了充分的讨论, 最终提出了作为通信协议设计指标的OSI参考模型.这一模型将通信协议中必要 的功能分成了7层.通过这些分层,使得那些比较复杂的网络协议更加简单化. 在这一模型中,每个分层都接收由它下一层所提供的特定服务,并且负责为自己的上一层提供特定的服务.上下层之间进行交互时所遵循的约定叫做"接口".同一层之间的交互所遵循的约定叫做"协议". 协议分层就如同计算机软件中的模块化开发.