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: Created Nov. 6, 2014, 10:39 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
« no previous file with comments | « libs/RootTools-3.3.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 <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2014 Eyeo GmbH 3 * Copyright (C) 2006-2014 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> sendShell(final String command, final int timeout) throws IOException, TimeoutException,
59 RootDeniedException
60 {
61 final CommandOutput cmd = new CommandOutput(0, DEFAULT_TIMEOUT, 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 File ipt = this.context.getFileStreamPath("iptables"); 85 final File ipt = this.context.getFileStreamPath("iptables");
62 86
63 if (!ipt.exists()) 87 if (!ipt.exists())
64 { 88 {
65 throw new FileNotFoundException("No iptables executable"); 89 throw new FileNotFoundException("No iptables executable");
66 } 90 }
67 91
68 final String path = ipt.getAbsolutePath(); 92 final String path = ipt.getAbsolutePath();
69 93
70 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT); 94 sendShell("chmod 700 " + path, DEFAULT_TIMEOUT);
71 95
72 boolean compatible = false; 96 boolean compatible = false;
73 boolean version = false; 97 boolean version = false;
74 98
75 final String command = path + " --version\n" + path + " -L -t nat -n\n"; 99 final String command = path + " --version\n" + path + " -L -t nat -n\n";
76 100
77 final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT); 101 final List<String> result = sendShell(command, DEFAULT_TIMEOUT);
78 102
79 for (final String line : result) 103 for (final String line : result)
80 { 104 {
81 if (line.contains("OUTPUT")) 105 if (line.contains("OUTPUT"))
82 { 106 {
83 compatible = true; 107 compatible = true;
84 } 108 }
85 if (line.contains("v1.4.")) 109 if (line.contains("v1.4."))
86 { 110 {
87 version = true; 111 version = true;
88 } 112 }
89 } 113 }
90 114
91 if (!(compatible && version)) 115 if (!(compatible && version))
92 { 116 {
93 throw new IllegalStateException("Incompatible iptables excutable"); 117 throw new IllegalStateException("Incompatible iptables excutable");
94 } 118 }
95 119
96 this.iptables = path; 120 this.iptables = path;
97 121
98 return true; 122 return true;
99 } 123 }
100 catch (final Exception e) 124 catch (final Exception e)
101 { 125 {
126 Log.e(TAG, "iptables setup failed", e);
102 return false; 127 return false;
103 } 128 }
104 } 129 }
105 130
106 @Override 131 @Override
107 public boolean registerProxy(final InetAddress address, final int port) 132 public boolean registerProxy(final InetAddress address, final int port)
108 { 133 {
109 try 134 try
110 { 135 {
111 final int uid = this.context.getPackageManager().getPackageInfo(this.conte xt.getPackageName(), 0).applicationInfo.uid; 136 final int uid = this.context.getPackageManager().getPackageInfo(this.conte xt.getPackageName(), 0).applicationInfo.uid;
112 137
113 final StringBuilder cmd = new StringBuilder(); 138 final StringBuilder cmd = new StringBuilder();
114 cmd.append(this.iptables); 139 cmd.append(this.iptables);
115 cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid))); 140 cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid)));
116 cmd.append('\n'); 141 cmd.append('\n');
117 cmd.append(this.iptables); 142 cmd.append(this.iptables);
118 cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port))); 143 cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port)));
119 144
120 RootTools.sendShell(cmd.toString(), DEFAULT_TIMEOUT); 145 sendShell(cmd.toString(), DEFAULT_TIMEOUT);
121 146
122 this.isRegistered = true; 147 this.isRegistered = true;
123 148
124 return true; 149 return true;
125 } 150 }
126 catch (final Exception e) 151 catch (final Exception e)
127 { 152 {
128 // I leave this logging message for now, passing 'init' and failing 'regis ter' definitely is a failure 153 // 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); 154 Log.e(TAG, "Couldn't register proxy using iptables.", e);
130 return false; 155 return false;
131 } 156 }
132 } 157 }
133 158
134 @Override 159 @Override
135 public void unregisterProxy() 160 public void unregisterProxy()
136 { 161 {
137 try 162 try
138 { 163 {
139 RootTools.sendShell(this.iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT); 164 sendShell(this.iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT);
140 } 165 }
141 catch (final Exception e) 166 catch (final Exception e)
142 { 167 {
143 Log.w(TAG, "Failed to unregister proxy using iptables.", e); 168 Log.w(TAG, "Failed to unregister proxy using iptables.", e);
144 } 169 }
145 finally 170 finally
146 { 171 {
147 this.isRegistered = false; 172 this.isRegistered = false;
148 } 173 }
149 } 174 }
(...skipping 15 matching lines...) Expand all
165 190
166 final File ipt = context.getFileStreamPath("iptables"); 191 final File ipt = context.getFileStreamPath("iptables");
167 192
168 if (!ipt.exists()) 193 if (!ipt.exists())
169 { 194 {
170 throw new FileNotFoundException("No iptables executable"); 195 throw new FileNotFoundException("No iptables executable");
171 } 196 }
172 197
173 final String path = ipt.getAbsolutePath(); 198 final String path = ipt.getAbsolutePath();
174 199
175 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT); 200 sendShell("chmod 700 " + path, DEFAULT_TIMEOUT);
176 201
177 boolean compatible = false; 202 boolean compatible = false;
178 boolean version = false; 203 boolean version = false;
179 204
180 String command = path + " --version\n" + path + " -L -t nat -n\n"; 205 String command = path + " --version\n" + path + " -L -t nat -n\n";
181 206
182 final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT); 207 final List<String> result = sendShell(command, DEFAULT_TIMEOUT);
183 208
184 for (final String line : result) 209 for (final String line : result)
185 { 210 {
186 if (line.contains("OUTPUT")) 211 if (line.contains("OUTPUT"))
187 { 212 {
188 compatible = true; 213 compatible = true;
189 } 214 }
190 if (line.contains("v1.4.")) 215 if (line.contains("v1.4."))
191 { 216 {
192 version = true; 217 version = true;
193 } 218 }
194 } 219 }
195 220
196 if (!(compatible && version)) 221 if (!(compatible && version))
197 { 222 {
198 throw new IllegalStateException("Incompatible iptables excutable"); 223 throw new IllegalStateException("Incompatible iptables excutable");
199 } 224 }
200 225
201 command = path + " -L -t nat -n\n"; 226 command = path + " -L -t nat -n\n";
202 227
203 return RootTools.sendShell(command, DEFAULT_TIMEOUT); 228 return sendShell(command, DEFAULT_TIMEOUT);
204 } 229 }
205 catch (final Throwable t) 230 catch (final Throwable t)
206 { 231 {
207 return null; 232 return null;
208 } 233 }
209 } 234 }
210 235
211 @Override 236 @Override
212 public ProxyRegistrationType getType() 237 public ProxyRegistrationType getType()
213 { 238 {
(...skipping 10 matching lines...) Expand all
224 public boolean isSticky() 249 public boolean isSticky()
225 { 250 {
226 return false; 251 return false;
227 } 252 }
228 253
229 @Override 254 @Override
230 public String toString() 255 public String toString()
231 { 256 {
232 return "[ProxyConfigurator: " + this.getType() + "]"; 257 return "[ProxyConfigurator: " + this.getType() + "]";
233 } 258 }
259
260 private final static class CommandOutput extends Command
261 {
262 private final Semaphore completionNotify = new Semaphore(1);
263
264 public List<String> output = new ArrayList<String>();
265
266 public CommandOutput(final int id, final int timeout, final String command)
267 {
268 super(id, timeout, command);
269
270 this.completionNotify.acquireUninterruptibly();
271 }
272
273 @Override
274 public void commandOutput(int id, String line)
275 {
276 this.output.add(line);
277 }
278
279 @Override
280 public void commandCompleted(int id, int exitCode)
281 {
282 this.completionNotify.release();
283 }
284
285 @Override
286 public void commandTerminated(int id, String reason)
287 {
288 this.completionNotify.release();
289 }
290
291 public void waitForCompletion()
292 {
293 this.completionNotify.acquireUninterruptibly();
294 }
295 }
234 } 296 }
OLDNEW
« no previous file with comments | « libs/RootTools-3.3.jar ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld