mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
Add crypto support
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"math/rand"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Crypto struct {
|
||||
password string
|
||||
cipher.AEAD
|
||||
}
|
||||
|
||||
func NewCrypto(password string) (*Crypto, error) {
|
||||
aead, err := newAEAD(password)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "AEAD")
|
||||
}
|
||||
|
||||
return &Crypto{
|
||||
password: password,
|
||||
AEAD: aead,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Crypto) Crypto() (encrypt, decrypt func(src []byte) []byte) {
|
||||
nonce := newNonce(c.password, c.AEAD.NonceSize())
|
||||
|
||||
return func(src []byte) []byte {
|
||||
return c.AEAD.Seal(nil, nonce(), src, nil)
|
||||
},
|
||||
func(src []byte) []byte {
|
||||
dst, err := c.AEAD.Open(nil, nonce(), src, nil)
|
||||
if err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
}
|
||||
|
||||
func newAEAD(password string) (cipher.AEAD, error) {
|
||||
block, err := aes.NewCipher([]byte(password + password)[:16])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "password too short")
|
||||
}
|
||||
|
||||
aead, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GCM")
|
||||
}
|
||||
|
||||
return aead, nil
|
||||
}
|
||||
|
||||
func newNonce(password string, size int) func() []byte {
|
||||
num, _ := binary.Varint([]byte(password))
|
||||
rnd := rand.New(rand.NewSource(num))
|
||||
|
||||
buf := make([]byte, size)
|
||||
return func() []byte {
|
||||
rnd.Read(buf)
|
||||
return buf
|
||||
}
|
||||
}
|
||||
+10
-2
@@ -4,6 +4,7 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/wweir/sower/crypto"
|
||||
"github.com/wweir/sower/proxy/kcp"
|
||||
"github.com/wweir/sower/proxy/quic"
|
||||
"github.com/wweir/sower/proxy/tcp"
|
||||
@@ -20,11 +21,16 @@ func StartClient(netType, server, password string) {
|
||||
case QUIC.String():
|
||||
client = quic.NewClient()
|
||||
case KCP.String():
|
||||
client = kcp.NewClient(password)
|
||||
client = kcp.NewClient()
|
||||
case TCP.String():
|
||||
client = tcp.NewClient()
|
||||
}
|
||||
|
||||
cryptor, err := crypto.NewCrypto(password)
|
||||
if err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
|
||||
for {
|
||||
conn := <-connCh
|
||||
glog.V(1).Infof("new conn from (%s)", conn.RemoteAddr())
|
||||
@@ -36,7 +42,9 @@ func StartClient(netType, server, password string) {
|
||||
continue
|
||||
}
|
||||
|
||||
go relay(conn, rc)
|
||||
encrypt, decrypt := cryptor.Crypto()
|
||||
|
||||
go relay(conn, rc, encrypt, decrypt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-6
@@ -8,7 +8,6 @@ import (
|
||||
)
|
||||
|
||||
type client struct {
|
||||
Password []byte
|
||||
DataShard int
|
||||
ParityShard int
|
||||
DSCP int
|
||||
@@ -23,9 +22,8 @@ type client struct {
|
||||
MTU int
|
||||
}
|
||||
|
||||
func NewClient(password string) *client {
|
||||
func NewClient() *client {
|
||||
return &client{
|
||||
Password: fillPassword(password),
|
||||
DataShard: 10,
|
||||
ParityShard: 3,
|
||||
DSCP: 0,
|
||||
@@ -41,10 +39,9 @@ func NewClient(password string) *client {
|
||||
}
|
||||
|
||||
func (c *client) Dial(server string) (net.Conn, error) {
|
||||
block, _ := kcp.NewAESBlockCrypt(c.Password)
|
||||
conn, err := kcp.DialWithOptions(server, block, c.DataShard, c.ParityShard)
|
||||
conn, err := kcp.DialWithOptions(server, nil, c.DataShard, c.ParityShard)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "createConn()")
|
||||
return nil, errors.Wrap(err, "dial")
|
||||
}
|
||||
|
||||
conn.SetStreamMode(true)
|
||||
|
||||
+2
-6
@@ -9,7 +9,6 @@ import (
|
||||
)
|
||||
|
||||
type server struct {
|
||||
Password []byte
|
||||
DataShard int
|
||||
ParityShard int
|
||||
DSCP int
|
||||
@@ -18,7 +17,6 @@ type server struct {
|
||||
|
||||
func NewServer(password string) *server {
|
||||
return &server{
|
||||
Password: fillPassword(password),
|
||||
DataShard: 10,
|
||||
ParityShard: 3,
|
||||
DSCP: 0,
|
||||
@@ -27,8 +25,7 @@ func NewServer(password string) *server {
|
||||
}
|
||||
|
||||
func (s *server) Listen(port string) (<-chan net.Conn, error) {
|
||||
block, _ := kcp.NewAESBlockCrypt(s.Password)
|
||||
ln, err := kcp.ListenWithOptions(port, block, s.DataShard, s.ParityShard)
|
||||
ln, err := kcp.ListenWithOptions(port, nil, s.DataShard, s.ParityShard)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,8 +45,7 @@ func (s *server) Listen(port string) (<-chan net.Conn, error) {
|
||||
for {
|
||||
conn, err := ln.AcceptKCP()
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
continue
|
||||
glog.Fatalln("KCP listen:", err)
|
||||
}
|
||||
|
||||
connCh <- conn
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package kcp
|
||||
|
||||
func fillPassword(password string) []byte {
|
||||
for len(password) < 16 {
|
||||
password += password
|
||||
}
|
||||
return []byte(password)[:16]
|
||||
}
|
||||
@@ -4,9 +4,9 @@ package proxy
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _netType_name = "QUICKCP"
|
||||
const _netType_name = "QUICKCPTCP"
|
||||
|
||||
var _netType_index = [...]uint8{0, 4, 7}
|
||||
var _netType_index = [...]uint8{0, 4, 7, 10}
|
||||
|
||||
func (i netType) String() string {
|
||||
if i < 0 || i >= netType(len(_netType_index)-1) {
|
||||
|
||||
@@ -10,9 +10,8 @@ import (
|
||||
)
|
||||
|
||||
type client struct {
|
||||
server string
|
||||
conf *quic.Config
|
||||
sess quic.Session
|
||||
conf *quic.Config
|
||||
sess quic.Session
|
||||
}
|
||||
|
||||
func NewClient() *client {
|
||||
@@ -27,7 +26,7 @@ func NewClient() *client {
|
||||
|
||||
func (c *client) Dial(server string) (net.Conn, error) {
|
||||
if c.sess == nil {
|
||||
if sess, err := quic.DialAddr(c.server, &tls.Config{InsecureSkipVerify: true}, c.conf); err != nil {
|
||||
if sess, err := quic.DialAddr(server, &tls.Config{InsecureSkipVerify: true}, c.conf); err != nil {
|
||||
return nil, errors.Wrap(err, "session")
|
||||
} else {
|
||||
c.sess = sess
|
||||
|
||||
@@ -50,8 +50,7 @@ func accept(sess quic.Session, connCh chan<- net.Conn) {
|
||||
for {
|
||||
stream, err := sess.AcceptStream()
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return
|
||||
glog.Fatalln("QUIC listen:", err)
|
||||
}
|
||||
|
||||
connCh <- &streamConn{stream, sess}
|
||||
|
||||
+11
-3
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/wweir/sower/crypto"
|
||||
"github.com/wweir/sower/parse"
|
||||
"github.com/wweir/sower/proxy/kcp"
|
||||
"github.com/wweir/sower/proxy/quic"
|
||||
@@ -37,13 +38,18 @@ func StartServer(netType, port, password string) {
|
||||
glog.Fatalf("listen %v fail: %s", port, err)
|
||||
}
|
||||
|
||||
cryptor, err := crypto.NewCrypto(password)
|
||||
if err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
|
||||
for {
|
||||
conn := <-connCh
|
||||
go handle(conn)
|
||||
go handle(conn, cryptor)
|
||||
}
|
||||
}
|
||||
|
||||
func handle(conn net.Conn) {
|
||||
func handle(conn net.Conn, cryptor *crypto.Crypto) {
|
||||
defer conn.Close()
|
||||
|
||||
conn, addr, err := parse.ParseAddr(conn)
|
||||
@@ -62,5 +68,7 @@ func handle(conn net.Conn) {
|
||||
if err := rc.(*net.TCPConn).SetKeepAlive(true); err != nil {
|
||||
glog.Warningln(err)
|
||||
}
|
||||
relay(rc, conn)
|
||||
|
||||
encrypt, decrypt := cryptor.Crypto()
|
||||
relay(rc, conn, encrypt, decrypt)
|
||||
}
|
||||
|
||||
+1
-2
@@ -24,8 +24,7 @@ func (s *server) Listen(port string) (<-chan net.Conn, error) {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
continue
|
||||
glog.Fatalln("TCP listen:", err)
|
||||
}
|
||||
|
||||
connCh <- conn
|
||||
|
||||
+21
-9
@@ -19,24 +19,36 @@ const (
|
||||
TCP
|
||||
)
|
||||
|
||||
func relay(conn1, conn2 net.Conn) {
|
||||
func relay(transparentConn, cryptoConn net.Conn, encrypt, decrypt func([]byte) []byte) {
|
||||
wg := &sync.WaitGroup{}
|
||||
exitFlag := new(int32)
|
||||
wg.Add(2)
|
||||
go redirect(conn1, conn2, wg, exitFlag)
|
||||
redirect(conn2, conn1, wg, exitFlag)
|
||||
go redirect(transparentConn, cryptoConn, encrypt, wg, exitFlag)
|
||||
redirect(cryptoConn, transparentConn, decrypt, wg, exitFlag)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func redirect(conn1, conn2 net.Conn, wg *sync.WaitGroup, exitFlag *int32) {
|
||||
if _, err := io.Copy(conn2, conn1); err != nil && (atomic.LoadInt32(exitFlag) == 0) {
|
||||
glog.V(1).Infof("%s<>%s -> %s<>%s: %s", conn1.RemoteAddr(), conn1.LocalAddr(), conn2.LocalAddr(), conn2.RemoteAddr(), err)
|
||||
func redirect(dst, src net.Conn, fn func([]byte) []byte, wg *sync.WaitGroup, exitFlag *int32) {
|
||||
var buf = make([]byte, 4<<20 /*4M*/)
|
||||
var n int
|
||||
var err error
|
||||
for {
|
||||
if n, err = src.Read(buf); err != nil {
|
||||
break
|
||||
}
|
||||
if _, err = dst.Write(fn(buf[:n])); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// wakeup all conn goroutine
|
||||
if err != io.EOF && (atomic.LoadInt32(exitFlag) == 0) {
|
||||
glog.V(1).Infof("%s<>%s -> %s<>%s: %s", src.RemoteAddr(), src.LocalAddr(), dst.LocalAddr(), dst.RemoteAddr(), err)
|
||||
}
|
||||
atomic.AddInt32(exitFlag, 1)
|
||||
|
||||
// wakeup all conn goroutine
|
||||
now := time.Now()
|
||||
conn1.SetDeadline(now)
|
||||
conn2.SetDeadline(now)
|
||||
dst.SetDeadline(now)
|
||||
src.SetDeadline(now)
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user