测试内核版本:Linux Kernel 2.6.35----Linux Kernel 3.2.1

原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7572382

更多请查看专栏http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

知识基础:本防火墙的开发基于对Linux内核网络栈有个良好的概念,本人对网络栈的分析是基于早期版本(Linux 1.2.13),在明确了网络栈架构的前提下,上升一步分析高级版本内核中的Netfilter防火墙实现原理,然后进行模块或内核编程,开发一款基于包过滤的个人防火墙。

包过滤防火墙:包过滤防火墙是用一个软件查看所流经的数据包的包头(header),由此决定整个包的命运。它可能会决定丢弃(DROP)这个包,可能会接受(ACCEPT)这个包(让这个包通过),也可能执行其它更复杂的动作。工作于网络层,能对IP数据报进行首部检查。例如:IP源地址,目的地址,源端口和目的端口等。

本防火墙的包过滤功能如下:  

* 拒绝来自某主机或某网段的所有连接。
  * 允许来自某主机或某网段的所有连接。
  * 拒绝来自某主机或某网段的指定端口的连接。
  * 允许来自某主机或某网段的指定端口的连接。
  * 拒绝发去某主机或某网段的所有连接。
  * 允许发去某主机或某网段的所有连接。
  * 拒绝发去某主机或某网段的指定端口的连接。
  * 允许发去某主机或某网段的指定端口的连接。

Netfilter框架是Linux内核分析和过滤特定协议数据包处理框架,为其他模块动态参与网络层数据包处理提供了方便的途径。

该防火墙的总体结构如下:

本防火墙的简单功能就是检查数据包是否符合过滤的条件,如果不符合就舍弃(Drop),否则就接受(Accept),这里定义八个链表头结点

  1. struct ip_node  ip_allowed_in_node_head;/*允许的远程主机或网络IP地址头节点*/
  2. struct ip_node  ip_denied_in_node_head;/*拒绝的远程主机或网络IP地址头节点*/
  3. struct ip_node  ip_allowed_out_node_head;/*允许的本地主机或网络IP地址头节点*/
  4. struct ip_node  ip_denied_out_node_head;/*拒绝的本地主机或网络IP地址头节点*/
  5. struct port_node port_allowed_in_node_head;/*允许的远程主机或网络传输层端口号头节点*/
  6. struct port_node port_denied_in_node_head;/*拒绝的远程主机或网络传输层端口号头节点*/
  7. struct port_node port_allowed_out_node_head;/*允许的本地主机或网络传输层端口号头节点*/
  8. struct port_node port_denied_out_node_head;/*拒绝的本地主机或网络传输层端口号头节点*/

用于保存配置文件中的地址或端口信息。

定义两个钩子函数hook_func_in和hook_func_out,分别将其挂载到INET协议族的入口NF_INET_LOCAL_IN和出口NF_INET_LOCAL_OUT:

  1. static struct nf_hook_ops my_netfilter[] =
  2. {
  3. {
  4. .hook       =hook_func_in,
  5. .owner      =THIS_MODULE,
  6. .pf     =PF_INET,
  7. .hooknum    =NF_INET_LOCAL_IN,
  8. .priority   =100
  9. },
  10. {
  11. .hook       =hook_func_out,
  12. .owner      =THIS_MODULE,
  13. .pf     =PF_INET,
  14. .hooknum    =NF_INET_LOCAL_OUT,
  15. .priority   =100
  16. }
  17. };

说明一下自己定义的一些宏和引用的头文件:

  1. #ifndef MODULE
  2. #define MODULE
  3. #endif
  4. #ifndef __KERNEL__
  5. #define __KERNEL__
  6. #endif
  7. //#define NET_DOWN
  8. #define MY_FIREWALL_DEBUG
  9. #include <asm/system.h>
  10. #include <linux/module.h>
  11. #include <linux/types.h>
  12. #include <linux/kernel.h>
  13. #include <linux/string.h>
  14. #include <linux/net.h>
  15. #include <linux/socket.h>
  16. #include <linux/sockios.h>
  17. #include <linux/in.h>
  18. #include <linux/inet.h>
  19. #include <net/ip.h>
  20. #include <net/protocol.h>
  21. #include <linux/skbuff.h>
  22. #include <net/sock.h>
  23. #include <net/icmp.h>
  24. #include <net/raw.h>
  25. #include <net/checksum.h>
  26. #include <linux/netfilter_ipv4.h>
  27. #include <linux/tcp.h>
  28. #include <linux/udp.h>
  29. #include <linux/igmp.h>
  30. #include <linux/fs.h>
  31. #include <linux/mm.h>
  32. #include <asm/uaccess.h>
  33. #define YES 1
  34. #define NO 0
  35. #define IP_MAX_LEN 20
  36. #define PORT_MAX_LEN 20
  37. #define ALLOWED_IP_IN 0
  38. #define DENIED_IP_IN 1
  39. #define ALLOWED_IP_OUT 2
  40. #define DENIED_IP_OUT 3
  41. #define ALLOWED_PORT_IN 0
  42. #define DENIED_PORT_IN 1
  43. #define ALLOWED_PORT_OUT 2
  44. #define DENIED_PORT_OUT 3
  45. #define ALLOWED_IN_IP_CONF_FILE_DIR "/etc/my_firewall/ip_allowed_in"
  46. #define DENIED_IN_IP_CONF_FILE_DIR "/etc/my_firewall/ip_denied_in"
  47. #define ALLOWED_IN_PORT_CONF_FILE_DIR "/etc/my_firewall/port_allowed_in"
  48. #define DENIED_IN_PORT_CONF_FILE_DIR "/etc/my_firewall/port_denied_in"
  49. #define ALLOWED_OUT_IP_CONF_FILE_DIR "/etc/my_firewall/ip_allowed_out"
  50. #define DENIED_OUT_IP_CONF_FILE_DIR "/etc/my_firewall/ip_denied_out"
  51. #define ALLOWED_OUT_PORT_CONF_FILE_DIR "/etc/my_firewall/port_allowed_out"
  52. #define DENIED_OUT_PORT_CONF_FILE_DIR "/etc/my_firewall/port_denied_out"
  53. //DEFINE FOR WORK_MODE
  54. /*不工作状态,默认*/
  55. #define MODE_FREE 0
  56. /*允许来自某主机或某网段的所有连接*/
  57. #define MODE_IP_ONLY_ALLOWED_IN 1
  58. /*拒绝来自某主机或某网段的所有连接*/
  59. #define MODE_IP_ONLY_DENIED_IN 2
  60. /*允许来自某主机或某网段指定端口的连接*/
  61. #define MODE_IP_PORT_ALLOWED_IN 3
  62. /*拒绝来自某主机或某网段的指定端口的连接*/
  63. #define MODE_IP_PORT_DENIED_IN 4
  64. /*允许本地主机或本地网络与其他主机或网络的所有连接*/
  65. #define MODE_IP_ONLY_ALLOWED_OUT 5
  66. /*拒绝本地主机或本地网络与其他主机或网络的所有连接*/
  67. #define MODE_IP_ONLY_DENIED_OUT 6
  68. /*允许本地主机或网络与其他主机或其他网络的指定端口的连接*/
  69. #define MODE_IP_PORT_ALLOWED_OUT 7
  70. /*拒绝本地主机或网络与其他主机或其他网络的指定端口的连接*/
  71. #define MODE_IP_PORT_DENIED_OUT 8

下面是防火墙模块的初始化函数:

  1. int init_firewall()
  2. {
  3. (&ip_allowed_in_node_head)->next = NULL;
  4. (&ip_denied_in_node_head)->next = NULL;
  5. (&port_allowed_in_node_head)->next = NULL;
  6. (&port_denied_in_node_head)->next = NULL;
  7. (&ip_allowed_out_node_head)->next = NULL;
  8. (&ip_denied_out_node_head)->next = NULL;
  9. (&port_allowed_out_node_head)->next = NULL;
  10. (&port_denied_out_node_head)->next = NULL;
  11. switch(work_mode)
  12. {
  13. case MODE_IP_ONLY_ALLOWED_IN:
  14. open_ip_cfg_file(ALLOWED_IN_IP_CONF_FILE_DIR,ALLOWED_IP_IN);
  15. break;
  16. case MODE_IP_ONLY_DENIED_IN:
  17. open_ip_cfg_file(DENIED_IN_IP_CONF_FILE_DIR,DENIED_IP_IN);
  18. break;
  19. case MODE_IP_PORT_ALLOWED_IN:
  20. open_port_cfg_file(ALLOWED_IN_PORT_CONF_FILE_DIR,ALLOWED_PORT_IN);
  21. open_ip_cfg_file(ALLOWED_IN_IP_CONF_FILE_DIR,ALLOWED_IP_IN);
  22. break;
  23. case MODE_IP_PORT_DENIED_IN:
  24. open_port_cfg_file(DENIED_IN_PORT_CONF_FILE_DIR,DENIED_PORT_IN);
  25. open_ip_cfg_file(ALLOWED_IN_IP_CONF_FILE_DIR,ALLOWED_IP_IN);
  26. break;
  27. case MODE_IP_ONLY_ALLOWED_OUT:
  28. open_ip_cfg_file(ALLOWED_OUT_IP_CONF_FILE_DIR,ALLOWED_IP_OUT);
  29. break;
  30. case MODE_IP_ONLY_DENIED_OUT:
  31. open_ip_cfg_file(DENIED_OUT_IP_CONF_FILE_DIR,DENIED_IP_OUT);
  32. break;
  33. case MODE_IP_PORT_ALLOWED_OUT:
  34. open_port_cfg_file(ALLOWED_OUT_PORT_CONF_FILE_DIR,ALLOWED_PORT_OUT);
  35. open_ip_cfg_file(ALLOWED_OUT_IP_CONF_FILE_DIR,ALLOWED_IP_OUT);
  36. break;
  37. case MODE_IP_PORT_DENIED_OUT:
  38. open_port_cfg_file(DENIED_OUT_PORT_CONF_FILE_DIR,DENIED_PORT_OUT);
  39. open_ip_cfg_file(ALLOWED_OUT_IP_CONF_FILE_DIR,ALLOWED_IP_OUT);
  40. break;
  41. default:break;
  42. }
  43. //open_port_cfg_file(DENIED_PORT_CONF_FILE,DENIED_PORT);
  44. nf_register_hook(&my_netfilter[0]);
  45. nf_register_hook(&my_netfilter[1]);
  46. printk("INIT my firewall OK!\n");
  47. return 0;
  48. }

先从文件读取配置文件,加载到内核,然后注册钩子操作结构my_netfilter[0],my_netfilter[1]

下图是Netfilter的IPV4下的结构

上述的两个函数挂载位置NF_INET_LOCAL_IN和NF_INET_LOCAL_OUT,分别处理从本机发出和到达本机的数据包。

下面就是挂载到这两个挂载点的钩子函数,用于数据包的检查

  1. static unsigned int hook_func_in(unsigned int hook,
  2. struct sk_buff *skb,
  3. const struct net_device *in,
  4. const struct net_device *out,
  5. int (*okfn)(struct sk_buff *))
  6. {
  7. #ifdef NET_DOWN
  8. return NF_DROP;
  9. #else
  10. struct iphdr *iph = ip_hdr(skb);
  11. __be32 saddr = ntohl(iph->saddr);
  12. __be16 sport = 0,dport = 0;
  13. if(trans_port(iph,skb,&sport,&dport) == NO && \
  14. work_mode == MODE_IP_PORT_ALLOWED_IN || \
  15. work_mode == MODE_IP_PORT_DENIED_IN)
  16. return NF_ACCEPT;
  17. #ifdef MY_FIREWALL_DEBUG
  18. __be32 daddr = ntohl(iph->daddr);
  19. printk("saddr= %u : %u  daddr= %u : %d\n",saddr,sport,daddr,dport);
  20. #endif
  21. switch(work_mode)
  22. {
  23. case MODE_FREE:
  24. return NF_ACCEPT;
  25. case MODE_IP_ONLY_ALLOWED_IN:
  26. if(ip_in_cfg_file(saddr,&ip_allowed_in_node_head))
  27. return NF_ACCEPT;
  28. else return NF_DROP;
  29. break;
  30. case MODE_IP_ONLY_DENIED_IN:
  31. if(ip_in_cfg_file(saddr,&ip_denied_in_node_head))
  32. return NF_DROP;
  33. else return NF_ACCEPT;
  34. break;
  35. case MODE_IP_PORT_ALLOWED_IN:
  36. if(ip_in_cfg_file(saddr,&ip_allowed_in_node_head) && \
  37. port_in_cfg_file(sport,&port_allowed_in_node_head))
  38. return NF_ACCEPT;
  39. else return NF_DROP;
  40. break;
  41. case MODE_IP_PORT_DENIED_IN:
  42. if(ip_in_cfg_file(saddr,&ip_allowed_in_node_head) && \
  43. !port_in_cfg_file(sport,&port_denied_in_node_head))
  44. return NF_ACCEPT;
  45. else return NF_DROP;
  46. break;
  47. default:
  48. return NF_DROP;
  49. break;
  50. }
  51. #endif
  52. }
  53. static unsigned int hook_func_out(unsigned int hook,
  54. struct sk_buff *skb,
  55. const struct net_device *in,
  56. const struct net_device *out,
  57. int (*okfn)(struct sk_buff *))
  58. {
  59. #ifdef NET_DOWN
  60. return NF_DROP;
  61. #else
  62. struct iphdr *iph = ip_hdr(skb);
  63. __be32 daddr = ntohl(iph->daddr);
  64. __be16 sport = 0,dport = 0;
  65. if(trans_port(iph,skb,&sport,&dport) == NO && \
  66. work_mode == MODE_IP_PORT_ALLOWED_OUT && \
  67. work_mode == MODE_IP_PORT_DENIED_OUT)
  68. return NF_ACCEPT;
  69. #ifdef MY_FIREWALL_DEBUG
  70. __be32 saddr = ntohl(iph->saddr);
  71. printk("saddr= %u : %u  daddr= %u : %d\n",saddr,sport,daddr,dport);
  72. #endif
  73. switch(work_mode)
  74. {
  75. case MODE_FREE:
  76. return NF_ACCEPT;
  77. case MODE_IP_ONLY_ALLOWED_OUT:
  78. if(ip_in_cfg_file(daddr,&ip_allowed_out_node_head))
  79. return NF_ACCEPT;
  80. else return NF_DROP;
  81. break;
  82. case MODE_IP_ONLY_DENIED_OUT:
  83. if(ip_in_cfg_file(daddr,&ip_denied_out_node_head))
  84. return NF_DROP;
  85. else return NF_ACCEPT;
  86. break;
  87. case MODE_IP_PORT_ALLOWED_OUT:
  88. if(ip_in_cfg_file(daddr,&ip_allowed_out_node_head) && \
  89. port_in_cfg_file(dport,&port_allowed_out_node_head))
  90. return NF_ACCEPT;
  91. else return NF_DROP;
  92. break;
  93. case MODE_IP_PORT_DENIED_OUT:
  94. if(ip_in_cfg_file(daddr,&ip_allowed_out_node_head) && \
  95. !port_in_cfg_file(dport,&port_denied_out_node_head))
  96. return NF_ACCEPT;
  97. else return NF_DROP;
  98. break;
  99. default:
  100. return NF_DROP;
  101. break;
  102. }
  103. #endif
  104. }

下面是打开文件并读取信息的函数,这里以打开IP地址的配置文件为例

  1. static int open_ip_cfg_file(char * file_dir,int flag)
  2. {
  3. struct file * filp = NULL;
  4. char str[IP_MAX_LEN];
  5. int i = 0;
  6. if((filp = filp_open(file_dir,O_RDONLY,0)) < 0)
  7. return NO;
  8. mm_segment_t fs;
  9. fs = get_fs();
  10. set_fs(KERNEL_DS);
  11. struct ip_node * work = NULL;
  12. while((filp->f_op->read(filp,&str[i],1,&filp->f_pos)) == 1)
  13. {
  14. if(str[i] == '\n')//next line
  15. {
  16. str[i] = '\0';//the end of a string
  17. i = 0;
  18. #ifdef MY_FIREWALL_DEBUG
  19. printk("%s\n",str);
  20. #endif
  21. work = (struct ip_node *)kmalloc(sizeof(ip_allowed_in_node_head),GFP_ATOMIC);
  22. if( ip_to_unsigned(str,&(work->ip_start),&(work->ip_end)) == 0 )
  23. return NO;
  24. switch(flag)
  25. {
  26. case ALLOWED_IP_IN:
  27. work->next = (&ip_allowed_in_node_head)->next;
  28. (&ip_allowed_in_node_head)->next = work;//head insert
  29. break;
  30. case DENIED_IP_IN:
  31. work->next = (&ip_denied_in_node_head)->next;
  32. (&ip_denied_in_node_head)->next = work;//head insert
  33. break;
  34. case ALLOWED_IP_OUT:
  35. work->next = (&ip_allowed_out_node_head)->next;
  36. (&ip_allowed_out_node_head)->next = work;//head insert
  37. break;
  38. case DENIED_IP_OUT:
  39. work->next = (&ip_denied_out_node_head)->next;
  40. (&ip_denied_out_node_head)->next = work;//head insert
  41. break;
  42. default:break;
  43. }
  44. filp->f_op->read(filp,&str[0],1,&filp->f_pos);//eat the '\r'
  45. }
  46. if(i > IP_MAX_LEN) return NO;
  47. i++;
  48. }
  49. return YES;
  50. }

这里配置文件中不仅支持具体的IP地址,还支持IP地址网段,例如

192.168.1.1

192.168.1.*

192.168.*.*

192.*.*.*

下面是处理函数

  1. /************************************************
  2. str:The IP Address like 192.168.1.1
  3. start:The pointer to the start IP
  4. end:The pointer to the end IP
  5. ***********************************************/
  6. static int ip_to_unsigned(const char * str,unsigned int * start,unsigned int * end)
  7. {
  8. char cache[4][4];
  9. /*split the IP address*/
  10. int i;
  11. int k = 0;
  12. int j = 0;
  13. for(i = 0;str[i] != '\0';i++)
  14. {
  15. cache[j][k] = str[i];
  16. if(str[i] == '.')
  17. {
  18. cache[j][k] = '\0';
  19. k = 0;
  20. j++;
  21. }
  22. else k++;
  23. if(j > 3) return NO;
  24. }
  25. cache[3][k] = '\0';
  26. short int a[4];
  27. for(i = 0;i < 4;i++)
  28. {
  29. if(cache[i][0] != '*')
  30. {
  31. a[i] = (short)simple_strtol(cache[i],NULL,0);
  32. if(a[i] < 0 || a[i] > 255) return NO;
  33. }
  34. else
  35. {
  36. break;
  37. }
  38. }
  39. switch(i)
  40. {
  41. case 4:/*Specific IP Address eg.  192.168.1.1   */
  42. *start = *end = (a[0]<<24) + (a[1]<<16) + (a[2]<<8 )+a[3];
  43. break;
  44. case 3:/*  eg. 192.168.1.*   */
  45. *start = (a[0]<<24) + (a[1]<<16) + (a[2]<<8);
  46. *end = *start + (1<<8) - 1;
  47. break;
  48. case 2:/*  eg. 192.168.*.*   */
  49. *start = (a[0]<<24) + (a[1]<<16);
  50. *end = *start + (1<<16) - 1;
  51. break;
  52. case 1:/*  eg. 192.*.*.*    */
  53. *start = (a[0]<<24);
  54. *end = *start + (1<<24) - 1;
  55. break;
  56. default:
  57. *start = 0;
  58. *end = (1<<32) - 1;
  59. break;
  60. }
  61. return  YES;
  62. }

模块的移除函数

  1. void remove_firewall()
  2. {
  3. free_ip_list(&ip_allowed_in_node_head);
  4. free_ip_list(&ip_denied_in_node_head);
  5. free_ip_list(&ip_allowed_out_node_head);
  6. free_ip_list(&ip_denied_out_node_head);
  7. free_port_list(&port_allowed_in_node_head);
  8. free_port_list(&port_denied_in_node_head);
  9. free_port_list(&port_allowed_out_node_head);
  10. free_port_list(&port_denied_out_node_head);
  11. nf_unregister_hook(&my_netfilter[0]);
  12. nf_unregister_hook(&my_netfilter[1]);
  13. printk("CLEAN up my firewall OK!\n");
  14. }
  1. MODULE_LICENSE("Dual BSD/GPL");
  2. MODULE_AUTHOR("yming0221@gmail.com");

该防火墙支持命令参数设置,根据参数设置防火墙的工作模式,只需定义和声明

  1. static int work_mode = 0;//default mode
  2. module_param(work_mode,int,S_IRUGO);

目前测试,防火墙正常工作。

可以看到数据包能到达网络层,但由于防火墙启用的相应检查规则,浏览器等应用层软件无法联网,数据包被丢弃。

Linux内核--基于Netfilter的内核级包过滤防火墙实现的更多相关文章

  1. 戴文的Linux内核专题:07内核配置(3)

    转自Linux中国 OK,我们还继续配置内核.还有更多功能等待着去配置. 下一个问题(Enable ELF core dumps (ELF_CORE))询问的是内核是否可以生成内核转储文件.这会使内核 ...

  2. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

  3. Linux与其它类Unix内核的比较

    单块结构的内核:由几个逻辑上独立的成分构成,单块结构,大多数据商用Unix变体也是单块结构: 编译并静态连接的传统Unix内核:Linux能自动按需动态地装载和卸载部分内核代码(模块),而传统Unix ...

  4. linux下TCP/IP及内核参数优化调优(转)

    Linux下TCP/IP及内核参数优化有多种方式,参数配置得当可以大大提高系统的性能,也可以根据特定场景进行专门的优化,如TIME_WAIT过高,DDOS攻击等等. 如下配置是写在sysctl.con ...

  5. Linux内核@系统组成与内核配置编译

    Linux系统由什么组成? 由用户空间(应用程序+GNU C标准库)和内核空间(系统调用接口+内核+内核架构代码)组成. Linux内核到底是什么?以及组成. ARM的七种操作级别? 内核网络协议栈( ...

  6. linux进程用户内存空间和内核空间

    When a process running in user mode requests additional memory, pages are allocated from the list of ...

  7. 如何在Linux上通过grub添加内核参数

    转自Linux中国 我们可以在linux内核启动时为其提供各种各样的参数.这些参数可以自定义内核默认的行为,或者通知内核关于硬件的配置信息.内核参数应在内核启动时通过引导装载程序,如GRUB或LILO ...

  8. 戴文的Linux内核专题:08内核配置(5)

    转自Linux中国 Linux内核拥有许多可以配置的特性,接下来我们还有许多要配置. 下一个可以配置的特性是x86的随机数生成器(x86 architectural random number gen ...

  9. 戴文的Linux内核专题:08内核配置(4)

    转自Linux中国 这个第四部分里,我们将继续配置更多的设置和特性. 这里我们被问及关于"IBM Calgary IOMMU support (CALGARY_IOMMU)".这个 ...

随机推荐

  1. HWM的实验

    HWM是数据段中使用空间和未使用空间之间的界限,假如现有自由链表上的数据块不能满足需求,Oracle把HWM指向的数据块加入到自由链表上,HWM向前移动到下一个数据块.简单说,一个数据段中,HWM左边 ...

  2. PAT 1076. Forwards on Weibo (30)

    Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and may ...

  3. MFC之树控件

    树控件对应的类: CTreeControl 树控件属性设置: 启用复选框:Check Boxes = True 父节点显示+-按钮:Has Button = True ; Lines At Roots ...

  4. Android 关于操作UI线程

    在非UI线程里访问 Android UI toolkit—这个在一个worker线程修改了 View .这会导致不可预期的结果,而且还难以调试. 为了修复这个问题,Android提供了几个方法从非UI ...

  5. JS学习之路,之弹性运动框架

    弹性运动:顾名思义,就如同物理中的加速减速运动,当开始时速度过大,到达终点时,速度不会立刻停下,而是再前进一段距离,而后再向相反方向运动,如此往复. var timer=null; var speed ...

  6. springboot(十九):使用Spring Boot Actuator监控应用

    微服务的特点决定了功能模块的部署是分布式的,大部分功能模块都是运行在不同的机器上,彼此通过服务调用进行交互,前后台的业务流会经过很多个微服务的处理和传递,出现了异常如何快速定位是哪个环节出现了问题? ...

  7. 基于jq的表单填充

    //表单填充 formDataLoad: function (domId, obj) { for (var property in obj) { if (obj.hasOwnProperty(prop ...

  8. css选择器补充

    前面文章总结了常用的8种选择器,今天再来补充5中选择器,其中一部分是css3中新加入的. 1.相邻选择器 E+F { sRules } 相邻选择符只会命中符合条件的相邻的兄弟元素. 2.兄弟选择器 E ...

  9. H3C系列之三层交换机开启telnet管理的配置

    环境介绍>>>>>>>>>>>>>>>>>>>>交换机名牌:H3C交换机类型:三 ...

  10. windows下快速启动或关闭系统服务方法

    在windows下有些后台服务会开机自动启动. 用命令行方式启动关闭应用服务 使用sc.exe命令功能列表 修改服务启动类型的命令行格式为(特别注意start=后面有一个空格) sc config 服 ...