2017-04-09 23:51:38 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
"github.com/golang/glog"
|
2017-09-17 18:42:31 +00:00
|
|
|
|
2017-04-09 23:51:38 +00:00
|
|
|
"github.com/paultag/sniff/parser"
|
|
|
|
)
|
|
|
|
|
|
|
|
type server struct {
|
2017-05-11 18:04:19 +00:00
|
|
|
Hostname string
|
|
|
|
IP string
|
|
|
|
Port int
|
2017-04-28 22:21:47 +00:00
|
|
|
ProxyProtocol bool
|
2017-04-09 23:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type proxy struct {
|
|
|
|
ServerList []*server
|
|
|
|
Default *server
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *proxy) Get(host string) *server {
|
2017-05-26 18:25:06 +00:00
|
|
|
if p.ServerList == nil {
|
|
|
|
return p.Default
|
|
|
|
}
|
|
|
|
|
2017-04-09 23:51:38 +00:00
|
|
|
for _, s := range p.ServerList {
|
|
|
|
if s.Hostname == host {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-08 21:44:43 +00:00
|
|
|
return p.Default
|
2017-04-09 23:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *proxy) Handle(conn net.Conn) {
|
|
|
|
defer conn.Close()
|
|
|
|
data := make([]byte, 4096)
|
|
|
|
|
|
|
|
length, err := conn.Read(data)
|
|
|
|
if err != nil {
|
|
|
|
glog.V(4).Infof("error reading the first 4k of the connection: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-05-11 18:04:19 +00:00
|
|
|
proxy := p.Default
|
2017-04-09 23:51:38 +00:00
|
|
|
hostname, err := parser.GetHostname(data[:])
|
|
|
|
if err == nil {
|
2017-05-11 18:04:19 +00:00
|
|
|
glog.V(4).Infof("parsed hostname from TLS Client Hello: %s", hostname)
|
2017-04-09 23:51:38 +00:00
|
|
|
proxy = p.Get(hostname)
|
2017-05-11 18:04:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if proxy == nil {
|
|
|
|
glog.V(4).Infof("there is no configured proxy for SSL connections")
|
|
|
|
return
|
2017-04-09 23:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
clientConn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", proxy.IP, proxy.Port))
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer clientConn.Close()
|
|
|
|
|
2017-04-28 22:21:47 +00:00
|
|
|
if proxy.ProxyProtocol {
|
|
|
|
//Write out the proxy-protocol header
|
|
|
|
localAddr := conn.LocalAddr().(*net.TCPAddr)
|
|
|
|
remoteAddr := conn.RemoteAddr().(*net.TCPAddr)
|
|
|
|
protocol := "UNKNOWN"
|
|
|
|
if remoteAddr.IP.To4() != nil {
|
|
|
|
protocol = "TCP4"
|
|
|
|
} else if remoteAddr.IP.To16() != nil {
|
|
|
|
protocol = "TCP6"
|
|
|
|
}
|
|
|
|
proxyProtocolHeader := fmt.Sprintf("PROXY %s %s %s %d %d\r\n", protocol, remoteAddr.IP.String(), localAddr.IP.String(), remoteAddr.Port, localAddr.Port)
|
|
|
|
glog.V(4).Infof("Writing proxy protocol header - %s", proxyProtocolHeader)
|
|
|
|
_, err = fmt.Fprintf(clientConn, proxyProtocolHeader)
|
|
|
|
}
|
2017-04-09 23:51:38 +00:00
|
|
|
if err != nil {
|
2017-04-28 22:21:47 +00:00
|
|
|
glog.Errorf("unexpected error writing proxy-protocol header: %s", err)
|
2017-04-09 23:51:38 +00:00
|
|
|
clientConn.Close()
|
2017-04-28 22:21:47 +00:00
|
|
|
} else {
|
|
|
|
_, err = clientConn.Write(data[:length])
|
|
|
|
if err != nil {
|
|
|
|
glog.Errorf("unexpected error writing first 4k of proxy data: %s", err)
|
|
|
|
clientConn.Close()
|
|
|
|
}
|
2017-04-09 23:51:38 +00:00
|
|
|
}
|
2017-04-28 22:21:47 +00:00
|
|
|
|
2017-04-09 23:51:38 +00:00
|
|
|
pipe(clientConn, conn)
|
|
|
|
}
|
|
|
|
|
|
|
|
func pipe(client, server net.Conn) {
|
|
|
|
doCopy := func(s, c net.Conn, cancel chan<- bool) {
|
|
|
|
io.Copy(s, c)
|
|
|
|
cancel <- true
|
|
|
|
}
|
|
|
|
|
|
|
|
cancel := make(chan bool, 2)
|
|
|
|
|
|
|
|
go doCopy(server, client, cancel)
|
|
|
|
go doCopy(client, server, cancel)
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-cancel:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|