Android 8.1移植:針對某個APK做到wifi和gprs分別做到允許和禁止兩種策略
阿新 • • 發佈:2018-12-30
在MTK平臺JB5開始後預設有該功能,昨天在檢視8.1的程式碼時發現沒有該功能,現在我把移植流程記錄下來,親測驗證ok。
1.frameworks
frameworks/base/core/java/android/os/INetworkManagementService.aidl
void setFirewallUidChainRule(int uid, int networkType, boolean allow); //zrx add
void clearFirewallChain(String chain); //zrx add
frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
//add by zrx
/**
* @hide
* @param uid
* @param networkType
* @param allow
*/
public void setFirewallUidChainRule(int uid, int networkType, boolean allow) {
//enforceSystemUid();
final String MOBILE = "mobile";
final String WIFI = "wifi";
final String rule = allow ? "allow" : "deny";
final String chain = (networkType == 1) ? WIFI : MOBILE;
try {
mConnector.execute("firewall", "set_uid_fw_rule", uid, chain, rule);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
/**
* @internal Configure firewall rule by uid and chain
* @hide
*/
public void clearFirewallChain(String chain) {
//enforceSystemUid();
try {
mConnector.execute("firewall", "clear_fw_chain", chain);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
//add by zrx
上面兩個函式是提供給上層呼叫的,setFirewallUidChainRule和clearFirewallChain為設定和清空相應的APP的限制
2.system/netd/server/路徑
CommandListener.cpp
int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,char **argv) {
//add by zrx 在cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);之前加上
if (!strcmp(argv[1], "set_uid_fw_rule")) {
if (argc != 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: firewall set_uid_fw_rule <uid> <mobile|wifi> <allow|deny>",
false);
return 0;
}
int uid = atoi(argv[2]);
FirewallChinaRule chain = parseChain(argv[3]);
FirewallRule rule = parseRule(argv[4]);
int res = gCtls->firewallCtrl.setUidFwRule(uid, chain, rule);
return sendGenericOkFail(cli, res);
}
if (!strcmp(argv[1], "clear_fw_chain")) {
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: firewall clear_fw_chain <chain>",
false);
return 0;
}
const char* chain = argv[2];
int res = gCtls->firewallCtrl.clearFwChain(chain);
return sendGenericOkFail(cli, res);
}
//add by zrx
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
return 0;
}
FirewallChinaRule CommandListener::FirewallCmd::parseChain(const char* arg) {
if (!strcmp(arg, "mobile")) {
return MOBILE;
} else {
return WIFI;
}
}
CommandListener.h宣告parseChain函式
int sendGenericOkFail(SocketClient *cli, int cond);
static FirewallRule parseRule(const char* arg);
static FirewallType parseFirewallType(const char* arg);
static ChildChain parseChildChain(const char* arg);
// zrx add: Support enhanced firewall @{
static FirewallChinaRule parseChain(const char* arg);
FirewallController.cpp對setUidFwRule和clearFwChain函式新增
// zrx add Support tencent firewall @{
const char* FirewallController::FIREWALL = "firewall";
const char* FirewallController::FIREWALL_MOBILE = "mobile";
const char* FirewallController::FIREWALL_WIFI = "wifi";
//@}
/****************************************************************************
* zrx add: support tencent firewall
* set FIREWALL_MOBILE and FIREWALL_WIFI rule to reject packets based on uid
*****************************************************************************/
int FirewallController::setUidFwRule(int uid, FirewallChinaRule chain, FirewallRule rule) {
char uidStr[16];
int res = 0;
const char* op;
const char* fwChain;
sprintf(uidStr, "%d", uid);
if (rule == ALLOW) {
op = "-I";
} else {
op = "-D";
}
if(chain == MOBILE) {
fwChain = "mobile";
}else{
fwChain = "wifi";
}
//在8.1上用execIptablesRestore函式,但因為我對C++語言不精通,我就把6.0上的execIptables函式移植過來了。
res |= execIptables(V4, op, fwChain, "-m", "owner", "--uid-owner", uidStr,
"-j", "REJECT", "--reject-with", "icmp-net-prohibited", NULL);
res |= execIptables(V6, op, fwChain, "-m", "owner", "--uid-owner", uidStr,
"-j", "REJECT", "--reject-with", "icmp6-adm-prohibited", NULL);
return res;
}
/************************************************************
* zrx add: support tencent firewall
* flush FIREWALL_MOBILE and FIREWALL_WIFI
************************************************************/
int FirewallController::clearFwChain(const char* chain) {
int res = 0;
if(chain != NULL){
if(strlen(chain) > 0){
res |= execIptables(V4V6, "-F", chain, NULL);
}else{
ALOGD("Clear all chain");
res |= execIptables(V4V6, "-F", NULL);
}
}else{
ALOGE("Chain is NULL");
}
return res;
}
int FirewallController::setupIptablesHooks(void) {
// zrx add: Support enhanced firewall @{
int res = 0;
res |= execIptables(V4V6, "-F", FIREWALL, NULL);
res |= execIptables(V4V6, "-A", FIREWALL, "-o", "ppp+", "-j", FIREWALL_MOBILE, NULL);
res |= execIptables(V4V6, "-A", FIREWALL, "-o", "ccmni+", "-j", FIREWALL_MOBILE, NULL);
res |= execIptables(V4V6, "-A", FIREWALL, "-o", "ccemni+", "-j", FIREWALL_MOBILE, NULL);
res |= execIptables(V4V6, "-A", FIREWALL, "-o", "usb+", "-j", FIREWALL_MOBILE, NULL);
res |= execIptables(V4V6, "-A", FIREWALL, "-o", "cc2mni+", "-j", FIREWALL_MOBILE, NULL);
res |= execIptables(V4V6, "-A", FIREWALL, "-o", "wlan+", "-j", FIREWALL_WIFI, NULL);
//@}
res |= createChain(LOCAL_DOZABLE, getFirewallType(DOZABLE));
res |= createChain(LOCAL_STANDBY, getFirewallType(STANDBY));
res |= createChain(LOCAL_POWERSAVE, getFirewallType(POWERSAVE));
return res;
}
FirewallController.h
enum FirewallChinaRule { MOBILE, WIFI };//zrx add
public:
FirewallController();
int setupIptablesHooks(void);
int enableFirewall(FirewallType);
int disableFirewall(void);
int isFirewallEnabled(void);
// zrx add, Support enhanced firewall @{
static const char* FIREWALL;
static const char* FIREWALL_MOBILE;
static const char* FIREWALL_WIFI;
int setUidFwRule(int, FirewallChinaRule, FirewallRule);
int clearFwChain(const char* chain);
//@}
//add by zrx
NetdConstants.cpp實現execIptables函式
//zrx add
const char * const IPTABLES_PATH = "/system/bin/iptables";
const char * const IP6TABLES_PATH = "/system/bin/ip6tables";
static void logExecError(const char* argv[], int res, int status) {
const char** argp = argv;
std::string args = "";
while (*argp) {
args += *argp;
args += ' ';
argp++;
}
ALOGE("exec() res=%d, status=%d for %s", res, status, args.c_str());
}
static int execIptablesCommand(int argc, const char *argv[], bool silent) {
int res;
int status;
ALOGI("execIptablesCommand android_fork_execvp enter");
res = android_fork_execvp(argc, (char **)argv, &status, false,
!silent);
ALOGI("execIptablesCommand android_fork_execvp exit");
if (res || !WIFEXITED(status) || WEXITSTATUS(status)) {
if (!silent) {
logExecError(argv, res, status);
}
if (res)
return res;
if (!WIFEXITED(status))
return ECHILD;
}
return WEXITSTATUS(status);
}
static int execIptables(IptablesTarget target, bool silent, va_list args) {
/* Read arguments from incoming va_list; we expect the list to be NULL terminated. */
std::list<const char*> argsList;
argsList.push_back(NULL);
const char* arg;
// Wait to avoid failure due to another process holding the lock
argsList.push_back("-w");
do {
arg = va_arg(args, const char *);
argsList.push_back(arg);
} while (arg);
int i = 0;
const char* argv[argsList.size()];
std::list<const char*>::iterator it;
for (it = argsList.begin(); it != argsList.end(); it++, i++) {
argv[i] = *it;
}
int res = 0;
if (target == V4 || target == V4V6) {
argv[0] = IPTABLES_PATH;
res |= execIptablesCommand(argsList.size(), argv, silent);
}
if (target == V6 || target == V4V6) {
argv[0] = IP6TABLES_PATH;
res |= execIptablesCommand(argsList.size(), argv, silent);
}
return res;
}
int execIptables(IptablesTarget target, ...) {
va_list args;
va_start(args, target);
int res = execIptables(target, false, args);
va_end(args);
return res;
}
int execIptablesSilently(IptablesTarget target, ...) {
va_list args;
va_start(args, target);
int res = execIptables(target, true, args);
va_end(args);
return res;
}
//zrx add
NetdConstants.h
int execIptables(IptablesTarget target, ...); //zrx add
int execIptablesSilently(IptablesTarget target, ...);//zrx add
Controllers.cpp
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,
// zrx add: Support enhanced firewall @{
FirewallController::FIREWALL,
///@}
FirewallController::LOCAL_INPUT,
};
static const std::vector<const char*> FILTER_OUTPUT = {
OEM_IPTABLES_FILTER_OUTPUT,
// zrx add: Support enhanced firewall @{
FirewallController::FIREWALL,
///@}
FirewallController::LOCAL_OUTPUT,
StrictController::LOCAL_OUTPUT,
BandwidthController::LOCAL_OUTPUT,
};
// zrx add: @{
static const std::vector<const char*> FILTER_FIREWALL = {
FirewallController::FIREWALL_MOBILE,
FirewallController::FIREWALL_WIFI,
NULL,
};///@}
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.
createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT, true);
// zrx add: @{
createChildChains(V4V6, "filter", "firewall", FILTER_FIREWALL,true);
///@}
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);
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);
}
4.上層app驗證
import android.os.INetworkManagementService;
import android.os.ServiceManager;
private INetworkManagementService mNetworkService;
mNetworkService = INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
//允許系統瀏覽器上網功能
try {
mNetworkService.setFirewallUidChainRule(10057,1, false);//uid通過eng版本cat /data/system/packages.xml獲得,1為允許wifi,2或者其他數字代表gprs,false為不禁止,true為允許禁止
mNetworkService.setFirewallUidChainRule(10057,2, false);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
//禁止系統瀏覽器上網功能
mNetworkService.setFirewallUidChainRule(10057,1, true);
mNetworkService.setFirewallUidChainRule(10057,2, true);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
最後還需要在AndroidManifest.xml中加上android:sharedUserId=”android.uid.system”這個屬性。