/* * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If * not, see <http://www.gnu.org/licenses/>. */ package silentium.authserver; import java.io.IOException; import java.net.InetAddress; import java.nio.ByteBuffer; import java.security.interfaces.RSAPrivateKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import silentium.authserver.network.serverpackets.L2LoginServerPacket; import silentium.authserver.network.serverpackets.LoginFail; import silentium.authserver.network.serverpackets.LoginFail.LoginFailReason; import silentium.authserver.network.serverpackets.PlayFail; import silentium.authserver.network.serverpackets.PlayFail.PlayFailReason; import silentium.commons.crypt.LoginCrypt; import silentium.commons.crypt.ScrambledKeyPair; import silentium.commons.network.mmocore.MMOClient; import silentium.commons.network.mmocore.MMOConnection; import silentium.commons.network.mmocore.SendablePacket; import silentium.commons.utils.Rnd; /** * Represents a client connected into the LoginServer * * @author KenM */ public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>> { private static Logger _log = LoggerFactory.getLogger(L2LoginClient.class.getName()); public enum LoginClientState { CONNECTED, AUTHED_GG, AUTHED_LOGIN } private LoginClientState _state; // Crypt private final LoginCrypt _loginCrypt; private final ScrambledKeyPair _scrambledPair; private final byte[] _blowfishKey; private String _account; private int _accessLevel; private int _lastServer; private boolean _usesInternalIP; private SessionKey _sessionKey; private final int _sessionId; private boolean _joinedGS; private final long _connectionStartTime; /** * @param con */ public L2LoginClient(final MMOConnection<L2LoginClient> con) { super(con); _state = LoginClientState.CONNECTED; final String ip = getConnection().getInetAddress().getHostAddress(); // TODO unhardcode this if (ip.startsWith("192.168") || ip.startsWith("10.0") || "127.0.0.1".equals(ip)) { _usesInternalIP = true; } _scrambledPair = LoginController.getInstance().getScrambledRSAKeyPair(); _blowfishKey = LoginController.getInstance().getBlowfishKey(); _sessionId = Rnd.nextInt(); _connectionStartTime = System.currentTimeMillis(); _loginCrypt = new LoginCrypt(); _loginCrypt.setKey(_blowfishKey); } public boolean usesInternalIP() { return _usesInternalIP; } @Override public boolean decrypt(final ByteBuffer buf, final int size) { boolean ret = false; try { ret = _loginCrypt.decrypt(buf.array(), buf.position(), size); } catch (IOException e) { e.printStackTrace(); getConnection().close((SendablePacket<L2LoginClient>) null); return false; } if (!ret) { final byte[] dump = new byte[size]; System.arraycopy(buf.array(), buf.position(), dump, 0, size); _log.warn("Wrong checksum from client: " + toString()); getConnection().close((SendablePacket<L2LoginClient>) null); } return ret; } @Override public boolean encrypt(final ByteBuffer buf, int size) { final int offset = buf.position(); try { size = _loginCrypt.encrypt(buf.array(), offset, size); } catch (IOException e) { e.printStackTrace(); return false; } buf.position(offset + size); return true; } public LoginClientState getState() { return _state; } public void setState(final LoginClientState state) { _state = state; } public byte[] getBlowfishKey() { return _blowfishKey; } public byte[] getScrambledModulus() { return _scrambledPair._scrambledModulus; } public RSAPrivateKey getRSAPrivateKey() { return (RSAPrivateKey) _scrambledPair._pair.getPrivate(); } public String getAccount() { return _account; } public void setAccount(final String account) { _account = account; } public void setAccessLevel(final int accessLevel) { _accessLevel = accessLevel; } public int getAccessLevel() { return _accessLevel; } public void setLastServer(final int lastServer) { _lastServer = lastServer; } public int getLastServer() { return _lastServer; } public int getSessionId() { return _sessionId; } public boolean hasJoinedGS() { return _joinedGS; } public void setJoinedGS(final boolean val) { _joinedGS = val; } public void setSessionKey(final SessionKey sessionKey) { _sessionKey = sessionKey; } public SessionKey getSessionKey() { return _sessionKey; } public long getConnectionStartTime() { return _connectionStartTime; } public void sendPacket(final L2LoginServerPacket lsp) { getConnection().sendPacket(lsp); } public void close(final LoginFailReason reason) { getConnection().close(new LoginFail(reason)); } public void close(final PlayFailReason reason) { getConnection().close(new PlayFail(reason)); } public void close(final L2LoginServerPacket lsp) { getConnection().close(lsp); } @Override public void onDisconnection() { _log.debug("DISCONNECTED: " + toString()); if (!hasJoinedGS() || getConnectionStartTime() + LoginController.LOGIN_TIMEOUT < System.currentTimeMillis()) LoginController.getInstance().removeAuthedLoginClient(_account); } @Override public String toString() { final InetAddress address = getConnection().getInetAddress(); if (_state == LoginClientState.AUTHED_LOGIN) { return "[" + _account + " (" + (address == null ? "disconnected" : address.getHostAddress()) + ")]"; } return "[" + (address == null ? "disconnected" : address.getHostAddress()) + "]"; } @Override protected void onForcedDisconnection() { // Empty } }