編輯:關於Android編程
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 與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 (kernel\include\uapi\linux)
NF_ACCEPT 繼續正常傳輸數據報,這個返回值告訴 Netfilter:到目前為止,該數據包還是被接受的並且該數據包應當被遞交到網絡協議棧的下一個階段。 NF_DROP 丟棄該數據報,不再傳輸。 NF_STOLEN 回調函數接管該數據報,該回調函數從此開始對數據包的處理,並且Netfilter應當放棄對該數據包做任何的處理。 NF_QUEUE 對該數據報進行排隊(通常用於將數據報給用戶空間的進程進行處理) NF_REPEAT 再次調用該回調函數,應當謹慎使用這個值,以免造成死循環。 NF_STOP 功能和NF_ACCEPT類似但強於NF_ACCEPT,一旦掛接鏈表中某個hook節點返回NF_STOP,該skb包就立即結束檢查而被其他模塊接受,不再需要進入後續hook點檢查。
注:感謝,圖片來自http://blog.chinaunix.net/uid-23069658-id-3160506.html Netfilter支持的協議棧: netfilter.h (kernel\include\uapi\linux)
enum { NFPROTO_IPV4 = 2, NFPROTO_ARP = 3, NFPROTO_BRIDGE = 7, NFPROTO_IPV6 = 10, NFPROTO_DECNET = 12, };以Ipv4為例,從協議棧正常流程,經過A,B,C,D,E每個點時,切入到Netfilter框架中,依次去調用每個HOOK點的回調(鉤子)函數,檢查完後返回,根據結果確定之後走向: ip_input.c (kernel\net\ipv4) ip_output.c (kernel\net\ipv4) ip_forward.c (kernel\net\ipv4)
(1):NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,ip_rcv_finish) (2):NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, skb, skb->dev, NULL,ip_local_deliver_finish); (3):NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev, rt->u.dst.dev,ip_forward_finish); (4):NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); (5):NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,ip_finish_output, cond); NF_HOOK(pf, hook, skb, in, out, okfn) pf:協議棧名稱,定義在socket.h (kernel\include\linux) hook:HOOK點的名字,對於IPv4就是上述五個值 skb:內核中網絡數據包的結構體 in:數據包進來的設備,以struct net_device結構表示 out:數據包出去的設備,以struct net_device結構表示 okfn:函數指針,該HOOK點的所有登記的函數調用完後調用該函數
3、用戶層iptables與內核交互方式、流程 Netfilter框架具有三個主要模塊,如下:
iptables維護這三張表,查看或設置使用參數-t:
iptables -t filter -L iptables -t nat -L iptables -t mangle -L
內核負責和用戶層iptables命令交互的是ip-tables模塊:
ip_tables.c (kernel\net\ipv4\netfilter) 56679 2016-03-08 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\n"); // 系統啟動打印該log return 0; } static void __exit ip_tables_fini(void) module_init(ip_tables_init); module_exit(ip_tables_fini);
ip_tables.c (kernel\net\ipv4\netfilter) static struct nf_sockopt_ops ipt_sockopts = { .set = do_ipt_set_ctl, .get = do_ipt_get_ctl, .owner = THIS_MODULE, };
ip_tables.c (kernel\net\ipv4\netfilter) static int do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) { switch (cmd) { case IPT_SO_SET_REPLACE: ret = do_replace(sock_net(sk), user, len); break; case IPT_SO_SET_ADD_COUNTERS: ret = do_add_counters(sock_net(sk), user, len, 0); break; default: ret = -EINVAL; } return ret; } static intdo_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) { switch (cmd) { case IPT_SO_GET_INFO: ret = get_info(sock_net(sk), user, len, 0); break; case IPT_SO_GET_ENTRIES: ret = get_entries(sock_net(sk), user, len); break; case IPT_SO_GET_REVISION_MATCH: case IPT_SO_GET_REVISION_TARGET: break; } default: ret = -EINVAL; } return ret; }
root@KoolRegister:/ # iptables -t filter -L Chain INPUT (policy ACCEPT) target prot opt source destination bw_INPUT all -- anywhere anywhere fw_INPUT all -- anywhere anywhere
CommandListener.cpp (system\netd) CommandListener::CommandListener(UidMarkMap *map) :FrameworkListener("netd", true) { // Create chains for children modules createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT); createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD); createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT); createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING); createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING); createChildChains(V4V6, "mangle", "OUTPUT", MANGLE_OUTPUT); createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING); createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING); }
CommandListener.cpp (system\netd) /** * List of module chains to be created, along with explicit ordering. ORDERING * IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE. */ static const char* FILTER_INPUT[] = { // Bandwidth should always be early in input chain, to make sure we // correctly count incoming traffic against data plan. BandwidthController::LOCAL_INPUT, // "bw_INPUT" FirewallController::LOCAL_INPUT, // "fw_INPUT" NULL, }; 【log截圖中綠色框部分】 void createChildChains(IptablesTarget target, const char* table, const char* parentChain, const char** childChains); -->int execIptablesSilently(IptablesTarget target, ...); ---->int execIptables(IptablesTarget target, bool silent, va_list args) { const char *argv[argsList.size()]; ... argv[0] = IPTABLES_PATH; // IPTABLES_PATH = "/system/bin/iptables" } ------>int execIptablesCommand(int argc, const char *argv[], bool silent); -------->int android_fork_execvp(int argc, char* argv[], int *status,boolignore_int_quit, bool logwrap) { pid = fork(); if (pid == 0) { child(argc, argv); } } ---------->static void child(int argc, char* argv[]) { // create null terminated argv_child array char* argv_child[argc + 1]; memcpy(argv_child, argv, argc * sizeof(char *)); argv_child[argc] = NULL; if (execvp(argv_child[0], argv_child)) { FATAL_CHILD("executing %s failed: %s\n", argv_child[0], strerror(errno)); } }還有一個地方,也用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; }
參考資料:
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)
arp_tables.c (kernel\net\ipv4\netfilter) BandwidthController.cpp (system\netd) BandwidthController.h (system\netd) CommandListener.cpp (system\netd) CommandListener.h (system\netd) core.c (kernel\net\netfilter) FirewallController.cpp (system\netd) FirewallController.h (system\netd) iptables.h (external\iptables\include) iptable_filter.c (kernel\net\ipv4\netfilter) iptable_nat.c (kernel\net\ipv4\netfilter) iptable_raw.c (kernel\net\ipv4\netfilter) ip_forward.c (kernel\net\ipv4) ip_input.c (kernel\net\ipv4) ip_output.c (kernel\net\ipv4) ip_tables.c (kernel\net\ipv4\netfilter) ip_tables.h (kernel\include\linux\netfilter_ipv4) ip_tables.h (kernel\include\uapi\linux\netfilter_ipv4) kmod.h (kernel\include\linux) logwrap.c (system\core\logwrapper) logwrap.h (system\core\logwrapper\include\logwrap) NetdCommand.cpp (system\netd) NetdCommand.h (system\netd) NetdConstants.cpp (system\netd) NetdConstants.h (system\netd) netfilter.h (kernel\include\linux) netfilter.h (kernel\include\uapi\linux) nfnetlink.c (kernel\net\netfilter) nf_sockopt.c (kernel\net\netfilter) socket.h (kernel\include\linux) x_tables.c (kernel\net\netfilter) x_tables.h (kernel\include\linux\netfilter) x_tables.h (kernel\include\uapi\linux\netfilter)
本文實例講述了Android基於service實現音樂的後台播放功能。分享給大家供大家參考,具體如下:Service是一個生命周期長且沒有用戶界面的程序,當程序在各個ac
最近項目上用到了卡片的翻轉效果,大致研究了下,也參考了網上的一些Demo,簡單實現如下:activity_main.xml<?xml version=1.0
在網上看到了一個IOS組件PendulumView,實現了鐘擺的動畫效果。由於原生的進度條確實是不好看,所以想可以自定義View實現這樣的效果,以後也可以用於加載頁面的進
目錄:? UIScrollView的常見屬性 ? UIScrollView的常用代理方法 ? UIScrollView的縮放 ? UIScr