I have a task to modify result of a query to MySQL server. I've created a simple Golang tcp proxy-server which can bypass packets from client to server and reverse. Now it looks like this:
package proxy
import (
"io"
"net"
ll "common/logger"
)
type MysqlProxy struct {
logger ll.Logger
proxy net.Listener
mysqlAddr string
}
func NewMysqlProxy(logger ll.Logger, proxyAddr, mysqlAddr string) (*MysqlProxy, error) {
tcpServer, err := net.Listen("tcp", proxyAddr)
if err != nil {
return nil, err
}
return &MysqlProxy{
logger: logger,
proxy: tcpServer,
mysqlAddr: mysqlAddr,
}, nil
}
func (p *MysqlProxy) Close() error {
return p.proxy.Close()
}
func (p *MysqlProxy) AcceptConnection() {
tlsConn, err := p.proxy.Accept()
if err != nil {
p.logger.Error(
"[MysqlProxy] error on accepting a new tls-connection",
)
return
}
p.logger.Info(
"[MysqlProxy] accepted a connection on a proxy server",
ll.LogField("proxy_server_remote_addr", ll.FieldTypeString, tlsConn.RemoteAddr().String()),
ll.LogField("proxy_server_local_addr", ll.FieldTypeString, tlsConn.LocalAddr().String()),
ll.LogField("target_db_server", ll.FieldTypeString, p.mysqlAddr),
)
go p.handleConnection(tlsConn)
}
func (p *MysqlProxy) handleConnection(proxyConn net.Conn) {
defer func(proxyConn net.Conn) {
if err := proxyConn.Close(); err != nil {
p.logger.Error(
"[MysqlProxy] error on closing connection from proxy",
)
}
}(proxyConn)
mysql, err := net.Dial("tcp", p.mysqlAddr)
if err != nil {
return
}
go func() {
_, err := io.Copy(proxyConn, mysql)
if err != nil {
p.logger.Error(
"[MysqlProxy] error on coping bytes from mysql to proxy",
)
}
}()
if _, err := io.Copy(mysql, proxyConn); err != nil {
p.logger.Error(
"[MysqlProxy] error on coping bytes from proxy to mysql",
)
}
}
However, now it just bypass bytes and I need to analyze the packets from the server to the client:
if _, err := io.Copy(mysql, proxyConn); err != nil {
There are several libs in Go which provide a client, proxy or protocol itself:
- https://github.com/go-mysql-org/go-mysql
- https://github.com/shogo82148/go-sql-proxy
- https://github.com/xelabs/go-mysqlstack
but I've not found examples of working with raw bytes from the server there. I need to get a string representation from the result (ex. rows from the "SELECT..." query), work with them, then pack back to the raw-bytes response and send it to the client.