mirror of
https://github.com/luscis/openlan.git
synced 2025-10-07 09:30:54 +08:00
fea: merge http and socks5 proxy.
This commit is contained in:
33
Makefile
33
Makefile
@@ -78,11 +78,9 @@ builder:
|
|||||||
# tar xvf libreswan_4.10.orig.tar.gz
|
# tar xvf libreswan_4.10.orig.tar.gz
|
||||||
# cd libreswan-4.10 && make deb
|
# cd libreswan-4.10 && make deb
|
||||||
|
|
||||||
|
|
||||||
docker-bin: ## binary by Docker
|
docker-bin: ## binary by Docker
|
||||||
docker exec openlan_builder bash -c "cd /opt/openlan && make linux-bin"
|
docker exec openlan_builder bash -c "cd /opt/openlan && make linux-bin"
|
||||||
|
|
||||||
|
|
||||||
docker-test: ## test by Docker
|
docker-test: ## test by Docker
|
||||||
docker exec openlan_builder bash -c "cd /opt/openlan && make test"
|
docker exec openlan_builder bash -c "cd /opt/openlan && make test"
|
||||||
|
|
||||||
@@ -92,6 +90,9 @@ docker-darwin: ## binary for MacOS by Docker
|
|||||||
docker-windows: ## binary for Windows by Docker
|
docker-windows: ## binary for Windows by Docker
|
||||||
docker exec openlan_builder bash -c "cd /opt/openlan && make windows-gzip"
|
docker exec openlan_builder bash -c "cd /opt/openlan && make windows-gzip"
|
||||||
|
|
||||||
|
docker-ceci: ## binary for ceci by Docker
|
||||||
|
docker exec openlan_builder bash -c "cd /opt/openlan && make ceci"
|
||||||
|
|
||||||
docker-rhel: docker-bin ## build image for redhat
|
docker-rhel: docker-bin ## build image for redhat
|
||||||
cp -rf $(SD)/docker/centos $(BD)
|
cp -rf $(SD)/docker/centos $(BD)
|
||||||
cd $(BD) && \
|
cd $(BD) && \
|
||||||
@@ -118,13 +119,19 @@ docker-compose: ## create a compose files
|
|||||||
echo "$ cd /tmp/openlan.c" && \
|
echo "$ cd /tmp/openlan.c" && \
|
||||||
echo "$ docker-compose up -d"
|
echo "$ docker-compose up -d"
|
||||||
|
|
||||||
linux: env ## build linux binary
|
ceci: linux-ceci darwin-ceci windows-ceci ## build all platform ceci
|
||||||
|
|
||||||
|
linux: env linux-ceci linux-proxy ## build linux binary
|
||||||
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan ./cmd/main.go
|
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan ./cmd/main.go
|
||||||
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy ./cmd/proxy
|
|
||||||
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci ./cmd/ceci
|
|
||||||
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-point ./cmd/point
|
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-point ./cmd/point
|
||||||
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-switch ./cmd/switch
|
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-switch ./cmd/switch
|
||||||
|
|
||||||
|
linux-ceci:
|
||||||
|
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci ./cmd/ceci
|
||||||
|
|
||||||
|
linux-proxy:
|
||||||
|
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy ./cmd/proxy
|
||||||
|
|
||||||
linux-gzip: install ## build linux packages
|
linux-gzip: install ## build linux packages
|
||||||
@rm -rf $(LIN_DIR).tar.gz
|
@rm -rf $(LIN_DIR).tar.gz
|
||||||
tar -cf $(LIN_DIR).tar $(LIN_DIR) && mv $(LIN_DIR).tar $(BD)
|
tar -cf $(LIN_DIR).tar $(LIN_DIR) && mv $(LIN_DIR).tar $(BD)
|
||||||
@@ -152,8 +159,12 @@ install: env linux ## install packages
|
|||||||
@echo "Installed to $(LIN_DIR)"
|
@echo "Installed to $(LIN_DIR)"
|
||||||
|
|
||||||
## cross build for windows
|
## cross build for windows
|
||||||
windows: ## build windows binary
|
windows: env windows-ceci windows-proxy ## build windows binary
|
||||||
|
|
||||||
|
windows-proxy:
|
||||||
GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.exe ./cmd/proxy
|
GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.exe ./cmd/proxy
|
||||||
|
|
||||||
|
windows-ceci:
|
||||||
GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.exe ./cmd/ceci
|
GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.exe ./cmd/ceci
|
||||||
|
|
||||||
windows-gzip: env windows ## build windows packages
|
windows-gzip: env windows ## build windows packages
|
||||||
@@ -166,12 +177,16 @@ windows-gzip: env windows ## build windows packages
|
|||||||
## cross build for osx
|
## cross build for osx
|
||||||
osx: darwin
|
osx: darwin
|
||||||
|
|
||||||
darwin: env ## build darwin binary
|
darwin: env darwin-ceci darwin-proxy ## build darwin binary
|
||||||
GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.dar ./cmd/proxy
|
|
||||||
GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.arm64.dar ./cmd/proxy
|
darwin-ceci:
|
||||||
GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.dar ./cmd/ceci
|
GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.dar ./cmd/ceci
|
||||||
GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.arm64.dar ./cmd/ceci
|
GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.arm64.dar ./cmd/ceci
|
||||||
|
|
||||||
|
darwin-proxy:
|
||||||
|
GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.dar ./cmd/proxy
|
||||||
|
GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.arm64.dar ./cmd/proxy
|
||||||
|
|
||||||
darwin-gzip: env darwin ## build darwin packages
|
darwin-gzip: env darwin ## build darwin packages
|
||||||
@rm -rf $(MAC_DIR) && mkdir -p $(MAC_DIR)
|
@rm -rf $(MAC_DIR) && mkdir -p $(MAC_DIR)
|
||||||
@cp -rf $(SD)/dist/rootfs/etc/openlan/proxy.json.local $(MAC_DIR)/proxy.json
|
@cp -rf $(SD)/dist/rootfs/etc/openlan/proxy.json.local $(MAC_DIR)/proxy.json
|
||||||
|
91
cmd/api/v5/ceci.go
Executable file
91
cmd/api/v5/ceci.go
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
package v5
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/luscis/openlan/cmd/api"
|
||||||
|
"github.com/luscis/openlan/pkg/schema"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Ceci struct {
|
||||||
|
Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Ceci) Url(prefix, name string) string {
|
||||||
|
return prefix + "/api/interface/" + name + "/ceci"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Ceci) Tmpl() string {
|
||||||
|
return `# total {{ len . }}
|
||||||
|
{{ps -16 "Name"}} {{ps -8 "Configure"}}
|
||||||
|
{{- range . }}
|
||||||
|
{{ps -16 .Name}} {{pi .Configure}}
|
||||||
|
{{- end }}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Ceci) List(c *cli.Context) error {
|
||||||
|
url := u.Url(c.String("url"), "")
|
||||||
|
clt := u.NewHttp(c.String("token"))
|
||||||
|
var items []schema.Ceci
|
||||||
|
if err := clt.GetJSON(url, &items); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return u.Out(items, c.String("format"), u.Tmpl())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Ceci) Add(c *cli.Context) error {
|
||||||
|
name := c.String("name")
|
||||||
|
rate := &schema.Ceci{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
url := u.Url(c.String("url"), name)
|
||||||
|
clt := u.NewHttp(c.String("token"))
|
||||||
|
if err := clt.PostJSON(url, rate, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Ceci) Remove(c *cli.Context) error {
|
||||||
|
name := c.String("name")
|
||||||
|
|
||||||
|
url := u.Url(c.String("url"), name)
|
||||||
|
clt := u.NewHttp(c.String("token"))
|
||||||
|
if err := clt.DeleteJSON(url, nil, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Ceci) Commands(app *api.App) {
|
||||||
|
app.Command(&cli.Command{
|
||||||
|
Name: "ceci",
|
||||||
|
Usage: "Ceci proxy",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "list",
|
||||||
|
Usage: "Display all ceci proxy",
|
||||||
|
Aliases: []string{"ls"},
|
||||||
|
Action: u.List,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Usage: "Add a ceci proxy",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{Name: "name", Required: true},
|
||||||
|
&cli.StringFlag{Name: "file", Required: true},
|
||||||
|
},
|
||||||
|
Action: u.Add,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove",
|
||||||
|
Usage: "Remove a ceci proxy",
|
||||||
|
Aliases: []string{"rm"},
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{Name: "name", Required: true},
|
||||||
|
},
|
||||||
|
Action: u.Remove,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
@@ -40,4 +40,5 @@ func Commands(app *api.App) {
|
|||||||
Log{}.Commands(app)
|
Log{}.Commands(app)
|
||||||
ZTrust{}.Commands(app)
|
ZTrust{}.Commands(app)
|
||||||
Rate{}.Commands(app)
|
Rate{}.Commands(app)
|
||||||
|
Ceci{}.Commands(app)
|
||||||
}
|
}
|
||||||
|
12
dist/rootfs/etc/openlan/switch/ceci/https.yaml.example
vendored
Normal file
12
dist/rootfs/etc/openlan/switch/ceci/https.yaml.example
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
listen: 127.0.0.1:1080
|
||||||
|
socks:
|
||||||
|
listen: 127.0.0.1:1081
|
||||||
|
cacert: ca.crt
|
||||||
|
backends:
|
||||||
|
- protocol: ssl
|
||||||
|
server: <s1>:18000
|
||||||
|
socks:
|
||||||
|
server: <s2:18001>
|
||||||
|
match:
|
||||||
|
- a.b.com
|
@@ -2,8 +2,10 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/luscis/openlan/pkg/libol"
|
"github.com/luscis/openlan/pkg/libol"
|
||||||
)
|
)
|
||||||
@@ -18,11 +20,69 @@ type ShadowProxy struct {
|
|||||||
Protocol string `json:"protocol,omitempty"`
|
Protocol string `json:"protocol,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ForwardSocks struct {
|
||||||
|
Server string `json:"server,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpForward struct {
|
||||||
|
Protocol string `json:"protocol,omitempty" yaml:"protocol,omitempty"`
|
||||||
|
Server string `json:"server,omitempty" yaml:"server,omitempty"`
|
||||||
|
Insecure bool `json:"insecure,omitempty" yaml:"insecure,omitempty"`
|
||||||
|
Match []string `json:"match,omitempty" yaml:"match,omitempty"`
|
||||||
|
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
|
||||||
|
Socks ForwardSocks `json:"socks,omitempty" yaml:"socks,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *HttpForward) SocksAddr() string {
|
||||||
|
if f.Socks.Server != "" {
|
||||||
|
return f.Socks.Server
|
||||||
|
}
|
||||||
|
return f.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpBackends []*HttpForward
|
||||||
|
|
||||||
|
func (h HttpBackends) isMatch(value string, rules []string) bool {
|
||||||
|
if len(rules) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rule := range rules {
|
||||||
|
pattern := fmt.Sprintf(`(^|\.)%s(:\d+)?$`, regexp.QuoteMeta(rule))
|
||||||
|
re := regexp.MustCompile(pattern)
|
||||||
|
if re.MatchString(value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h HttpBackends) FindBackend(host string) *HttpForward {
|
||||||
|
for _, via := range h {
|
||||||
|
if via == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if via.Server == "" && via.Socks.Server == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if h.isMatch(host, via.Match) {
|
||||||
|
return via
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type FindBackend interface {
|
||||||
|
FindBackend(host string) *HttpForward
|
||||||
|
}
|
||||||
|
|
||||||
type SocksProxy struct {
|
type SocksProxy struct {
|
||||||
Conf string `json:"-" yaml:"-"`
|
Conf string `json:"-" yaml:"-"`
|
||||||
Listen string `json:"listen,omitempty" yaml:"listen,omitempty"`
|
Listen string `json:"listen,omitempty" yaml:"listen,omitempty"`
|
||||||
Auth *Password `json:"auth,omitempty" yaml:"auth,omitempty"`
|
Auth *Password `json:"auth,omitempty" yaml:"auth,omitempty"`
|
||||||
Backends []*HttpForward `json:"backends,omitempty" yaml:"backends,omitempty"`
|
Backends HttpBackends `json:"backends,omitempty" yaml:"backends,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocksProxy) Initialize() error {
|
func (s *SocksProxy) Initialize() error {
|
||||||
@@ -41,12 +101,8 @@ func (s *SocksProxy) Load() error {
|
|||||||
return libol.UnmarshalLoad(s, s.Conf)
|
return libol.UnmarshalLoad(s, s.Conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
type HttpForward struct {
|
type HttpSocks struct {
|
||||||
Protocol string `json:"protocol,omitempty" yaml:"protocol,omitempty"`
|
Listen string `json:"listen,omitempty"`
|
||||||
Server string `json:"server,omitempty" yaml:"server,omitempty"`
|
|
||||||
Insecure bool `json:"insecure,omitempty" yaml:"insecure,omitempty"`
|
|
||||||
Match []string `json:"match,omitempty" yaml:"match,omitempty"`
|
|
||||||
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type HttpProxy struct {
|
type HttpProxy struct {
|
||||||
@@ -57,8 +113,9 @@ type HttpProxy struct {
|
|||||||
Cert *Cert `json:"cert,omitempty" yaml:"cert,omitempty"`
|
Cert *Cert `json:"cert,omitempty" yaml:"cert,omitempty"`
|
||||||
Password string `json:"password,omitempty" yaml:"password,omitempty"`
|
Password string `json:"password,omitempty" yaml:"password,omitempty"`
|
||||||
CaCert string `json:"cacert,omitempty" yaml:"cacert,omitempty"`
|
CaCert string `json:"cacert,omitempty" yaml:"cacert,omitempty"`
|
||||||
Forward *HttpForward `json:"forward,omitempty" yaml:"forward,omitempty"`
|
Backends HttpBackends `json:"backends,omitempty" yaml:"backends,omitempty"`
|
||||||
Backends []*HttpForward `json:"backends,omitempty" yaml:"backends,omitempty"`
|
Socks *HttpSocks `json:"socks,omitempty" yaml:"socks,omitempty"`
|
||||||
|
SocksProxy *SocksProxy `json:"-" yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpProxy) Initialize() error {
|
func (h *HttpProxy) Initialize() error {
|
||||||
@@ -93,6 +150,11 @@ func (h *HttpProxy) Correct() {
|
|||||||
h.CaCert = "ca.crt"
|
h.CaCert = "ca.crt"
|
||||||
}
|
}
|
||||||
h.CaCert = path.Join(h.ConfDir, h.CaCert)
|
h.CaCert = path.Join(h.ConfDir, h.CaCert)
|
||||||
|
if h.Socks != nil {
|
||||||
|
h.SocksProxy = &SocksProxy{
|
||||||
|
Listen: h.Socks.Listen,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpProxy) FindMatch(domain string, to *HttpForward) int {
|
func (h *HttpProxy) FindMatch(domain string, to *HttpForward) int {
|
||||||
@@ -105,9 +167,6 @@ func (h *HttpProxy) FindMatch(domain string, to *HttpForward) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpProxy) FindBackend(remote string) *HttpForward {
|
func (h *HttpProxy) FindBackend(remote string) *HttpForward {
|
||||||
if remote == "" || remote == "null" {
|
|
||||||
return h.Forward
|
|
||||||
}
|
|
||||||
for _, to := range h.Backends {
|
for _, to := range h.Backends {
|
||||||
if to.Server == remote {
|
if to.Server == remote {
|
||||||
return to
|
return to
|
||||||
|
@@ -13,7 +13,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -57,6 +56,7 @@ type HttpProxy struct {
|
|||||||
startat time.Time
|
startat time.Time
|
||||||
requests map[string]*HttpRecord
|
requests map[string]*HttpRecord
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
|
socks *SocksProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -134,7 +134,10 @@ func NewHttpProxy(cfg *co.HttpProxy, px Proxyer) *HttpProxy {
|
|||||||
if auth != nil && auth.Username != "" {
|
if auth != nil && auth.Username != "" {
|
||||||
h.pass[auth.Username] = auth.Password
|
h.pass[auth.Username] = auth.Password
|
||||||
}
|
}
|
||||||
|
if cfg.SocksProxy != nil {
|
||||||
|
h.socks = NewSocksProxy(cfg.SocksProxy)
|
||||||
|
h.socks.server.SetBackends(h)
|
||||||
|
}
|
||||||
h.loadUrl()
|
h.loadUrl()
|
||||||
h.loadPass()
|
h.loadPass()
|
||||||
|
|
||||||
@@ -271,7 +274,7 @@ func (t *HttpProxy) toTunnel(w http.ResponseWriter, conn net.Conn, update func(b
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *HttpProxy) openConn(protocol, remote string, insecure bool) (net.Conn, error) {
|
func (t *HttpProxy) openConn(protocol, remote string, insecure bool) (net.Conn, error) {
|
||||||
if protocol == "https" {
|
if protocol == "https" || protocol == "tls" {
|
||||||
conf := &tls.Config{
|
conf := &tls.Config{
|
||||||
InsecureSkipVerify: insecure,
|
InsecureSkipVerify: insecure,
|
||||||
}
|
}
|
||||||
@@ -294,6 +297,12 @@ func (t *HttpProxy) openConn(protocol, remote string, insecure bool) (net.Conn,
|
|||||||
return net.DialTimeout("tcp", remote, 10*time.Second)
|
return net.DialTimeout("tcp", remote, 10*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HttpProxy) FindBackend(host string) *co.HttpForward {
|
||||||
|
h.lock.RLock()
|
||||||
|
defer h.lock.RUnlock()
|
||||||
|
return h.cfg.Backends.FindBackend(host)
|
||||||
|
}
|
||||||
|
|
||||||
func (t *HttpProxy) cloneRequest(r *http.Request, secret string) ([]byte, error) {
|
func (t *HttpProxy) cloneRequest(r *http.Request, secret string) ([]byte, error) {
|
||||||
var err error
|
var err error
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
@@ -344,36 +353,6 @@ func (t *HttpProxy) cloneRequest(r *http.Request, secret string) ([]byte, error)
|
|||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HttpProxy) isMatch(value string, rules []string) bool {
|
|
||||||
if len(rules) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, rule := range rules {
|
|
||||||
pattern := fmt.Sprintf(`(^|\.)%s(:\d+)?$`, regexp.QuoteMeta(rule))
|
|
||||||
re := regexp.MustCompile(pattern)
|
|
||||||
if re.MatchString(value) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *HttpProxy) findForward(r *http.Request) *co.HttpForward {
|
|
||||||
t.lock.RLock()
|
|
||||||
defer t.lock.RUnlock()
|
|
||||||
|
|
||||||
via := t.cfg.Forward
|
|
||||||
if via != nil && t.isMatch(r.URL.Host, via.Match) {
|
|
||||||
return via
|
|
||||||
}
|
|
||||||
for _, via := range t.cfg.Backends {
|
|
||||||
if via != nil && t.isMatch(r.URL.Host, via.Match) {
|
|
||||||
return via
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *HttpProxy) doRecord(r *http.Request, bytes int64) {
|
func (t *HttpProxy) doRecord(r *http.Request, bytes int64) {
|
||||||
t.lock.Lock()
|
t.lock.Lock()
|
||||||
defer t.lock.Unlock()
|
defer t.lock.Unlock()
|
||||||
@@ -401,7 +380,7 @@ func (t *HttpProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.doRecord(r, 0)
|
t.doRecord(r, 0)
|
||||||
via := t.findForward(r)
|
via := t.FindBackend(r.URL.Host)
|
||||||
if via != nil {
|
if via != nil {
|
||||||
t.out.Info("HttpProxy.ServeHTTP %s %s -> %s via %s", r.Method, r.RemoteAddr, r.URL.Host, via.Server)
|
t.out.Info("HttpProxy.ServeHTTP %s %s -> %s via %s", r.Method, r.RemoteAddr, r.URL.Host, via.Server)
|
||||||
conn, err := t.openConn(via.Protocol, via.Server, via.Insecure)
|
conn, err := t.openConn(via.Protocol, via.Server, via.Insecure)
|
||||||
@@ -450,6 +429,11 @@ func (t *HttpProxy) Start() {
|
|||||||
if t.server == nil || t.cfg == nil {
|
if t.server == nil || t.cfg == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.socks != nil {
|
||||||
|
t.socks.Start()
|
||||||
|
}
|
||||||
|
|
||||||
crt := t.cfg.Cert
|
crt := t.cfg.Cert
|
||||||
if crt == nil || crt.KeyFile == "" {
|
if crt == nil || crt.KeyFile == "" {
|
||||||
t.out.Info("HttpProxy.start http://%s", t.server.Addr)
|
t.out.Info("HttpProxy.start http://%s", t.server.Addr)
|
||||||
|
@@ -50,7 +50,7 @@ func (s *SocksProxy) Start() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
addr := s.cfg.Listen
|
addr := s.cfg.Listen
|
||||||
s.out.Info("SocksProxy.Start: %s", s.cfg.Listen)
|
s.out.Info("SocksProxy.Start: socks5://%s", s.cfg.Listen)
|
||||||
|
|
||||||
promise := &libol.Promise{
|
promise := &libol.Promise{
|
||||||
First: time.Second * 2,
|
First: time.Second * 2,
|
||||||
|
6
pkg/schema/ceci.go
Normal file
6
pkg/schema/ceci.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
type Ceci struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Config interface{} `json:"config"`
|
||||||
|
}
|
@@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
co "github.com/luscis/openlan/pkg/config"
|
co "github.com/luscis/openlan/pkg/config"
|
||||||
@@ -54,7 +53,7 @@ type Config struct {
|
|||||||
Dial func(ctx context.Context, network, addr string) (net.Conn, error)
|
Dial func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||||
|
|
||||||
// Backends forwarding socks request
|
// Backends forwarding socks request
|
||||||
Backends []*co.HttpForward
|
Backends co.FindBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server is reponsible for accepting connections and handling
|
// Server is reponsible for accepting connections and handling
|
||||||
@@ -121,7 +120,6 @@ func (s *Server) Serve(l net.Listener) error {
|
|||||||
}
|
}
|
||||||
go s.ServeConn(conn)
|
go s.ServeConn(conn)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeConn is used to serve a single connection.
|
// ServeConn is used to serve a single connection.
|
||||||
@@ -132,14 +130,14 @@ func (s *Server) ServeConn(conn net.Conn) error {
|
|||||||
// Read the version byte
|
// Read the version byte
|
||||||
version := []byte{0}
|
version := []byte{0}
|
||||||
if _, err := bufConn.Read(version); err != nil {
|
if _, err := bufConn.Read(version); err != nil {
|
||||||
s.config.Logger.Error("socks: Failed to get version byte: %v", err)
|
s.config.Logger.Error("Socks.ServeConn Failed to get version byte: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we are compatible
|
// Ensure we are compatible
|
||||||
if version[0] != socks5Version {
|
if version[0] != socks5Version {
|
||||||
err := fmt.Errorf("Unsupported SOCKS version: %v", version)
|
err := fmt.Errorf("Unsupported SOCKS version: %v", version)
|
||||||
s.config.Logger.Error("socks: %v", err)
|
s.config.Logger.Error("Socks.ServeConn %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +145,7 @@ func (s *Server) ServeConn(conn net.Conn) error {
|
|||||||
authContext, err := s.authenticate(conn, bufConn)
|
authContext, err := s.authenticate(conn, bufConn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Failed to authenticate: %v", err)
|
err = fmt.Errorf("Failed to authenticate: %v", err)
|
||||||
s.config.Logger.Error("socks: %v", err)
|
s.config.Logger.Error("Socks.ServeConn %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,20 +164,22 @@ func (s *Server) ServeConn(conn net.Conn) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dstAddr := request.DestAddr
|
dstAddr := request.DestAddr
|
||||||
via := s.findForward(dstAddr.Address())
|
if s.config.Backends != nil {
|
||||||
|
via := s.config.Backends.FindBackend(dstAddr.Address())
|
||||||
if via != nil {
|
if via != nil {
|
||||||
if err := s.toForward(request, conn, via); err != nil {
|
if err := s.toForward(request, conn, via); err != nil {
|
||||||
s.config.Logger.Error("socks.forward: %v", err)
|
s.config.Logger.Error("Socks.ServeConn: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.config.Logger.Info("socks.ServeConn: %s", dstAddr.Address())
|
s.config.Logger.Info("Socks.ServeConn CONNECT %s", dstAddr.Address())
|
||||||
//Process the client request
|
//Process the client request
|
||||||
if err := s.handleRequest(request, conn); err != nil {
|
if err := s.handleRequest(request, conn); err != nil {
|
||||||
err = fmt.Errorf("Failed to handle request: %v", err)
|
err = fmt.Errorf("Failed to handle request: %v", err)
|
||||||
s.config.Logger.Error("socks: %v", err)
|
s.config.Logger.Error("Socks.ServeConn %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -205,34 +205,13 @@ func (s *Server) openConn(remote string) (net.Conn, error) {
|
|||||||
return net.DialTimeout("tcp", remote, 10*time.Second)
|
return net.DialTimeout("tcp", remote, 10*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) isMatch(value string, rules []string) bool {
|
|
||||||
if len(rules) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, rule := range rules {
|
|
||||||
pattern := fmt.Sprintf(`(^|\.)%s(:\d+)?$`, regexp.QuoteMeta(rule))
|
|
||||||
re := regexp.MustCompile(pattern)
|
|
||||||
if re.MatchString(value) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) findForward(host string) *co.HttpForward {
|
|
||||||
for _, via := range s.config.Backends {
|
|
||||||
if via != nil && s.isMatch(host, via.Match) {
|
|
||||||
return via
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) toForward(req *Request, local net.Conn, via *co.HttpForward) error {
|
func (s *Server) toForward(req *Request, local net.Conn, via *co.HttpForward) error {
|
||||||
dstAddr := req.DestAddr
|
dstAddr := req.DestAddr
|
||||||
s.config.Logger.Info("socks.toForward: %s via %s", dstAddr.Address(), via.Server)
|
proxy := via.SocksAddr()
|
||||||
|
|
||||||
target, err := s.openConn(via.Server)
|
s.config.Logger.Info("Socks.ServeConn CONNECT %s via %s", dstAddr.Address(), proxy)
|
||||||
|
|
||||||
|
target, err := s.openConn(proxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendReply(local, networkUnreachable, nil)
|
sendReply(local, networkUnreachable, nil)
|
||||||
return err
|
return err
|
||||||
@@ -270,3 +249,7 @@ func (s *Server) toForward(req *Request, local net.Conn, via *co.HttpForward) er
|
|||||||
s.toTunnel(local, target)
|
s.toTunnel(local, target)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) SetBackends(find co.FindBackend) {
|
||||||
|
s.config.Backends = find
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user