可以看到以白名單方式使能防火墻,fw_FORWARD fw_INPUT fw_OUTPUT 的操作是DROP或REJEDCT。即默認所有應用不允許上網,需要
XXX:/ # ndc firewall enable whitelist
200 0 Firewall command succeeded
XXX:/ # iptables -t filter -L
Chain INPUT (policy ACCEPT)
target prot opt source destinationChain FORWARD (policy ACCEPT)
target prot opt source destinationChain OUTPUT (policy ACCEPT)
target prot opt source destinationChain fw_FORWARD (0 references)
target prot opt source destination
REJECT all -- anywhere anywhere reject-with icmp-port-unreachableChain fw_INPUT (0 references)
target prot opt source destination
DROP all -- anywhere anywhereChain fw_OUTPUT (0 references)
target prot opt source destination
REJECT all -- anywhere anywhere reject-with icmp-port-unreachable
static const std::vector<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,FirewallController::LOCAL_INPUT,
};
const char BandwidthController::LOCAL_INPUT[] = "bw_INPUT";
const char BandwidthController::LOCAL_FORWARD[] = "bw_FORWARD";
const char BandwidthController::LOCAL_OUTPUT[] = "bw_OUTPUT";
const char BandwidthController::LOCAL_RAW_PREROUTING[] = "bw_raw_PREROUTING";
const char BandwidthController::LOCAL_MANGLE_POSTROUTING[] = "bw_mangle_POSTROUTING";
const char BandwidthController::LOCAL_GLOBAL_ALERT[] = "bw_global_alert";
const char* FirewallController::TABLE = "filter";const char* FirewallController::LOCAL_INPUT = "fw_INPUT";
const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
const char* FirewallController::LOCAL_STANDBY = "fw_standby";
const char* FirewallController::LOCAL_POWERSAVE = "fw_powersave";
void Controllers::initChildChains() {/** This is the only time we touch top-level chains in iptables; controllers* should only mutate rules inside of their children chains, as created by* the constants above.** Modules should never ACCEPT packets (except in well-justified cases);* they should instead defer to any remaining modules using RETURN, or* otherwise DROP/REJECT.*/// Create chains for child modules.//往filter表的INPUT鏈添加子鏈fw_INPUTcreateChildChains(V4V6, "filter", "INPUT", FILTER_INPUT, true);//往filter表的FORWARD鏈添加子鏈fw_FORWARDcreateChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD, true);createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING, true);createChildChains(V4V6, "mangle", "FORWARD", MANGLE_FORWARD, true);createChildChains(V4V6, "mangle", "INPUT", MANGLE_INPUT, true);createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING, true);createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING, true);//往filter表的OUTPUT鏈添加子鏈fw_OUTPUTcreateChildChains(V4, "filter", "OUTPUT", FILTER_OUTPUT, false);createChildChains(V6, "filter", "OUTPUT", FILTER_OUTPUT, false);createChildChains(V4, "mangle", "POSTROUTING", MANGLE_POSTROUTING, false);createChildChains(V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING, false);
}
/* static */
//以 createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT, true);為例
void Controllers::createChildChains(IptablesTarget target, const char* table,const char* parentChain,const std::vector<const char*>& childChains,bool exclusive) {std::string command = StringPrintf("*%s\n", table);//*后指跟的table表,這里是filter//*filter// We cannot just clear all the chains we create because vendor code modifies filter OUTPUT and// mangle POSTROUTING directly. So://// - If we're the exclusive owner of this chain, simply clear it entirely.// - If not, then list the chain's current contents to ensure that if we restart after a crash,// we leave the existing rules alone in the positions they currently occupy. This is faster// than blindly deleting our rules and recreating them, because deleting a rule that doesn't// exists causes iptables-restore to quit, which takes ~30ms per delete. It's also more// correct, because if we delete rules and re-add them, they'll be in the wrong position with// regards to the vendor rules.//// TODO: Make all chains exclusive once vendor code uses the oem_* rules.std::set<std::string> existingChildChains;if (exclusive) {// Just running ":chain -" flushes user-defined chains, but not built-in chains like INPUT.// Since at this point we don't know if parentChain is a built-in chain, do both.StringAppendF(&command, ":%s -\n", parentChain);// 鏈名默認策略表示相應的鏈及默認策略,具體的規則部分省略了命令名iptables//:INPUT -StringAppendF(&command, "-F %s\n", parentChain);//-F指代清空防火墻規則,默認規則除外//-F INPUT} else {existingChildChains = findExistingChildChains(target, table, parentChain);}for (const auto& childChain : childChains) {// Always clear the child chain.StringAppendF(&command, ":%s -\n", childChain);// But only add it to the parent chain if it's not already there.if (existingChildChains.find(childChain) == existingChildChains.end()) {//static const char* CHILD_CHAIN_TEMPLATE = "-A %s -j %s\n";StringAppendF(&command, CHILD_CHAIN_TEMPLATE, parentChain, childChain);}}command += "COMMIT\n";execIptablesRestore(target, command);
}
//以 createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT, true);為例,相當于執行了
iptable-restore <
*filter \n
:INPUT - \n
-F INPUT \n
:fw_INPUT - \n
-A INPUT -j fw_INPUT
//即在filter表的INPUT鏈處理時調用 fw_INPUT 鏈,所以fw_INPUT 時INPUT鏈的子鏈
int FirewallController::resetFirewall(void) {mFirewallType = WHITELIST;mIfaceRules.clear();// flush any existing rulesstd::string command ="*filter\n"":fw_INPUT -\n"":fw_OUTPUT -\n"":fw_FORWARD -\n""COMMIT\n";return (execIptablesRestore(V4V6, command.c_str()) == 0) ? 0 : -EREMOTEIO;
}int FirewallController::setFirewallType(FirewallType ftype) {int res = 0;if (mFirewallType != ftype) {// flush any existing rulesresetFirewall();if (ftype == WHITELIST) {// create default rule to drop all trafficstd::string command ="*filter\n""-A fw_INPUT -j DROP\n""-A fw_OUTPUT -j REJECT\n""-A fw_FORWARD -j REJECT\n""COMMIT\n";res = execIptablesRestore(V4V6, command.c_str());}// Set this after calling disableFirewall(), since it defaults to WHITELIST theremFirewallType = ftype;}return res ? -EREMOTEIO : 0;
}
所以調用ndc firewall enable whitelist相當于:
無論防火墻是黑白名單哪種類型,都先清空規則,此時所有應用可以上網
iptable-restore < "*filter\n"":fw_INPUT -\n"":fw_OUTPUT -\n"":fw_FORWARD -\n""COMMIT\n";//白名單類型再調用如下規則,再將所有鏈的數據都DROp或REJECT,相當與所有應用默認無法上網。
iptable-restore < "*filter\n""-A fw_INPUT -j DROP\n""-A fw_OUTPUT -j REJECT\n""-A fw_FORWARD -j REJECT\n""COMMIT\n";
即,黑名單默認上網,白名單默認不上網