Skip to content

Commit

Permalink
Init: first commit 🎉
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreamacro committed Jun 10, 2018
1 parent 8532718 commit 4f192ef
Show file tree
Hide file tree
Showing 27 changed files with 1,451 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# dep
vendor
84 changes: 84 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true


[[constraint]]
name = "github.com/oschwald/geoip2-golang"
version = "1.2.1"

[[constraint]]
name = "github.com/riobard/go-shadowsocks2"
version = "0.1.0"

[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.5"

[[constraint]]
name = "gopkg.in/eapache/channels.v1"
version = "1.1.0"

[[constraint]]
name = "gopkg.in/ini.v1"
version = "1.37.0"

[prune]
go-tests = true
unused-packages = true
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Clash

A rule based proxy in Go.

## Features

- HTTP/HTTPS and SOCKS proxy
- Surge like configuration
- GeoIP rule support

## Install

You can build from source:

```sh
go get -u -v github.com/Dreamacro/clash
```

Requires Go >= 1.10.

## Config

Configuration file at `$HOME/.config/clash/config.ini`

Below is a simple demo configuration file:

```ini
[General]
port = 7890
socks-port = 7891

[Proxy]
# name = ss, server, port, cipter, password
Proxy = ss, server, port, AEAD_CHACHA20_POLY1305, password

[Rule]
DOMAIN-SUFFIX,google.com,Proxy
DOMAIN-KEYWORD,google,Proxy
DOMAIN-SUFFIX,ad.com,REJECT
GEOIP,CN,DIRECT
FINAL,,Proxy
```

## TODO

- [ ] Complementing the necessary rule operators
44 changes: 44 additions & 0 deletions adapters/direct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package adapters

import (
"io"
"net"

C "github.com/Dreamacro/clash/constant"
)

// DirectAdapter is a directly connected adapter
type DirectAdapter struct {
conn net.Conn
}

// Writer is used to output network traffic
func (d *DirectAdapter) Writer() io.Writer {
return d.conn
}

// Reader is used to input network traffic
func (d *DirectAdapter) Reader() io.Reader {
return d.conn
}

// Close is used to close connection
func (d *DirectAdapter) Close() {
d.conn.Close()
}

type Direct struct {
}

func (d *Direct) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
c, err := net.Dial("tcp", net.JoinHostPort(addr.Host, addr.Port))
if err != nil {
return
}
c.(*net.TCPConn).SetKeepAlive(true)
return &DirectAdapter{conn: c}, nil
}

func NewDirect() *Direct {
return &Direct{}
}
46 changes: 46 additions & 0 deletions adapters/reject.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package adapters

import (
"io"

C "github.com/Dreamacro/clash/constant"
)

// RejectAdapter is a reject connected adapter
type RejectAdapter struct {
}

// Writer is used to output network traffic
func (r *RejectAdapter) Writer() io.Writer {
return &NopRW{}
}

// Reader is used to input network traffic
func (r *RejectAdapter) Reader() io.Reader {
return &NopRW{}
}

// Close is used to close connection
func (r *RejectAdapter) Close() {
}

type Reject struct {
}

func (r *Reject) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
return &RejectAdapter{}, nil
}

func NewReject() *Reject {
return &Reject{}
}

type NopRW struct{}

func (rw *NopRW) Read(b []byte) (int, error) {
return len(b), nil
}

func (rw *NopRW) Write(b []byte) (int, error) {
return 0, io.EOF
}
97 changes: 97 additions & 0 deletions adapters/shadowsocks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package adapters

import (
"bytes"
"fmt"
"io"
"net"
"net/url"
"strconv"

C "github.com/Dreamacro/clash/constant"

"github.com/riobard/go-shadowsocks2/core"
"github.com/riobard/go-shadowsocks2/socks"
)

// ShadowsocksAdapter is a shadowsocks adapter
type ShadowsocksAdapter struct {
conn net.Conn
}

// Writer is used to output network traffic
func (ss *ShadowsocksAdapter) Writer() io.Writer {
return ss.conn
}

// Reader is used to input network traffic
func (ss *ShadowsocksAdapter) Reader() io.Reader {
return ss.conn
}

// Close is used to close connection
func (ss *ShadowsocksAdapter) Close() {
ss.conn.Close()
}

type ShadowSocks struct {
server string
cipher string
password string
}

func (ss *ShadowSocks) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
var key []byte
ciph, _ := core.PickCipher(ss.cipher, key, ss.password)
c, err := net.Dial("tcp", ss.server)
if err != nil {
return nil, fmt.Errorf("%s connect error", ss.server)
}
c.(*net.TCPConn).SetKeepAlive(true)
c = ciph.StreamConn(c)
_, err = c.Write(serializesSocksAddr(addr))
return &ShadowsocksAdapter{conn: c}, err
}

func NewShadowSocks(ssURL string) *ShadowSocks {
server, cipher, password, _ := parseURL(ssURL)
return &ShadowSocks{
server: server,
cipher: cipher,
password: password,
}
}

func parseURL(s string) (addr, cipher, password string, err error) {
u, err := url.Parse(s)
if err != nil {
return
}

addr = u.Host
if u.User != nil {
cipher = u.User.Username()
password, _ = u.User.Password()
}
return
}

func serializesSocksAddr(addr *C.Addr) []byte {
var buf [][]byte
aType := uint8(addr.AddrType)
p, _ := strconv.Atoi(addr.Port)
port := []byte{uint8(p >> 8), uint8(p & 0xff)}
switch addr.AddrType {
case socks.AtypDomainName:
len := uint8(len(addr.Host))
host := []byte(addr.Host)
buf = [][]byte{[]byte{aType, len}, host, port}
case socks.AtypIPv4:
host := net.ParseIP(addr.Host).To4()
buf = [][]byte{[]byte{aType}, host, port}
case socks.AtypIPv6:
host := net.ParseIP(addr.Host).To16()
buf = [][]byte{[]byte{aType}, host, port}
}
return bytes.Join(buf, []byte(""))
}
Loading

0 comments on commit 4f192ef

Please sign in to comment.