可以看到以白名单方式使能防火墙,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 destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain fw_FORWARD (0 references)
target prot opt source destination
REJECT all -- anywhere anywhere reject-with icmp-port-unreachable
Chain fw_INPUT (0 references)
target prot opt source destination
DROP all -- anywhere anywhere
Chain 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_INPUT
createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT, true);
//往filter表的FORWARD链添加子链fw_FORWARD
createChildChains(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_OUTPUT
createChildChains(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 rules
std::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 rules
resetFirewall();
if (ftype == WHITELIST) {
// create default rule to drop all traffic
std::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 there
mFirewallType = 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";
即,黑名单默认上网,白名单默认不上网