Search in sources :

Example 1 with TrackerException

use of com.biglybt.pif.tracker.TrackerException in project BiglyBT by BiglySoftware.

the class RPTracker method _process.

@Override
public RPReply _process(RPRequest request) {
    String method = request.getMethod();
    Object[] params = request.getParams();
    if (method.equals("host[Torrent,boolean]")) {
        try {
            Torrent torrent = params[0] == null ? null : (Torrent) ((RPTorrent) params[0])._setLocal();
            if (torrent == null) {
                throw (new RPException("Invalid torrent"));
            }
            TrackerTorrent tt = delegate.host(torrent, ((Boolean) params[1]).booleanValue());
            RPTrackerTorrent res = RPTrackerTorrent.create(tt);
            return (new RPReply(res));
        } catch (TrackerException e) {
            return (new RPReply(e));
        }
    } else if (method.equals("getTorrents")) {
        TrackerTorrent[] torrents = delegate.getTorrents();
        RPTrackerTorrent[] res = new RPTrackerTorrent[torrents.length];
        for (int i = 0; i < res.length; i++) {
            res[i] = RPTrackerTorrent.create(torrents[i]);
        }
        return (new RPReply(res));
    }
    throw (new RPException("Unknown method: " + method));
}
Also used : TrackerException(com.biglybt.pif.tracker.TrackerException) RPTorrent(com.biglybt.pifimpl.remote.torrent.RPTorrent) Torrent(com.biglybt.pif.torrent.Torrent) TrackerTorrent(com.biglybt.pif.tracker.TrackerTorrent) TrackerTorrent(com.biglybt.pif.tracker.TrackerTorrent) RPException(com.biglybt.pifimpl.remote.RPException) RPTorrent(com.biglybt.pifimpl.remote.torrent.RPTorrent) RPReply(com.biglybt.pifimpl.remote.RPReply) RPObject(com.biglybt.pifimpl.remote.RPObject)

Example 2 with TrackerException

use of com.biglybt.pif.tracker.TrackerException in project BiglyBT by BiglySoftware.

the class WebPlugin method setupServer.

protected void setupServer() {
    try {
        if (!plugin_enabled) {
            if (tracker_context != null) {
                tracker_context.destroy();
                tracker_context = null;
            }
            return;
        }
        final int port = param_port.getValue();
        String protocol_str = param_protocol.getValue().trim();
        String bind_str = param_bind.getValue().trim();
        InetAddress bind_ip = null;
        if (bind_str.length() > 0) {
            try {
                bind_ip = InetAddress.getByName(bind_str);
            } catch (Throwable e) {
            }
            if (bind_ip == null) {
                // might be an interface name, see if we can resolve it
                final NetworkAdmin na = NetworkAdmin.getSingleton();
                InetAddress[] addresses = na.resolveBindAddresses(bind_str);
                if (addresses.length > 0) {
                    bind_ip = addresses[0];
                    if (!na_intf_listener_added) {
                        na_intf_listener_added = true;
                        na.addPropertyChangeListener(new NetworkAdminPropertyChangeListener() {

                            @Override
                            public void propertyChanged(String property) {
                                if (unloaded) {
                                    na.removePropertyChangeListener(this);
                                } else {
                                    if (property == NetworkAdmin.PR_NETWORK_INTERFACES) {
                                        new AEThread2("setupserver") {

                                            @Override
                                            public void run() {
                                                setupServer();
                                            }
                                        }.start();
                                    }
                                }
                            }
                        });
                    }
                }
            }
            if (bind_ip == null) {
                log.log(LoggerChannel.LT_ERROR, "Bind IP parameter '" + bind_str + "' is invalid");
            }
        }
        if (tracker_context != null) {
            URL url = tracker_context.getURLs()[0];
            String existing_protocol = url.getProtocol();
            int existing_port = url.getPort() == -1 ? url.getDefaultPort() : url.getPort();
            InetAddress existing_bind_ip = tracker_context.getBindIP();
            if (existing_port == port && existing_protocol.equalsIgnoreCase(protocol_str) && sameAddress(bind_ip, existing_bind_ip)) {
                return;
            }
            tracker_context.destroy();
            tracker_context = null;
        }
        int protocol = protocol_str.equalsIgnoreCase("HTTP") ? Tracker.PR_HTTP : Tracker.PR_HTTPS;
        Map<String, Object> tc_properties = new HashMap<>();
        Boolean prop_non_blocking = (Boolean) properties.get(PR_NON_BLOCKING);
        if (prop_non_blocking != null && prop_non_blocking) {
            tc_properties.put(Tracker.PR_NON_BLOCKING, true);
        }
        log.log(LoggerChannel.LT_INFORMATION, "Server initialisation: port=" + port + (bind_ip == null ? "" : (", bind=" + bind_str + "->" + bind_ip + ")")) + ", protocol=" + protocol_str + (root_dir.length() == 0 ? "" : (", root=" + root_dir)) + (properties.size() == 0 ? "" : (", props=" + properties)));
        tracker_context = plugin_interface.getTracker().createWebContext(Constants.APP_NAME + " - " + plugin_interface.getPluginName(), port, protocol, bind_ip, tc_properties);
        Boolean prop_enable_i2p = (Boolean) properties.get(PR_ENABLE_I2P);
        if (prop_enable_i2p == null || prop_enable_i2p) {
            network_dispatcher.dispatch(new AERunnable() {

                @Override
                public void runSupport() {
                    Map<String, Object> options = new HashMap<>();
                    options.put(AEProxyFactory.SP_PORT, port);
                    Map<String, Object> reply = AEProxyFactory.getPluginServerProxy(plugin_interface.getPluginName(), AENetworkClassifier.AT_I2P, plugin_interface.getPluginID(), options);
                    if (reply != null) {
                        param_i2p_dest.setVisible(true);
                        String host = (String) reply.get("host");
                        if (!param_i2p_dest.getValue().equals(host)) {
                            param_i2p_dest.setValue(host);
                            if (p_sid != null) {
                                updatePairing(p_sid);
                            }
                        }
                    }
                }
            });
        }
        Boolean prop_enable_tor = (Boolean) properties.get(PR_ENABLE_TOR);
        if (prop_enable_tor == null || prop_enable_tor) {
            network_dispatcher.dispatch(new AERunnable() {

                @Override
                public void runSupport() {
                    Map<String, Object> options = new HashMap<>();
                    options.put(AEProxyFactory.SP_PORT, port);
                    Map<String, Object> reply = AEProxyFactory.getPluginServerProxy(plugin_interface.getPluginName(), AENetworkClassifier.AT_TOR, plugin_interface.getPluginID(), options);
                    if (reply != null) {
                        param_tor_dest.setVisible(true);
                        String host = (String) reply.get("host");
                        if (!param_tor_dest.getValue().equals(host)) {
                            param_tor_dest.setValue(host);
                            if (p_sid != null) {
                                updatePairing(p_sid);
                            }
                        }
                    }
                }
            });
        }
        Boolean pr_enable_keep_alive = (Boolean) properties.get(PR_ENABLE_KEEP_ALIVE);
        if (pr_enable_keep_alive != null && pr_enable_keep_alive) {
            tracker_context.setEnableKeepAlive(true);
        }
        tracker_context.addPageGenerator(this);
        tracker_context.addAuthenticationListener(new TrackerAuthenticationAdapter() {

            private String last_pw = "";

            private byte[] last_hash = {};

            private final int DELAY = 10 * 1000;

            private Map<String, Object[]> fail_map = new HashMap<>();

            @Override
            public boolean authenticate(String headers, URL resource, String user, String pw) {
                // System.out.println( resource + ": " + user + "/" + pw );
                long now = SystemTime.getMonotonousTime();
                String client_address = getHeaderField(headers, "X-Real-IP");
                if (client_address == null) {
                    client_address = "<unknown>";
                }
                synchronized (logout_timer) {
                    Long logout_time = logout_timer.get(client_address);
                    if (logout_time != null && now - logout_time <= LOGOUT_GRACE_MILLIS) {
                        tls.set(GRACE_PERIOD_MARKER);
                        return (true);
                    }
                }
                boolean result = authenticateSupport(headers, resource, user, pw);
                if (!result) {
                    if (!pw.equals("")) {
                        AESemaphore waiter = null;
                        synchronized (fail_map) {
                            Object[] x = fail_map.get(client_address);
                            if (x == null) {
                                x = new Object[] { new AESemaphore("af:waiter"), new Long(-1), new Long(-1), now };
                                fail_map.put(client_address, x);
                            } else {
                                x[1] = x[2];
                                x[2] = x[3];
                                x[3] = now;
                                long t = (Long) x[1];
                                if (now - t < 10 * 1000) {
                                    log("Too many recent authentication failures from '" + client_address + "' - rate limiting");
                                    x[2] = now + DELAY;
                                    // there's a bug where flipping the password on doesn't reset the pw so we automatically fail without checking
                                    // this is not the correct fix, but it works
                                    last_pw = "";
                                    waiter = (AESemaphore) x[0];
                                }
                            }
                        }
                        if (waiter != null) {
                            waiter.reserve(DELAY);
                        }
                    }
                } else {
                    synchronized (fail_map) {
                        fail_map.remove(client_address);
                    }
                    String cookies = getHeaderField(headers, "Cookie");
                    if (pairing_session_code != null) {
                        if (cookies == null || !cookies.contains(pairing_session_code)) {
                            tls.set(pairing_session_code);
                        }
                    }
                }
                recordAuthRequest(client_address, result);
                if (!result) {
                // going to be generous here as (old android browsers at least) sometimes fail to provide
                // auth on .png files
                // no I'm not, too many risks associated with this (e.g. xmwebui has some
                // prefix url logic which may be exploitable)
                // if ( resource.getPath().endsWith( ".png" )){
                // 
                // result = true;
                // }
                }
                return (result);
            }

            private boolean authenticateSupport(String headers, URL resource, String user, String pw) {
                boolean result;
                boolean auto_auth = param_auto_auth != null && param_auto_auth.getValue();
                if (!pw_enable.getValue()) {
                    String whitelist = p_no_pw_whitelist.getValue().trim();
                    if (whitelist.equals("*")) {
                        result = true;
                    } else {
                        String actual_host = getHeaderField(headers, "host");
                        int actual_port = protocol == Tracker.PR_HTTP ? 80 : 443;
                        String referrer = getHeaderField(headers, "referer");
                        if (actual_host.startsWith("[")) {
                            int pos = actual_host.lastIndexOf(']');
                            if (pos != -1) {
                                String rem = actual_host.substring(pos + 1);
                                actual_host = actual_host.substring(0, pos + 1);
                                pos = rem.indexOf(':');
                                if (pos != -1) {
                                    actual_port = Integer.parseInt(rem.substring(pos + 1).trim());
                                }
                            }
                        } else {
                            int pos = actual_host.indexOf(':');
                            if (pos != -1) {
                                actual_port = Integer.parseInt(actual_host.substring(pos + 1).trim());
                                actual_host = actual_host.substring(0, pos);
                            }
                        }
                        String[] allowed = whitelist.split(",");
                        result = false;
                        String msg = "";
                        if (actual_port != port) {
                            msg = "port mismatch: " + port + "/" + actual_port;
                        } else {
                            for (String a : allowed) {
                                a = a.trim();
                                if (a.equals("$")) {
                                    InetAddress bind = getServerBindIP();
                                    if (bind != null) {
                                        if (bind instanceof Inet6Address) {
                                            a = "[" + bind.getHostAddress() + "]";
                                        } else {
                                            a = bind.getHostAddress();
                                        }
                                    }
                                }
                                if (actual_host.equals(a.trim())) {
                                    result = true;
                                    break;
                                }
                                // Support ranges (copied from code in setupAccess)
                                IPRange ip_range = plugin_interface.getIPFilter().createRange(true);
                                String aTrimmed = a.trim();
                                int sep = aTrimmed.indexOf("-");
                                if (sep == -1) {
                                    ip_range.setStartIP(aTrimmed);
                                    ip_range.setEndIP(aTrimmed);
                                } else {
                                    ip_range.setStartIP(aTrimmed.substring(0, sep).trim());
                                    ip_range.setEndIP(aTrimmed.substring(sep + 1).trim());
                                }
                                ip_range.checkValid();
                                if (ip_range.isValid() && ip_range.isInRange(actual_host)) {
                                    result = true;
                                    break;
                                }
                            }
                            if (!result) {
                                msg = "host '" + actual_host + "' not in whitelist";
                            } else {
                                if (referrer != null) {
                                    result = false;
                                    try {
                                        URL url = new URL(referrer);
                                        int ref_port = url.getPort();
                                        if (ref_port == -1) {
                                            ref_port = url.getDefaultPort();
                                        }
                                        if (ref_port == port) {
                                            result = true;
                                        }
                                    } catch (Throwable e) {
                                    }
                                    if (!result) {
                                        msg = "referrer mismatch: " + referrer;
                                    }
                                }
                            }
                        }
                        if (!result) {
                            log.log("Access denied: No password and " + msg);
                        }
                    }
                } else {
                    if (auto_auth) {
                        user = user.trim().toLowerCase();
                        pw = pw.toUpperCase();
                    }
                    if (!user.equals(p_user_name.getValue())) {
                        log.log("Access denied: Incorrect user name: " + user);
                        result = false;
                    } else {
                        byte[] hash = last_hash;
                        if (!last_pw.equals(pw)) {
                            hash = plugin_interface.getUtilities().getSecurityManager().calculateSHA1(auto_auth ? pw.toUpperCase().getBytes() : pw.getBytes());
                            last_pw = pw;
                            last_hash = hash;
                        }
                        result = Arrays.equals(hash, p_password.getValue());
                        if (!result) {
                            log.log("Access denied: Incorrect password");
                        }
                    }
                }
                if (result) {
                    // user name and password match, see if we've come from the pairing process
                    checkCookieSet(headers, resource);
                } else if (auto_auth) {
                    // either the ac is in the url, referer or we have a cookie set
                    int x = checkCookieSet(headers, resource);
                    if (x == 1) {
                        result = true;
                    } else if (x == 0) {
                        result = hasOurCookie(getHeaderField(headers, "Cookie"));
                    }
                } else {
                    result = hasOurCookie(getHeaderField(headers, "Cookie"));
                }
                return (result);
            }

            /**
             * @param headers
             * @param resource
             * @return 0 = unknown, 1 = ok, 2 = bad
             */
            private int checkCookieSet(String headers, URL resource) {
                if (pairing_access_code == null) {
                    return (2);
                }
                String[] locations = { resource.getQuery(), getHeaderField(headers, "Referer") };
                for (String location : locations) {
                    if (location != null) {
                        boolean skip_fail = false;
                        int param_len = 0;
                        int p1 = location.indexOf("vuze_pairing_ac=");
                        if (p1 == -1) {
                            p1 = location.indexOf("ac=");
                            if (p1 != -1) {
                                param_len = 3;
                                skip_fail = true;
                            }
                        } else {
                            param_len = 16;
                        }
                        if (p1 != -1) {
                            int p2 = location.indexOf('&', p1);
                            String ac = location.substring(p1 + param_len, p2 == -1 ? location.length() : p2).trim();
                            p2 = ac.indexOf('#');
                            if (p2 != -1) {
                                ac = ac.substring(0, p2);
                            }
                            if (ac.equalsIgnoreCase(pairing_access_code)) {
                                tls.set(pairing_session_code);
                                return (1);
                            } else {
                                if (!skip_fail) {
                                    return (2);
                                }
                            }
                        }
                    }
                }
                return (0);
            }

            private String getHeaderField(String headers, String field) {
                String[] lines = headers.split("\n");
                for (String line : lines) {
                    int pos = line.indexOf(':');
                    if (pos != -1) {
                        if (line.substring(0, pos).equalsIgnoreCase(field)) {
                            return (line.substring(pos + 1).trim());
                        }
                    }
                }
                return (null);
            }
        });
    } catch (TrackerException e) {
        log.log("Server initialisation failed", e);
    }
}
Also used : IPRange(com.biglybt.pif.ipfilter.IPRange) URL(java.net.URL) NetworkAdmin(com.biglybt.core.networkmanager.admin.NetworkAdmin) TrackerException(com.biglybt.pif.tracker.TrackerException) Inet6Address(java.net.Inet6Address) NetworkAdminPropertyChangeListener(com.biglybt.core.networkmanager.admin.NetworkAdminPropertyChangeListener) JSONObject(org.json.simple.JSONObject) InetAddress(java.net.InetAddress)

Example 3 with TrackerException

use of com.biglybt.pif.tracker.TrackerException in project BiglyBT by BiglySoftware.

the class RPTracker method host.

// ************************************************************************
@Override
public TrackerTorrent host(Torrent torrent, boolean persistent) throws TrackerException {
    try {
        RPTrackerTorrent resp = (RPTrackerTorrent) _dispatcher.dispatch(new RPRequest(this, "host[Torrent,boolean]", new Object[] { torrent, Boolean.valueOf(persistent) })).getResponse();
        resp._setRemote(_dispatcher);
        return (resp);
    } catch (RPException e) {
        if (e.getCause() instanceof TrackerException) {
            throw ((TrackerException) e.getCause());
        }
        throw (e);
    }
}
Also used : RPRequest(com.biglybt.pifimpl.remote.RPRequest) TrackerException(com.biglybt.pif.tracker.TrackerException) RPException(com.biglybt.pifimpl.remote.RPException) RPObject(com.biglybt.pifimpl.remote.RPObject)

Aggregations

TrackerException (com.biglybt.pif.tracker.TrackerException)3 RPException (com.biglybt.pifimpl.remote.RPException)2 RPObject (com.biglybt.pifimpl.remote.RPObject)2 NetworkAdmin (com.biglybt.core.networkmanager.admin.NetworkAdmin)1 NetworkAdminPropertyChangeListener (com.biglybt.core.networkmanager.admin.NetworkAdminPropertyChangeListener)1 IPRange (com.biglybt.pif.ipfilter.IPRange)1 Torrent (com.biglybt.pif.torrent.Torrent)1 TrackerTorrent (com.biglybt.pif.tracker.TrackerTorrent)1 RPReply (com.biglybt.pifimpl.remote.RPReply)1 RPRequest (com.biglybt.pifimpl.remote.RPRequest)1 RPTorrent (com.biglybt.pifimpl.remote.torrent.RPTorrent)1 Inet6Address (java.net.Inet6Address)1 InetAddress (java.net.InetAddress)1 URL (java.net.URL)1 JSONObject (org.json.simple.JSONObject)1