pupy/services/proxy/main.go

171 lines
4.6 KiB
Go

package main
import (
"fmt"
"path"
"io/ioutil"
"crypto/tls"
"crypto/x509"
"strconv"
"strings"
"flag"
log "github.com/sirupsen/logrus"
iniflags "github.com/vharitonsky/iniflags"
)
var (
ProxyBindHost = "0.0.0.0"
ExternalBindHost = "0.0.0.0"
ProxyBindPort uint = 9876
DnsBindPort uint = 5454
ProxyHostname = ""
UDPSize uint = 1400
ListenerCA = path.Join("..", "crypto", "proxy-ca.crt")
ListenerCAKey = path.Join("..", "crypto", "proxy-ca.key")
ListenerKey = path.Join("..", "crypto", "proxy.key")
ListenerCert = path.Join("..", "crypto", "proxy.crt")
ClientKey = path.Join("..", "crypto", "proxy-client.key")
ClientCert = path.Join("..", "crypto", "proxy-client.crt")
PortMaps []PortMap
OnListenerEnabledURL = ""
OnListenerDisabledURL = ""
ListenerConfig *tls.Config
)
func init() {
generate := false
loglevel := "ERROR"
portmap := ""
flag.StringVar(&ProxyBindHost, "listen-proxy", ProxyBindHost, "IP address to bind pupysh listener side")
flag.UintVar(&ProxyBindPort, "port-proxy", ProxyBindPort, "Port to bind pupysh listener side")
flag.StringVar(&ExternalBindHost, "listen", ExternalBindHost, "IP address to bind services listener side")
flag.UintVar(&DnsBindPort, "dns-port", DnsBindPort, "Port to bind DNS listeners (if any)")
flag.UintVar(&UDPSize, "udp-mtu-size", UDPSize, "MTU Size for DNS and KCP UDP Packets")
flag.StringVar(&ListenerCA, "ca", ListenerCA, "Path to CA certificate (pupysh side)")
flag.StringVar(&ListenerKey, "key", ListenerKey, "Path to TLS key (pupysh side)")
flag.StringVar(&ListenerCert, "cert", ListenerCert, "Path to TLS cert (pupysh side)")
flag.StringVar(&portmap, "port-map", portmap, "Automatically substitute ports (example: \"443:1443 80:8080\")")
flag.StringVar(&ProxyHostname, "hostname-proxy", ProxyHostname,
"Hostname for pupysh listener side (used with generate)")
flag.StringVar(&loglevel, "loglevel", loglevel, "Set log level")
flag.StringVar(&OnListenerEnabledURL, "on-enabled-url", OnListenerEnabledURL,
"Send GET request when at least one client connected")
flag.StringVar(&OnListenerDisabledURL, "on-disabled-url", OnListenerDisabledURL,
"Send GET request when at least one client connected")
flag.BoolVar(&generate, "generate", false, "Generate all the keys")
iniflags.Parse()
switch strings.ToLower(loglevel) {
case "error":
log.SetLevel(log.ErrorLevel)
case "err":
log.SetLevel(log.ErrorLevel)
case "warning":
log.SetLevel(log.WarnLevel)
case "warn":
log.SetLevel(log.WarnLevel)
case "info":
log.SetLevel(log.InfoLevel)
case "debug":
log.SetLevel(log.DebugLevel)
default:
log.Fatalln("Invalid log level", loglevel)
}
if strings.Contains(portmap, ":") {
for _, mapping := range strings.Split(portmap, " ") {
if !strings.Contains(portmap, ":") {
continue
}
parts := strings.Split(mapping, ":")
if len(parts) != 2 {
log.Fatalln("Invalid mapping specification: ", parts)
}
var (
from, to int
err error
)
from, err = strconv.Atoi(parts[0])
if err != nil {
log.Fatalln("Invalid mapping specification: ", parts, "From: ", err)
}
to, err = strconv.Atoi(parts[1])
if err != nil {
log.Fatalln("Invalid mapping specification: ", parts, "To: ", err)
}
PortMaps = append(PortMaps, PortMap{
From: from,
To: to,
})
}
}
if strings.Index(ProxyBindHost, ":") == -1 {
if ExternalBindHost == "0.0.0.0" {
ExternalBindHost = ProxyBindHost
}
ProxyBindHost = fmt.Sprintf("%s:%d", ProxyBindHost, ProxyBindPort)
} else {
if ExternalBindHost == "0.0.0.0" {
ExternalBindHost = strings.SplitN(ProxyBindHost, ":", 1)[0]
}
}
if strings.Index(ExternalBindHost, ":") != -1 {
log.Fatalln("External IP address should be specified without port")
}
if generate {
log.Warn("Genrating NEW keys")
generateKeys()
}
cert, err := tls.LoadX509KeyPair(ListenerCert, ListenerKey)
if err != nil {
log.Fatalln(err)
}
pem, err := ioutil.ReadFile(ListenerCA)
if err != nil {
log.Fatalln(err)
}
caPool := x509.NewCertPool()
if !caPool.AppendCertsFromPEM(pem) {
log.Fatalln("Could't append CA certificates to CA pool")
}
ListenerConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: caPool,
NextProtos: []string{"pp/1"},
}
}
func main() {
NewDaemon(ProxyBindHost).ListenAndServe()
}