-
Notifications
You must be signed in to change notification settings - Fork 32
S5 #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Open
S5 #7
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,3 +17,5 @@ output/ | |
|
|
||
| # Dependency directories (remove the comment below to include it) | ||
| # vendor/ | ||
|
|
||
| app.yaml | ||
5 changes: 5 additions & 0 deletions
example_app.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| app: | ||
| listenAddress: 127.0.0.1:39000 | ||
| ip_list: | ||
| - 127.0.0.1 | ||
| - 0.0.0.0 |
2 changes: 2 additions & 0 deletions
go.mod
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| module httpsproxy | ||
|
|
||
| go 1.14 | ||
|
|
||
| require github.com/spf13/viper v1.15.0 // indirect |
1,295 changes: 1,295 additions & 0 deletions
go.sum
Oops, something went wrong.
51 changes: 40 additions & 11 deletions
main.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,33 +1,62 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "flag" | ||
| "fmt" | ||
| "github.com/spf13/viper" | ||
| "httpsproxy/httpsserve" | ||
| "httpsproxy/socket5" | ||
| "log" | ||
| "net" | ||
| "os" | ||
| ) | ||
|
|
||
| var logger = log.New(os.Stderr, "httpsproxy:", log.Llongfile|log.LstdFlags) | ||
|
|
||
| func main(){ | ||
| var listenAdress string | ||
| flag.StringVar(&listenAdress, "L", "0.0.0.0:8080", "listen address.eg: 127.0.0.1:8080") | ||
| flag.Parse() | ||
| func init() { | ||
| initConfig() | ||
| } | ||
|
|
||
| func main() { | ||
| listenAddress := viper.GetString("app.listenAddress") | ||
| fmt.Println("开始监听端口:", listenAddress) | ||
| if !checkAddress(listenAddress) { | ||
| logger.Fatal("监听端口失败") | ||
| } | ||
|
|
||
| if !checkAdress(listenAdress){ | ||
| logger.Fatal("-L listen address format incorrect.Please check it") | ||
| ipList := viper.GetStringSlice("app.ip_list") | ||
| fmt.Println("代理ip数:", len(ipList)) | ||
| if len(ipList) < 1 { | ||
| logger.Fatal("代理ip不能为空") | ||
| } | ||
|
|
||
| httpsserve.Serve(listenAdress) | ||
| if !checkAddress(listenAddress) { | ||
| logger.Fatal("监听端口失败") | ||
| } | ||
|
|
||
| if viper.GetString("app.type") == "http" { | ||
| httpsserve.Serve(listenAddress) | ||
| } else { | ||
| socket5.Serve(listenAddress) | ||
| } | ||
|
|
||
| } | ||
|
|
||
| func checkAdress(adress string) bool{ | ||
| _, err := net.ResolveTCPAddr("tcp", adress) | ||
| if err != nil{ | ||
| func checkAddress(listenAddress string) bool{ | ||
| _, err := net.ResolveTCPAddr("tcp", listenAddress) | ||
| if err != nil{ | ||
| return false | ||
| } | ||
| return true | ||
|
|
||
| } | ||
|
|
||
| func initConfig() { | ||
| viper.SetConfigName("app") | ||
| viper.AddConfigPath(".") // 添加搜索路径 | ||
|
|
||
| err := viper.ReadInConfig() | ||
| if err != nil { | ||
| panic(fmt.Errorf("Fatal error config file: %s \n", err)) | ||
| } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
203 changes: 203 additions & 0 deletions
socket5/server.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| package socket5 | ||
|
|
||
| import ( | ||
| "bufio" | ||
| "context" | ||
| "encoding/binary" | ||
| "errors" | ||
| "fmt" | ||
| "httpsproxy/proxy" | ||
| "io" | ||
| "log" | ||
| "net" | ||
| "time" | ||
| ) | ||
|
|
||
| const socks5Ver = 0x05 | ||
| const cmdBind = 0x01 | ||
| const atypeIPV4 = 0x01 | ||
| const atypeHOST = 0x03 | ||
| const atypeIPV6 = 0x04 | ||
|
|
||
| func Serve(listenAddress string) { | ||
| server, err := net.Listen("tcp", listenAddress) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
| for { | ||
| client, err := server.Accept() | ||
| if err != nil { | ||
| log.Printf("Accept failed %v", err) | ||
| continue | ||
| } | ||
| go process(client) | ||
| } | ||
| } | ||
|
|
||
| func process(conn net.Conn) { | ||
| defer conn.Close() | ||
| reader := bufio.NewReader(conn) | ||
| err := auth(reader, conn) | ||
| if err != nil { | ||
| log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err) | ||
| return | ||
| } | ||
| err = connect(reader, conn) | ||
| if err != nil { | ||
| log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err) | ||
| return | ||
| } | ||
| } | ||
|
|
||
| func auth(reader *bufio.Reader, conn net.Conn) (err error) { | ||
| // 读取协议版本(VER) | ||
| // +----+----------+----------+ | ||
| // |VER | NMETHODS | METHODS | | ||
| // +----+----------+----------+ | ||
| // | 1 | 1 | 1 to 255 | | ||
| // +----+----------+----------+ | ||
| // VER: 协议版本,socks5为0x05 | ||
| // NMETHODS: 支持认证的方法数量 | ||
| // METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下: | ||
| // X’00’ NO AUTHENTICATION REQUIRED | ||
| // X’02’ USERNAME/PASSWORD | ||
| ver, err := reader.ReadByte() | ||
| if err != nil { | ||
| return fmt.Errorf("read ver failed:%w", err) | ||
| } | ||
| // 检查协议版本是否为 SOCKS5 | ||
| if ver != socks5Ver { | ||
| return fmt.Errorf("not supported ver:%v", ver) | ||
| } | ||
|
|
||
| // 读取支持的认证方法数(NMETHODS) | ||
| methodSize, err := reader.ReadByte() | ||
| if err != nil { | ||
| return fmt.Errorf("read methodSize failed:%w", err) | ||
| } | ||
| // 读取每个认证方法的字节 | ||
| method := make([]byte, methodSize) | ||
| _, err = io.ReadFull(reader, method) | ||
| if err != nil { | ||
| return fmt.Errorf("read method failed:%w", err) | ||
| } | ||
| //log.Println("ver", ver, "method", method) | ||
|
|
||
| // 回复客户端的协议版本和认证方法(VER, METHOD) | ||
| // +----+--------+ | ||
| // |VER | METHOD | | ||
| // +----+--------+ | ||
| // | 1 | 1 | | ||
| // +----+--------+ | ||
| _, err = conn.Write([]byte{socks5Ver, 0x00}) | ||
| if err != nil { | ||
| return fmt.Errorf("write failed:%w", err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func connect(reader *bufio.Reader, conn net.Conn) (err error) { | ||
| // +----+-----+-------+------+----------+----------+ | ||
| // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | | ||
| // +----+-----+-------+------+----------+----------+ | ||
| // | 1 | 1 | X'00' | 1 | Variable | 2 | | ||
| // +----+-----+-------+------+----------+----------+ | ||
| // VER 版本号,socks5的值为0x05 | ||
| // CMD 0x01表示CONNECT请求 | ||
| // RSV 保留字段,值为0x00 | ||
| // ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。 | ||
| // 0x01表示IPv4地址,DST.ADDR为4个字节 | ||
| // 0x03表示域名,DST.ADDR是一个可变长度的域名 | ||
| // DST.ADDR 一个可变长度的值 | ||
| // DST.PORT 目标端口,固定2个字节 | ||
| // 读取协议头部信息 | ||
| buf := make([]byte, 4) | ||
| _, err = io.ReadFull(reader, buf) | ||
| if err != nil { | ||
| return fmt.Errorf("read header failed:%w", err) | ||
| } | ||
| ver, cmd, atyp := buf[0], buf[1], buf[3] | ||
| if ver != socks5Ver { // 检查版本号是否为 SOCKS5 | ||
| return fmt.Errorf("not supported ver:%v", ver) | ||
| } | ||
| if cmd != cmdBind { // 检查指令是否为 CONNECT 请求 | ||
| return fmt.Errorf("not supported cmd:%v", cmd) | ||
| } | ||
|
|
||
| // 解析目标地址 | ||
| addr := "" | ||
| switch atyp { | ||
| case atypeIPV4: // IPv4 地址 | ||
| _, err = io.ReadFull(reader, buf) | ||
| if err != nil { | ||
| return fmt.Errorf("read atyp failed:%w", err) | ||
| } | ||
| addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]) | ||
| case atypeHOST: // 域名 | ||
| hostSize, err := reader.ReadByte() | ||
| if err != nil { | ||
| return fmt.Errorf("read hostSize failed:%w", err) | ||
| } | ||
| host := make([]byte, hostSize) | ||
| _, err = io.ReadFull(reader, host) | ||
| if err != nil { | ||
| return fmt.Errorf("read host failed:%w", err) | ||
| } | ||
| addr = string(host) | ||
| case atypeIPV6: // IPv6 地址,暂不支持 | ||
| return errors.New("IPv6: no supported yet") | ||
| default: // 无效的地址类型 | ||
| return errors.New("invalid atyp") | ||
| } | ||
|
|
||
| // 解析目标端口 | ||
| _, err = io.ReadFull(reader, buf[:2]) | ||
| if err != nil { | ||
| return fmt.Errorf("read port failed:%w", err) | ||
| } | ||
| port := binary.BigEndian.Uint16(buf[:2]) | ||
|
|
||
| localIP := proxy.GetRandomIp() | ||
| // 连接到目标地址 | ||
| dest, err := proxy.DialCustom("tcp", fmt.Sprintf("%v:%v", addr, port), time.Second*10, localIP) | ||
| if err != nil { | ||
| return fmt.Errorf("dial dst failed:%w", err) | ||
| } | ||
| defer dest.Close() | ||
| log.Println("dial", addr, port) | ||
|
|
||
| // +----+-----+-------+------+----------+----------+ | ||
| // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | | ||
| // +----+-----+-------+------+----------+----------+ | ||
| // | 1 | 1 | X'00' | 1 | Variable | 2 | | ||
| // +----+-----+-------+------+----------+----------+ | ||
| // VER socks版本,这里为0x05 | ||
| // REP Relay field,内容取值如下 X’00’ succeeded | ||
| // RSV 保留字段 | ||
| // ATYPE 地址类型 | ||
| // BND.ADDR 服务绑定的地址 | ||
| // BND.PORT 服务绑定的端口DST.PORT | ||
|
|
||
| // 发送代理成功响应 | ||
| _, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0}) | ||
| if err != nil { | ||
| return fmt.Errorf("write failed: %w", err) | ||
| } | ||
|
|
||
| // 启动双向数据传输协程 | ||
| ctx, cancel := context.WithCancel(context.Background()) | ||
| defer cancel() | ||
|
|
||
| go func() { | ||
| _, _ = io.Copy(dest, reader) // 从客户端读取数据并发送到目标地址 | ||
| cancel() | ||
| }() | ||
| go func() { | ||
| _, _ = io.Copy(conn, dest) // 从目标地址读取数据并发送回客户端 | ||
| cancel() | ||
| }() | ||
|
|
||
| <-ctx.Done() | ||
| return nil | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.