// Copyright 2000-2005 the Contributors, as shown in the revision logs. // Licensed under the Apache Public Source License 2.0 ("the License"). // You may not use this file except in compliance with the License. package org.ibex.js; import java.net.*; import java.io.*; import java.util.*; import java.net.*; import org.ibex.util.*; import org.ibex.net.*; import org.ibex.crypto.*; public class ProxyAutoConfig { public static class PacProxy extends HTTP.Proxy { private final JS pacFunc; public PacProxy(JS pacFunc) { this.pacFunc = pacFunc; } public Socket attempt(String url, String host, HTTP http) { if (Log.verbose) Log.info(this, "evaluating PAC script"); String pac = null; try { pac = JSU.toString(pacFunc.call(null, new JS[] { JSU.S(url), JSU.S(host) })); if (Log.verbose) Log.info(this, " PAC script returned \"" + pac + "\""); } catch (Throwable e) { if (Log.on) Log.info(this, "PAC script threw exception " + e); return null; } StringTokenizer st = new StringTokenizer(pac, ";", false); while (st.hasMoreTokens()) { String token = st.nextToken().trim(); if (Log.verbose) Log.info(this, " trying \"" + token + "\"..."); try { Socket ret = null; if (token.startsWith("DIRECT")) ret = attemptDirect(http); else if (token.startsWith("PROXY")) ret = attemptHttpProxy(http, token.substring(token.indexOf(' ') + 1, token.indexOf(':')), Integer.parseInt(token.substring(token.indexOf(':') + 1))); else if (token.startsWith("SOCKS")) ret = attemptSocksProxy(http, token.substring(token.indexOf(' ') + 1, token.indexOf(':')), Integer.parseInt(token.substring(token.indexOf(':') + 1))); if (ret != null) return ret; } catch (Throwable e) { if (Log.on) Log.info(this, "attempt at \"" + token + "\" failed due to " + e + "; trying next token"); } } if (Log.on) Log.info(this, "all PAC results exhausted"); return null; } } public static class ProxyAutoConfigRootScope extends JSScope.Global { public ProxyAutoConfigRootScope() { super(); } private final static JS.Method METHOD = new JS.Method(); public JS get(JS name) throws JSExn { //#jsswitch(name) case "isPlainHostName": return METHOD; case "dnsDomainIs": return METHOD; case "localHostOrDomainIs": return METHOD; case "isResolvable": return METHOD; case "isInNet": return METHOD; case "dnsResolve": return METHOD; case "myIpAddress": return METHOD; case "dnsDomainLevels": return METHOD; case "shExpMatch": return METHOD; case "weekdayRange": return METHOD; case "dateRange": return METHOD; case "timeRange": return METHOD; case "ProxyConfig": return ProxyConfig; //#end return super.get(name); } private static final JS proxyConfigBindings = new JS.Obj(); private static final JS ProxyConfig = new JS.Obj() { public JS get(JS name) throws JSExn { //#jsswitch(name) case "bindings": return proxyConfigBindings; //#end return null; } }; public JS call(JS method, JS[] args) throws JSExn { //#jsswitch(method) case "isPlainHostName": return JSU.B(JSU.toString(args[0]).indexOf('.') == -1); case "dnsDomainIs": return JSU.B(JSU.toString(args[0]).endsWith(JSU.toString(args[1]))); case "localHostOrDomainIs": return JSU.B(args[0].equals(args[1]) || (JSU.toString(args[0]).indexOf('.') == -1 && JSU.toString(args[1]).startsWith(JSU.toString(args[0])))); case "isResolvable": try { return JSU.B(InetAddress.getByName(JSU.toString(args[0])) != null); } catch (UnknownHostException e) { return JSU.F; } case "isInNet": if (args.length != 3) return JSU.F; try { byte[] host = InetAddress.getByName(JSU.toString(args[0])).getAddress(); byte[] net = InetAddress.getByName(JSU.toString(args[1])).getAddress(); byte[] mask = InetAddress.getByName(args[2].toString()).getAddress(); return JSU.B((host[0] & mask[0]) == net[0] && (host[1] & mask[1]) == net[1] && (host[2] & mask[2]) == net[2] && (host[3] & mask[3]) == net[3]); } catch (Exception e) { throw new JSExn("exception in isInNet(): " + e); } case "dnsResolve": try { return JSU.S(InetAddress.getByName(JSU.toString(args[0])).getHostAddress()); } catch (UnknownHostException e) { return null; } case "myIpAddress": try { return JSU.S(InetAddress.getLocalHost().getHostAddress()); } catch (UnknownHostException e) { if (Log.on) Log.info(this, "strange... host does not know its own address"); return null; } case "dnsDomainLevels": String s = JSU.toString(args[0]); int i = 0; while((i = s.indexOf('.', i)) != -1) i++; return JSU.N(i); case "shExpMatch": StringTokenizer st = new StringTokenizer(JSU.toString(args[1]), "*", false); String[] arr = new String[st.countTokens()]; String s = JSU.toString(args[0]); for (int i=0; st.hasMoreTokens(); i++) arr[i] = st.nextToken(); return JSU.B(match(arr, s, 0)); case "weekdayRange": TimeZone tz = (args.length < 3 || args[2] == null || !args[2].equals("GMT")) ? TimeZone.getTimeZone("UTC") : TimeZone.getDefault(); Calendar c = new GregorianCalendar(); c.setTimeZone(tz); c.setTime(new java.util.Date()); java.util.Date d = c.getTime(); int day = d.getDay(); String d1s = JSU.toString(args[0]).toUpperCase(); int d1 = 0, d2 = 0; for(int i=0; i= d1 && day <= d2) || (d1 > d2 && (day >= d1 || day <= d2))); case "dateRange": throw new JSExn("Ibex does not support dateRange() in PAC scripts"); case "timeRange": throw new JSExn("Ibex does not support timeRange() in PAC scripts"); //#end return super.call(method, args); } private static boolean match(String[] arr, String s, int index) { if (index >= arr.length) return true; for(int i=0; i