Support for making requests to Mojang from different IPv4 addresses

(Related #27)
This commit is contained in:
games647
2016-06-20 13:52:37 +02:00
parent 0d89614f3c
commit 6faf00e1bf
13 changed files with 166 additions and 26 deletions
@@ -0,0 +1,80 @@
package com.github.games647.fastlogin.core;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.net.ssl.SSLSocketFactory;
public class BalancedSSLFactory extends SSLSocketFactory {
private final SSLSocketFactory oldFactory;
//in order to be thread-safe
private final List<InetAddress> localAddresses;
private final Object lock = new Object();
private int id;
public BalancedSSLFactory(SSLSocketFactory oldFactory, Set<InetAddress> localAddresses) {
this.oldFactory = oldFactory;
this.localAddresses = new ArrayList<>(localAddresses);
}
@Override
public String[] getDefaultCipherSuites() {
return oldFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return oldFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoclose) throws IOException {
return oldFactory.createSocket(host, port, getNextLocalAddress(), 0);
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return oldFactory.createSocket(host, port, getNextLocalAddress(), 0);
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort)
throws IOException, UnknownHostException {
//default
return oldFactory.createSocket(host, port, localAddress, localPort);
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return oldFactory.createSocket(host, port, getNextLocalAddress(), 0);
}
@Override
public Socket createSocket(InetAddress host, int port, InetAddress local, int localPort) throws IOException {
//Default
return oldFactory.createSocket(host, port, local, localPort);
}
private InetAddress getNextLocalAddress() {
int next;
synchronized (lock) {
next = id;
id++;
if (next == Integer.MAX_VALUE) {
id = 0;
}
}
int index = next % localAddresses.size();
return localAddresses.get(index);
}
}
@@ -4,11 +4,18 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.regex.Pattern;
import javax.net.ssl.HttpsURLConnection;
public abstract class MojangApiConnector {
//http connection, read timeout and user agent for a connection to mojang api servers
@@ -23,10 +30,33 @@ public abstract class MojangApiConnector {
//compile the pattern only on plugin enable -> and this have to be threadsafe
private final Pattern playernameMatcher = Pattern.compile(VALID_PLAYERNAME);
private final BalancedSSLFactory sslFactory;
protected final FastLoginCore plugin;
public MojangApiConnector(FastLoginCore plugin) {
public MojangApiConnector(FastLoginCore plugin, List<String> localAddresses) {
this.plugin = plugin;
if (localAddresses.isEmpty()) {
this.sslFactory = null;
} else {
Set<InetAddress> addresses = new HashSet<>();
for (String localAddress : localAddresses) {
try {
InetAddress address = InetAddress.getByName(localAddress);
if (!address.isAnyLocalAddress()) {
plugin.getLogger().log(Level.WARNING, "Submitted IP-Address is not local", address);
continue;
}
addresses.add(address);
} catch (UnknownHostException ex) {
plugin.getLogger().log(Level.SEVERE, "IP-Address is unknown to us", ex);
}
}
this.sslFactory = new BalancedSSLFactory(HttpsURLConnection.getDefaultSSLSocketFactory(), addresses);
}
}
/**
@@ -39,7 +69,7 @@ public abstract class MojangApiConnector {
if (playernameMatcher.matcher(playerName).matches()) {
//only make a API call if the name is valid existing mojang account
try {
HttpURLConnection connection = getConnection(UUID_LINK + playerName);
HttpsURLConnection connection = getConnection(UUID_LINK + playerName);
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = reader.readLine();
@@ -61,14 +91,18 @@ public abstract class MojangApiConnector {
protected abstract UUID getUUIDFromJson(String json);
protected HttpURLConnection getConnection(String url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
protected HttpsURLConnection getConnection(String url) throws IOException {
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setConnectTimeout(TIMEOUT);
connection.setReadTimeout(2 * TIMEOUT);
//the new Mojang API just uses json as response
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("User-Agent", USER_AGENT);
if (sslFactory != null) {
connection.setSSLSocketFactory(sslFactory);
}
return connection;
}
}
+16
View File
@@ -106,6 +106,22 @@ forwardSkin: true
# If they still want to invoke the command, they have to invoke /premium again
premium-warning: true
# If you have autoRegister or nameChangeCheck enabled, you could be rate-limited by Mojang.
# The requests of the both options will be only made by FastLogin if the username is unknown to the server
# You are allowed to make 600 requests per 10-minutes (60 per minute)
# If you own a big server this value could be too low
# Once the limit is reached, new players are always logged in as cracked until the rate-limit is expired.
# (to the next ten minutes)
#
# The limit is IP-wide. If you have multiple IPv4-Addreses you specify them here. FastLogin will then use it in rotating
# order --> 5 different IP-addreses 5 * 600 per 10 minutes
# If this list is empty only the default one will be used
#
# Lists are created like this:
#ip-addresses:
# - 192-168-0-2
ip-addresses: []
# Database configuration
# Recommened is the use of MariaDB (a better version of MySQL)