diff --git a/deployer/src/main/resources/spring/default-instance.xml b/deployer/src/main/resources/spring/default-instance.xml
index 6fe11744..095b0031 100644
--- a/deployer/src/main/resources/spring/default-instance.xml
+++ b/deployer/src/main/resources/spring/default-instance.xml
@@ -111,7 +111,6 @@
-
@@ -140,6 +139,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -150,6 +161,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/deployer/src/main/resources/spring/file-instance.xml b/deployer/src/main/resources/spring/file-instance.xml
index 738d19c9..5719e68f 100644
--- a/deployer/src/main/resources/spring/file-instance.xml
+++ b/deployer/src/main/resources/spring/file-instance.xml
@@ -97,7 +97,6 @@
-
diff --git a/deployer/src/main/resources/spring/group-instance.xml b/deployer/src/main/resources/spring/group-instance.xml
index 8b4fc427..f33cb9f4 100644
--- a/deployer/src/main/resources/spring/group-instance.xml
+++ b/deployer/src/main/resources/spring/group-instance.xml
@@ -103,7 +103,6 @@
-
@@ -211,7 +210,6 @@
-
diff --git a/deployer/src/main/resources/spring/memory-instance.xml b/deployer/src/main/resources/spring/memory-instance.xml
index 5c5c6d37..55b7e687 100644
--- a/deployer/src/main/resources/spring/memory-instance.xml
+++ b/deployer/src/main/resources/spring/memory-instance.xml
@@ -94,7 +94,6 @@
-
@@ -114,6 +113,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -124,6 +135,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlConnector.java b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlConnector.java
index 4850e249..45103ab3 100644
--- a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlConnector.java
+++ b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/MysqlConnector.java
@@ -12,13 +12,18 @@ import org.slf4j.LoggerFactory;
import com.alibaba.otter.canal.parse.driver.mysql.packets.HeaderPacket;
import com.alibaba.otter.canal.parse.driver.mysql.packets.client.AuthSwitchResponsePacket;
import com.alibaba.otter.canal.parse.driver.mysql.packets.client.ClientAuthenticationPacket;
+import com.alibaba.otter.canal.parse.driver.mysql.packets.client.ClientAuthenticationSHA2Packet;
import com.alibaba.otter.canal.parse.driver.mysql.packets.client.QuitCommandPacket;
+import com.alibaba.otter.canal.parse.driver.mysql.packets.client.SslRequestCommandPacket;
import com.alibaba.otter.canal.parse.driver.mysql.packets.server.*;
import com.alibaba.otter.canal.parse.driver.mysql.socket.SocketChannel;
import com.alibaba.otter.canal.parse.driver.mysql.socket.SocketChannelPool;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslMode;
import com.alibaba.otter.canal.parse.driver.mysql.utils.MSC;
import com.alibaba.otter.canal.parse.driver.mysql.utils.MySQLPasswordEncrypter;
import com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;
+import static com.alibaba.otter.canal.parse.driver.mysql.packets.Capability.CLIENT_SSL;
/**
* 基于mysql socket协议的链接实现
@@ -32,8 +37,8 @@ public class MysqlConnector {
private InetSocketAddress address;
private String username;
private String password;
+ private SslInfo sslInfo;
- private byte charsetNumber = 33;
private String defaultSchema;
private int soTimeout = 30 * 1000;
private int connTimeout = 5 * 1000;
@@ -62,20 +67,26 @@ public class MysqlConnector {
this.password = password;
}
- public MysqlConnector(InetSocketAddress address, String username, String password, byte charsetNumber,
+ public MysqlConnector(InetSocketAddress address, String username, String password,
String defaultSchema){
this(address, username, password);
- this.charsetNumber = charsetNumber;
this.defaultSchema = defaultSchema;
}
+ public MysqlConnector(InetSocketAddress address, String username, String password,
+ String defaultSchema, SslInfo sslInfo) {
+ this(address, username, password, defaultSchema);
+ this.sslInfo = sslInfo;
+ }
+
public void connect() throws IOException {
if (connected.compareAndSet(false, true)) {
try {
channel = SocketChannelPool.open(address);
logger.info("connect MysqlConnection to {}...", address);
negotiate(channel);
+ printSslStatus();
} catch (Exception e) {
disconnect();
throw new IOException("connect " + this.address + " failure", e);
@@ -85,6 +96,27 @@ public class MysqlConnector {
}
}
+ private void printSslStatus() {
+ try {
+ MysqlQueryExecutor executor = new MysqlQueryExecutor(this);
+ ResultSetPacket result = executor.query("SHOW STATUS LIKE 'Ssl_version'");
+ String sslVersion = "";
+ if (result.getFieldValues() != null && result.getFieldValues().size() >= 2) {
+ sslVersion = result.getFieldValues().get(1);
+ }
+ result = executor.query("SHOW STATUS LIKE 'Ssl_cipher'");
+ String sslCipher = "";
+ if (result.getFieldValues() != null && result.getFieldValues().size() >= 2) {
+ sslCipher = result.getFieldValues().get(1);
+ }
+ logger.info("connect MysqlConnection in sslMode {}, Ssl_version:{}, Ssl_cipher:{}",
+ (sslInfo != null ? sslInfo.getSslMode() : SslMode.DISABLED), sslVersion, sslCipher);
+ } catch (Exception e) {
+ logger.info("Can't show SSL status, server may not standard MySQL server: {}", e.toString());
+ logger.debug("show SSL status exception", e);
+ }
+ }
+
public void reconnect() throws IOException {
disconnect();
connect();
@@ -131,7 +163,6 @@ public class MysqlConnector {
public MysqlConnector fork() {
MysqlConnector connector = new MysqlConnector();
- connector.setCharsetNumber(getCharsetNumber());
connector.setDefaultSchema(getDefaultSchema());
connector.setAddress(getAddress());
connector.setPassword(password);
@@ -140,6 +171,7 @@ public class MysqlConnector {
connector.setSendBufferSize(getSendBufferSize());
connector.setSoTimeout(getSoTimeout());
connector.setConnTimeout(connTimeout);
+ connector.setSslInfo(getSslInfo());
return connector;
}
@@ -170,29 +202,53 @@ public class MysqlConnector {
}
HandshakeInitializationPacket handshakePacket = new HandshakeInitializationPacket();
handshakePacket.fromBytes(body);
+ SslMode sslMode = sslInfo != null ? sslInfo.getSslMode() : SslMode.DISABLED;
+ if (sslMode != SslMode.DISABLED) {
+ boolean serverSupportSsl = (handshakePacket.serverCapabilities & CLIENT_SSL) > 0;
+ if (!serverSupportSsl) {
+ throw new IOException("MySQL Server does not support SSL: " + address
+ + " serverCapabilities: " + handshakePacket.serverCapabilities);
+ }
+ byte[] sslPacket = new SslRequestCommandPacket(handshakePacket.serverCharsetNumber).toBytes();
+ HeaderPacket sslHeader = new HeaderPacket();
+ sslHeader.setPacketBodyLength(sslPacket.length);
+ sslHeader.setPacketSequenceNumber((byte)(header.getPacketSequenceNumber() + 1));
+ header.setPacketSequenceNumber((byte)(header.getPacketSequenceNumber() + 1));
+ PacketManager.writePkg(channel, sslHeader.toBytes(), sslPacket);
+ channel = SocketChannelPool.connectSsl(channel, sslInfo);
+ this.channel = channel;
+ }
if (handshakePacket.protocolVersion != MSC.DEFAULT_PROTOCOL_VERSION) {
// HandshakeV9
- auth323(channel, (byte) (header.getPacketSequenceNumber() + 1), handshakePacket.seed);
+ auth323(channel, (byte)(header.getPacketSequenceNumber() + 1), handshakePacket.seed);
return;
}
connectionId = handshakePacket.threadId; // 记录一下connection
serverVersion = handshakePacket.serverVersion; // 记录serverVersion
logger.info("handshake initialization packet received, prepare the client authentication packet to send");
- ClientAuthenticationPacket clientAuth = new ClientAuthenticationPacket();
- clientAuth.setCharsetNumber(charsetNumber);
+ logger.info("auth plugin: {}", new String(handshakePacket.authPluginName));
+ boolean isSha2Password = false;
+ ClientAuthenticationPacket clientAuth;
+ if ("caching_sha2_password".equals(new String(handshakePacket.authPluginName))) {
+ clientAuth = new ClientAuthenticationSHA2Packet();
+ isSha2Password = true;
+ } else {
+ clientAuth = new ClientAuthenticationPacket();
+ }
+ clientAuth.setCharsetNumber(handshakePacket.serverCharsetNumber);
clientAuth.setUsername(username);
clientAuth.setPassword(password);
clientAuth.setServerCapabilities(handshakePacket.serverCapabilities);
clientAuth.setDatabaseName(defaultSchema);
clientAuth.setScrumbleBuff(joinAndCreateScrumbleBuff(handshakePacket));
- clientAuth.setAuthPluginName("mysql_native_password".getBytes());
+ clientAuth.setAuthPluginName(handshakePacket.authPluginName);
byte[] clientAuthPkgBody = clientAuth.toBytes();
HeaderPacket h = new HeaderPacket();
h.setPacketBodyLength(clientAuthPkgBody.length);
- h.setPacketSequenceNumber((byte) (header.getPacketSequenceNumber() + 1));
+ h.setPacketSequenceNumber((byte)(header.getPacketSequenceNumber() + 1));
PacketManager.writePkg(channel, h.toBytes(), clientAuthPkgBody);
logger.info("client authentication packet is sent out.");
@@ -205,57 +261,64 @@ public class MysqlConnector {
assert body != null;
byte marker = body[0];
if (marker == -2 || marker == 1) {
- byte[] authData = null;
- String pluginName = null;
- if (marker == 1) {
- AuthSwitchRequestMoreData packet = new AuthSwitchRequestMoreData();
- packet.fromBytes(body);
- authData = packet.authData;
+ if (isSha2Password && body[1] == 3) {
+ // sha2 auth ok
+ logger.info("caching_sha2_password auth success.");
+ header = PacketManager.readHeader(channel, 4);
+ body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
} else {
- AuthSwitchRequestPacket packet = new AuthSwitchRequestPacket();
- packet.fromBytes(body);
- authData = packet.authData;
- pluginName = packet.authName;
- logger.info("auth switch pluginName is {}.", pluginName);
- }
-
- byte[] encryptedPassword = null;
- if ("mysql_clear_password".equals(pluginName)) {
- encryptedPassword = getPassword().getBytes();
- header = authSwitchAfterAuth(encryptedPassword, header);
- body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
- } else if ("mysql_native_password".equals(pluginName)) {
- try {
- encryptedPassword = MySQLPasswordEncrypter.scramble411(getPassword().getBytes(), authData);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("can't encrypt password that will be sent to MySQL server.", e);
- }
- header = authSwitchAfterAuth(encryptedPassword, header);
- body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
- } else if ("caching_sha2_password".equals(pluginName)) {
- byte[] scramble = authData;
- try {
- encryptedPassword = MySQLPasswordEncrypter.scrambleCachingSha2(getPassword().getBytes(), scramble);
- } catch (DigestException e) {
- throw new RuntimeException("can't encrypt password that will be sent to MySQL server.", e);
- }
- header = authSwitchAfterAuth(encryptedPassword, header);
- body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
- assert body != null;
- if (body[0] == 0x01 && body[1] == 0x04) {
- // fixed issue https://github.com/alibaba/canal/pull/4767, support mysql 8.0.30+
- header = cachingSha2PasswordFullAuth(channel, header, getPassword().getBytes(), scramble);
- body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
+ byte[] authData = null;
+ String pluginName = null;
+ if (marker == 1) {
+ AuthSwitchRequestMoreData packet = new AuthSwitchRequestMoreData();
+ packet.fromBytes(body);
+ authData = packet.authData;
} else {
- header = PacketManager.readHeader(channel, 4);
+ AuthSwitchRequestPacket packet = new AuthSwitchRequestPacket();
+ packet.fromBytes(body);
+ authData = packet.authData;
+ pluginName = packet.authName;
+ logger.info("auth switch pluginName is {}.", pluginName);
+ }
+
+ byte[] encryptedPassword = null;
+ if ("mysql_clear_password".equals(pluginName)) {
+ encryptedPassword = getPassword().getBytes();
+ header = authSwitchAfterAuth(encryptedPassword, header);
+ body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
+ } else if ("mysql_native_password".equals(pluginName)) {
+ try {
+ encryptedPassword = MySQLPasswordEncrypter.scramble411(getPassword().getBytes(), authData);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("can't encrypt password that will be sent to MySQL server.", e);
+ }
+ header = authSwitchAfterAuth(encryptedPassword, header);
+ body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
+ } else if ("caching_sha2_password".equals(pluginName)) {
+ byte[] scramble = authData;
+ try {
+ encryptedPassword = MySQLPasswordEncrypter.scrambleCachingSha2(getPassword().getBytes(),
+ scramble);
+ } catch (DigestException e) {
+ throw new RuntimeException("can't encrypt password that will be sent to MySQL server.", e);
+ }
+ header = authSwitchAfterAuth(encryptedPassword, header);
+ body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
+ assert body != null;
+ if (body[0] == 0x01 && body[1] == 0x04) {
+ // fixed issue https://github.com/alibaba/canal/pull/4767, support mysql 8.0.30+
+ header = cachingSha2PasswordFullAuth(channel, header, getPassword().getBytes(), scramble);
+ body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
+ } else {
+ header = PacketManager.readHeader(channel, 4);
+ body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
+ }
+ } else {
+ header = authSwitchAfterAuth(encryptedPassword, header);
body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
}
- } else {
- header = authSwitchAfterAuth(encryptedPassword, header);
- body = PacketManager.readBytes(channel, header.getPacketBodyLength(), timeout);
}
}
- assert body != null;
if (body[0] < 0) {
if (body[0] == -1) {
ErrorPacket err = new ErrorPacket();
@@ -380,14 +443,6 @@ public class MysqlConnector {
this.username = username;
}
- public byte getCharsetNumber() {
- return charsetNumber;
- }
-
- public void setCharsetNumber(byte charsetNumber) {
- this.charsetNumber = charsetNumber;
- }
-
public String getDefaultSchema() {
return defaultSchema;
}
@@ -464,4 +519,11 @@ public class MysqlConnector {
return serverVersion;
}
+ public SslInfo getSslInfo() {
+ return sslInfo;
+ }
+
+ public void setSslInfo(SslInfo sslInfo) {
+ this.sslInfo = sslInfo;
+ }
}
diff --git a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/ClientAuthenticationSHA2Packet.java b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/ClientAuthenticationSHA2Packet.java
new file mode 100644
index 00000000..f8e22f6e
--- /dev/null
+++ b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/ClientAuthenticationSHA2Packet.java
@@ -0,0 +1,65 @@
+package com.alibaba.otter.canal.parse.driver.mysql.packets.client;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import com.alibaba.otter.canal.parse.driver.mysql.packets.Capability;
+import com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;
+import com.alibaba.otter.canal.parse.driver.mysql.utils.MSC;
+import com.alibaba.otter.canal.parse.driver.mysql.utils.MySQLPasswordEncrypter;
+
+import org.apache.commons.lang.StringUtils;
+
+public class ClientAuthenticationSHA2Packet extends ClientAuthenticationPacket {
+
+ @Override
+ public byte[] toBytes() throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ // 1. write client_flags
+ int clientCapability = 0;
+ clientCapability |= Capability.CLIENT_LONG_PASSWORD;
+ clientCapability |= Capability.CLIENT_LONG_FLAG;
+ clientCapability |= Capability.CLIENT_PROTOCOL_41;
+ clientCapability |= Capability.CLIENT_TRANSACTIONS;
+ clientCapability |= Capability.CLIENT_SECURE_CONNECTION;
+ clientCapability |= Capability.CLIENT_MULTI_STATEMENTS;
+ clientCapability |= Capability.CLIENT_PLUGIN_AUTH;
+ clientCapability |= Capability.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA;
+ if (getDatabaseName() != null) {
+ clientCapability |= Capability.CLIENT_CONNECT_WITH_DB;
+ }
+ ByteHelper.writeUnsignedIntLittleEndian(clientCapability, out);
+
+ // 2. write max_packet_size
+ ByteHelper.writeUnsignedIntLittleEndian(MSC.MAX_PACKET_LENGTH, out);
+ // 3. write charset_number
+ out.write(getCharsetNumber());
+ // 4. write (filler) always 0x00...
+ out.write(new byte[23]);
+ // 5. write (Null-Terminated String) user
+ ByteHelper.writeNullTerminatedString(getUsername(), out);
+ // 6. write (Length Coded Binary) scramble_buff (1 + x bytes)
+ if (StringUtils.isEmpty(getPassword())) {
+ out.write(0x00);
+ } else {
+ try {
+ byte[] encryptedPassword = MySQLPasswordEncrypter.scrambleCachingSha2(getPassword().getBytes(),
+ getScrumbleBuff());
+ ByteHelper.writeBinaryCodedLengthBytes(encryptedPassword, out);
+ } catch (Exception e) {
+ throw new IOException("can't encrypt password that will be sent to MySQL server.", e);
+ }
+ }
+ // 7 . (Null-Terminated String) databasename (optional)
+ if (getDatabaseName() != null) {
+ ByteHelper.writeNullTerminatedString(getDatabaseName(), out);
+ }
+ // 8 . (Null-Terminated String) auth plugin name (optional)
+ if (getAuthPluginName() != null) {
+ ByteHelper.writeNullTerminated(getAuthPluginName(), out);
+ }
+ // end write
+ return out.toByteArray();
+ }
+
+}
diff --git a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/SslRequestCommandPacket.java b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/SslRequestCommandPacket.java
new file mode 100644
index 00000000..274472f5
--- /dev/null
+++ b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/packets/client/SslRequestCommandPacket.java
@@ -0,0 +1,41 @@
+package com.alibaba.otter.canal.parse.driver.mysql.packets.client;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import com.alibaba.otter.canal.parse.driver.mysql.packets.Capability;
+import com.alibaba.otter.canal.parse.driver.mysql.packets.IPacket;
+import com.alibaba.otter.canal.parse.driver.mysql.utils.ByteHelper;
+
+/**
+ * @author 枭博
+ * @date 2024/05/14
+ */
+public class SslRequestCommandPacket implements IPacket {
+
+ private final int serverCharsetNumber;
+
+ public SslRequestCommandPacket(int serverCharsetNumber) {this.serverCharsetNumber = serverCharsetNumber;}
+
+ @Override
+ public void fromBytes(byte[] data) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] toBytes() throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int clientCapabilities = Capability.CLIENT_LONG_FLAG
+ | Capability.CLIENT_PROTOCOL_41
+ | Capability.CLIENT_SECURE_CONNECTION
+ | Capability.CLIENT_PLUGIN_AUTH
+ | Capability.CLIENT_SSL;
+ ByteHelper.writeUnsignedIntLittleEndian(clientCapabilities, out);
+ ByteHelper.writeUnsignedIntLittleEndian(0, out);
+ out.write(serverCharsetNumber);
+ for (int i = 0; i < 23; i++) {
+ out.write(0);
+ }
+ return out.toByteArray();
+ }
+}
diff --git a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannel.java b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannel.java
index dfa2783f..23cb7ab3 100644
--- a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannel.java
+++ b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannel.java
@@ -10,6 +10,8 @@ import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.channels.ClosedByInterruptException;
+import javax.net.ssl.SSLSocket;
+
/**
* 使用BIO进行dump
*
@@ -22,11 +24,13 @@ public class BioSocketChannel implements SocketChannel {
private Socket socket;
private InputStream input;
private OutputStream output;
+ private final boolean ssl;
BioSocketChannel(Socket socket) throws IOException{
this.socket = socket;
this.input = new BufferedInputStream(socket.getInputStream(), 16384);
this.output = socket.getOutputStream();
+ this.ssl = (socket instanceof SSLSocket);
}
public void write(byte[]... buf) throws IOException {
@@ -133,6 +137,12 @@ public class BioSocketChannel implements SocketChannel {
}
return false;
}
+ public boolean isSsl() {
+ return ssl;
+ }
+ public Socket getSocket() {
+ return socket;
+ }
public SocketAddress getRemoteSocketAddress() {
Socket socket = this.socket;
diff --git a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannelPool.java b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannelPool.java
index dcc17bad..e77d0a60 100644
--- a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannelPool.java
+++ b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannelPool.java
@@ -1,22 +1,324 @@
package com.alibaba.otter.canal.parse.driver.mysql.socket;
+import java.io.IOException;
+import java.io.InputStream;
import java.net.Socket;
import java.net.SocketAddress;
+import java.net.URL;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.cert.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.net.ssl.*;
+import javax.security.auth.x500.X500Principal;
+
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslMode;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* @author luoyaogui 实现channel的管理(监听连接、读数据、回收) 2016-12-28
* @author chuanyi 2018-3-3 保留open减少文件变更数量
*/
public abstract class BioSocketChannelPool {
+ private static final Logger logger = LoggerFactory.getLogger(BioSocketChannelPool.class);
public static BioSocketChannel open(SocketAddress address) throws Exception {
- Socket socket = new Socket();
+ Socket socket = createSocket(address);
+ return new BioSocketChannel(socket);
+ }
+
+ public static BioSocketChannel openSsl(Socket socket, SslInfo sslInfo) throws Exception {
+ SslMode sslMode = sslInfo.getSslMode();
+
+ switch (sslMode) {
+ case REQUIRED:
+ case PREFERRED:
+ case VERIFY_CA:
+ case VERIFY_IDENTITY:
+ SSLSocket sslSocket = createSslSocket(socket, sslInfo);
+ return new BioSocketChannel(sslSocket);
+ default:
+ throw new UnsupportedOperationException("Unsupported ssl mode: " + sslMode);
+ }
+ }
+
+ private static Socket createSocket(SocketAddress address) throws IOException {
+ Socket socket;
+ socket = new Socket();
socket.setSoTimeout(BioSocketChannel.SO_TIMEOUT);
socket.setTcpNoDelay(true);
socket.setKeepAlive(true);
socket.setReuseAddress(true);
socket.connect(address, BioSocketChannel.DEFAULT_CONNECT_TIMEOUT);
- return new BioSocketChannel(socket);
+ return socket;
+ }
+
+ /**
+ * from JDBC driver
+ *
+ * com.mysql.cj.protocol.ExportControlled#performTlsHandshake
+ * com.mysql.cj.protocol.ExportControlled#getSSLContext
+ *
+ * @param socket
+ * @param sslInfo
+ * @return
+ * @throws Exception
+ */
+ private static SSLSocket createSslSocket(Socket socket, SslInfo sslInfo) throws Exception {
+ SslMode sslMode = sslInfo.getSslMode();
+ boolean verifyServerCert = sslMode == SslMode.VERIFY_CA || sslMode == SslMode.VERIFY_IDENTITY;
+
+ String clientCertificateKeyStoreUrl = sslInfo.getClientCertificateKeyStoreUrl();
+ String clientCertificateKeyStoreType = sslInfo.getClientCertificateKeyStoreType() != null
+ ? sslInfo.getClientCertificateKeyStoreType()
+ : "JKS";
+ String clientCertificateKeyStorePassword = sslInfo.getClientCertificateKeyStorePassword();
+ String trustCertificateKeyStoreUrl = sslInfo.getTrustCertificateKeyStoreUrl();
+ String trustCertificateKeyStoreType = sslInfo.getTrustCertificateKeyStoreType() != null
+ ? sslInfo.getTrustCertificateKeyStoreType()
+ : "JKS";
+ String trustCertificateKeyStorePassword = sslInfo.getTrustCertificateKeyStorePassword();
+ boolean fallbackToDefaultTrustStore = true;
+ String hostName = sslMode == SslMode.VERIFY_IDENTITY ? socket.getInetAddress().getHostName() : null;
+
+ SSLContext sslContext = getSSLContext(clientCertificateKeyStoreUrl,
+ clientCertificateKeyStoreType,
+ clientCertificateKeyStorePassword,
+ trustCertificateKeyStoreUrl, trustCertificateKeyStoreType,
+ trustCertificateKeyStorePassword,
+ fallbackToDefaultTrustStore,
+ verifyServerCert, hostName);
+ SSLSocketFactory socketFactory = sslContext.getSocketFactory();
+
+ SSLSocket sslSocket = (SSLSocket)socketFactory.createSocket(
+ socket, socket.getInetAddress().getHostName(), socket.getPort(), true);
+
+ String[] protocolArr = null;
+ if (StringUtils.isNotEmpty(sslInfo.getTlsVersions())) {
+ protocolArr = StringUtils.split(sslInfo.getTlsVersions(), ",");
+ }
+ if (protocolArr == null || protocolArr.length == 0) {
+ protocolArr = new String[] {"TLSv1.2", "TLSv1.3"};
+ }
+ logger.info("SSL protocol: {}", StringUtils.join(protocolArr, ","));
+ sslSocket.setEnabledProtocols(protocolArr);
+ //sslSocket.setEnabledCipherSuites("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA".split(","));
+ sslSocket.startHandshake();
+ logger.info("SSL socket handshake success.");
+ return sslSocket;
+ }
+
+ private static SSLContext getSSLContext(String clientCertificateKeyStoreUrl, String clientCertificateKeyStoreType,
+ String clientCertificateKeyStorePassword,
+ String trustCertificateKeyStoreUrl, String trustCertificateKeyStoreType,
+ String trustCertificateKeyStorePassword,
+ boolean fallbackToDefaultTrustStore, boolean verifyServerCert, String hostName)
+ throws Exception {
+
+ KeyManager[] kms = null;
+ List tms = new ArrayList<>();
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+
+ if (StringUtils.isNotEmpty(clientCertificateKeyStoreUrl)) {
+ InputStream ksIS = null;
+ try {
+ if (StringUtils.isNotEmpty(clientCertificateKeyStoreType)) {
+ KeyStore clientKeyStore = KeyStore.getInstance(clientCertificateKeyStoreType);
+ URL ksURL = new URL(clientCertificateKeyStoreUrl);
+ char[] password = (clientCertificateKeyStorePassword == null) ? new char[0]
+ : clientCertificateKeyStorePassword.toCharArray();
+ ksIS = ksURL.openStream();
+ clientKeyStore.load(ksIS, password);
+ kmf.init(clientKeyStore, password);
+ kms = kmf.getKeyManagers();
+ }
+ } finally {
+ if (ksIS != null) {
+ try {
+ ksIS.close();
+ } catch (IOException e) {
+ // can't close input stream, but keystore can be properly initialized so we shouldn't throw
+ // this exception
+ }
+ }
+ }
+ }
+
+ InputStream trustStoreIS = null;
+ try {
+ String trustStoreType = "";
+ char[] trustStorePassword = null;
+ KeyStore trustKeyStore = null;
+
+ if (StringUtils.isNotEmpty(trustCertificateKeyStoreUrl) && StringUtils.isNotEmpty(
+ trustCertificateKeyStoreType)) {
+ trustStoreType = trustCertificateKeyStoreType;
+ trustStorePassword = (trustCertificateKeyStorePassword == null) ? new char[0]
+ : trustCertificateKeyStorePassword.toCharArray();
+ trustStoreIS = new URL(trustCertificateKeyStoreUrl).openStream();
+
+ trustKeyStore = KeyStore.getInstance(trustStoreType);
+ trustKeyStore.load(trustStoreIS, trustStorePassword);
+ }
+
+ if (trustKeyStore != null || fallbackToDefaultTrustStore) {
+ tmf.init(trustKeyStore);
+ // (trustKeyStore == null) initializes the TrustManagerFactory with the default truststore.
+
+ // building the customized list of TrustManagers from original one if it's available
+ TrustManager[] origTms = tmf.getTrustManagers();
+
+ for (TrustManager tm : origTms) {
+ // wrap X509TrustManager or put original if non-X509 TrustManager
+ tms.add(tm instanceof X509TrustManager ? new X509TrustManagerWrapper((X509TrustManager)tm,
+ verifyServerCert, hostName) : tm);
+ }
+ }
+
+ } finally {
+ if (trustStoreIS != null) {
+ try {
+ trustStoreIS.close();
+ } catch (IOException e) {
+ // can't close input stream, but keystore can be properly initialized so we shouldn't throw this
+ // exception
+ }
+ }
+ }
+
+ // if original TrustManagers are not available then putting one X509TrustManagerWrapper which take care only
+ // about expiration check
+ if (tms.size() == 0) {
+ tms.add(new X509TrustManagerWrapper(verifyServerCert, hostName));
+ }
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(kms, tms.toArray(new TrustManager[tms.size()]), null);
+ return sslContext;
+ }
+
+ public static class X509TrustManagerWrapper implements X509TrustManager {
+
+ private X509TrustManager origTm = null;
+ private boolean verifyServerCert = false;
+ private String hostName = null;
+ private CertificateFactory certFactory = null;
+ private PKIXParameters validatorParams = null;
+ private CertPathValidator validator = null;
+
+ public X509TrustManagerWrapper(X509TrustManager tm, boolean verifyServerCertificate, String hostName)
+ throws CertificateException {
+ this.origTm = tm;
+ this.verifyServerCert = verifyServerCertificate;
+ this.hostName = hostName;
+
+ if (verifyServerCertificate) {
+ try {
+ Set anch = Arrays.stream(tm.getAcceptedIssuers()).map(c -> new TrustAnchor(c, null))
+ .collect(
+ Collectors.toSet());
+ this.validatorParams = new PKIXParameters(anch);
+ this.validatorParams.setRevocationEnabled(false);
+ this.validator = CertPathValidator.getInstance("PKIX");
+ this.certFactory = CertificateFactory.getInstance("X.509");
+ } catch (Exception e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ }
+
+ public X509TrustManagerWrapper(boolean verifyServerCertificate, String hostName) {
+ this.verifyServerCert = verifyServerCertificate;
+ this.hostName = hostName;
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return this.origTm != null ? this.origTm.getAcceptedIssuers() : new X509Certificate[0];
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ for (int i = 0; i < chain.length; i++) {
+ chain[i].checkValidity();
+ }
+
+ if (this.validatorParams != null) {
+ X509CertSelector certSelect = new X509CertSelector();
+ certSelect.setSerialNumber(chain[0].getSerialNumber());
+
+ try {
+ CertPath certPath = this.certFactory.generateCertPath(Arrays.asList(chain));
+ // Validate against truststore
+ CertPathValidatorResult result = this.validator.validate(certPath, this.validatorParams);
+ // Check expiration for the CA used to validate this path
+ ((PKIXCertPathValidatorResult)result).getTrustAnchor().getTrustedCert().checkValidity();
+
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new CertificateException(e);
+ } catch (CertPathValidatorException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ if (this.verifyServerCert) {
+ if (this.origTm != null) {
+ this.origTm.checkServerTrusted(chain, authType);
+ } else {
+ throw new CertificateException(
+ "Can't verify server certificate because no trust manager is found.");
+ }
+
+ // verify server certificate identity
+ if (this.hostName != null) {
+ logger.info("verify hostName: {}", this.hostName);
+ Set expectHostNames = new HashSet<>();
+ for (X509Certificate certificate : chain) {
+ String dn = certificate.getSubjectX500Principal().getName(X500Principal.RFC2253);
+ String cn = null;
+ try {
+ LdapName ldapDN = new LdapName(dn);
+ for (Rdn rdn : ldapDN.getRdns()) {
+ if (rdn.getType().equalsIgnoreCase("CN")) {
+ cn = rdn.getValue().toString();
+ break;
+ }
+ }
+ } catch (InvalidNameException e) {
+ throw new CertificateException(
+ "Failed to retrieve the Common Name (CN) from the server certificate.");
+ }
+ expectHostNames.add(cn);
+ }
+
+ if (!expectHostNames.contains(this.hostName)) {
+ throw new CertificateException(
+ "Server certificate identity check failed. The certificate Common Name "
+ + expectHostNames.stream().map(h -> "'" + h + "'").collect(Collectors.joining(", "))
+ + " does not match with '" + this.hostName + "'.");
+ }
+
+ }
+ }
+ }
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ this.origTm.checkClientTrusted(chain, authType);
+ }
}
}
diff --git a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/SocketChannelPool.java b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/SocketChannelPool.java
index 27ad961e..0bd1348b 100644
--- a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/SocketChannelPool.java
+++ b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/SocketChannelPool.java
@@ -1,14 +1,21 @@
package com.alibaba.otter.canal.parse.driver.mysql.socket;
+import java.io.IOException;
import java.net.SocketAddress;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslMode;
+
import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* @author agapple 2018年3月12日 下午10:46:22
* @since 1.0.26
*/
public abstract class SocketChannelPool {
+ private static final Logger logger = LoggerFactory.getLogger(SocketChannelPool.class);
public static SocketChannel open(SocketAddress address) throws Exception {
String type = chooseSocketChannel();
@@ -17,7 +24,34 @@ public abstract class SocketChannelPool {
} else {
return BioSocketChannelPool.open(address);
}
+ }
+ public static SocketChannel connectSsl(SocketChannel channel, SslInfo sslInfo) throws IOException {
+ SslMode sslMode = sslInfo.getSslMode();
+
+ String type = chooseSocketChannel();
+ if ("netty".equalsIgnoreCase(type)) {
+ throw new UnsupportedOperationException("canal.socketChannel netty not support ssl mode: " + sslMode);
+ } else {
+ SocketAddress remoteSocketAddress = channel.getRemoteSocketAddress();
+ try {
+ return BioSocketChannelPool.openSsl(
+ ((BioSocketChannel)channel).getSocket(), sslInfo);
+ } catch (Exception e) {
+ if (sslMode == SslMode.PREFERRED) {
+ // still use non ssl channel
+ logger.info("{} still use non SSL channel due to SSL connect failed.", remoteSocketAddress, e);
+ return channel;
+ }
+ IOException ioe;
+ if (e instanceof IOException) {
+ ioe = (IOException)e;
+ } else {
+ ioe = new IOException(e);
+ }
+ throw ioe;
+ }
+ }
}
private static String chooseSocketChannel() {
diff --git a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/ssl/SslInfo.java b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/ssl/SslInfo.java
new file mode 100644
index 00000000..90152501
--- /dev/null
+++ b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/ssl/SslInfo.java
@@ -0,0 +1,98 @@
+package com.alibaba.otter.canal.parse.driver.mysql.ssl;
+
+/**
+ * @author 枭博
+ * @date 2024/05/14
+ */
+public class SslInfo {
+
+ private SslMode sslMode = SslMode.DISABLED;
+ private String tlsVersions; // 和 enabledTLSProtocols 同含义,TLSv1.2,TLSv1.3
+ private String trustCertificateKeyStoreType; // trustStore 证书类型,支持 JKS (默认) 和 PKCS12
+ private String trustCertificateKeyStoreUrl; // trustStore 证书
+ private String trustCertificateKeyStorePassword; // trustStore 证书密码
+ private String clientCertificateKeyStoreType; // client 证书类型,支持 JKS (默认) 和 PKCS12
+ private String clientCertificateKeyStoreUrl; // client 证书
+ private String clientCertificateKeyStorePassword; // client 证书密码
+
+ public SslInfo(SslMode sslMode, String tlsVersions, String trustCertificateKeyStoreType,
+ String trustCertificateKeyStoreUrl, String trustCertificateKeyStorePassword,
+ String clientCertificateKeyStoreType,
+ String clientCertificateKeyStoreUrl, String clientCertificateKeyStorePassword) {
+ this.sslMode = sslMode;
+ this.tlsVersions = tlsVersions;
+ this.trustCertificateKeyStoreType = trustCertificateKeyStoreType;
+ this.trustCertificateKeyStoreUrl = trustCertificateKeyStoreUrl;
+ this.trustCertificateKeyStorePassword = trustCertificateKeyStorePassword;
+ this.clientCertificateKeyStoreType = clientCertificateKeyStoreType;
+ this.clientCertificateKeyStoreUrl = clientCertificateKeyStoreUrl;
+ this.clientCertificateKeyStorePassword = clientCertificateKeyStorePassword;
+ }
+
+ public SslInfo() {
+ }
+
+ public SslMode getSslMode() {
+ return sslMode;
+ }
+
+ public void setSslMode(SslMode sslMode) {
+ this.sslMode = sslMode;
+ }
+
+ public String getTlsVersions() {
+ return tlsVersions;
+ }
+
+ public void setTlsVersions(String tlsVersions) {
+ this.tlsVersions = tlsVersions;
+ }
+
+ public String getTrustCertificateKeyStoreType() {
+ return trustCertificateKeyStoreType;
+ }
+
+ public void setTrustCertificateKeyStoreType(String trustCertificateKeyStoreType) {
+ this.trustCertificateKeyStoreType = trustCertificateKeyStoreType;
+ }
+
+ public String getTrustCertificateKeyStoreUrl() {
+ return trustCertificateKeyStoreUrl;
+ }
+
+ public void setTrustCertificateKeyStoreUrl(String trustCertificateKeyStoreUrl) {
+ this.trustCertificateKeyStoreUrl = trustCertificateKeyStoreUrl;
+ }
+
+ public String getTrustCertificateKeyStorePassword() {
+ return trustCertificateKeyStorePassword;
+ }
+
+ public void setTrustCertificateKeyStorePassword(String trustCertificateKeyStorePassword) {
+ this.trustCertificateKeyStorePassword = trustCertificateKeyStorePassword;
+ }
+
+ public String getClientCertificateKeyStoreType() {
+ return clientCertificateKeyStoreType;
+ }
+
+ public void setClientCertificateKeyStoreType(String clientCertificateKeyStoreType) {
+ this.clientCertificateKeyStoreType = clientCertificateKeyStoreType;
+ }
+
+ public String getClientCertificateKeyStoreUrl() {
+ return clientCertificateKeyStoreUrl;
+ }
+
+ public void setClientCertificateKeyStoreUrl(String clientCertificateKeyStoreUrl) {
+ this.clientCertificateKeyStoreUrl = clientCertificateKeyStoreUrl;
+ }
+
+ public String getClientCertificateKeyStorePassword() {
+ return clientCertificateKeyStorePassword;
+ }
+
+ public void setClientCertificateKeyStorePassword(String clientCertificateKeyStorePassword) {
+ this.clientCertificateKeyStorePassword = clientCertificateKeyStorePassword;
+ }
+}
diff --git a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/ssl/SslMode.java b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/ssl/SslMode.java
new file mode 100644
index 00000000..a9ae77eb
--- /dev/null
+++ b/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/ssl/SslMode.java
@@ -0,0 +1,26 @@
+package com.alibaba.otter.canal.parse.driver.mysql.ssl;
+
+public enum SslMode {
+
+ /**
+ * 关闭SSL
+ */
+ DISABLED,
+ /**
+ * 尝试SSL传输
+ */
+ PREFERRED,
+ /**
+ * 要求SSL传输,不校验证书
+ */
+ REQUIRED,
+ /**
+ * 要求SSL传输,校验证书,不校验证书里的域名
+ */
+ VERIFY_CA,
+ /**
+ * 要求SSL传输,校验证书,校验证书里的域名
+ */
+ VERIFY_IDENTITY
+
+}
diff --git a/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java b/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java
index 55c0141f..4e85af52 100644
--- a/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java
+++ b/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java
@@ -276,8 +276,7 @@ public class CanalInstanceWithManager extends AbstractCanalInstance {
mysqlEventParser.setDestination(destination);
// 编码参数
mysqlEventParser.setConnectionCharset(parameters.getConnectionCharset());
- mysqlEventParser.setConnectionCharsetNumber(parameters.getConnectionCharsetNumber());
- // 网络相关参数
+ // 网络相关参数1
mysqlEventParser.setDefaultConnectionTimeoutInSeconds(parameters.getDefaultConnectionTimeoutInSeconds());
mysqlEventParser.setSendBufferSize(parameters.getSendBufferSize());
mysqlEventParser.setReceiveBufferSize(parameters.getReceiveBufferSize());
@@ -291,13 +290,15 @@ public class CanalInstanceWithManager extends AbstractCanalInstance {
mysqlEventParser.setMasterInfo(new AuthenticationInfo(dbAddresses.get(0),
parameters.getDbUsername(),
parameters.getDbPassword(),
- parameters.getDefaultDatabaseName()));
+ parameters.getDefaultDatabaseName(),
+ parameters.getSslInfo()));
if (dbAddresses.size() > 1) {
mysqlEventParser.setStandbyInfo(new AuthenticationInfo(dbAddresses.get(1),
parameters.getDbUsername(),
parameters.getDbPassword(),
- parameters.getDefaultDatabaseName()));
+ parameters.getDefaultDatabaseName(),
+ parameters.getSslInfo()));
}
}
@@ -369,7 +370,6 @@ public class CanalInstanceWithManager extends AbstractCanalInstance {
localBinlogEventParser.setDestination(destination);
localBinlogEventParser.setBufferSize(parameters.getReceiveBufferSize());
localBinlogEventParser.setConnectionCharset(parameters.getConnectionCharset());
- localBinlogEventParser.setConnectionCharsetNumber(parameters.getConnectionCharsetNumber());
localBinlogEventParser.setDirectory(parameters.getLocalBinlogDirectory());
localBinlogEventParser.setProfilingEnabled(false);
localBinlogEventParser.setDetectingEnable(parameters.getDetectingEnable());
@@ -381,7 +381,8 @@ public class CanalInstanceWithManager extends AbstractCanalInstance {
localBinlogEventParser.setMasterInfo(new AuthenticationInfo(dbAddresses.get(0),
parameters.getDbUsername(),
parameters.getDbPassword(),
- parameters.getDefaultDatabaseName()));
+ parameters.getDefaultDatabaseName(),
+ parameters.getSslInfo()));
}
eventParser = localBinlogEventParser;
diff --git a/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/model/CanalParameter.java b/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/model/CanalParameter.java
index 0db7c158..366cbdca 100644
--- a/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/model/CanalParameter.java
+++ b/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/model/CanalParameter.java
@@ -9,6 +9,8 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import com.alibaba.otter.canal.common.utils.CanalToStringStyle;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslMode;
/**
* canal运行相关参数
@@ -56,8 +58,6 @@ public class CanalParameter implements Serializable {
private Integer defaultConnectionTimeoutInSeconds = 30; // sotimeout
private Integer receiveBufferSize = 64 * 1024;
private Integer sendBufferSize = 64 * 1024;
- // 编码信息
- private Byte connectionCharsetNumber = (byte) 33;
private String connectionCharset = "UTF-8";
// 数据库信息
@@ -66,6 +66,15 @@ public class CanalParameter implements Serializable {
private String dbUsername; // 数据库用户
private String dbPassword; // 数据库密码
+ private String sslMode = SslMode.DISABLED.name();
+ private String tlsVersions; // 和 enabledTLSProtocols 同含义,TLSv1.2,TLSv1.3
+ private String trustCertificateKeyStoreType; // trustStore 证书类型,支持 JKS (默认) 和 PKCS12
+ private String trustCertificateKeyStoreUrl; // trustStore 证书路径
+ private String trustCertificateKeyStorePassword; // trustStore 证书密码
+ private String clientCertificateKeyStoreType; // client 证书类型,支持 JKS (默认) 和 PKCS12
+ private String clientCertificateKeyStoreUrl; // client 证书路径
+ private String clientCertificateKeyStorePassword; // client 证书密码
+
// binlog链接信息
private IndexMode indexMode;
private List positions; // 数据库positions信息
@@ -108,10 +117,27 @@ public class CanalParameter implements Serializable {
private InetSocketAddress masterAddress; // 主库信息
private String masterUsername; // 帐号
private String masterPassword; // 密码
+ private String masterSslMode = SslMode.DISABLED.name();
+ private String masterTlsVersions; // 和 enabledTLSProtocols 同含义,TLSv1.2,TLSv1.3
+ private String masterTrustCertificateKeyStoreType; // trustStore 证书类型,支持 JKS (默认) 和 PKCS12
+ private String masterTrustCertificateKeyStoreUrl; // trustStore 证书路径
+ private String masterTrustCertificateKeyStorePassword; // trustStore 证书密码
+ private String masterClientCertificateKeyStoreType; // client 证书类型,支持 JKS (默认) 和 PKCS12
+ private String masterClientCertificateKeyStoreUrl; // client 证书路径
+ private String masterClientCertificateKeyStorePassword; // client 证书密码
private InetSocketAddress standbyAddress; // 备库信息
private String standbyUsername; // 帐号
private String standbyPassword;
+ private String standbySslMode = SslMode.DISABLED.name();
+ private String standbyTlsVersions; // 和 enabledTLSProtocols 同含义,TLSv1.2,TLSv1.3
+ private String standbyTrustCertificateKeyStoreType; // trustStore 证书类型,支持 JKS (默认) 和 PKCS12
+ private String standbyTrustCertificateKeyStoreUrl; // trustStore 证书路径
+ private String standbyTrustCertificateKeyStorePassword; // trustStore 证书密码
+ private String standbyClientCertificateKeyStoreType; // client 证书类型,支持 JKS (默认) 和 PKCS12
+ private String standbyClientCertificateKeyStoreUrl; // client 证书路径
+ private String standbyClientCertificateKeyStorePassword; // client 证书密码
+
private String masterLogfileName = null; // master起始位置
private Long masterLogfileOffest = null;
private Long masterTimestamp = null;
@@ -533,14 +559,6 @@ public class CanalParameter implements Serializable {
this.sendBufferSize = sendBufferSize;
}
- public Byte getConnectionCharsetNumber() {
- return connectionCharsetNumber;
- }
-
- public void setConnectionCharsetNumber(Byte connectionCharsetNumber) {
- this.connectionCharsetNumber = connectionCharsetNumber;
- }
-
public String getConnectionCharset() {
return connectionCharset;
}
@@ -685,16 +703,16 @@ public class CanalParameter implements Serializable {
groupDbAddresses.add(groupAddresses);
}
} else {
- if (masterAddress != null) {
- List groupAddresses = new ArrayList<>();
+ if (masterAddress != null) {
+ List groupAddresses = new ArrayList<>();
groupAddresses.add(new DataSourcing(sourcingType, masterAddress));
- groupDbAddresses.add(groupAddresses);
- }
+ groupDbAddresses.add(groupAddresses);
+ }
- if (standbyAddress != null) {
- List groupAddresses = new ArrayList<>();
+ if (standbyAddress != null) {
+ List groupAddresses = new ArrayList<>();
groupAddresses.add(new DataSourcing(sourcingType, standbyAddress));
- groupDbAddresses.add(groupAddresses);
+ groupDbAddresses.add(groupAddresses);
}
}
}
@@ -731,6 +749,134 @@ public class CanalParameter implements Serializable {
this.dbPassword = dbPassword;
}
+ public SslInfo getSslInfo() {
+ if (dbUsername == null) {
+ if (masterUsername != null) {
+ return new SslInfo(SslMode.valueOf(masterSslMode),
+ masterTlsVersions,
+ masterTrustCertificateKeyStoreType,
+ masterTrustCertificateKeyStoreUrl,
+ masterTrustCertificateKeyStorePassword,
+ masterClientCertificateKeyStoreType,
+ masterClientCertificateKeyStoreUrl,
+ masterClientCertificateKeyStorePassword);
+ } else {
+ return new SslInfo(SslMode.valueOf(standbySslMode),
+ standbyTlsVersions,
+ standbyTrustCertificateKeyStoreType,
+ standbyTrustCertificateKeyStoreUrl,
+ standbyTrustCertificateKeyStorePassword,
+ standbyClientCertificateKeyStoreType,
+ standbyClientCertificateKeyStoreUrl,
+ standbyClientCertificateKeyStorePassword);
+ }
+ }
+ return new SslInfo(SslMode.valueOf(sslMode),
+ tlsVersions,
+ trustCertificateKeyStoreType,
+ trustCertificateKeyStoreUrl,
+ trustCertificateKeyStorePassword,
+ clientCertificateKeyStoreType,
+ clientCertificateKeyStoreUrl,
+ clientCertificateKeyStorePassword);
+ }
+
+ public void setSslMode(String sslMode) {
+ this.sslMode = sslMode;
+ }
+
+ public void setTlsVersions(String tlsVersions) {
+ this.tlsVersions = tlsVersions;
+ }
+
+ public void setTrustCertificateKeyStoreType(String trustCertificateKeyStoreType) {
+ this.trustCertificateKeyStoreType = trustCertificateKeyStoreType;
+ }
+
+ public void setTrustCertificateKeyStoreUrl(String trustCertificateKeyStoreUrl) {
+ this.trustCertificateKeyStoreUrl = trustCertificateKeyStoreUrl;
+ }
+
+ public void setTrustCertificateKeyStorePassword(String trustCertificateKeyStorePassword) {
+ this.trustCertificateKeyStorePassword = trustCertificateKeyStorePassword;
+ }
+
+ public void setClientCertificateKeyStoreType(String clientCertificateKeyStoreType) {
+ this.clientCertificateKeyStoreType = clientCertificateKeyStoreType;
+ }
+
+ public void setClientCertificateKeyStoreUrl(String clientCertificateKeyStoreUrl) {
+ this.clientCertificateKeyStoreUrl = clientCertificateKeyStoreUrl;
+ }
+
+ public void setClientCertificateKeyStorePassword(String clientCertificateKeyStorePassword) {
+ this.clientCertificateKeyStorePassword = clientCertificateKeyStorePassword;
+ }
+
+ public void setMasterSslMode(String masterSslMode) {
+ this.masterSslMode = masterSslMode;
+ }
+
+ public void setMasterTlsVersions(String masterTlsVersions) {
+ this.masterTlsVersions = masterTlsVersions;
+ }
+
+ public void setMasterTrustCertificateKeyStoreType(String masterTrustCertificateKeyStoreType) {
+ this.masterTrustCertificateKeyStoreType = masterTrustCertificateKeyStoreType;
+ }
+
+ public void setMasterTrustCertificateKeyStoreUrl(String masterTrustCertificateKeyStoreUrl) {
+ this.masterTrustCertificateKeyStoreUrl = masterTrustCertificateKeyStoreUrl;
+ }
+
+ public void setMasterTrustCertificateKeyStorePassword(String masterTrustCertificateKeyStorePassword) {
+ this.masterTrustCertificateKeyStorePassword = masterTrustCertificateKeyStorePassword;
+ }
+
+ public void setMasterClientCertificateKeyStoreType(String masterClientCertificateKeyStoreType) {
+ this.masterClientCertificateKeyStoreType = masterClientCertificateKeyStoreType;
+ }
+
+ public void setMasterClientCertificateKeyStoreUrl(String masterClientCertificateKeyStoreUrl) {
+ this.masterClientCertificateKeyStoreUrl = masterClientCertificateKeyStoreUrl;
+ }
+
+ public void setMasterClientCertificateKeyStorePassword(String masterClientCertificateKeyStorePassword) {
+ this.masterClientCertificateKeyStorePassword = masterClientCertificateKeyStorePassword;
+ }
+
+ public void setStandbySslMode(String standbySslMode) {
+ this.standbySslMode = standbySslMode;
+ }
+
+ public void setStandbyTlsVersions(String standbyTlsVersions) {
+ this.standbyTlsVersions = standbyTlsVersions;
+ }
+
+ public void setStandbyTrustCertificateKeyStoreType(String standbyTrustCertificateKeyStoreType) {
+ this.standbyTrustCertificateKeyStoreType = standbyTrustCertificateKeyStoreType;
+ }
+
+ public void setStandbyTrustCertificateKeyStoreUrl(String standbyTrustCertificateKeyStoreUrl) {
+ this.standbyTrustCertificateKeyStoreUrl = standbyTrustCertificateKeyStoreUrl;
+ }
+
+ public void setStandbyTrustCertificateKeyStorePassword(String standbyTrustCertificateKeyStorePassword) {
+ this.standbyTrustCertificateKeyStorePassword = standbyTrustCertificateKeyStorePassword;
+ }
+
+ public void setStandbyClientCertificateKeyStoreType(String standbyClientCertificateKeyStoreType) {
+ this.standbyClientCertificateKeyStoreType = standbyClientCertificateKeyStoreType;
+ }
+
+ public void setStandbyClientCertificateKeyStoreUrl(String standbyClientCertificateKeyStoreUrl) {
+ this.standbyClientCertificateKeyStoreUrl = standbyClientCertificateKeyStoreUrl;
+ }
+
+ public void setStandbyClientCertificateKeyStorePassword(String standbyClientCertificateKeyStorePassword) {
+ this.standbyClientCertificateKeyStorePassword = standbyClientCertificateKeyStorePassword;
+ }
+
public List getPositions() {
if (positions == null) {
positions = new ArrayList<>();
diff --git a/instance/spring/src/test/resources/spring/default-instance.xml b/instance/spring/src/test/resources/spring/default-instance.xml
index d86ea04e..2622e50d 100644
--- a/instance/spring/src/test/resources/spring/default-instance.xml
+++ b/instance/spring/src/test/resources/spring/default-instance.xml
@@ -114,7 +114,6 @@
-
diff --git a/instance/spring/src/test/resources/spring/file-instance.xml b/instance/spring/src/test/resources/spring/file-instance.xml
index ccf82931..1301a261 100644
--- a/instance/spring/src/test/resources/spring/file-instance.xml
+++ b/instance/spring/src/test/resources/spring/file-instance.xml
@@ -100,7 +100,6 @@
-
diff --git a/instance/spring/src/test/resources/spring/group-instance.xml b/instance/spring/src/test/resources/spring/group-instance.xml
index 543396b2..9e2940b1 100644
--- a/instance/spring/src/test/resources/spring/group-instance.xml
+++ b/instance/spring/src/test/resources/spring/group-instance.xml
@@ -106,7 +106,6 @@
-
@@ -186,7 +185,6 @@
-
diff --git a/instance/spring/src/test/resources/spring/memory-instance.xml b/instance/spring/src/test/resources/spring/memory-instance.xml
index f889c334..287755cc 100644
--- a/instance/spring/src/test/resources/spring/memory-instance.xml
+++ b/instance/spring/src/test/resources/spring/memory-instance.xml
@@ -97,7 +97,6 @@
-
diff --git a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/AbstractMysqlEventParser.java b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/AbstractMysqlEventParser.java
index 0c863bd5..b60fa6cc 100644
--- a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/AbstractMysqlEventParser.java
+++ b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/AbstractMysqlEventParser.java
@@ -33,7 +33,6 @@ public abstract class AbstractMysqlEventParser extends AbstractEventParser {
protected TableMetaTSDB tableMetaTSDB;
// 编码信息
- protected byte connectionCharsetNumber = (byte) 33;
protected Charset connectionCharset = Charset.forName("UTF-8");
protected boolean filterQueryDcl = false;
protected boolean filterQueryDml = false;
@@ -205,10 +204,6 @@ public abstract class AbstractMysqlEventParser extends AbstractEventParser {
// ============================ setter / getter =========================
- public void setConnectionCharsetNumber(byte connectionCharsetNumber) {
- this.connectionCharsetNumber = connectionCharsetNumber;
- }
-
public void setConnectionCharsetStd(Charset connectionCharset) {
this.connectionCharset = connectionCharset;
}
diff --git a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/LocalBinlogEventParser.java b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/LocalBinlogEventParser.java
index db235d9b..117afb17 100644
--- a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/LocalBinlogEventParser.java
+++ b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/LocalBinlogEventParser.java
@@ -116,7 +116,6 @@ public class LocalBinlogEventParser extends AbstractMysqlEventParser implements
MysqlConnection connection = new MysqlConnection(runningInfo.getAddress(),
runningInfo.getUsername(),
runningInfo.getPassword(),
- connectionCharsetNumber,
runningInfo.getDefaultDatabaseName());
connection.getConnector().setReceiveBufferSize(64 * 1024);
connection.getConnector().setSendBufferSize(64 * 1024);
diff --git a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlConnection.java b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlConnection.java
index c2c26174..6762e3fb 100644
--- a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlConnection.java
+++ b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlConnection.java
@@ -27,6 +27,7 @@ import com.alibaba.otter.canal.parse.driver.mysql.packets.client.RegisterSlaveCo
import com.alibaba.otter.canal.parse.driver.mysql.packets.client.SemiAckCommandPacket;
import com.alibaba.otter.canal.parse.driver.mysql.packets.server.ErrorPacket;
import com.alibaba.otter.canal.parse.driver.mysql.packets.server.ResultSetPacket;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;
import com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager;
import com.alibaba.otter.canal.parse.exception.CanalParseException;
import com.alibaba.otter.canal.parse.inbound.ErosaConnection;
@@ -73,14 +74,28 @@ public class MysqlConnection implements ErosaConnection {
connector.setConnTimeout(connTimeout);
}
- public MysqlConnection(InetSocketAddress address, String username, String password, byte charsetNumber,
- String defaultSchema){
+ public MysqlConnection(InetSocketAddress address, String username, String password,
+ String defaultSchema){
authInfo = new AuthenticationInfo();
authInfo.setAddress(address);
authInfo.setUsername(username);
authInfo.setPassword(password);
authInfo.setDefaultDatabaseName(defaultSchema);
- connector = new MysqlConnector(address, username, password, charsetNumber, defaultSchema);
+ connector = new MysqlConnector(address, username, password, defaultSchema);
+ // 将connection里面的参数透传下
+ connector.setSoTimeout(soTimeout);
+ connector.setConnTimeout(connTimeout);
+ }
+
+ public MysqlConnection(InetSocketAddress address, String username, String password,
+ String defaultSchema, SslInfo sslInfo){
+ authInfo = new AuthenticationInfo();
+ authInfo.setAddress(address);
+ authInfo.setUsername(username);
+ authInfo.setPassword(password);
+ authInfo.setDefaultDatabaseName(defaultSchema);
+ authInfo.setSslInfo(sslInfo);
+ connector = new MysqlConnector(address, username, password, defaultSchema, sslInfo);
// 将connection里面的参数透传下
connector.setSoTimeout(soTimeout);
connector.setConnTimeout(connTimeout);
diff --git a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlEventParser.java b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlEventParser.java
index f510f9af..f7d0cc0b 100644
--- a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlEventParser.java
+++ b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlEventParser.java
@@ -305,8 +305,8 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
MysqlConnection connection = new MysqlConnection(runningInfo.getAddress(),
runningInfo.getUsername(),
runningInfo.getPassword(),
- connectionCharsetNumber,
- runningInfo.getDefaultDatabaseName());
+ runningInfo.getDefaultDatabaseName(),
+ runningInfo.getSslInfo());
connection.getConnector().setReceiveBufferSize(receiveBufferSize);
connection.getConnector().setSendBufferSize(sendBufferSize);
connection.getConnector().setSoTimeout(defaultConnectionTimeoutInSeconds * 1000);
diff --git a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/RdsBinlogEventParserProxy.java b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/RdsBinlogEventParserProxy.java
index 775ffb49..c6c5312d 100644
--- a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/RdsBinlogEventParserProxy.java
+++ b/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/rds/RdsBinlogEventParserProxy.java
@@ -51,7 +51,6 @@ public class RdsBinlogEventParserProxy extends MysqlEventParser {
rdsLocalBinlogEventParser.setDestination(destination);
rdsLocalBinlogEventParser.setAlarmHandler(this.getAlarmHandler());
rdsLocalBinlogEventParser.setConnectionCharsetStd(this.connectionCharset);
- rdsLocalBinlogEventParser.setConnectionCharsetNumber(this.connectionCharsetNumber);
rdsLocalBinlogEventParser.setEnableTsdb(this.enableTsdb);
rdsLocalBinlogEventParser.setEventBlackFilter(this.eventBlackFilter);
rdsLocalBinlogEventParser.setFilterQueryDcl(this.filterQueryDcl);
diff --git a/parse/src/main/java/com/alibaba/otter/canal/parse/support/AuthenticationInfo.java b/parse/src/main/java/com/alibaba/otter/canal/parse/support/AuthenticationInfo.java
index 00d3521e..799b4ed1 100644
--- a/parse/src/main/java/com/alibaba/otter/canal/parse/support/AuthenticationInfo.java
+++ b/parse/src/main/java/com/alibaba/otter/canal/parse/support/AuthenticationInfo.java
@@ -3,6 +3,8 @@ package com.alibaba.otter.canal.parse.support;
import java.net.InetSocketAddress;
import com.alibaba.otter.canal.common.utils.CommonUtils;
+import com.alibaba.otter.canal.parse.driver.mysql.ssl.SslInfo;
+
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
@@ -22,6 +24,7 @@ public class AuthenticationInfo {
private String defaultDatabaseName;// 默认链接的数据库
private String pwdPublicKey; //公钥
private boolean enableDruid; //是否使用druid加密解密数据库密码
+ private SslInfo sslInfo;
public void initPwd() throws Exception{
if (enableDruid) {
@@ -37,13 +40,19 @@ public class AuthenticationInfo {
this(address, username, password, "");
}
- public AuthenticationInfo(InetSocketAddress address, String username, String password, String defaultDatabaseName){
+ private AuthenticationInfo(InetSocketAddress address, String username, String password, String defaultDatabaseName){
this.address = address;
this.username = username;
this.password = password;
this.defaultDatabaseName = defaultDatabaseName;
}
+ public AuthenticationInfo(InetSocketAddress address, String username, String password,
+ String defaultDatabaseName, SslInfo sslInfo) {
+ this(address, username, password, defaultDatabaseName);
+ this.sslInfo = sslInfo;
+ }
+
public InetSocketAddress getAddress() {
return address;
}
@@ -92,6 +101,14 @@ public class AuthenticationInfo {
this.enableDruid = enableDruid;
}
+ public SslInfo getSslInfo() {
+ return sslInfo;
+ }
+
+ public void setSslInfo(SslInfo sslInfo) {
+ this.sslInfo = sslInfo;
+ }
+
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE);
diff --git a/server/src/test/java/com/alibaba/otter/canal/server/CanalServerTest.java b/server/src/test/java/com/alibaba/otter/canal/server/CanalServerTest.java
index dee7034e..4f7e7568 100644
--- a/server/src/test/java/com/alibaba/otter/canal/server/CanalServerTest.java
+++ b/server/src/test/java/com/alibaba/otter/canal/server/CanalServerTest.java
@@ -253,7 +253,6 @@ public class CanalServerTest {
parameter.setDefaultConnectionTimeoutInSeconds(30);
parameter.setConnectionCharset("UTF-8");
- parameter.setConnectionCharsetNumber((byte) 33);
parameter.setReceiveBufferSize(8 * 1024);
parameter.setSendBufferSize(8 * 1024);
diff --git a/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_FileModeTest.java b/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_FileModeTest.java
index 7a4f4acb..7dbb51f6 100644
--- a/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_FileModeTest.java
+++ b/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_FileModeTest.java
@@ -40,7 +40,6 @@ public class CanalServerWithEmbedded_FileModeTest extends BaseCanalServerWithEmb
parameter.setDefaultConnectionTimeoutInSeconds(30);
parameter.setConnectionCharset("UTF-8");
- parameter.setConnectionCharsetNumber((byte) 33);
parameter.setReceiveBufferSize(8 * 1024);
parameter.setSendBufferSize(8 * 1024);
diff --git a/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandaloneTest.java b/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandaloneTest.java
index b600ba16..5d97962a 100644
--- a/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandaloneTest.java
+++ b/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandaloneTest.java
@@ -43,7 +43,6 @@ public class CanalServerWithEmbedded_StandaloneTest extends BaseCanalServerWithE
parameter.setDefaultConnectionTimeoutInSeconds(30);
parameter.setConnectionCharset("UTF-8");
- parameter.setConnectionCharsetNumber((byte) 33);
parameter.setReceiveBufferSize(8 * 1024);
parameter.setSendBufferSize(8 * 1024);
diff --git a/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandbyTest.java b/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandbyTest.java
index 55416ffa..b9593e9a 100644
--- a/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandbyTest.java
+++ b/server/src/test/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded_StandbyTest.java
@@ -55,7 +55,6 @@ public class CanalServerWithEmbedded_StandbyTest extends BaseCanalServerWithEmbe
parameter.setDefaultConnectionTimeoutInSeconds(30);
parameter.setConnectionCharset("UTF-8");
- parameter.setConnectionCharsetNumber((byte) 33);
parameter.setReceiveBufferSize(8 * 1024);
parameter.setSendBufferSize(8 * 1024);