diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/firewall/IpTablesController.java b/app/src/main/java/io/github/muntashirakon/AppManager/firewall/IpTablesController.java new file mode 100644 index 0000000000000000000000000000000000000000..90aa5c534f1d6f57a1322ae256edc3e54448fe6b --- /dev/null +++ b/app/src/main/java/io/github/muntashirakon/AppManager/firewall/IpTablesController.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2020 Muntashir Al-Islam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.muntashirakon.AppManager.firewall; + +import java.util.Locale; + +import androidx.annotation.NonNull; +import io.github.muntashirakon.AppManager.runner.Runner; + +/** + * iptables -N am_wifi_reject_list iptables -N am_mobile_reject_list iptables -N am_bw + * <p> + * iptables -A INPUT -j am_bw iptables -A OUTPUT -j am_bw + * <p> + * iptables -A am_bw -o wlan+ -j am_wifi_reject_list iptables -A am_bw -o tiwlan+ -j am_wifi_reject_list + * <p> + * iptables -A am_bw -o rmnet+ -j am_mobile_reject_list + * iptables -A am_bw -o rmnet_data+ -j am_mobile_reject_list + * iptables -A am_bw -o pdp+ -j am_mobile_reject_list + * iptables -A am_bw -o ppp+ -j am_mobile_reject_list + * iptables -A am_bw -o uwbr+ -j am_mobile_reject_list + * iptables -A am_bw -o wimax+ -j am_mobile_reject_list + * iptables -A am_bw -o vsnet+ -j am_mobile_reject_list + * iptables -A am_bw -o ccmni+ -j am_mobile_reject_list + * iptables -A am_bw -o eth_x+ -j am_mobile_reject_list + * <p> + * iptables -A am_wifi_reject_list -m owner --uid-owner 10255 -j REJECT --reject-with icmp-port-unreachable + * <p> + * iptables -D am_wifi_reject_list -m owner --uid-owner 10255 -j REJECT --reject-with icmp-port-unreachable + * <p> + */ + +class IpTablesController { + private static final String RULE_REJECT = " -m owner --uid-owner %d -j REJECT --reject-with icmp-port-unreachable"; + + private static final String BW_CHAIN = "am_bw"; + private static final String MOBILE_DATA = "am_mobile_reject_list"; + private static final String WIFI_DATA = "am_wifi_reject_list"; + + private static final String[] INIT_CHAIN; + private static final String[] CHAIN_NAMES = {"-N " + MOBILE_DATA, "-N " + WIFI_DATA, "-N " + BW_CHAIN}; + + static { + INIT_CHAIN = new String[]{ + "INPUT -j " + BW_CHAIN, + "OUTPUT -j " + BW_CHAIN, + BW_CHAIN + " -o wlan+ -j " + WIFI_DATA, + BW_CHAIN + " -o tiwlan+ -j " + WIFI_DATA, + BW_CHAIN + " -o rmnet+ -j " + MOBILE_DATA, + BW_CHAIN + " -o rmnet_data+ -j " + MOBILE_DATA, + BW_CHAIN + " -o pdp+ -j " + MOBILE_DATA, + BW_CHAIN + " -o ppp+ -j " + MOBILE_DATA, + BW_CHAIN + " -o uwbr+ -j " + MOBILE_DATA, + BW_CHAIN + " -o wimax+ -j " + MOBILE_DATA, + BW_CHAIN + " -o vsnet+ -j " + MOBILE_DATA, + BW_CHAIN + " -o ccmni+ -j " + MOBILE_DATA, + BW_CHAIN + " -o eth_x+ -j " + MOBILE_DATA, + }; + } + + IpTablesController() { + Runner.Result result = runIptablesCmd("-C INPUT -j " + BW_CHAIN); + if (!result.isSuccessful()) { + // + for (String chainName : CHAIN_NAMES) { + runIptablesCmd(chainName); + } + + for (String s : INIT_CHAIN) { + //first delete + runIptablesCmd("-D " + s); + //second add + runIptablesCmd("-A " + s); + } + } + + try { + saveIptables(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + private boolean check(String rejectList, int uid) { + Runner.Result result = runIptablesCmd( + " -C " + String.format(Locale.ENGLISH, rejectList + RULE_REJECT, uid)); + System.out.println("check " + result.getOutput() + " " + result.getExitCode()); + return result.isSuccessful(); + } + + @NonNull + private Runner.Result runIptablesCmd(String cmd) { + return Runner.runCommand("iptables " + cmd); + } + + boolean isMobileDataEnable(int uid) { + return !check(MOBILE_DATA, uid); + } + + boolean isWifiDataEnable(int uid) { + return !check(WIFI_DATA, uid); + } + + void setMobileData(int uid, boolean enable) { + change(MOBILE_DATA, uid, enable); + } + + void setWifiData(int uid, boolean enable) { + change(WIFI_DATA, uid, enable); + } + + private void change(String list, int uid, boolean enable) { + if (enable) { + // Accept connections (delete rules) + runIptablesCmd("-D " + String.format(Locale.ROOT, list + RULE_REJECT, uid)); + } else { + // Reject connection (add rules) + if (!check(list, uid)) { + runIptablesCmd("-A " + String.format(Locale.ROOT, list + RULE_REJECT, uid)); + } + } + } + + private boolean saveIptables() { + System.out.println("saveIptables -->>> "); + Runner.Result result = Runner.runCommand("iptables-save"); + return result.isSuccessful(); + } + + private void restoreIptables(String rules) { + // TODO: 28/1/21 + } +}