zoukankan      html  css  js  c++  java
  • Android 网络安全:Netfilter与iptables

    受不了xxxx恶心人的行为,遂搬迁至博客园。
    始发:2016-05-22 11:09:05
    版本信息:
    Android 4.4.4

    1、netfilter 与 iptables 关系

    Netfilter:

    http://www.netfilter.org/:
    
    Netfilter is a framework provided by the Linux kernel that allows
    various networking-related operations to be implemented in the
    form of customized handlers. 
     
    Netfilter offers various functions and operations for packet
    filtering, network address translation, and port translation,
    which provide the functionality required for directing packets
    through a network, as well as for providing ability to prohibit
    packets from reaching sensitive locations within a computer network.
     
    netfilter 利用一些封包过滤的【规则】设定,来定义出什么数据包可以接收,什么数据包需要剔除。位于内核层。
    iptables 通过命令的方式对 netfilter 规则进行排序与修改。位于用户层。
     
    用户层的 iptables 命令和内核层的 netfilter 之间的关系和其通讯方式:

    图片来自:http://blog.chinaunix.net/uid-23069658-id-3160506.html

    netfilter 与 IP 协议栈无缝契合,因此它的效率非常的高。主要完成:

    • 拒绝让 Internet 的封包进入主机的某些端口
    • 拒绝让某些来源 IP 的封包进入
    • 拒绝让带有某些特殊标志(flag)的封包进入,最常拒绝的就是带有 SYN 的主动联机的 flag,只要一经发现就将该封包丢弃
    • 分析硬件地址(MAC)来决定联机与否

    2、netfilter 工作流程

    图片来自:http://blog.chinaunix.net/uid-23069658-id-3160506.html

    收到的每个数据包,都从“A”点进来,经过路由判决,如果是发送给本机的就经过“B”点,然后往协议栈的上层继续传递;否则,如果该数据包的目的地不是本机,那么就经过“C”点,然后顺着“E”点将该包转发出去。
    netfilter在A,B,C,D和E设置回调函数(hook函数),对每一个进出的数据包进行检测,检测完向 netfilter 报告一下该数据包的情况,返回结果含:
    netfilter.h (kernelincludeuapilinux)
    • NF_ACCEPT 继续正常传输数据报,这个返回值告诉 netfilter:到目前为止,该数据包还是被接受的并且该数据包应当被递交到网络协议栈的下一个阶段。
    • NF_DROP 丢弃该数据报,不再传输。
    • NF_STOLEN 回调函数接管该数据报,该回调函数从此开始对数据包的处理,并且netfilter应当放弃对该数据包做任何的处理。
    • NF_QUEUE 对该数据报进行排队(通常用于将数据报给用户空间的进程进行处理)。
    • NF_REPEAT 再次调用该回调函数,应当谨慎使用这个值,以免造成死循环。
    • NF_STOP 功能和 NF_ACCEPT 类似但强于 NF_ACCEPT,一旦挂接链表中某个hook节点返回 NF_STOP,该 skb 包就立即结束检查而被其他模块接受,不再需要进入后续hook点检查。

    和 A、B、C、D、E 五个点对应的在Netfilter中的术语为:

    图片来自:http://blog.chinaunix.net/uid-23069658-id-3160506.html

    netfilter支持的协议栈:
    netfilter.h (kernelincludeuapilinux)
    1 enum {
    2     NFPROTO_IPV4   =  2,
    3     NFPROTO_ARP    =  3,
    4     NFPROTO_BRIDGE =  7,
    5     NFPROTO_IPV6   = 10,
    6     NFPROTO_DECNET = 12,
    7 };
     
    以 IPv4 为例,从协议栈正常流程,经过 A、B、C、D、E 每个点时,切入到 netfilter 框架中,依次去调用每个 hook 点的回调(钩子)函数,检查完后返回,根据结果确定之后走向:
    ip_input.c (kernel etipv4)
    ip_output.c (kernel etipv4)
    ip_forward.c (kernel etipv4)
     11):NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,ip_rcv_finish)
     22):NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, skb, skb->dev, NULL,ip_local_deliver_finish);
     33):NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev, rt->u.dst.dev,ip_forward_finish);
     44):NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
     55):NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,ip_finish_output, cond);
     6  
     7  
     8 NF_HOOK(pf, hook, skb, in,  out, okfn)
     9 pf:协议栈名称,定义在socket.h (kernelincludelinux)
    10 hook:HOOK点的名字,对于IPv4就是上述五个值
    11 skb:内核中网络数据包的结构体
    12 in:数据包进来的设备,以struct net_device结构表示
    13 out:数据包出去的设备,以struct net_device结构表示
    14 okfn:函数指针,该HOOK点的所有登记的函数调用完后调用该函数
     

    3、用户层 iptables 与内核交互方式、流程

    netfilter 框架具有三个主要模块,如下:

    iptables维护这三张表,查看或设置使用参数-t:

    1 iptables -t filter -L
    2 iptables -t nat -L
    3 iptables -t mangle -L

    内核负责和用户层 iptables 命令交互的是 ip-tables 模块:

    ip_tables.c (kernel
    etipv4
    etfilter)
    static int __init ip_tables_init(void)
    {
        /* Register setsockopt */
        ret = nf_register_sockopt(&ipt_sockopts);
        if (ret < 0)
            goto err5;
        pr_info("(C) 2000-2006 Netfilter Core Team
    "); // 系统启动打印该log
        return 0;
    }
    static void __exit ip_tables_fini(void)
     
    module_init(ip_tables_init);
    module_exit(ip_tables_fini);

    用户层 iptables 通过 setsockopt/getsockopt 设置/查询这三张表,并最终调用 ip_tables_init() 注册的 do_ipt_set_ctl/do_ipt_get_ctl() 函数:

     1 ip_tables.c (kernel
    etipv4
    etfilter)
     2 static struct nf_sockopt_ops ipt_sockopts = {
     3     .set        = do_ipt_set_ctl,
     4     .get        = do_ipt_get_ctl,
     5     .owner    = THIS_MODULE,
     6 };
     7 
     8 
     9 ip_tables.c (kernel
    etipv4
    etfilter)
    10 static int do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
    11 {
    12     switch (cmd) {
    13     case IPT_SO_SET_REPLACE:
    14         ret = do_replace(sock_net(sk), user, len);
    15         break;
    16     case IPT_SO_SET_ADD_COUNTERS:
    17         ret = do_add_counters(sock_net(sk), user, len, 0);
    18         break;
    19     default:
    20         ret = -EINVAL;
    21     }
    22     return ret;
    23 }
    24 static intdo_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
    25 {
    26     switch (cmd) {
    27     case IPT_SO_GET_INFO:
    28         ret = get_info(sock_net(sk), user, len, 0);
    29         break;
    30     case IPT_SO_GET_ENTRIES:    
    31         ret = get_entries(sock_net(sk), user, len);
    32         break;
    33     case IPT_SO_GET_REVISION_MATCH:
    34     case IPT_SO_GET_REVISION_TARGET:
    35         break;
    36     }
    37     default:
    38         ret = -EINVAL;
    39     }
    40     return ret;
    41 }

    4、Netfilter默认rules的创建

    在没有使用iptables命令设置规则表(filter表、nat表、mangle表)的情况下,系统也自动生成默认的规则表,如下filter表(只列出INPUT链):
    1 root@rocky:/ # iptables -t filter -L                                    
    2 Chain INPUT (policy ACCEPT)
    3 target     prot opt source               destination         
    4 bw_INPUT   all  --  anywhere             anywhere            
    5 fw_INPUT   all  --  anywhere             anywhere

    这个默认规则在代码里通过 iptables 命令生成:

     1 CommandListener.cpp (system
    etd)
     2 CommandListener::CommandListener(UidMarkMap *map) :FrameworkListener("netd", true)
     3 {
     4     // Create chains for children modules
     5     createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT);
     6     createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD);
     7     createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);
     8     createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);
     9     createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);
    10     createChildChains(V4V6, "mangle", "OUTPUT", MANGLE_OUTPUT);
    11     createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);
    12     createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);
    13 }
    14 
    15 CommandListener.cpp (system
    etd)
    16     /**
    17      * List of module chains to be created, along with explicit ordering. ORDERING
    18      * IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE.
    19      */
    20     static const char* FILTER_INPUT[] = {
    21             // Bandwidth should always be early in input chain, to make sure we
    22             // correctly count incoming traffic against data plan.
    23             BandwidthController::LOCAL_INPUT, // "bw_INPUT"
    24             FirewallController::LOCAL_INPUT, // "fw_INPUT"
    25             NULL,
    26     };
    27  
    28     【log截图中绿色框部分】
    29     void createChildChains(IptablesTarget target, const char* table, const char* parentChain, const char** childChains);
    30     -->int execIptablesSilently(IptablesTarget target, ...);
    31     ---->int execIptables(IptablesTarget target, bool silent, va_list args) {
    32             const char *argv[argsList.size()];
    33             ...
    34             argv[0] = IPTABLES_PATH; // IPTABLES_PATH = "/system/bin/iptables"
    35         }
    36     ------>int execIptablesCommand(int argc, const char *argv[], bool silent);
    37     -------->int android_fork_execvp(int argc, char* argv[], int *status,boolignore_int_quit, bool logwrap) {
    38                  pid = fork();
    39                  if (pid == 0) {
    40                      child(argc, argv);
    41                  }
    42              }
    43     ---------->static void child(int argc, char* argv[]) {
    44                    // create null terminated argv_child array
    45                    char* argv_child[argc + 1];
    46                    memcpy(argv_child, argv, argc * sizeof(char *));
    47                    argv_child[argc] = NULL;
    48                    if (execvp(argv_child[0], argv_child)) {
    49                         FATAL_CHILD("executing %s failed: %s
    ", argv_child[0],
    50                         strerror(errno));
    51                    }
    52                }

    还有一个地方,也用 iptables 命令设置了规则表:

    int NatController::setupIptablesHooks() {
        res = setDefaults();
    【log截图中蓝色框部分】    
    struct CommandsAndArgs defaultCommands[] = {
            {{IPTABLES_PATH, "-F", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
            {{IPTABLES_PATH, "-X", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
            {{IPTABLES_PATH, "-N", LOCAL_TETHER_COUNTERS_CHAIN,}, 1},
        };
        for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE; cmdNum++) {
            if (runCmd(ARRAY_SIZE, defaultCommands[cmdNum].cmd) && defaultCommands[cmdNum].checkRes) {}
        }
    }
    
    【log截图中黄色框部分】
    int NatController::setDefaults() {
        struct CommandsAndArgs defaultCommands[] = {
            {{IPTABLES_PATH, "-F", LOCAL_FORWARD,}, 1},
            {{IPTABLES_PATH, "-A", LOCAL_FORWARD, "-j", "DROP"}, 1},
            {{IPTABLES_PATH, "-t", "nat", "-F", LOCAL_NAT_POSTROUTING}, 1},
            {{IP_PATH, "rule", "flush"}, 0},
            {{IP_PATH, "-6", "rule", "flush"}, 0},
            {{IP_PATH, "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
            {{IP_PATH, "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
            {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
            {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
            {{IP_PATH, "route", "flush", "cache"}, 0},
        };
        for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE; cmdNum++) {
            if (runCmd(ARRAY_SIZE, defaultCommands[cmdNum].cmd) && defaultCommands[cmdNum].checkRes) {}
        }
    }
    int NatController::runCmd(int argc, const char **argv) {
        res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
        ALOGV("runCmd(%s) res=%d", full_cmd.c_str(), res);
        return res;
    }

    Log:

    参考资料:

    1、鸟哥的Linux私房菜服务器架设篇(第三版)——第九章、防火墙与 NAT 服务器
    2、http://www.netfilter.org/
    3、iptables使用文档:https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html 
    4、系列:
       (一)洞悉linux下的Netfilter&iptables:什么是Netfilter?()
       (二)洞悉linux下的Netfilter&iptables:内核中的ip_tables小觑 (http://blog.chinaunix.net/uid-23069658-id-3162264.html)
       (三)洞悉linux下的Netfilter&iptables:内核中的rule,match和target (http://blog.chinaunix.net/uid-23069658-id-3163999.html)
       (四)洞悉linux下的Netfilter&iptables:包过滤子系统iptable_filter (http://blog.chinaunix.net/uid-23069658-id-3166140.html)
    
    Source Code:
    arp_tables.c (kernel
    etipv4
    etfilter)
    BandwidthController.cpp (system
    etd)
    BandwidthController.h (system
    etd)
    CommandListener.cpp (system
    etd)
    CommandListener.h (system
    etd)
    core.c (kernel
    et
    etfilter)
    FirewallController.cpp (system
    etd)
    FirewallController.h (system
    etd)
    iptables.h (externaliptablesinclude)
    iptable_filter.c (kernel
    etipv4
    etfilter)
    iptable_nat.c (kernel
    etipv4
    etfilter)
    iptable_raw.c (kernel
    etipv4
    etfilter)
    ip_forward.c (kernel
    etipv4)
    ip_input.c (kernel
    etipv4)
    ip_output.c (kernel
    etipv4)
    ip_tables.c (kernel
    etipv4
    etfilter)
    ip_tables.h (kernelincludelinux
    etfilter_ipv4)
    ip_tables.h (kernelincludeuapilinux
    etfilter_ipv4)
    kmod.h (kernelincludelinux)
    logwrap.c (systemcorelogwrapper)
    logwrap.h (systemcorelogwrapperincludelogwrap)
    NetdCommand.cpp (system
    etd)
    NetdCommand.h (system
    etd)
    NetdConstants.cpp (system
    etd)
    NetdConstants.h (system
    etd)
    netfilter.h (kernelincludelinux)
    netfilter.h (kernelincludeuapilinux)
    nfnetlink.c (kernel
    et
    etfilter)
    nf_sockopt.c (kernel
    et
    etfilter)
    socket.h (kernelincludelinux)
    x_tables.c (kernel
    et
    etfilter)
    x_tables.h (kernelincludelinux
    etfilter)
    x_tables.h (kernelincludeuapilinux
    etfilter)
  • 相关阅读:
    Legacy和UEFI,MBR和GPT的区别
    如何升级laravel5.4到laravel5.5并使用新特性?
    value toDF is not a member of org.apache.spark.rdd.RDD
    spark能传递外部命名参数给main函数吗?
    spark在idea中本地如何运行?(处理问题NoSuchFieldException: SHUTDOWN_HOOK_PRIORITY)
    工作随笔-20171012
    maven使用实战
    介绍maven构建的生命周期
    python中的pip
    python中的None
  • 原文地址:https://www.cnblogs.com/rockyching2009/p/13468019.html
Copyright © 2011-2022 走看看