Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/org/adblockplus/android/configurators/IptablesProxyConfigurator.java

Issue 4705284891082752: Proxy configurators (Closed)
Patch Set: Last batch of review issues Created Aug. 24, 2014, 11:52 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2014 Eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package org.adblockplus.android.configurators;
19
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import java.net.InetAddress;
23 import java.util.List;
24
25 import org.adblockplus.android.Utils;
26
27 import com.stericson.RootTools.RootTools;
28
29 import android.content.Context;
30 import android.util.Log;
31
32 /**
33 * Proxy registration using RootTools and iptables.
34 */
35 public class IptablesProxyConfigurator implements ProxyConfigurator
36 {
37 private static final String TAG = Utils.getTag(IptablesProxyConfigurator.class );
38 private static final int DEFAULT_TIMEOUT = 3000;
39 private static final String IPTABLES_RETURN = " -t nat -m owner --uid-owner {{ UID}} -A OUTPUT -p tcp -j RETURN\n";
40 private static final String IPTABLES_ADD_HTTP = " -t nat -A OUTPUT -p tcp --dp ort 80 -j REDIRECT --to {{PORT}}\n";
41
42 private final Context context;
43 private String iptables;
44 private boolean isRegistered = false;
45
46 public IptablesProxyConfigurator(final Context context)
47 {
48 this.context = context;
49 }
50
51 @Override
52 public boolean initialize()
53 {
54 try
55 {
56 if (!RootTools.isAccessGiven())
57 {
58 throw new IllegalStateException("No root access");
59 }
60
61 final File ipt = this.context.getFileStreamPath("iptables");
62
63 if (!ipt.exists())
64 {
65 throw new FileNotFoundException("No iptables executable");
66 }
67
68 final String path = ipt.getAbsolutePath();
69
70 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT);
71
72 boolean compatible = false;
73 boolean version = false;
74
75 final String command = path + " --version\n" + path + " -L -t nat -n\n";
76
77 final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT);
78
79 for (final String line : result)
80 {
81 if (line.contains("OUTPUT"))
82 {
83 compatible = true;
84 }
85 if (line.contains("v1.4."))
86 {
87 version = true;
88 }
89 }
90
91 if (!(compatible && version))
92 {
93 throw new IllegalStateException("Incompatible iptables excutable");
94 }
95
96 this.iptables = path;
97
98 return true;
99 }
100 catch (final Exception e)
101 {
102 return false;
103 }
104 }
105
106 @Override
107 public boolean registerProxy(final InetAddress address, final int port)
108 {
109 try
110 {
111 final int uid = this.context.getPackageManager().getPackageInfo(this.conte xt.getPackageName(), 0).applicationInfo.uid;
112
113 final StringBuilder cmd = new StringBuilder();
114 cmd.append(this.iptables);
115 cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid)));
116 cmd.append('\n');
117 cmd.append(this.iptables);
118 cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port)));
119
120 RootTools.sendShell(cmd.toString(), DEFAULT_TIMEOUT);
121
122 this.isRegistered = true;
123
124 return true;
125 }
126 catch (final Exception e)
127 {
128 // I leave this logging message for now, passing 'init' and failing 'regis ter' definitely is a failure
129 Log.e(TAG, "Couldn't register proxy using iptables.", e);
130 return false;
131 }
132 }
133
134 @Override
135 public void unregisterProxy()
136 {
137 try
138 {
139 RootTools.sendShell(this.iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT);
140 }
141 catch (final Exception e)
142 {
143 Log.w(TAG, "Failed to unregister proxy using iptables.", e);
144 }
145 finally
146 {
147 this.isRegistered = false;
148 }
149 }
150
151 @Override
152 public void shutdown()
153 {
154 // Nothing to do here
155 }
156
157 public static List<String> getIptablesOutput(final Context context)
158 {
159 try
160 {
161 if (!RootTools.isAccessGiven())
162 {
163 throw new IllegalStateException("No root access");
164 }
165
166 final File ipt = context.getFileStreamPath("iptables");
167
168 if (!ipt.exists())
169 {
170 throw new FileNotFoundException("No iptables executable");
171 }
172
173 final String path = ipt.getAbsolutePath();
174
175 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT);
176
177 boolean compatible = false;
178 boolean version = false;
179
180 String command = path + " --version\n" + path + " -L -t nat -n\n";
181
182 final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT);
183
184 for (final String line : result)
185 {
186 if (line.contains("OUTPUT"))
187 {
188 compatible = true;
189 }
190 if (line.contains("v1.4."))
191 {
192 version = true;
193 }
194 }
195
196 if (!(compatible && version))
197 {
198 throw new IllegalStateException("Incompatible iptables excutable");
199 }
200
201 command = path + " -L -t nat -n\n";
202
203 return RootTools.sendShell(command, DEFAULT_TIMEOUT);
204 }
205 catch (final Throwable t)
206 {
207 return null;
208 }
209 }
210
211 @Override
212 public ProxyRegistrationType getType()
213 {
214 return ProxyRegistrationType.IPTABLES;
215 }
216
217 @Override
218 public boolean isRegistered()
219 {
220 return this.isRegistered;
221 }
222
223 @Override
224 public boolean isSticky()
225 {
226 return false;
227 }
228
229 @Override
230 public String toString()
231 {
232 return "[ProxyConfigurator: " + this.getType() + "]";
233 }
234 }
OLDNEW

Powered by Google App Engine
This is Rietveld