Init: first commit 🎉

This commit is contained in:
Dreamacro
2018-06-10 22:50:03 +08:00
parent 8532718345
commit 4f192ef575
27 changed files with 1451 additions and 0 deletions

52
tunnel/log.go Normal file
View File

@ -0,0 +1,52 @@
package tunnel
import (
"fmt"
log "github.com/sirupsen/logrus"
)
const (
INFO LogType = iota
WARNING
ERROR
DEBUG
)
type LogType int
type Log struct {
LogType LogType
Payload string
}
func print(data Log) {
switch data.LogType {
case INFO:
log.Infoln(data.Payload)
case WARNING:
log.Warnln(data.Payload)
case ERROR:
log.Errorln(data.Payload)
case DEBUG:
log.Debugln(data.Payload)
}
}
func (t *Tunnel) subscribeLogs() {
sub, err := t.observable.Subscribe()
if err != nil {
log.Fatalf("Can't subscribe tunnel log: %s", err.Error())
}
for elm := range sub {
data := elm.(Log)
print(data)
}
}
func newLog(logType LogType, format string, v ...interface{}) Log {
return Log{
LogType: logType,
Payload: fmt.Sprintf(format, v...),
}
}

146
tunnel/tunnel.go Normal file
View File

@ -0,0 +1,146 @@
package tunnel
import (
"fmt"
"io"
"strings"
"sync"
"github.com/Dreamacro/clash/adapters"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/observable"
R "github.com/Dreamacro/clash/rules"
"gopkg.in/eapache/channels.v1"
)
var (
tunnel *Tunnel
once sync.Once
)
type Tunnel struct {
queue *channels.InfiniteChannel
rules []C.Rule
proxys map[string]C.Proxy
observable *observable.Observable
logCh chan interface{}
}
func (t *Tunnel) Add(req C.ServerAdapter) {
t.queue.In() <- req
}
func (t *Tunnel) UpdateConfig() (err error) {
cfg, err := C.GetConfig()
if err != nil {
return
}
proxys := cfg.Section("Proxy")
rules := cfg.Section("Rule")
// parse proxy
for _, key := range proxys.Keys() {
proxy := strings.Split(key.Value(), ",")
if len(proxy) == 0 {
continue
}
proxy = trimArr(proxy)
switch proxy[0] {
// ss, server, port, cipter, password
case "ss":
if len(proxy) < 5 {
continue
}
ssURL := fmt.Sprintf("ss://%s:%s@%s:%s", proxy[3], proxy[4], proxy[1], proxy[2])
t.proxys[key.Name()] = adapters.NewShadowSocks(ssURL)
}
}
// init proxy
t.proxys["DIRECT"] = adapters.NewDirect()
t.proxys["REJECT"] = adapters.NewReject()
// parse rules
for _, key := range rules.Keys() {
rule := strings.Split(key.Name(), ",")
if len(rule) < 3 {
continue
}
rule = trimArr(rule)
switch rule[0] {
case "DOMAIN-SUFFIX":
t.rules = append(t.rules, R.NewDomainSuffix(rule[1], rule[2]))
case "DOMAIN-KEYWORD":
t.rules = append(t.rules, R.NewDomainKeyword(rule[1], rule[2]))
case "GEOIP":
t.rules = append(t.rules, R.NewGEOIP(rule[1], rule[2]))
case "IP-CIDR", "IP-CIDR6":
t.rules = append(t.rules, R.NewIPCIDR(rule[1], rule[2]))
case "FINAL":
t.rules = append(t.rules, R.NewFinal(rule[2]))
}
}
return nil
}
func (t *Tunnel) process() {
queue := t.queue.Out()
for {
elm := <-queue
conn := elm.(C.ServerAdapter)
go t.handleConn(conn)
}
}
func (t *Tunnel) handleConn(localConn C.ServerAdapter) {
defer localConn.Close()
addr := localConn.Addr()
proxy := t.match(addr)
remoConn, err := proxy.Generator(addr)
if err != nil {
t.logCh <- newLog(WARNING, "Proxy connect error: %s", err.Error())
return
}
defer remoConn.Close()
go io.Copy(localConn.Writer(), remoConn.Reader())
io.Copy(remoConn.Writer(), localConn.Reader())
}
func (t *Tunnel) match(addr *C.Addr) C.Proxy {
for _, rule := range t.rules {
if rule.IsMatch(addr) {
a, ok := t.proxys[rule.Adapter()]
if !ok {
continue
}
t.logCh <- newLog(INFO, "%v match %d using %s", addr.Host, rule.RuleType(), rule.Adapter())
return a
}
}
t.logCh <- newLog(INFO, "don't find, direct")
return t.proxys["DIRECT"]
}
func newTunnel() *Tunnel {
logCh := make(chan interface{})
tunnel := &Tunnel{
queue: channels.NewInfiniteChannel(),
proxys: make(map[string]C.Proxy),
observable: observable.NewObservable(logCh),
logCh: logCh,
}
go tunnel.process()
go tunnel.subscribeLogs()
return tunnel
}
func GetInstance() *Tunnel {
once.Do(func() {
tunnel = newTunnel()
})
return tunnel
}

12
tunnel/utils.go Normal file
View File

@ -0,0 +1,12 @@
package tunnel
import (
"strings"
)
func trimArr(arr []string) (r []string) {
for _, e := range arr {
r = append(r, strings.Trim(e, " "))
}
return
}