├── image ├── capture.png └── capture2.PNG ├── README.md ├── LICENSE └── main.go /image/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blogcin/ToTo/HEAD/image/capture.png -------------------------------------------------------------------------------- /image/capture2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blogcin/ToTo/HEAD/image/capture2.PNG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ToTo 2 | [![GoDoc](https://godoc.org/github.com/blogcin/ToTo?status.svg)](https://godoc.org/github.com/blogcin/ToTo) 3 | 4 | ToTo is a simple proxy server written in Go Language 5 | 6 | - light! 7 | - easy to use! 8 | 9 | ### Version 10 | --- 11 | 1.0 12 | ### Clone 13 | --- 14 | ```sh 15 | $ git clone http://github.com/blogcin/ToTo 16 | ``` 17 | 18 | ### How to use? 19 | --- 20 | ```sh 21 | $ go run main.go 22 | ``` 23 | Execute and enter the port on intermediate computer(to circumvent), set proxy setting on your program (like browser, messenger if that support proxy setting) 24 | 25 | [Picture1](https://raw.githubusercontent.com/blogcin/ToTo/master/image/capture.png) 26 | --- 27 | [Picture2](https://raw.githubusercontent.com/blogcin/ToTo/master/image/capture2.PNG) 28 | --- 29 | ### Contribute 30 | --- 31 | Just pull-request to me! 32 | 33 | ### License 34 | --- 35 | MIT Licensed. See the LICENSE file for details. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Song Hyeon Sik (blogcin@naver.com) 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | * ToTo - Go language proxy server 5 | * Song Hyeon Sik 2016 6 | */ 7 | 8 | import ( 9 | "fmt" 10 | "io" 11 | "net" 12 | "strconv" 13 | "strings" 14 | ) 15 | 16 | const ( 17 | bufferLength = 8192 18 | headerLine = 30 19 | ) 20 | 21 | // ProxyServer stores the configuration for ProxyServer and some functions. 22 | type ProxyServer struct { 23 | port string 24 | } 25 | 26 | // ask port 27 | func (ps *ProxyServer) askPort() int { 28 | port := 0 29 | 30 | fmt.Print("Port : ") 31 | fmt.Scanf("%d", &port) 32 | 33 | return port 34 | } 35 | 36 | // initialize socket server 37 | func (ps *ProxyServer) init(port int) net.Listener { 38 | ps.port = ":" 39 | ps.port += strconv.Itoa(port) 40 | 41 | server, err := net.Listen("tcp", ps.port) 42 | 43 | if server == nil { 44 | panic("init: port listening error : " + err.Error()) 45 | } 46 | 47 | return server 48 | } 49 | 50 | // accept client 51 | func (ps *ProxyServer) acceptClient(server net.Listener) chan net.Conn { 52 | channel := make(chan net.Conn) 53 | 54 | go func() { 55 | for { 56 | client, err := server.Accept() 57 | if client == nil { 58 | fmt.Println("ps: acceptClient: Couldn't accept : ", err.Error()) 59 | continue 60 | } 61 | channel <- client 62 | } 63 | 64 | }() 65 | return channel 66 | } 67 | 68 | // connect host by socket 69 | func (ps *ProxyServer) connectHost(client net.Conn) { 70 | HeaderInfo, Datas := ps.getData(client) 71 | 72 | if (Datas[0] == 0) || (HeaderInfo == "-1") { 73 | return 74 | } 75 | requestType, host, _, port := ps.parseHTTPHeaderMethod(HeaderInfo) 76 | 77 | if port == -1 { 78 | return 79 | } 80 | 81 | connectionHost, _ := net.Dial("tcp", host+":"+strconv.Itoa(port)) 82 | 83 | if requestType == "CONNECT" { 84 | connectionHost.Write([]byte("HTTP/1.1 200 Connection established\n")) 85 | } else { 86 | connectionHost.Write(Datas) 87 | go func() { 88 | io.Copy(connectionHost, client) 89 | }() 90 | io.Copy(client, connectionHost) 91 | } 92 | client.Close() 93 | connectionHost.Close() 94 | return 95 | } 96 | 97 | // Get first line of http header 98 | func (ps *ProxyServer) getData(client net.Conn) (string, []byte) { 99 | 100 | buffer := make([]byte, bufferLength) 101 | client.Read(buffer) 102 | 103 | return ps.splitHeader(buffer)[0], buffer 104 | } 105 | 106 | // parse HTTPHeader from packets 107 | func (ps *ProxyServer) parseHTTPHeaderMethod(headerMethod string) (string, string, string, int) { 108 | var ( 109 | requestType string 110 | host string 111 | protocol string 112 | port int 113 | ) 114 | errorCounter := false 115 | 116 | // ex: GET http://google.com/ HTTP/1.1 117 | temp := headerMethod[strings.Index(headerMethod, " ")+1:] 118 | protocol = temp[strings.Index(temp, " ")+1:] 119 | 120 | url := temp[:strings.Index(temp, " ")] 121 | 122 | i := strings.Index(url, "://") 123 | 124 | if i == -1 { 125 | fmt.Println("Uncorrect URL") 126 | errorCounter = true 127 | } else { 128 | host = url[i+3 : len(url)-1] 129 | } 130 | 131 | if errorCounter == false { 132 | i = strings.Index(host, ":") 133 | if i == -1 { 134 | port = 80 135 | } else { 136 | port, _ = strconv.Atoi(host[i+1:]) 137 | host = host[:i] 138 | } 139 | 140 | i = strings.Index(host, "/") 141 | if i != -1 { 142 | host = host[:i] 143 | } 144 | requestType = headerMethod[:strings.Index(headerMethod, " ")] 145 | 146 | return requestType, host, protocol, port 147 | } 148 | 149 | return "", "", "", -1 150 | } 151 | 152 | // split header each lines 153 | func (ps *ProxyServer) splitHeader(bytearray []byte) []string { 154 | 155 | result := make([]string, headerLine) 156 | lineNumber := 0 157 | temp := false 158 | 159 | if bytearray[0] == 0 { 160 | fmt.Println("ps: splitHeader: Couldn't get httpheader, zero filter") 161 | result[0] = string("-1") 162 | return result 163 | } 164 | 165 | for index, element := range bytearray { 166 | if element == '\r' { 167 | if bytearray[index+1] == '\n' { 168 | temp = true 169 | } 170 | } 171 | 172 | if temp != true { 173 | result[lineNumber] += string(element) 174 | } 175 | 176 | if element == '\n' { 177 | temp = false 178 | lineNumber++ 179 | } 180 | } 181 | 182 | return result 183 | } 184 | 185 | func main() { 186 | proxyServer := &ProxyServer{} 187 | 188 | port := proxyServer.askPort() 189 | 190 | server := proxyServer.init(port) 191 | defer server.Close() 192 | 193 | connections := proxyServer.acceptClient(server) 194 | 195 | for { 196 | go proxyServer.connectHost(<-connections) 197 | } 198 | } 199 | --------------------------------------------------------------------------------