Add crypto support

This commit is contained in:
wweir
2019-01-04 14:34:00 +08:00
parent 578d9162aa
commit c62e3a3284
11 changed files with 123 additions and 44 deletions
+69
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-8
View File
@@ -1,8 +0,0 @@
package kcp
func fillPassword(password string) []byte {
for len(password) < 16 {
password += password
}
return []byte(password)[:16]
}
+2 -2
View File
@@ -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) {
+3 -4
View File
@@ -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
+1 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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()
}