| 
									
										
										
										
											2023-03-16 20:54:19 +08:00
										 |  |  | package mysql | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2023-12-06 16:35:05 +08:00
										 |  |  | 	"crypto/md5" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2023-03-16 20:54:19 +08:00
										 |  |  | 	"net" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/go-sql-driver/mysql" | 
					
						
							|  |  |  | 	"golang.org/x/net/proxy" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // registerProxyDialerContext registers a new dialer context to be used by mysql when the proxy network is
 | 
					
						
							|  |  |  | // specified in the connection string
 | 
					
						
							| 
									
										
										
										
											2024-02-14 20:05:47 +08:00
										 |  |  | func registerProxyDialerContext(protocol, cnnstr string, dialer proxy.Dialer) (string, error) { | 
					
						
							|  |  |  | 	// the mysqlDialer contains the true network used behind the scenes
 | 
					
						
							|  |  |  | 	mysqlDialer, err := getProxyDialerContext(protocol, dialer) | 
					
						
							| 
									
										
										
										
											2023-03-16 20:54:19 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// the dialer context can be updated everytime the datasource is updated
 | 
					
						
							|  |  |  | 	// have a unique network per connection string
 | 
					
						
							| 
									
										
										
										
											2023-12-06 16:35:05 +08:00
										 |  |  | 	hash := fmt.Sprintf("%x", md5.Sum([]byte(cnnstr))) | 
					
						
							| 
									
										
										
										
											2023-03-16 20:54:19 +08:00
										 |  |  | 	network := "proxy-" + hash | 
					
						
							| 
									
										
										
										
											2024-02-14 20:05:47 +08:00
										 |  |  | 	mysql.RegisterDialContext(network, mysqlDialer.DialContext) | 
					
						
							| 
									
										
										
										
											2023-03-16 20:54:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return network, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // mySQLContextDialer turns a golang proxy driver into a MySQL proxy driver
 | 
					
						
							|  |  |  | type mySQLContextDialer struct { | 
					
						
							|  |  |  | 	dialer  proxy.ContextDialer | 
					
						
							|  |  |  | 	network string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // getProxyDialerContext returns a context dialer that will send the request through to the secure socks proxy
 | 
					
						
							| 
									
										
										
										
											2024-02-14 20:05:47 +08:00
										 |  |  | func getProxyDialerContext(actualNetwork string, dialer proxy.Dialer) (*mySQLContextDialer, error) { | 
					
						
							| 
									
										
										
										
											2023-03-16 20:54:19 +08:00
										 |  |  | 	contextDialer, ok := dialer.(proxy.ContextDialer) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2024-02-14 20:05:47 +08:00
										 |  |  | 		return nil, fmt.Errorf("mysql proxy creation failed") | 
					
						
							| 
									
										
										
										
											2023-03-16 20:54:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return &mySQLContextDialer{dialer: contextDialer, network: actualNetwork}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DialContext implements the MySQL requirements for a proxy driver, and uses the underlying golang proxy driver with the assigned network
 | 
					
						
							|  |  |  | func (d *mySQLContextDialer) DialContext(ctx context.Context, addr string) (net.Conn, error) { | 
					
						
							|  |  |  | 	return d.dialer.DialContext(ctx, d.network, addr) | 
					
						
							|  |  |  | } |