Clientinit is finally being accepted

[DEBUG] error id=525 msg=client\sis\smodified
This commit is contained in:
Manevolent
2018-07-27 13:27:40 -04:00
parent 7c1d0dfa4e
commit 146f2b6564
6 changed files with 47 additions and 44 deletions
@@ -151,6 +151,8 @@ public class LocalClientHandlerConnecting extends LocalClientHandler {
} else if (packet.getBody() instanceof PacketBody2Command) { } else if (packet.getBody() instanceof PacketBody2Command) {
SimpleCommand command = ((PacketBody2Command) packet.getBody()).parse(); SimpleCommand command = ((PacketBody2Command) packet.getBody()).parse();
Ts3Debugging.debug(command.build());
if (command.getName().equalsIgnoreCase("initivexpand2")) { if (command.getName().equalsIgnoreCase("initivexpand2")) {
// 3.2.2 initivexpand2 (Client <- Server) // 3.2.2 initivexpand2 (Client <- Server)
@@ -160,9 +162,9 @@ public class LocalClientHandlerConnecting extends LocalClientHandler {
throw new IllegalArgumentException("ot constant != 1: " + command.get("ot").getValue()); throw new IllegalArgumentException("ot constant != 1: " + command.get("ot").getValue());
byte[] license = Base64.getDecoder().decode(command.get("l").getValue()); byte[] license = Base64.getDecoder().decode(command.get("l").getValue());
byte[] licsense_validation = !command.has("tvd") ? /*byte[] licsense_validation = !command.has("tvd") && command.get("tvd").getValue() != null ?
null : null :
Base64.getDecoder().decode(command.get("tvd").getValue()); Base64.getDecoder().decode(command.get("tvd").getValue());*/
byte[] beta = Base64.getDecoder().decode(command.get("beta").getValue()); // beta byte[] beta = Base64.getDecoder().decode(command.get("beta").getValue()); // beta
byte[] omega = Base64.getDecoder().decode(command.get("omega").getValue()); // omega byte[] omega = Base64.getDecoder().decode(command.get("omega").getValue()); // omega
@@ -187,29 +189,19 @@ public class LocalClientHandlerConnecting extends LocalClientHandler {
Ts3Debugging.debug("Sending clientek..."); Ts3Debugging.debug("Sending clientek...");
PacketBody2Command clientek = new PacketBody2Command(ProtocolRole.CLIENT); getClient().sendCommand(
clientek.setText(
new SimpleCommand( new SimpleCommand(
"clientek", ProtocolRole.CLIENT, "clientek", ProtocolRole.CLIENT,
new CommandSingleParameter("ek", Base64.getEncoder().encodeToString(keyPair.getKey())), new CommandSingleParameter("ek", Base64.getEncoder().encodeToString(keyPair.getKey())),
new CommandSingleParameter("proof", Base64.getEncoder().encodeToString(signature)) new CommandSingleParameter("proof", Base64.getEncoder().encodeToString(signature))
).build() )
); );
Ts3Debugging.debug(clientek.getText()); getClient().setSecureParameters(Ts3Crypt.cryptoInit2(license, alphaBytes, beta, keyPair.getValue()));
getClient().writePacket(clientek);
getClient().setSecureParameters(
Ts3Crypt.cryptoInit2(license, alphaBytes, omega, proof, beta, keyPair.getValue())
);
Ts3Debugging.debug("Sending clientinit..."); Ts3Debugging.debug("Sending clientinit...");
PacketBody2Command clientinit = new PacketBody2Command(ProtocolRole.CLIENT); getClient().sendCommand(new SimpleCommand(
clientinit.setText(
new SimpleCommand(
"clientinit", "clientinit",
ProtocolRole.CLIENT, ProtocolRole.CLIENT,
new CommandSingleParameter("client_nickname", "test"), new CommandSingleParameter("client_nickname", "test"),
@@ -235,12 +227,8 @@ public class LocalClientHandlerConnecting extends LocalClientHandler {
"hwid", "hwid",
"+LyYqbDqOvJJpN5pdAbF8/v5kZ0=" "+LyYqbDqOvJJpN5pdAbF8/v5kZ0="
) )
).build() )
); );
Ts3Debugging.debug(clientinit.getText());
getClient().writePacket(clientinit);
} }
} }
} }
@@ -5,6 +5,7 @@ import com.github.manevolent.ts3j.command.response.CommandResponse;
import com.github.manevolent.ts3j.identity.Identity; import com.github.manevolent.ts3j.identity.Identity;
import com.github.manevolent.ts3j.protocol.NetworkPacket; import com.github.manevolent.ts3j.protocol.NetworkPacket;
import com.github.manevolent.ts3j.protocol.Packet; import com.github.manevolent.ts3j.protocol.Packet;
import com.github.manevolent.ts3j.protocol.ProtocolRole;
import com.github.manevolent.ts3j.protocol.SocketRole; import com.github.manevolent.ts3j.protocol.SocketRole;
import com.github.manevolent.ts3j.protocol.client.ClientConnectionState; import com.github.manevolent.ts3j.protocol.client.ClientConnectionState;
import com.github.manevolent.ts3j.protocol.header.ClientPacketHeader; import com.github.manevolent.ts3j.protocol.header.ClientPacketHeader;
@@ -36,9 +37,9 @@ public abstract class AbstractTeamspeakClientSocket
private final Object connectionStateLock = new Object(); private final Object connectionStateLock = new Object();
private final LinkedBlockingDeque<Packet> readQueue = new LinkedBlockingDeque<>(65536); private final LinkedBlockingDeque<Packet> readQueue = new LinkedBlockingDeque<>(65536);
private final Map<PacketBodyType, Reassembly> reassemblyQueue = new LinkedHashMap<>(); private final Map<PacketBodyType, Reassembly> reassemblyQueue = new ConcurrentHashMap<>();
private final Map<String, Object> clientOptions = new LinkedHashMap<>(); private final Map<String, Object> clientOptions = new ConcurrentHashMap<>();
private final Map<Integer, PacketResponse> sendQueue = new LinkedHashMap<>(); private final Map<Integer, PacketResponse> sendQueue = new ConcurrentHashMap<>();
private Identity identity = null; private Identity identity = null;
private ClientConnectionState connectionState = null; private ClientConnectionState connectionState = null;
@@ -153,12 +154,12 @@ public abstract class AbstractTeamspeakClientSocket
} }
/** /**
* Sends a command to the remote server. * Sends a command to the remote.
* @param command Command to send. * @param command Command to send.
* @return Command response object to track command response. * @return Command response object to track command response.
* @throws IOException * @throws IOException
*/ */
public CommandResponse sendCommand(Command command) throws IOException { public CommandResponse sendCommand(Command command) throws IOException, TimeoutException {
if (command.willExpectResponse() && !isConnected()) if (command.willExpectResponse() && !isConnected())
throw new IOException("not connected"); throw new IOException("not connected");
@@ -175,9 +176,12 @@ public abstract class AbstractTeamspeakClientSocket
response.setDispatchedTime(System.currentTimeMillis()); response.setDispatchedTime(System.currentTimeMillis());
writePacket(new PacketBody2Command(ProtocolRole.CLIENT, command));
return response; return response;
} }
@Override @Override
public void writePacket(PacketBody body) throws IOException, TimeoutException { public void writePacket(PacketBody body) throws IOException, TimeoutException {
PacketHeader header; PacketHeader header;
@@ -316,7 +320,7 @@ public abstract class AbstractTeamspeakClientSocket
// Find if the packet must be acknowledged and create a promise for that action // Find if the packet must be acknowledged and create a promise for that action
boolean willAcknowledge = packet.getHeader().getType().getAcknolwedgedBy() != null; boolean willAcknowledge = packet.getHeader().getType().getAcknolwedgedBy() != null;
PacketResponse response; final PacketResponse response;
if (willAcknowledge) if (willAcknowledge)
sendQueue.put( sendQueue.put(
@@ -342,15 +346,14 @@ public abstract class AbstractTeamspeakClientSocket
if (getState() == ClientConnectionState.DISCONNECTED) if (getState() == ClientConnectionState.DISCONNECTED)
throw new IllegalStateException("no longer connected"); throw new IllegalStateException("no longer connected");
response.getFuture().get(1000L, TimeUnit.MILLISECONDS); // Wait one cycle for an ACK
response.waitForAcknowledgement(1000);
break; break;
} catch (TimeoutException e) { } catch (TimeoutException e) {
response.resend(); response.resend();
} catch (CancellationException e) { } catch (CancellationException e) {
throw e; throw e;
} catch (InterruptedException e) { } catch (Exception e) {
} catch (ExecutionException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@@ -456,9 +459,11 @@ public abstract class AbstractTeamspeakClientSocket
// Find if the packet is itself an acknowledgement // Find if the packet is itself an acknowledgement
switch (packet.getHeader().getType()) { switch (packet.getHeader().getType()) {
case ACK: case ACK:
int packetId = packet.getHeader().getPacketId(); int packetId = ((PacketBody6Ack)packet.getBody()).getPacketId();
PacketResponse response = sendQueue.get(packetId); PacketResponse response = sendQueue.get(packetId);
if (response != null) response.getFuture().complete(packet); if (response != null) {
response.acknowledge(packet);
}
break; break;
case ACK_LOW: case ACK_LOW:
break; break;
@@ -578,9 +583,9 @@ public abstract class AbstractTeamspeakClientSocket
private class PacketResponse { private class PacketResponse {
private final NetworkPacket sentPacket; private final NetworkPacket sentPacket;
private final CompletableFuture future = new CompletableFuture<>(); private final CompletableFuture<Packet> future = new CompletableFuture<>();
private long lastSent = 0L; private long lastSent = 0L;
private int tries, maxTries; private int tries = 1, maxTries;
private boolean willResend; private boolean willResend;
public PacketResponse(NetworkPacket sentPacket,int maxTries) { public PacketResponse(NetworkPacket sentPacket,int maxTries) {
@@ -596,10 +601,23 @@ public abstract class AbstractTeamspeakClientSocket
public void resend() throws IOException { public void resend() throws IOException {
AbstractTeamspeakClientSocket.this.writeNetworkPacket(sentPacket); AbstractTeamspeakClientSocket.this.writeNetworkPacket(sentPacket);
setLastSent(System.currentTimeMillis());
tries ++; tries ++;
} }
public boolean waitForAcknowledgement()
throws ExecutionException, InterruptedException {
Packet acknowledgement = future.get();
return acknowledgement != null;
}
public boolean waitForAcknowledgement(long millis)
throws TimeoutException, ExecutionException, InterruptedException {
Packet acknowledgement = future.get(millis, TimeUnit.MILLISECONDS);
return acknowledgement != null;
}
public boolean isWillResend() { public boolean isWillResend() {
return willResend; return willResend;
} }
@@ -616,8 +634,8 @@ public abstract class AbstractTeamspeakClientSocket
return lastSent; return lastSent;
} }
public CompletableFuture getFuture() { public void acknowledge(Packet p) {
return future; future.complete(p);
} }
public void setLastSent(long lastSent) { public void setLastSent(long lastSent) {
@@ -102,7 +102,7 @@ public class LocalTeamspeakClientSocket extends AbstractTeamspeakClientSocket {
setGenerationId(0); setGenerationId(0);
setOption("client.hostname", remote.getHostString()); setOption("client.hostname", remote.getHostString());
setOption("client.password", password); //setOption("client.password", password);
socket.connect(remote); socket.connect(remote);
@@ -56,7 +56,6 @@ public final class Ts3Crypt {
} }
public static Ts3Crypt.SecureChannelParameters cryptoInit2(byte[] license, byte[] alpha, public static Ts3Crypt.SecureChannelParameters cryptoInit2(byte[] license, byte[] alpha,
byte[] omega, byte[] proof,
byte[] beta, byte[] privateKey) { byte[] beta, byte[] privateKey) {
// 3.2.2.2 Parsing the license // 3.2.2.2 Parsing the license
List<License> licenses = License.readLicenses(ByteBuffer.wrap(license)); List<License> licenses = License.readLicenses(ByteBuffer.wrap(license));
@@ -15,13 +15,11 @@ public class CryptoInit2Test extends TestCase {
public void testParser() throws Exception { public void testParser() throws Exception {
byte[] licenseBytes = hexStringToByteArray("0100358541498A24ACD30157918B8F50955C0DAE970AB65372CBE407415FCF3E029B02084D15E00AA793600700000020416E6F6E796D6F7573000047D9E4DC25AA2E90ACD4DB5FA61C8FED369B346D84C2CA2FCCCA86F73AFEF092200A77C8810A787141"); byte[] licenseBytes = hexStringToByteArray("0100358541498A24ACD30157918B8F50955C0DAE970AB65372CBE407415FCF3E029B02084D15E00AA793600700000020416E6F6E796D6F7573000047D9E4DC25AA2E90ACD4DB5FA61C8FED369B346D84C2CA2FCCCA86F73AFEF092200A77C8810A787141");
byte[] alpha = hexStringToByteArray("9500A5DB3B50ACECAB81"); byte[] alpha = hexStringToByteArray("9500A5DB3B50ACECAB81");
byte[] omega = hexStringToByteArray("304B03020700020120022025D13CF0C5A17A467961B04418E015941D6C6558DA6AEC79CFFDDA1DEF8AB55202200F3B3F0D3A4F1C5C02AD1F9A3A5114AC58E89905792FBB83AD4FFE7F82ACAADA");
byte[] proof = hexStringToByteArray("3046022100F4B921DDB2C9737D9AB100BA251D11216DF1601C62AF17150E6FC29A2C6EEC0F022100FC8948E595BBD895A2FDFE0EB22A5241655BD47591F8D2733035CF76A72245AD");
byte[] beta = hexStringToByteArray("EAFFC9A8BC996B25C8AA700264E99E372ECCDEB1C121D6EC0F4D49FB46CEEBA4E3C724B3070FD70CB03D7BC08129205690ECE228CA7C"); byte[] beta = hexStringToByteArray("EAFFC9A8BC996B25C8AA700264E99E372ECCDEB1C121D6EC0F4D49FB46CEEBA4E3C724B3070FD70CB03D7BC08129205690ECE228CA7C");
byte[] privateKey = hexStringToByteArray("102E591ABA4508129E812FF3437E2DDD3CA1F1EC341117CA3514CC347A7C2A77"); byte[] privateKey = hexStringToByteArray("102E591ABA4508129E812FF3437E2DDD3CA1F1EC341117CA3514CC347A7C2A77");
Ts3Crypt.SecureChannelParameters result = Ts3Crypt.SecureChannelParameters result =
Ts3Crypt.cryptoInit2(licenseBytes, alpha, omega, proof, beta, privateKey); Ts3Crypt.cryptoInit2(licenseBytes, alpha, beta, privateKey);
assertEquals(Ts3Debugging.getHex(result.getIvStruct()), "E4082A92F71C96A947452F5582EF2879B2051ED2D3F2C6B0643CF5A266EE6B5180573C2F5F3F1C4AC579188366F16AE0EADC3AAF860805D8F2A831E9E49F4513"); assertEquals(Ts3Debugging.getHex(result.getIvStruct()), "E4082A92F71C96A947452F5582EF2879B2051ED2D3F2C6B0643CF5A266EE6B5180573C2F5F3F1C4AC579188366F16AE0EADC3AAF860805D8F2A831E9E49F4513");
assertEquals(Ts3Debugging.getHex(result.getFakeSignature()), "54F2B4D661E0F9AB"); assertEquals(Ts3Debugging.getHex(result.getFakeSignature()), "54F2B4D661E0F9AB");
@@ -29,7 +29,7 @@ public class ServerConnectionTest {
client.setIdentity(localIdentity); client.setIdentity(localIdentity);
client.connect(new InetSocketAddress( client.connect(new InetSocketAddress(
"voice.teamspeak.com", "ts.teamlixo.net",
9987), 9987),
null, null,
10000L 10000L