转载请标明出处:http://blog.youkuaiyun.com/EdisonChang/article/details/52372701
这篇文章是对近期学习Iptables的一些小结,博文参考到一些网络上的资料,包括一些名称定义都是在各类文章中摘抄的,先推荐几篇文章。
iptables规则配置 增加、删除和修改命令
iptables详解
Linux防火墙iptables学习笔记(一)入门要领
Linux防火墙iptables学习笔记(二)参数指令
…..
Linux防火墙iptables学习笔记(五)linux+iptables构筑防火墙实例
Android基于Iptables的app网络访问控制讲解
相信感兴趣的朋友,通过ubuntuer 关于Linux 防火墙Iptables的这几篇文章的介绍,对Iptables也基本了解了。
Iptables是什么?
Iptables可以称为是linux中的防火墙,Iptables的前身叫Ipfirewall (内核1.x时代),到了内核2.x系列,软件更名为Ipchains,可以将规则组成一个列表,实现数据的访问控制功能。
他们都是工作在用户空间中,定义规则的工具,本身并不算是防火墙。它们定义的规则,可以让在内核空间当中的netfilter来读取,并且实现让防火墙工作。而放入内核的地方必须要是特定的位置,必须是tcp/ip的协议栈经过的地方。而这个tcp/ip协议栈必须经过的地方,可以实现读取规则的地方就叫做
netfilter.(网络过滤器)作者一共在内核空间中选择了5个位置,
1.内核空间中:从一个网络接口进来,到另一个网络接口去的
2.数据包从内核流入用户空间的
3.数据包从用户空间流出的
4.进入/离开本机的外网接口
5.进入/离开本机的内网接口
这五个位置也被称为五个钩子函数(hook functions),也叫五个规则链。
1.PREROUTING (路由前)
2.INPUT (数据包流入口)
3.FORWARD (转发管卡)
4.OUTPUT(数据包出口)
5.POSTROUTING(路由后)
这是NetFilter规定的五个规则链,任何一个数据包,只要经过本机,必将经过这五个链中的其中一个链。
Iptables定义规则的方式
格式:iptables [-t table] COMMAND chain CRETIRIA -j ACTION
-t table :3个filter nat mangle
COMMAND:定义如何对规则进行管理
chain:指定你接下来的规则到底是在哪个链上操作的,当定义策略的时候,是可以省略的
CRETIRIA:指定匹配标准
-j ACTION :指定如何进行处理
其他的命令参数列表在 Linux防火墙iptables学习笔记(二)参数指令 中有很详细的介绍,感兴趣的朋友可以到文中阅读。
Android 应用中如何使用?
在root过的Android设备上,通过shell,可以创建或者修改Iptables命令链,所以利用Iptables 可以针对不同的app、不同的域名配置不同的网络访问控制策略(允许访问/禁止访问)。
举个栗子,譬如需要限制应用A(包名:com.example.A)访问网络,Iptables规则是通过uid来区分应用,所以首先获取应用A的uid。关于uid我在换肤系列的博文中也提到过,Android系统在安装apk时会为应用分配一个uid,uid在此设备上将唯一且不再变化。但不同设备的uid是不一样的,应用也可以通过在AndroidManifest.xml中通过android:shareUserId字段来和其他应用共享uid,一旦共享了uid即实现应用间的资源共享。
try {
PackageManager pm = getPackageManager();
ApplicationInfo info = pm.getApplicationInfo("com.example.A", PackageManager.GET_ACTIVITIES);
Log.d("test", "uid" + info.uid);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
接下去就是创建规则并关联到应用A,
String argsOut[], argsIn[];
argsOut = new String[]{"-A", "OUTPUT", "-m", "owner", "--uid-owner", String.valueOf(uid), "-j", "DROP"};
argsIn = new String[]{"-A", "INPUT", "-m", "owner", "--uid-owner", String.valueOf(uid), "-j", "DROP"};
exec("iptables", argsOut, 5000);
exec("iptables", argsIn, 5000);
添加完规则后,可以通过 iptables -L 查看规则是否创建成功。
以下的代码是实现iptables 规则查询,如果发现应用自己被DROP就删除IpTables规则,实现网络诊断恢复。
private static String exec(String cmd, String args[], int timeOut) {
try {
String arg = "";
if (args != null) {
for (String s : args) {
arg += " ";
arg += s;
}
}
return CommandOutput(cmd + arg);
} catch (Throwable e) {
throw new AndroidRuntimeException("Root service has not run");
}
}
private static String CommandOutput(String cmd) throws Exception {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
InputStream is = p.getInputStream();
String result = null;
os.writeBytes(cmd + "\n");
int readed = 0;
byte[] buff = new byte[4096];
int count = 0;
while (is.available() <= 0 && count < 4) {
try {
count++;
Thread.sleep(2000);
} catch (Exception ex) {
}
}
while (is.available() > 0) {
readed = is.read(buff);
if (readed <= 0) break;
String seg = new String(buff, 0, readed);
result = seg;
}
os.writeBytes("exit\n");
os.flush();
return result;
}
public static void execIpTables() {
PriorityThreadFactory.newThread(TAG, new Runnable() {
@Override
public void run() {
String iptables;
try {
LogUtils.i(TAG, "iptables -L");
String args[];
args = new String[]{"-L"};
iptables = exec("iptables", args, 10000);
int rules = 0;
int uid = android.os.Process.myUid();
rules = getDropRules(uid, iptables);
for (int j = 0; j < rules; j++) {
String argsOut[], argsIn[];
argsOut = new String[]{"-D", "OUTPUT", "-m", "owner", "--uid-owner", String.valueOf(uid), "-j", "DROP"};
argsIn = new String[]{"-D", "INPUT", "-m", "owner", "--uid-owner", String.valueOf(uid), "-j", "DROP"};
exec("iptables", argsOut, 5000);
exec("iptables", argsIn, 5000);
}
String arg2s[];
arg2s = new String[]{"--line-numbers", "-L", "OUTPUT"};
iptables = exec("iptables", arg2s, 10000);
List<Integer> lineNum = getDropRuleLines(uid, iptables);
for (int j = 0; j < lineNum.size(); j++) {
String argsOut[];
argsOut = new String[]{"-D", "OUTPUT", String.valueOf(lineNum.get(j))};
exec("iptables", argsOut, 5000);
}
String arg3s[];
arg3s = new String[]{"--line-numbers", "-L", "INPUT"};
iptables = exec("iptables", arg3s, 10000);
List<Integer> lineNum2 = getDropRuleLines(uid, iptables);
for (int j = 0; j < lineNum2.size(); j++) {
String argsOut[];
argsOut = new String[]{"-D", "INPUT", String.valueOf(lineNum2.get(j))};
exec("iptables", argsOut, 5000);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}).start();
}
private static int getDropRules(int uid, String iptables) {
if (TextUtils.isEmpty(iptables)) {
return 0;
}
String[] ipTableArray = iptables.split("\n");
String uidFormat = String.format("u0_a" + uid % 1000);
int count = 0;
for (String ipTable : ipTableArray) {
if (ipTable.startsWith("DROP") && ipTable.contains(uidFormat)) {
++count;
}
}
LogUtils.i(TAG, "getDropRules uid = " + uid + " count = " + count);
return count;
}
private static List<Integer> getDropRuleLines(int uid, String iptables) {
List<Integer> lineNum = new ArrayList<>();
if (TextUtils.isEmpty(iptables)) {
return lineNum;
}
String[] ipTableArray = iptables.split("\n");
String uidFormat = String.format("u0_a" + uid % 1000);
for (int i = 0; i < ipTableArray.length; i++) {
if (ipTableArray[i].contains("DROP") && ipTableArray[i].contains(uidFormat)) {
String[] segment = ipTableArray[i].split(" ");
try {
lineNum.add(Integer.valueOf(segment[0]));
} catch (NumberFormatException e) {
lineNum.add(i);
}
}
}
LogUtils.i(TAG, "getDropRules uid = " + uid + " count = " + lineNum.size());
return lineNum;
}
Iptables是一个非常重要的工具,对其初步了解已经足够体会到它的强大,源码下载。文章就先写到这里,欢迎指正。