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

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

Issue 5624117646589952: Issue 1771 - Update RootTools (Closed)
Patch Set: Renamed some stuff Created Jan. 23, 2015, 1:38 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « libs/RootTools-3.4.jar ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 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/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 package org.adblockplus.android.configurators; 18 package org.adblockplus.android.configurators;
19 19
20 import java.io.File; 20 import java.io.File;
21 import java.io.FileNotFoundException; 21 import java.io.FileNotFoundException;
22 import java.io.IOException;
22 import java.net.InetAddress; 23 import java.net.InetAddress;
24 import java.util.ArrayList;
23 import java.util.List; 25 import java.util.List;
26 import java.util.concurrent.Semaphore;
27 import java.util.concurrent.TimeoutException;
24 28
25 import org.adblockplus.android.Utils; 29 import org.adblockplus.android.Utils;
26 30
27 import com.stericson.RootTools.RootTools;
28
29 import android.content.Context; 31 import android.content.Context;
30 import android.util.Log; 32 import android.util.Log;
31 33
34 import com.stericson.RootTools.RootTools;
35 import com.stericson.RootTools.exceptions.RootDeniedException;
36 import com.stericson.RootTools.execution.Command;
37 import com.stericson.RootTools.execution.Shell;
38
32 /** 39 /**
33 * Proxy registration using RootTools and iptables. 40 * Proxy registration using RootTools and iptables.
34 */ 41 */
35 public class IptablesProxyConfigurator implements ProxyConfigurator 42 public class IptablesProxyConfigurator implements ProxyConfigurator
36 { 43 {
37 private static final String TAG = Utils.getTag(IptablesProxyConfigurator.class ); 44 private static final String TAG = Utils.getTag(IptablesProxyConfigurator.class );
38 private static final int DEFAULT_TIMEOUT = 3000; 45 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"; 46 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"; 47 private static final String IPTABLES_ADD_HTTP = " -t nat -A OUTPUT -p tcp --dp ort 80 -j REDIRECT --to {{PORT}}\n";
41 48
42 private final Context context; 49 private final Context context;
43 private String iptables; 50 private String iptables;
44 private boolean isRegistered = false; 51 private boolean isRegistered = false;
45 52
46 public IptablesProxyConfigurator(final Context context) 53 public IptablesProxyConfigurator(final Context context)
47 { 54 {
48 this.context = context; 55 this.context = context;
49 } 56 }
50 57
58 private static List<String> runRootCommand(final String command, final int tim eout) throws IOException, TimeoutException,
59 RootDeniedException
60 {
61 final CapturingOutputCommand cmd = new CapturingOutputCommand(0, DEFAULT_TIM EOUT, command);
62
63 Shell.runRootCommand(cmd);
64
65 cmd.waitForCompletion();
66
67 return cmd.output;
68 }
69
51 @Override 70 @Override
52 public boolean initialize() 71 public boolean initialize()
53 { 72 {
54 try 73 try
55 { 74 {
75 // If we don't set `handlerEnabled` to `false`, RootTools uses Handlers
76 // which get executed on the UI thread which in fact renders it useless
77 // for our purpose (as it either finished too late or blocks forever).
78 RootTools.handlerEnabled = false;
79
56 if (!RootTools.isAccessGiven()) 80 if (!RootTools.isAccessGiven())
57 { 81 {
58 throw new IllegalStateException("No root access"); 82 throw new IllegalStateException("No root access");
59 } 83 }
60 84
61 final String path = getIptablesExecutablePath(); 85 final String path = getIptablesExecutablePath();
62 86
63 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT); 87 runRootCommand("chmod 700 " + path, DEFAULT_TIMEOUT);
64 88
65 boolean compatible = false; 89 boolean compatible = false;
66 boolean version = false; 90 boolean version = false;
67 91
68 final String command = path + " --version\n" + path + " -L -t nat -n\n"; 92 final String command = path + " --version\n" + path + " -L -t nat -n\n";
69 93
70 final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT); 94 final List<String> result = runRootCommand(command, DEFAULT_TIMEOUT);
71 95
72 for (final String line : result) 96 for (final String line : result)
73 { 97 {
74 if (line.contains("OUTPUT")) 98 if (line.contains("OUTPUT"))
75 { 99 {
76 compatible = true; 100 compatible = true;
77 } 101 }
78 if (line.contains("v1.4.")) 102 if (line.contains("v1.4."))
79 { 103 {
80 version = true; 104 version = true;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 { 140 {
117 final int uid = this.context.getPackageManager().getPackageInfo(this.conte xt.getPackageName(), 0).applicationInfo.uid; 141 final int uid = this.context.getPackageManager().getPackageInfo(this.conte xt.getPackageName(), 0).applicationInfo.uid;
118 142
119 final StringBuilder cmd = new StringBuilder(); 143 final StringBuilder cmd = new StringBuilder();
120 cmd.append(this.iptables); 144 cmd.append(this.iptables);
121 cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid))); 145 cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid)));
122 cmd.append('\n'); 146 cmd.append('\n');
123 cmd.append(this.iptables); 147 cmd.append(this.iptables);
124 cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port))); 148 cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port)));
125 149
126 RootTools.sendShell(cmd.toString(), DEFAULT_TIMEOUT); 150 runRootCommand(cmd.toString(), DEFAULT_TIMEOUT);
127 151
128 this.isRegistered = true; 152 this.isRegistered = true;
129 153
130 return true; 154 return true;
131 } 155 }
132 catch (final Exception e) 156 catch (final Exception e)
133 { 157 {
134 // I leave this logging message for now, passing 'init' and failing 'regis ter' definitely is a failure 158 // I leave this logging message for now, passing 'init' and failing 'regis ter' definitely is a failure
135 Log.e(TAG, "Couldn't register proxy using iptables.", e); 159 Log.e(TAG, "Couldn't register proxy using iptables.", e);
136 return false; 160 return false;
137 } 161 }
138 } 162 }
139 163
140 @Override 164 @Override
141 public void unregisterProxy() 165 public void unregisterProxy()
142 { 166 {
143 try 167 try
144 { 168 {
145 RootTools.sendShell(this.iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT); 169 runRootCommand(this.iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT);
146 } 170 }
147 catch (final Exception e) 171 catch (final Exception e)
148 { 172 {
149 Log.w(TAG, "Failed to unregister proxy using iptables.", e); 173 Log.w(TAG, "Failed to unregister proxy using iptables.", e);
150 } 174 }
151 finally 175 finally
152 { 176 {
153 this.isRegistered = false; 177 this.isRegistered = false;
154 } 178 }
155 } 179 }
(...skipping 15 matching lines...) Expand all
171 195
172 final File ipt = context.getFileStreamPath("iptables"); 196 final File ipt = context.getFileStreamPath("iptables");
173 197
174 if (!ipt.exists()) 198 if (!ipt.exists())
175 { 199 {
176 throw new FileNotFoundException("No iptables executable"); 200 throw new FileNotFoundException("No iptables executable");
177 } 201 }
178 202
179 final String path = ipt.getAbsolutePath(); 203 final String path = ipt.getAbsolutePath();
180 204
181 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT); 205 runRootCommand("chmod 700 " + path, DEFAULT_TIMEOUT);
182 206
183 boolean compatible = false; 207 boolean compatible = false;
184 boolean version = false; 208 boolean version = false;
185 209
186 String command = path + " --version\n" + path + " -L -t nat -n\n"; 210 String command = path + " --version\n" + path + " -L -t nat -n\n";
187 211
188 final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT); 212 final List<String> result = runRootCommand(command, DEFAULT_TIMEOUT);
189 213
190 for (final String line : result) 214 for (final String line : result)
191 { 215 {
192 if (line.contains("OUTPUT")) 216 if (line.contains("OUTPUT"))
193 { 217 {
194 compatible = true; 218 compatible = true;
195 } 219 }
196 if (line.contains("v1.4.")) 220 if (line.contains("v1.4."))
197 { 221 {
198 version = true; 222 version = true;
199 } 223 }
200 } 224 }
201 225
202 if (!(compatible && version)) 226 if (!(compatible && version))
203 { 227 {
204 throw new IllegalStateException("Incompatible iptables excutable"); 228 throw new IllegalStateException("Incompatible iptables excutable");
205 } 229 }
206 230
207 command = path + " -L -t nat -n\n"; 231 command = path + " -L -t nat -n\n";
208 232
209 return RootTools.sendShell(command, DEFAULT_TIMEOUT); 233 return runRootCommand(command, DEFAULT_TIMEOUT);
210 } 234 }
211 catch (final Throwable t) 235 catch (final Throwable t)
212 { 236 {
213 return null; 237 return null;
214 } 238 }
215 } 239 }
216 240
217 @Override 241 @Override
218 public ProxyRegistrationType getType() 242 public ProxyRegistrationType getType()
219 { 243 {
(...skipping 10 matching lines...) Expand all
230 public boolean isSticky() 254 public boolean isSticky()
231 { 255 {
232 return false; 256 return false;
233 } 257 }
234 258
235 @Override 259 @Override
236 public String toString() 260 public String toString()
237 { 261 {
238 return "[ProxyConfigurator: " + this.getType() + "]"; 262 return "[ProxyConfigurator: " + this.getType() + "]";
239 } 263 }
264
265 private final static class CapturingOutputCommand extends Command
266 {
267 private final Semaphore running = new Semaphore(1);
268
269 public List<String> output = new ArrayList<String>();
270
271 public CapturingOutputCommand(final int id, final int timeout, final String command)
272 {
273 super(id, timeout, command);
274
275 this.running.acquireUninterruptibly();
276 }
277
278 @Override
279 public void commandOutput(int id, String line)
280 {
281 this.output.add(line);
282 }
283
284 @Override
285 public void commandCompleted(int id, int exitCode)
286 {
287 this.running.release();
288 }
289
290 @Override
291 public void commandTerminated(int id, String reason)
292 {
293 this.running.release();
294 }
295
296 public void waitForCompletion()
297 {
298 this.running.acquireUninterruptibly();
299 }
300 }
240 } 301 }
OLDNEW
« no previous file with comments | « libs/RootTools-3.4.jar ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld