Initial socks-logger code
parent
e75332964e
commit
9c6b4a8df9
45
README.md
45
README.md
|
@ -1,45 +1,10 @@
|
||||||
go-socks5 [![Build Status](https://travis-ci.org/armon/go-socks5.png)](https://travis-ci.org/armon/go-socks5)
|
|
||||||
=========
|
|
||||||
|
|
||||||
Provides the `socks5` package that implements a [SOCKS5 server](http://en.wikipedia.org/wiki/SOCKS).
|
# socks-logger
|
||||||
SOCKS (Secure Sockets) is used to route traffic between a client and server through
|
|
||||||
an intermediate proxy layer. This can be used to bypass firewalls or NATs.
|
|
||||||
|
|
||||||
Feature
|
A SOCKS5 proxy that logs the domains you visit. See [this article](https://www.evilsocket.net/2017/06/30/BetterCap-1-6-1-TLS-Server-Name-Indication-and-Why-We-Need-to-Encrypt-It/) for a summary on how.
|
||||||
=======
|
|
||||||
|
|
||||||
The package has the following features:
|
```
|
||||||
* "No Auth" mode
|
go get github.com/serverwentdown/socks-logger
|
||||||
* User/Password authentication
|
go run $GOPATH/src/github.com/serverwentdown/socks-logger/socks-logger/main.go
|
||||||
* Support for the CONNECT command
|
|
||||||
* Rules to do granular filtering of commands
|
|
||||||
* Custom DNS resolution
|
|
||||||
* Unit tests
|
|
||||||
|
|
||||||
TODO
|
|
||||||
====
|
|
||||||
|
|
||||||
The package still needs the following:
|
|
||||||
* Support for the BIND command
|
|
||||||
* Support for the ASSOCIATE command
|
|
||||||
|
|
||||||
|
|
||||||
Example
|
|
||||||
=======
|
|
||||||
|
|
||||||
Below is a simple example of usage
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Create a SOCKS5 server
|
|
||||||
conf := &socks5.Config{}
|
|
||||||
server, err := socks5.New(conf)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create SOCKS5 proxy on localhost port 8000
|
|
||||||
if err := server.ListenAndServe("tcp", "127.0.0.1:8000"); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
130
request.go
130
request.go
|
@ -6,6 +6,8 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"math/big"
|
||||||
|
"bytes"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
@ -356,9 +358,135 @@ type closeWriter interface {
|
||||||
// proxy is used to suffle data from src to destination, and sends errors
|
// proxy is used to suffle data from src to destination, and sends errors
|
||||||
// down a dedicated channel
|
// down a dedicated channel
|
||||||
func proxy(dst io.Writer, src io.Reader, errCh chan error) {
|
func proxy(dst io.Writer, src io.Reader, errCh chan error) {
|
||||||
_, err := io.Copy(dst, src)
|
//_, err := io.Copy(dst, src)
|
||||||
|
_, err := copyAndModify(dst, src)
|
||||||
if tcpConn, ok := dst.(closeWriter); ok {
|
if tcpConn, ok := dst.(closeWriter); ok {
|
||||||
tcpConn.CloseWrite()
|
tcpConn.CloseWrite()
|
||||||
}
|
}
|
||||||
errCh <- err
|
errCh <- err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyAndModify(dst io.Writer, src io.Reader) (written int64, err error) {
|
||||||
|
// based on copyBuffer in io.go
|
||||||
|
buf := make([]byte, 32*1024)
|
||||||
|
for {
|
||||||
|
nr, er := src.Read(buf)
|
||||||
|
if written == 0 && nr > 0 {
|
||||||
|
if (buf[0] == 0x16 && buf[5] == 0x01) {// && buf[1] == 0x03 && buf[2] == 0x01) {
|
||||||
|
modifyHello(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nr > 0 {
|
||||||
|
nw, ew := dst.Write(buf[0:nr])
|
||||||
|
if nw > 0 {
|
||||||
|
written += int64(nw)
|
||||||
|
}
|
||||||
|
if ew != nil {
|
||||||
|
err = ew
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if nr != nw {
|
||||||
|
err = io.ErrShortWrite
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if er != nil {
|
||||||
|
if er != io.EOF {
|
||||||
|
err = er
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyHello(buf []byte) {
|
||||||
|
|
||||||
|
// 1 byte content type
|
||||||
|
|
||||||
|
// 2 byte tls version
|
||||||
|
|
||||||
|
// 2 byte tls frame length
|
||||||
|
frameLength := big.NewInt(0)
|
||||||
|
frameLength.SetBytes(buf[3:5])
|
||||||
|
|
||||||
|
// 1 byte handshake type
|
||||||
|
|
||||||
|
// 3 byte handshake length
|
||||||
|
handshakeLength := big.NewInt(0)
|
||||||
|
handshakeLength.SetBytes(buf[6:9])
|
||||||
|
|
||||||
|
// 2 byte version
|
||||||
|
|
||||||
|
// 32 byte random
|
||||||
|
|
||||||
|
// 1 byte session id length
|
||||||
|
sessionLength := big.NewInt(0)
|
||||||
|
sessionLength.SetBytes(buf[43:44])
|
||||||
|
|
||||||
|
// session id
|
||||||
|
|
||||||
|
// 2 byte cipher suites length (in bytes)
|
||||||
|
suitesLength := big.NewInt(0)
|
||||||
|
suitesLength.SetBytes(buf[44+sessionLength.Uint64():44+sessionLength.Uint64()+2])
|
||||||
|
|
||||||
|
// cipher suites
|
||||||
|
|
||||||
|
// 1 byte compression methods length
|
||||||
|
|
||||||
|
// 1 byte compression method
|
||||||
|
|
||||||
|
// 2 byte extensions length
|
||||||
|
extensionsLength := big.NewInt(0)
|
||||||
|
extensionsLength.SetBytes(buf[48+sessionLength.Uint64()+suitesLength.Uint64():48+sessionLength.Uint64()+suitesLength.Uint64()+2])
|
||||||
|
|
||||||
|
// extensions:
|
||||||
|
|
||||||
|
extensionsStart := 50 + sessionLength.Uint64() + suitesLength.Uint64()
|
||||||
|
extensionsEnd := extensionsStart + extensionsLength.Uint64()
|
||||||
|
cur := extensionsStart
|
||||||
|
for cur + 4 < extensionsEnd {
|
||||||
|
if (buf[cur] != 0x00 || buf[cur + 1] != 0x00) {
|
||||||
|
extensionLength := big.NewInt(0)
|
||||||
|
extensionLength.SetBytes(buf[cur+2:cur+4])
|
||||||
|
cur += 4 + extensionLength.Uint64()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// yay is sni header!
|
||||||
|
extensionLength := big.NewInt(0)
|
||||||
|
extensionLength.SetBytes(buf[cur+2:cur+4])
|
||||||
|
|
||||||
|
// 2 byte sni list length
|
||||||
|
listLength := big.NewInt(0)
|
||||||
|
listLength.SetBytes(buf[cur+4:cur+6])
|
||||||
|
|
||||||
|
var list []string
|
||||||
|
|
||||||
|
listStart := cur + 6
|
||||||
|
listEnd := cur + 6 + listLength.Uint64()
|
||||||
|
lcur := listStart
|
||||||
|
for lcur + 3 < listEnd {
|
||||||
|
// 1 byte type
|
||||||
|
// 2 byte length
|
||||||
|
nameLength := big.NewInt(0)
|
||||||
|
nameLength.SetBytes(buf[lcur+1:lcur+3])
|
||||||
|
//buf[lcur+3] = 'x'
|
||||||
|
// name
|
||||||
|
var name bytes.Buffer
|
||||||
|
name.Write(buf[lcur+3:lcur+3+nameLength.Uint64()])
|
||||||
|
name.WriteByte(0)
|
||||||
|
// append to list
|
||||||
|
list = append(list, name.String())
|
||||||
|
lcur += 3 + nameLength.Uint64()
|
||||||
|
}
|
||||||
|
fmt.Println(list)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2 byte extension type
|
||||||
|
// 2 byte extension length
|
||||||
|
// extension data
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/serverwentdown/socks-logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
conf := &socks5.Config{}
|
||||||
|
server, err := socks5.New(conf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := server.ListenAndServe("tcp", "127.0.0.1:8000"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue