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

Delta Between Two Patch Sets: src/org/adblockplus/android/ProxyService.java

Issue 8484110: ABP/Android proxy service (Closed)
Left Patch Set: ABP/Android proxy service Created Nov. 1, 2012, 9:46 a.m.
Right Patch Set: ABP/Android proxy service Created Nov. 12, 2012, 8:53 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 package org.adblockplus.android; 1 package org.adblockplus.android;
2 2
3 import java.io.File; 3 import java.io.File;
4 import java.io.FileNotFoundException;
4 import java.io.IOException; 5 import java.io.IOException;
5 import java.lang.reflect.Method; 6 import java.lang.reflect.Method;
6 import java.net.InetAddress; 7 import java.net.InetAddress;
7 import java.net.ServerSocket; 8 import java.net.ServerSocket;
8 import java.util.List; 9 import java.util.List;
9 import java.util.Properties; 10 import java.util.Properties;
10 import java.util.concurrent.TimeoutException; 11 import java.util.concurrent.TimeoutException;
11 12
12 import sunlabs.brazil.server.Server; 13 import sunlabs.brazil.server.Server;
13 import sunlabs.brazil.util.Base64; 14 import sunlabs.brazil.util.Base64;
(...skipping 16 matching lines...) Expand all
30 import android.os.IBinder; 31 import android.os.IBinder;
31 import android.preference.PreferenceManager; 32 import android.preference.PreferenceManager;
32 import android.util.Log; 33 import android.util.Log;
33 import android.widget.Toast; 34 import android.widget.Toast;
34 35
35 import com.stericson.RootTools.RootTools; 36 import com.stericson.RootTools.RootTools;
36 import com.stericson.RootTools.RootToolsException; 37 import com.stericson.RootTools.RootToolsException;
37 38
38 public class ProxyService extends Service implements OnSharedPreferenceChangeLis tener 39 public class ProxyService extends Service implements OnSharedPreferenceChangeLis tener
39 { 40 {
41 private static final String LOCALHOST = "127.0.0.1";
42 /**
43 * Indicates that system supports native proxy configuration.
44 */
45 public static boolean hasNativeProxy = Build.VERSION.SDK_INT >= 12; // Honeyco mb 3.1
46
40 static 47 static
41 { 48 {
42 RootTools.debugMode = false; 49 RootTools.debugMode = false;
43 } 50 }
44 51
45 private static final String TAG = "ProxyService"; 52 private static final String TAG = "ProxyService";
53 private static final boolean logRequests = false;
46 54
47 private final static int DEFAULT_TIMEOUT = 3000; 55 private final static int DEFAULT_TIMEOUT = 3000;
48 private final static int NO_TRAFFIC_TIMEOUT = 5 * 60 * 1000; // 5 minutes 56 private final static int NO_TRAFFIC_TIMEOUT = 5 * 60 * 1000; // 5 minutes
49 57
50 final static int ONGOING_NOTIFICATION_ID = R.string.app_name; 58 final static int ONGOING_NOTIFICATION_ID = R.string.app_name;
51 private final static int NOTRAFFIC_NOTIFICATION_ID = R.string.app_name + 3; 59 private final static int NOTRAFFIC_NOTIFICATION_ID = R.string.app_name + 3;
52 60
53 /** 61 /**
54 * Broadcasted when service starts or stops. 62 * Broadcasted when service starts or stops.
55 */ 63 */
(...skipping 10 matching lines...) Expand all
66 private PendingIntent contentIntent; 74 private PendingIntent contentIntent;
67 75
68 private Handler notrafficHandler; 76 private Handler notrafficHandler;
69 77
70 protected ProxyServer proxy = null; 78 protected ProxyServer proxy = null;
71 protected int port; 79 protected int port;
72 80
73 /** 81 /**
74 * Indicates that service is working with root privileges. 82 * Indicates that service is working with root privileges.
75 */ 83 */
76 private boolean isTransparent = false; 84 private boolean transparent = false;
77 /** 85 /**
78 * Indicates that service has autoconfigured Android proxy settings (version 86 * Indicates that service has autoconfigured Android proxy settings (version
79 * 3.1+). 87 * 3.1+).
80 */ 88 */
81 private boolean isNativeProxy = false; 89 private boolean nativeProxy = false;
82 90
83 private String iptables = null; 91 private String iptables = null;
84 92
85 @Override 93 @Override
86 public void onCreate() 94 public void onCreate()
87 { 95 {
88 super.onCreate(); 96 super.onCreate();
89 97
90 // Get port for local proxy 98 // Get port for local proxy
91 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this ); 99 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this );
92 String p = prefs.getString(getString(R.string.pref_port), null); 100 String p = prefs.getString(getString(R.string.pref_port), null);
93 try 101 try
94 { 102 {
95 port = p != null ? Integer.valueOf(p) : getResources().getInteger(R.intege r.def_port); 103 port = p != null ? Integer.valueOf(p) : getResources().getInteger(R.intege r.def_port);
96 } 104 }
97 catch (NumberFormatException e) 105 catch (NumberFormatException e)
98 { 106 {
99 Toast.makeText(this, getString(R.string.msg_badport) + ": " + p, Toast.LEN GTH_LONG).show(); 107 Toast.makeText(this, getString(R.string.msg_badport) + ": " + p, Toast.LEN GTH_LONG).show();
100 port = getResources().getInteger(R.integer.def_port); 108 port = getResources().getInteger(R.integer.def_port);
101 } 109 }
102 110
103 // Try to read user proxy settings 111 // Try to read user proxy settings
104 String proxyHost = null; 112 String proxyHost = null;
105 String proxyPort = null; 113 String proxyPort = null;
106 String proxyExcl = null; 114 String proxyExcl = null;
107 String proxyUser = null; 115 String proxyUser = null;
108 String proxyPass = null; 116 String proxyPass = null;
109 117
110 if (Build.VERSION.SDK_INT >= 12) // Honeycomb 3.1 118 if (hasNativeProxy)
Andrey Novikov 2012/11/09 09:23:47 What exactly are you referencing?
Felix Dahlke 2012/11/09 14:40:46 I think it was AdvancedPreferences.hasNativeProxy.
111 { 119 {
112 // Read system settings 120 // Read system settings
113 proxyHost = System.getProperty("http.proxyHost"); 121 proxyHost = System.getProperty("http.proxyHost");
114 proxyPort = System.getProperty("http.proxyPort"); 122 proxyPort = System.getProperty("http.proxyPort");
115 proxyExcl = System.getProperty("http.nonProxyHosts"); 123 proxyExcl = System.getProperty("http.nonProxyHosts");
116 124
117 Log.d(TAG, "PRX: " + proxyHost + ":" + proxyPort + "(" + proxyExcl + ")"); 125 Log.d(TAG, "PRX: " + proxyHost + ":" + proxyPort + "(" + proxyExcl + ")");
118 String[] px = ProxySettings.getUserProxy(getApplicationContext()); // not used but left for future reference 126 String[] px = ProxySettings.getUserProxy(getApplicationContext()); // not used but left for future reference
Felix Dahlke 2012/11/08 16:37:50 Future reference? It is in fact used below, if onl
Felix Dahlke 2012/11/09 14:40:46 I see, I misunderstood that then. I thought you me
119 if (px != null) 127 if (px != null)
120 Log.d(TAG, "PRX: " + px[0] + ":" + px[1] + "(" + px[2] + ")"); 128 Log.d(TAG, "PRX: " + px[0] + ":" + px[1] + "(" + px[2] + ")");
121 } 129 }
122 else 130 else
123 { 131 {
124 // Read application settings 132 // Read application settings
125 proxyHost = prefs.getString(getString(R.string.pref_proxyhost), null); 133 proxyHost = prefs.getString(getString(R.string.pref_proxyhost), null);
126 proxyPort = prefs.getString(getString(R.string.pref_proxyport), null); 134 proxyPort = prefs.getString(getString(R.string.pref_proxyport), null);
127 proxyUser = prefs.getString(getString(R.string.pref_proxyuser), null); 135 proxyUser = prefs.getString(getString(R.string.pref_proxyuser), null);
128 proxyPass = prefs.getString(getString(R.string.pref_proxypass), null); 136 proxyPass = prefs.getString(getString(R.string.pref_proxypass), null);
129 } 137 }
130 138
131 // Check for root privileges and try to install transparent proxy 139 // Check for root privileges and try to install transparent proxy
132 if (RootTools.isAccessGiven()) 140 if (RootTools.isAccessGiven())
133 { 141 {
134 try 142 try
135 { 143 {
136 iptables = getIptables(); 144 initIptables();
Andrey Novikov 2012/11/09 09:23:47 Done.
137 if (iptables != null) 145
138 { 146 StringBuffer cmd = new StringBuffer();
139 StringBuffer cmd = new StringBuffer(); 147 int uid = getPackageManager().getPackageInfo(getPackageName(), 0).applic ationInfo.uid;
140 int uid = getPackageManager().getPackageInfo(getPackageName(), 0).appl icationInfo.uid; 148 cmd.append(iptables);
141 cmd.append(iptables); 149 cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid)));
142 cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid))); 150 cmd.append(iptables);
143 cmd.append(iptables); 151 cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port)));
144 cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port)) ); 152 String rules = cmd.toString();
145 String rules = cmd.toString(); 153 RootTools.sendShell(rules, DEFAULT_TIMEOUT);
146 RootTools.sendShell(rules, DEFAULT_TIMEOUT); 154 transparent = true;
147 isTransparent = true; 155 }
148 } 156 catch (FileNotFoundException e)
157 {
158 // ignore - this is "normal" case
149 } 159 }
150 catch (NameNotFoundException e) 160 catch (NameNotFoundException e)
151 { 161 {
152 e.printStackTrace(); 162 Log.e(TAG, "Failed to initialize iptables", e);
Felix Dahlke 2012/11/08 16:37:50 Here and below, I'd prefer Log.e().
Andrey Novikov 2012/11/09 09:23:47 Done.
153 } 163 }
154 catch (IOException e) 164 catch (IOException e)
155 { 165 {
156 e.printStackTrace(); 166 Log.e(TAG, "Failed to initialize iptables", e);
157 } 167 }
158 catch (RootToolsException e) 168 catch (RootToolsException e)
159 { 169 {
160 e.printStackTrace(); 170 Log.e(TAG, "Failed to initialize iptables", e);
161 } 171 }
162 catch (TimeoutException e) 172 catch (TimeoutException e)
163 { 173 {
164 e.printStackTrace(); 174 Log.e(TAG, "Failed to initialize iptables", e);
165 } 175 }
166 } 176 }
167 177
168 if (!isTransparent) 178 if (!transparent)
169 { 179 {
170 // Try to set native proxy 180 // Try to set native proxy
171 isNativeProxy = ProxySettings.setConnectionProxy(getApplicationContext(), "127.0.0.1", port, ""); 181 nativeProxy = ProxySettings.setConnectionProxy(getApplicationContext(), LO CALHOST, port, "");
172 182
173 if (isNativeProxy) 183 if (nativeProxy)
174 { 184 {
175 registerReceiver(connectionReceiver, new IntentFilter(ConnectivityManage r.CONNECTIVITY_ACTION)); 185 registerReceiver(connectionReceiver, new IntentFilter(ConnectivityManage r.CONNECTIVITY_ACTION));
176 registerReceiver(connectionReceiver, new IntentFilter("android.net.wifi. LINK_CONFIGURATION_CHANGED")); 186 registerReceiver(connectionReceiver, new IntentFilter("android.net.wifi. LINK_CONFIGURATION_CHANGED"));
177 } 187 }
178 } 188 }
179 189
180 // Start engine 190 // Start engine
181 AdblockPlus.getApplication().startEngine(); 191 AdblockPlus.getApplication().startEngine();
182 192
183 registerReceiver(proxyReceiver, new IntentFilter(ProxyService.BROADCAST_PROX Y_FAILED)); 193 registerReceiver(proxyReceiver, new IntentFilter(ProxyService.BROADCAST_PROX Y_FAILED));
(...skipping 12 matching lines...) Expand all
196 { 206 {
197 sendBroadcast(new Intent(BROADCAST_PROXY_FAILED).putExtra("msg", e.getMe ssage())); 207 sendBroadcast(new Intent(BROADCAST_PROXY_FAILED).putExtra("msg", e.getMe ssage()));
198 Log.e(TAG, null, e); 208 Log.e(TAG, null, e);
199 return; 209 return;
200 } 210 }
201 211
202 Properties config = new Properties(); 212 Properties config = new Properties();
203 config.put("handler", "main"); 213 config.put("handler", "main");
204 config.put("main.prefix", ""); 214 config.put("main.prefix", "");
205 config.put("main.class", "sunlabs.brazil.server.ChainHandler"); 215 config.put("main.class", "sunlabs.brazil.server.ChainHandler");
206 if (isTransparent) 216 if (transparent)
207 { 217 {
208 config.put("main.handlers", "urlmodifier adblock"); 218 config.put("main.handlers", "urlmodifier adblock");
209 config.put("urlmodifier.class", "org.adblockplus.brazil.TransparentProxy Handler"); 219 config.put("urlmodifier.class", "org.adblockplus.brazil.TransparentProxy Handler");
210 } 220 }
211 else 221 else
212 { 222 {
213 config.put("main.handlers", "https adblock"); 223 config.put("main.handlers", "https adblock");
214 config.put("https.class", "org.adblockplus.brazil.SSLConnectionHandler") ; 224 config.put("https.class", "org.adblockplus.brazil.SSLConnectionHandler") ;
215 } 225 }
216 config.put("adblock.class", "org.adblockplus.brazil.RequestHandler"); 226 config.put("adblock.class", "org.adblockplus.brazil.RequestHandler");
217 // config.put("adblock.proxylog", "yes"); 227 if (logRequests)
228 config.put("adblock.proxylog", "yes");
218 229
219 configureUserProxy(config, proxyHost, proxyPort, proxyExcl, proxyUser, pro xyPass); 230 configureUserProxy(config, proxyHost, proxyPort, proxyExcl, proxyUser, pro xyPass);
220 231
221 proxy = new ProxyServer(); 232 proxy = new ProxyServer();
222 proxy.logLevel = Server.LOG_DIAGNOSTIC; 233 proxy.logLevel = Server.LOG_DIAGNOSTIC;
223 proxy.setup(listen, config.getProperty("handler"), config); 234 proxy.setup(listen, config.getProperty("handler"), config);
224 proxy.start(); 235 proxy.start();
225 } 236 }
226 237
227 prefs.registerOnSharedPreferenceChangeListener(this); 238 prefs.registerOnSharedPreferenceChangeListener(this);
228 239
229 String msg = getString(isTransparent ? R.string.notif_all : isNativeProxy ? R.string.notif_wifi : R.string.notif_waiting); 240 String msg = getString(transparent ? R.string.notif_all : nativeProxy ? R.st ring.notif_wifi : R.string.notif_waiting);
230 if (!isTransparent && !isNativeProxy) 241 if (!transparent && !nativeProxy)
231 { 242 {
232 // Initiate no traffic check 243 // Initiate no traffic check
233 notrafficHandler = new Handler(); 244 notrafficHandler = new Handler();
234 notrafficHandler.postDelayed(noTraffic, NO_TRAFFIC_TIMEOUT); 245 notrafficHandler.postDelayed(noTraffic, NO_TRAFFIC_TIMEOUT);
235 } 246 }
236 // Lock service 247 // Lock service
237 ongoingNotification = new Notification(); 248 ongoingNotification = new Notification();
238 ongoingNotification.when = 0; 249 ongoingNotification.when = 0;
239 contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Preferen ces.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TA SK), 0); 250 contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Preferen ces.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TA SK), 0);
240 ongoingNotification.icon = R.drawable.ic_stat_blocking; 251 ongoingNotification.icon = R.drawable.ic_stat_blocking;
241 ongoingNotification.setLatestEventInfo(getApplicationContext(), getText(R.st ring.app_name), msg, contentIntent); 252 ongoingNotification.setLatestEventInfo(getApplicationContext(), getText(R.st ring.app_name), msg, contentIntent);
242 startForeground(ONGOING_NOTIFICATION_ID, ongoingNotification); 253 startForeground(ONGOING_NOTIFICATION_ID, ongoingNotification);
243 254
244 sendBroadcast(new Intent(BROADCAST_STATE_CHANGED).putExtra("enabled", true). putExtra("port", port).putExtra("manual", !isTransparent && !isNativeProxy)); 255 sendBroadcast(new Intent(BROADCAST_STATE_CHANGED).putExtra("enabled", true). putExtra("port", port).putExtra("manual", !transparent && !nativeProxy));
245 Log.i(TAG, "Service started"); 256 Log.i(TAG, "Service started");
246 } 257 }
247 258
248 @Override 259 @Override
249 public void onDestroy() 260 public void onDestroy()
250 { 261 {
251 super.onDestroy(); 262 super.onDestroy();
252 263
253 stopNoTrafficCheck(false); 264 stopNoTrafficCheck(false);
254 265
255 unregisterReceiver(matchesReceiver); 266 unregisterReceiver(matchesReceiver);
256 unregisterReceiver(proxyReceiver); 267 unregisterReceiver(proxyReceiver);
257 268
258 // Stop IP redirecting 269 // Stop IP redirecting
259 if (isTransparent) 270 if (transparent)
260 { 271 {
261 new Thread() { 272 new Thread() {
262 @Override 273 @Override
263 public void run() 274 public void run()
264 { 275 {
265 try 276 try
266 { 277 {
267 RootTools.sendShell(iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT) ; 278 RootTools.sendShell(iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT) ;
268 } 279 }
269 catch (Exception e) 280 catch (Exception e)
270 { 281 {
271 e.printStackTrace(); 282 Log.e(TAG, "Failed to clear iptables", e);
Felix Dahlke 2012/11/08 16:37:50 Log.e()?
Andrey Novikov 2012/11/09 09:23:47 Done.
272 } 283 }
273 } 284 }
274 }.start(); 285 }.start();
275 } 286 }
276 287
277 // Clear native proxy 288 // Clear native proxy
278 if (isNativeProxy) 289 if (nativeProxy)
279 { 290 {
280 unregisterReceiver(connectionReceiver); 291 unregisterReceiver(connectionReceiver);
281 clearConnectionProxy(); 292 clearConnectionProxy();
282 } 293 }
283 294
284 sendBroadcast(new Intent(BROADCAST_STATE_CHANGED).putExtra("enabled", false) ); 295 sendBroadcast(new Intent(BROADCAST_STATE_CHANGED).putExtra("enabled", false) );
285 296
286 // Stop proxy server 297 // Stop proxy server
287 proxy.close(); 298 proxy.close();
288 299
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 /** 331 /**
321 * Sets user proxy settings in proxy service properties. 332 * Sets user proxy settings in proxy service properties.
322 */ 333 */
323 private void configureUserProxy(Properties config, String proxyHost, String pr oxyPort, String proxyExcl, String proxyUser, String proxyPass) 334 private void configureUserProxy(Properties config, String proxyHost, String pr oxyPort, String proxyExcl, String proxyUser, String proxyPass)
324 { 335 {
325 // Clean previous settings 336 // Clean previous settings
326 config.remove("adblock.proxyHost"); 337 config.remove("adblock.proxyHost");
327 config.remove("adblock.proxyPort"); 338 config.remove("adblock.proxyPort");
328 config.remove("adblock.auth"); 339 config.remove("adblock.auth");
329 config.remove("adblock.proxyExcl"); 340 config.remove("adblock.proxyExcl");
330 if (!isTransparent) 341 if (!transparent)
331 { 342 {
332 config.remove("https.proxyHost"); 343 config.remove("https.proxyHost");
333 config.remove("https.proxyPort"); 344 config.remove("https.proxyPort");
334 config.remove("https.auth"); 345 config.remove("https.auth");
335 } 346 }
336 347
337 if (isNativeProxy) 348 if (nativeProxy)
338 passProxySettings(proxyHost, proxyPort, proxyExcl); 349 passProxySettings(proxyHost, proxyPort, proxyExcl);
339 350
340 // Check if there are any settings 351 // Check if there are any settings
341 if (proxyHost == null || "".equals(proxyHost)) 352 if (proxyHost == null || "".equals(proxyHost))
342 return; 353 return;
343 354
344 // Check for dirty proxy settings - this indicated previous crash: 355 // Check for dirty proxy settings - this indicated previous crash:
345 // proxy points to ourselves 356 // proxy points to ourselves
346 // proxy port is null, 0 or not a number 357 // proxy port is null, 0 or not a number
347 // proxy is 127.0.0.1:8080 358 // proxy is 127.0.0.1:8080
348 if (proxyPort == null) 359 if (proxyPort == null)
349 return; 360 return;
350 int p = 0; 361 int p = 0;
351 try 362 try
352 { 363 {
353 p = Integer.valueOf(proxyPort); 364 p = Integer.valueOf(proxyPort);
354 } 365 }
355 catch (NumberFormatException e) 366 catch (NumberFormatException e)
356 { 367 {
357 return; 368 return;
358 } 369 }
359 if (p == 0 || isLocalHost(proxyHost) && (p == port || p == 8080)) 370 if (p == 0 || isLocalHost(proxyHost) && (p == port || p == 8080))
360 { 371 {
361 if (isNativeProxy) 372 if (nativeProxy)
362 passProxySettings(null, null, null); 373 passProxySettings(null, null, null);
363 return; 374 return;
364 } 375 }
365 376
366 config.put("adblock.proxyHost", proxyHost); 377 config.put("adblock.proxyHost", proxyHost);
367 config.put("adblock.proxyPort", proxyPort); 378 config.put("adblock.proxyPort", proxyPort);
368 if (!isTransparent) 379 if (!transparent)
369 { 380 {
370 config.put("https.proxyHost", proxyHost); 381 config.put("https.proxyHost", proxyHost);
371 config.put("https.proxyPort", proxyPort); 382 config.put("https.proxyPort", proxyPort);
372 } 383 }
373 384
374 // TODO Not implemented in our proxy but needed to restore settings 385 // TODO Not implemented in our proxy but needed to restore settings
375 if (proxyExcl != null) 386 if (proxyExcl != null)
376 config.put("adblock.proxyExcl", proxyExcl); 387 config.put("adblock.proxyExcl", proxyExcl);
377 388
378 if (proxyUser != null && !"".equals(proxyUser) && proxyPass != null && !"".e quals(proxyPass)) 389 if (proxyUser != null && !"".equals(proxyUser) && proxyPass != null && !"".e quals(proxyPass))
379 { 390 {
380 // Base64 encode user:password 391 // Base64 encode user:password
381 String proxyAuth = "Basic " + new String(Base64.encode(proxyUser + ":" + p roxyPass)); 392 String proxyAuth = "Basic " + new String(Base64.encode(proxyUser + ":" + p roxyPass));
382 config.put("adblock.auth", proxyAuth); 393 config.put("adblock.auth", proxyAuth);
383 if (!isTransparent) 394 if (!transparent)
384 config.put("https.auth", proxyAuth); 395 config.put("https.auth", proxyAuth);
385 } 396 }
386 } 397 }
387 398
388 private void passProxySettings(String proxyHost, String proxyPort, String prox yExcl) 399 private void passProxySettings(String proxyHost, String proxyPort, String prox yExcl)
389 { 400 {
390 try 401 try
391 { 402 {
392 CrashHandler handler = (CrashHandler) Thread.getDefaultUncaughtExceptionHa ndler(); 403 CrashHandler handler = (CrashHandler) Thread.getDefaultUncaughtExceptionHa ndler();
393 handler.saveProxySettings(proxyHost, proxyPort, proxyExcl); 404 handler.saveProxySettings(proxyHost, proxyPort, proxyExcl);
394 } 405 }
395 catch (ClassCastException e) 406 catch (ClassCastException e)
396 { 407 {
397 // ignore - default handler in use 408 // ignore - default handler in use
398 } 409 }
399 } 410 }
400 411
401 @Override 412 @Override
402 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Str ing key) 413 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Str ing key)
403 { 414 {
404 if (Build.VERSION.SDK_INT < 12) // Honeycomb 3.1 415 if (hasNativeProxy)
Felix Dahlke 2012/11/08 16:37:50 Like before, I think there's a global variable or
Felix Dahlke 2012/11/09 14:40:46 See my reasoning above. If we're doing this check
405 { 416 {
406 if (key.equals(getString(R.string.pref_proxyhost)) || key.equals(getString (R.string.pref_proxyport)) || key.equals(getString(R.string.pref_proxyuser)) 417 String ketHost = getString(R.string.pref_proxyhost);
407 || key.equals(getString(R.string.pref_proxypass))) 418 String keyPort = getString(R.string.pref_proxyport);
408 { 419 String keyUser = getString(R.string.pref_proxyuser);
409 String proxyHost = sharedPreferences.getString(getString(R.string.pref_p roxyhost), null); 420 String keyPass = getString(R.string.pref_proxypass);
410 String proxyPort = sharedPreferences.getString(getString(R.string.pref_p roxyport), null); 421 if (key.equals(ketHost) || key.equals(keyPort) || key.equals(keyUser) || k ey.equals(keyPass))
411 String proxyUser = sharedPreferences.getString(getString(R.string.pref_p roxyuser), null); 422 {
412 String proxyPass = sharedPreferences.getString(getString(R.string.pref_p roxypass), null); 423 String proxyHost = sharedPreferences.getString(ketHost, null);
424 String proxyPort = sharedPreferences.getString(keyPort, null);
425 String proxyUser = sharedPreferences.getString(keyUser, null);
426 String proxyPass = sharedPreferences.getString(keyPass, null);
413 if (proxy != null) 427 if (proxy != null)
414 { 428 {
415 configureUserProxy(proxy.props, proxyHost, proxyPort, null, proxyUser, proxyPass); 429 configureUserProxy(proxy.props, proxyHost, proxyPort, null, proxyUser, proxyPass);
416 proxy.restart(proxy.props.getProperty("handler")); 430 proxy.restart(proxy.props.getProperty("handler"));
417 } 431 }
418 } 432 }
419 } 433 }
420 } 434 }
421 435
422 public boolean isTransparent() 436 public boolean isTransparent()
423 { 437 {
424 return isTransparent; 438 return transparent;
Felix Dahlke 2012/11/08 16:37:50 I believe the bean conventions says that boolean g
Andrey Novikov 2012/11/09 09:23:47 Done.
425 } 439 }
426 440
427 public boolean isNativeProxy() 441 public boolean isNativeProxy()
428 { 442 {
429 return isNativeProxy; 443 return nativeProxy;
430 } 444 }
431 445
432 /** 446 /**
433 * Checks if specified host is local. 447 * Checks if specified host is local.
434 */ 448 */
435 private static final boolean isLocalHost(String host) 449 private static final boolean isLocalHost(String host)
436 { 450 {
437 if (host == null) 451 if (host == null)
438 return false; 452 return false;
439 453
440 try 454 try
441 { 455 {
442 if (host != null) 456 if (host.equalsIgnoreCase("localhost"))
443 { 457 return true;
444 if (host.equalsIgnoreCase("localhost")) 458
445 return true; 459 String className = "android.net.NetworkUtils";
446 460 Class<?> c = Class.forName(className);
447 String className = "android.net.NetworkUtils"; 461 /*
448 Class<?> c = Class.forName(className); 462 * InetAddress address = NetworkUtils.numericToInetAddress(host);
449 /* 463 */
450 * InetAddress address = NetworkUtils.numericToInetAddress(host); 464 Method method = c.getMethod("numericToInetAddress", String.class);
451 */ 465 InetAddress address = (InetAddress) method.invoke(null, host);
452 Method method = c.getMethod("numericToInetAddress", String.class); 466
453 InetAddress address = (InetAddress) method.invoke(null, host); 467 if (address.isLoopbackAddress())
454 468 return true;
455 if (address.isLoopbackAddress())
456 return true;
457 }
458 } 469 }
459 catch (Exception e) 470 catch (Exception e)
460 { 471 {
Felix Dahlke 2012/11/08 16:37:50 Comment or logging please.
Andrey Novikov 2012/11/09 09:23:47 Done.
472 Log.w(TAG, null, e);
461 } 473 }
462 return false; 474 return false;
463 } 475 }
464 476
465 /** 477 /**
466 * Returns path to iptables executable. 478 * Initializes iptables executable.
467 */ 479 *
468 public String getIptables() throws IOException, RootToolsException, TimeoutExc eption 480 * @throws FileNotFoundException If iptables initialization failed due to prov ided reasons.
Felix Dahlke 2012/11/08 16:37:50 Bean convention again: Can you think of another pr
Andrey Novikov 2012/11/12 08:53:12 Done.
481 */
482 private void initIptables() throws IOException, RootToolsException, TimeoutExc eption, FileNotFoundException
469 { 483 {
470 if (!RootTools.isAccessGiven()) 484 if (!RootTools.isAccessGiven())
471 return null; 485 throw new FileNotFoundException("No root access");
472 486
473 File ipt = getFileStreamPath("iptables"); 487 File ipt = getFileStreamPath("iptables");
474 488
475 if (!ipt.exists()) 489 if (!ipt.exists())
476 return null; 490 {
Felix Dahlke 2012/11/08 16:37:50 I think this is worth some logging, would help deb
Andrey Novikov 2012/11/09 09:23:47 Done.
477 491 Log.e(TAG, "No iptables excutable found");
492 throw new FileNotFoundException("No iptables executable");
493 }
494
478 String path = ipt.getAbsolutePath(); 495 String path = ipt.getAbsolutePath();
479 496
480 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT); 497 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT);
Andrey Novikov 2012/11/09 09:23:47 We do not want any others to be able to execute it
Felix Dahlke 2012/11/09 14:40:46 See above, I thought it was using a system wide ex
481 498
482 boolean compatible = false; 499 boolean compatible = false;
483 boolean version = false; 500 boolean version = false;
484 501
485 String command = path + " --version\n" + path + " -L -t nat -n\n"; 502 String command = path + " --version\n" + path + " -L -t nat -n\n";
486 503
487 List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT); 504 List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT);
488 for (String line : result) 505 for (String line : result)
489 { 506 {
490 if (line.contains("OUTPUT")) 507 if (line.contains("OUTPUT"))
491 compatible = true; 508 compatible = true;
492 if (line.contains("v1.4.")) 509 if (line.contains("v1.4."))
493 version = true; 510 version = true;
494 } 511 }
495 512
496 if (!compatible || !version) 513 if (!compatible || !version)
497 return null; 514 {
498 515 Log.e(TAG, "Incompatible iptables excutable");
499 return path; 516 throw new FileNotFoundException("Incompatible iptables excutable");
517 }
518
519 iptables = path;
500 } 520 }
501 521
502 public List<String> getIptablesOutput() 522 public List<String> getIptablesOutput()
503 { 523 {
504 if (iptables == null) 524 if (iptables == null)
505 return null; 525 return null;
506 526
507 String command = iptables + " -L -t nat -n\n"; 527 String command = iptables + " -L -t nat -n\n";
508 try 528 try
509 { 529 {
510 return RootTools.sendShell(command, DEFAULT_TIMEOUT); 530 return RootTools.sendShell(command, DEFAULT_TIMEOUT);
511 } 531 }
512 catch (Exception e) 532 catch (Exception e)
513 { 533 {
514 Log.e(TAG, "Failed to get iptables configuration", e); 534 Log.e(TAG, "Failed to get iptables configuration", e);
515 return null; 535 return null;
516 } 536 }
517 } 537 }
518 538
519 /** 539 /**
520 * Stops no traffic check, optionally resetting notification message. 540 * Stops no traffic check, optionally resetting notification message.
521 * 541 *
522 * @param changeStatus 542 * @param changeStatus
523 * true if notification message should me set to normal operating 543 * true if notification message should be set to normal operating
524 * mode 544 * mode
525 */ 545 */
526 private void stopNoTrafficCheck(boolean changeStatus) 546 private void stopNoTrafficCheck(boolean changeStatus)
527 { 547 {
528 if (notrafficHandler != null) 548 if (notrafficHandler != null)
529 { 549 {
530 notrafficHandler.removeCallbacks(noTraffic); 550 notrafficHandler.removeCallbacks(noTraffic);
531 if (changeStatus) 551 if (changeStatus)
532 { 552 {
533 NotificationManager notificationManager = (NotificationManager) getSyste mService(NOTIFICATION_SERVICE); 553 NotificationManager notificationManager = (NotificationManager) getSyste mService(NOTIFICATION_SERVICE);
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
613 String action = intent.getAction(); 633 String action = intent.getAction();
614 Log.i(TAG, "Action: " + action); 634 Log.i(TAG, "Action: " + action);
615 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) 635 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action))
616 { 636 {
617 NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_N ETWORK_INFO); 637 NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_N ETWORK_INFO);
618 String typeName = info.getTypeName(); 638 String typeName = info.getTypeName();
619 String subtypeName = info.getSubtypeName(); 639 String subtypeName = info.getSubtypeName();
620 boolean available = info.isAvailable(); 640 boolean available = info.isAvailable();
621 Log.i(TAG, "Network Type: " + typeName + ", subtype: " + subtypeName + " , available: " + available); 641 Log.i(TAG, "Network Type: " + typeName + ", subtype: " + subtypeName + " , available: " + available);
622 if (info.getType() == ConnectivityManager.TYPE_WIFI) 642 if (info.getType() == ConnectivityManager.TYPE_WIFI)
623 ProxySettings.setConnectionProxy(getApplicationContext(), "127.0.0.1", port, ""); 643 ProxySettings.setConnectionProxy(getApplicationContext(), LOCALHOST, p ort, "");
624 } 644 }
625 else if ("android.net.wifi.LINK_CONFIGURATION_CHANGED".equals(action)) 645 else if ("android.net.wifi.LINK_CONFIGURATION_CHANGED".equals(action))
626 { 646 {
627 Object lp = intent.getParcelableExtra("linkProperties"); 647 Object lp = intent.getParcelableExtra("linkProperties");
628 Method method; 648 Method method;
629 try 649 try
630 { 650 {
631 /* 651 /*
632 * lp.getHttpProxy(); 652 * lp.getHttpProxy();
633 */ 653 */
634 method = lp.getClass().getMethod("getHttpProxy"); 654 method = lp.getClass().getMethod("getHttpProxy");
635 Object pp = method.invoke(lp); 655 Object pp = method.invoke(lp);
636 656
637 String[] userProxy = ProxySettings.getUserProxy(pp); 657 String[] userProxy = ProxySettings.getUserProxy(pp);
638 if (userProxy != null && Integer.valueOf(userProxy[1]) != port) 658 if (userProxy != null && Integer.valueOf(userProxy[1]) != port)
639 { 659 {
640 Log.i(TAG, "User has set new proxy: " + userProxy[0] + ":" + userPro xy[1] + "(" + userProxy[2] + ")"); 660 Log.i(TAG, "User has set new proxy: " + userProxy[0] + ":" + userPro xy[1] + "(" + userProxy[2] + ")");
641 if (proxy != null) 661 if (proxy != null)
642 { 662 {
643 configureUserProxy(proxy.props, userProxy[0], userProxy[1], userPr oxy[2], null, null); 663 configureUserProxy(proxy.props, userProxy[0], userProxy[1], userPr oxy[2], null, null);
644 proxy.restart(proxy.props.getProperty("handler")); 664 proxy.restart(proxy.props.getProperty("handler"));
645 } 665 }
646 } 666 }
647 } 667 }
648 catch (Exception e) 668 catch (Exception e)
649 { 669 {
650 // This should not happen 670 // This should not happen
651 e.printStackTrace(); 671 Log.e(TAG, null, e);
652 } 672 }
653 673
654 } 674 }
655 } 675 }
656 }; 676 };
657 677
658 final class ProxyServer extends Server 678 final class ProxyServer extends Server
659 { 679 {
660 @Override 680 @Override
661 public void close() 681 public void close()
662 { 682 {
663 try 683 try
664 { 684 {
665 listen.close(); 685 listen.close();
666 this.interrupt(); 686 this.interrupt();
667 this.join(); 687 this.join();
668 } 688 }
669 catch (Exception e) 689 catch (Exception e)
670 { 690 {
Felix Dahlke 2012/11/08 16:37:50 Logging or a comment?
691 // ignore - it always happens
671 } 692 }
672 log(LOG_WARNING, null, "server stopped"); 693 log(LOG_WARNING, null, "server stopped");
673 } 694 }
674 695
675 @Override 696 @Override
676 public void log(int level, Object obj, String message) 697 public void log(int level, Object obj, String message)
677 { 698 {
678 if (level <= logLevel) 699 if (level <= logLevel)
679 { 700 {
680 Log.println(7 - level, obj != null ? obj.toString() : TAG, message); 701 Log.println(7 - level, obj != null ? obj.toString() : TAG, message);
681 } 702 }
682 } 703 }
683 } 704 }
684 } 705 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld