mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 01:15:41 +08:00
135 lines
2.8 KiB
Go
135 lines
2.8 KiB
Go
package pxyproto
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/nadoo/glider/pkg/log"
|
|
"github.com/nadoo/glider/proxy"
|
|
)
|
|
|
|
func init() {
|
|
proxy.RegisterServer("pxyproto", NewPxyProtoServer)
|
|
}
|
|
|
|
// PxyProtoServer struct.
|
|
type PxyProtoServer struct {
|
|
addr string
|
|
proxy proxy.Proxy
|
|
server proxy.Server
|
|
}
|
|
|
|
// NewPxyProtoServer returns a PxyProtoServer struct.
|
|
func NewPxyProtoServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
|
schemes := strings.SplitN(s, ",", 2)
|
|
u, err := url.Parse(schemes[0])
|
|
if err != nil {
|
|
log.F("[pxyproto] parse url err: %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
t := &PxyProtoServer{proxy: p, addr: u.Host}
|
|
if len(schemes) < 2 {
|
|
return nil, errors.New("[pxyproto] you must use pxyproto with a proxy server, e.g: pxyproto://:1234,http://")
|
|
}
|
|
|
|
t.server, err = proxy.ServerFromURL(schemes[1], p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return t, nil
|
|
}
|
|
|
|
// ListenAndServe listens on server's addr and serves connections.
|
|
func (s *PxyProtoServer) ListenAndServe() {
|
|
l, err := net.Listen("tcp", s.addr)
|
|
if err != nil {
|
|
log.Fatalf("[pxyproto] failed to listen on %s: %v", s.addr, err)
|
|
return
|
|
}
|
|
defer l.Close()
|
|
|
|
log.F("[pxyproto] listening TCP on %s", s.addr)
|
|
|
|
for {
|
|
c, err := l.Accept()
|
|
if err != nil {
|
|
log.F("[pxyproto] failed to accept: %v", err)
|
|
continue
|
|
}
|
|
|
|
go s.Serve(c)
|
|
}
|
|
}
|
|
|
|
// Serve serves a connection.
|
|
func (s *PxyProtoServer) Serve(cc net.Conn) {
|
|
c, err := newServerConn(cc)
|
|
if err != nil {
|
|
log.F("[pxyproto] parse header failed, error: %v", err)
|
|
cc.Close()
|
|
return
|
|
}
|
|
|
|
// log.F("[pxyproto] %s <-> %s <-> %s <-> %s",
|
|
// c.RemoteAddr(), c.LocalAddr(), cc.RemoteAddr(), cc.LocalAddr())
|
|
|
|
if s.server != nil {
|
|
s.server.Serve(c)
|
|
return
|
|
}
|
|
}
|
|
|
|
type serverConn struct {
|
|
*proxy.Conn
|
|
src, dst net.Addr
|
|
}
|
|
|
|
func newServerConn(c net.Conn) (*serverConn, error) {
|
|
sc := &serverConn{
|
|
Conn: proxy.NewConn(c),
|
|
src: c.RemoteAddr(),
|
|
dst: c.LocalAddr(),
|
|
}
|
|
return sc, sc.parseHeader()
|
|
}
|
|
|
|
// "PROXY TCPx SRC_IP DST_IP SRC_PORT DST_PORT"
|
|
func (c *serverConn) parseHeader() error {
|
|
line, err := c.Conn.Reader().ReadString('\n')
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
line = strings.ReplaceAll(line, "\r\n", "")
|
|
// log.F("[pxyproto] req header: %s", line)
|
|
|
|
header := strings.Split(line, " ")
|
|
if len(header) != 6 {
|
|
return fmt.Errorf("invalid header: %s", line)
|
|
}
|
|
|
|
if header[0] != "PROXY" {
|
|
return fmt.Errorf("invalid header: %s", line)
|
|
}
|
|
|
|
c.src, err = net.ResolveTCPAddr("tcp", net.JoinHostPort(header[2], header[4]))
|
|
if err != nil {
|
|
return fmt.Errorf("parse header: %s, error: %v", line, err)
|
|
}
|
|
|
|
c.dst, err = net.ResolveTCPAddr("tcp", net.JoinHostPort(header[3], header[5]))
|
|
if err != nil {
|
|
return fmt.Errorf("parse header: %s, error: %v", line, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *serverConn) LocalAddr() net.Addr { return c.dst }
|
|
func (c *serverConn) RemoteAddr() net.Addr { return c.src }
|