#73: Add shadowsocks UDP relay support
This commit is contained in:
parent
321b03712a
commit
8861ffba01
122
cmd/gost/vendor/github.com/Yawning/chacha20/LICENSE
generated
vendored
Normal file
122
cmd/gost/vendor/github.com/Yawning/chacha20/LICENSE
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
|
14
cmd/gost/vendor/github.com/Yawning/chacha20/README.md
generated
vendored
Normal file
14
cmd/gost/vendor/github.com/Yawning/chacha20/README.md
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
### chacha20 - ChaCha20
|
||||
#### Yawning Angel (yawning at schwanenlied dot me)
|
||||
|
||||
Yet another Go ChaCha20 implementation. Everything else I found was slow,
|
||||
didn't support all the variants I need to use, or relied on cgo to go fast.
|
||||
|
||||
Features:
|
||||
|
||||
* 20 round, 256 bit key only. Everything else is pointless and stupid.
|
||||
* IETF 96 bit nonce variant.
|
||||
* XChaCha 24 byte nonce variant.
|
||||
* SSE2 and AVX2 support on amd64 targets.
|
||||
* Incremental encrypt/decrypt support, unlike golang.org/x/crypto/salsa20.
|
||||
|
273
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20.go
generated
vendored
Normal file
273
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20.go
generated
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
// chacha20.go - A ChaCha stream cipher implementation.
|
||||
//
|
||||
// To the extent possible under law, Yawning Angel has waived all copyright
|
||||
// and related or neighboring rights to chacha20, using the Creative
|
||||
// Commons "CC0" public domain dedication. See LICENSE or
|
||||
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
// KeySize is the ChaCha20 key size in bytes.
|
||||
KeySize = 32
|
||||
|
||||
// NonceSize is the ChaCha20 nonce size in bytes.
|
||||
NonceSize = 8
|
||||
|
||||
// INonceSize is the IETF ChaCha20 nonce size in bytes.
|
||||
INonceSize = 12
|
||||
|
||||
// XNonceSize is the XChaCha20 nonce size in bytes.
|
||||
XNonceSize = 24
|
||||
|
||||
// HNonceSize is the HChaCha20 nonce size in bytes.
|
||||
HNonceSize = 16
|
||||
|
||||
// BlockSize is the ChaCha20 block size in bytes.
|
||||
BlockSize = 64
|
||||
|
||||
stateSize = 16
|
||||
chachaRounds = 20
|
||||
|
||||
// The constant "expand 32-byte k" as little endian uint32s.
|
||||
sigma0 = uint32(0x61707865)
|
||||
sigma1 = uint32(0x3320646e)
|
||||
sigma2 = uint32(0x79622d32)
|
||||
sigma3 = uint32(0x6b206574)
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidKey is the error returned when the key is invalid.
|
||||
ErrInvalidKey = errors.New("key length must be KeySize bytes")
|
||||
|
||||
// ErrInvalidNonce is the error returned when the nonce is invalid.
|
||||
ErrInvalidNonce = errors.New("nonce length must be NonceSize/INonceSize/XNonceSize bytes")
|
||||
|
||||
// ErrInvalidCounter is the error returned when the counter is invalid.
|
||||
ErrInvalidCounter = errors.New("block counter is invalid (out of range)")
|
||||
|
||||
useUnsafe = false
|
||||
usingVectors = false
|
||||
blocksFn = blocksRef
|
||||
)
|
||||
|
||||
// A Cipher is an instance of ChaCha20/XChaCha20 using a particular key and
|
||||
// nonce.
|
||||
type Cipher struct {
|
||||
state [stateSize]uint32
|
||||
|
||||
buf [BlockSize]byte
|
||||
off int
|
||||
ietf bool
|
||||
}
|
||||
|
||||
// Reset zeros the key data so that it will no longer appear in the process's
|
||||
// memory.
|
||||
func (c *Cipher) Reset() {
|
||||
for i := range c.state {
|
||||
c.state[i] = 0
|
||||
}
|
||||
for i := range c.buf {
|
||||
c.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// XORKeyStream sets dst to the result of XORing src with the key stream. Dst
|
||||
// and src may be the same slice but otherwise should not overlap.
|
||||
func (c *Cipher) XORKeyStream(dst, src []byte) {
|
||||
if len(dst) < len(src) {
|
||||
src = src[:len(dst)]
|
||||
}
|
||||
|
||||
for remaining := len(src); remaining > 0; {
|
||||
// Process multiple blocks at once.
|
||||
if c.off == BlockSize {
|
||||
nrBlocks := remaining / BlockSize
|
||||
directBytes := nrBlocks * BlockSize
|
||||
if nrBlocks > 0 {
|
||||
blocksFn(&c.state, src, dst, nrBlocks, c.ietf)
|
||||
remaining -= directBytes
|
||||
if remaining == 0 {
|
||||
return
|
||||
}
|
||||
dst = dst[directBytes:]
|
||||
src = src[directBytes:]
|
||||
}
|
||||
|
||||
// If there's a partial block, generate 1 block of keystream into
|
||||
// the internal buffer.
|
||||
blocksFn(&c.state, nil, c.buf[:], 1, c.ietf)
|
||||
c.off = 0
|
||||
}
|
||||
|
||||
// Process partial blocks from the buffered keystream.
|
||||
toXor := BlockSize - c.off
|
||||
if remaining < toXor {
|
||||
toXor = remaining
|
||||
}
|
||||
if toXor > 0 {
|
||||
for i, v := range src[:toXor] {
|
||||
dst[i] = v ^ c.buf[c.off+i]
|
||||
}
|
||||
dst = dst[toXor:]
|
||||
src = src[toXor:]
|
||||
|
||||
remaining -= toXor
|
||||
c.off += toXor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KeyStream sets dst to the raw keystream.
|
||||
func (c *Cipher) KeyStream(dst []byte) {
|
||||
for remaining := len(dst); remaining > 0; {
|
||||
// Process multiple blocks at once.
|
||||
if c.off == BlockSize {
|
||||
nrBlocks := remaining / BlockSize
|
||||
directBytes := nrBlocks * BlockSize
|
||||
if nrBlocks > 0 {
|
||||
blocksFn(&c.state, nil, dst, nrBlocks, c.ietf)
|
||||
remaining -= directBytes
|
||||
if remaining == 0 {
|
||||
return
|
||||
}
|
||||
dst = dst[directBytes:]
|
||||
}
|
||||
|
||||
// If there's a partial block, generate 1 block of keystream into
|
||||
// the internal buffer.
|
||||
blocksFn(&c.state, nil, c.buf[:], 1, c.ietf)
|
||||
c.off = 0
|
||||
}
|
||||
|
||||
// Process partial blocks from the buffered keystream.
|
||||
toCopy := BlockSize - c.off
|
||||
if remaining < toCopy {
|
||||
toCopy = remaining
|
||||
}
|
||||
if toCopy > 0 {
|
||||
copy(dst[:toCopy], c.buf[c.off:c.off+toCopy])
|
||||
dst = dst[toCopy:]
|
||||
remaining -= toCopy
|
||||
c.off += toCopy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReKey reinitializes the ChaCha20/XChaCha20 instance with the provided key
|
||||
// and nonce.
|
||||
func (c *Cipher) ReKey(key, nonce []byte) error {
|
||||
if len(key) != KeySize {
|
||||
return ErrInvalidKey
|
||||
}
|
||||
|
||||
switch len(nonce) {
|
||||
case NonceSize:
|
||||
case INonceSize:
|
||||
case XNonceSize:
|
||||
var subkey [KeySize]byte
|
||||
var subnonce [HNonceSize]byte
|
||||
copy(subnonce[:], nonce[0:16])
|
||||
HChaCha(key, &subnonce, &subkey)
|
||||
key = subkey[:]
|
||||
nonce = nonce[16:24]
|
||||
defer func() {
|
||||
for i := range subkey {
|
||||
subkey[i] = 0
|
||||
}
|
||||
}()
|
||||
default:
|
||||
return ErrInvalidNonce
|
||||
}
|
||||
|
||||
c.Reset()
|
||||
c.state[0] = sigma0
|
||||
c.state[1] = sigma1
|
||||
c.state[2] = sigma2
|
||||
c.state[3] = sigma3
|
||||
c.state[4] = binary.LittleEndian.Uint32(key[0:4])
|
||||
c.state[5] = binary.LittleEndian.Uint32(key[4:8])
|
||||
c.state[6] = binary.LittleEndian.Uint32(key[8:12])
|
||||
c.state[7] = binary.LittleEndian.Uint32(key[12:16])
|
||||
c.state[8] = binary.LittleEndian.Uint32(key[16:20])
|
||||
c.state[9] = binary.LittleEndian.Uint32(key[20:24])
|
||||
c.state[10] = binary.LittleEndian.Uint32(key[24:28])
|
||||
c.state[11] = binary.LittleEndian.Uint32(key[28:32])
|
||||
c.state[12] = 0
|
||||
if len(nonce) == INonceSize {
|
||||
c.state[13] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||
c.state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||
c.state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||
c.ietf = true
|
||||
} else {
|
||||
c.state[13] = 0
|
||||
c.state[14] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||
c.state[15] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||
c.ietf = false
|
||||
}
|
||||
c.off = BlockSize
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Seek sets the block counter to a given offset.
|
||||
func (c *Cipher) Seek(blockCounter uint64) error {
|
||||
if c.ietf {
|
||||
if blockCounter > math.MaxUint32 {
|
||||
return ErrInvalidCounter
|
||||
}
|
||||
c.state[12] = uint32(blockCounter)
|
||||
} else {
|
||||
c.state[12] = uint32(blockCounter)
|
||||
c.state[13] = uint32(blockCounter >> 32)
|
||||
}
|
||||
c.off = BlockSize
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewCipher returns a new ChaCha20/XChaCha20 instance.
|
||||
func NewCipher(key, nonce []byte) (*Cipher, error) {
|
||||
c := new(Cipher)
|
||||
if err := c.ReKey(key, nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// HChaCha is the HChaCha20 hash function used to make XChaCha.
|
||||
func HChaCha(key []byte, nonce *[HNonceSize]byte, out *[32]byte) {
|
||||
var x [stateSize]uint32 // Last 4 slots unused, sigma hardcoded.
|
||||
x[0] = binary.LittleEndian.Uint32(key[0:4])
|
||||
x[1] = binary.LittleEndian.Uint32(key[4:8])
|
||||
x[2] = binary.LittleEndian.Uint32(key[8:12])
|
||||
x[3] = binary.LittleEndian.Uint32(key[12:16])
|
||||
x[4] = binary.LittleEndian.Uint32(key[16:20])
|
||||
x[5] = binary.LittleEndian.Uint32(key[20:24])
|
||||
x[6] = binary.LittleEndian.Uint32(key[24:28])
|
||||
x[7] = binary.LittleEndian.Uint32(key[28:32])
|
||||
x[8] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||
x[9] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||
x[10] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||
x[11] = binary.LittleEndian.Uint32(nonce[12:16])
|
||||
hChaChaRef(&x, out)
|
||||
}
|
||||
|
||||
func init() {
|
||||
switch runtime.GOARCH {
|
||||
case "386", "amd64":
|
||||
// Abuse unsafe to skip calling binary.LittleEndian.PutUint32
|
||||
// in the critical path. This is a big boost on systems that are
|
||||
// little endian and not overly picky about alignment.
|
||||
useUnsafe = true
|
||||
}
|
||||
}
|
||||
|
||||
var _ cipher.Stream = (*Cipher)(nil)
|
95
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20_amd64.go
generated
vendored
Normal file
95
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20_amd64.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
// chacha20_amd64.go - AMD64 optimized chacha20.
|
||||
//
|
||||
// To the extent possible under law, Yawning Angel has waived all copyright
|
||||
// and related or neighboring rights to chacha20, using the Creative
|
||||
// Commons "CC0" public domain dedication. See LICENSE or
|
||||
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
var usingAVX2 = false
|
||||
|
||||
func blocksAmd64SSE2(x *uint32, inp, outp *byte, nrBlocks uint)
|
||||
|
||||
func blocksAmd64AVX2(x *uint32, inp, outp *byte, nrBlocks uint)
|
||||
|
||||
func cpuidAmd64(cpuidParams *uint32)
|
||||
|
||||
func xgetbv0Amd64(xcrVec *uint32)
|
||||
|
||||
func blocksAmd64(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) {
|
||||
// Probably unneeded, but stating this explicitly simplifies the assembly.
|
||||
if nrBlocks == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if isIetf {
|
||||
var totalBlocks uint64
|
||||
totalBlocks = uint64(x[8]) + uint64(nrBlocks)
|
||||
if totalBlocks > math.MaxUint32 {
|
||||
panic("chacha20: Exceeded keystream per nonce limit")
|
||||
}
|
||||
}
|
||||
|
||||
if in == nil {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
in = out
|
||||
}
|
||||
|
||||
// Pointless to call the AVX2 code for just a single block, since half of
|
||||
// the output gets discarded...
|
||||
if usingAVX2 && nrBlocks > 1 {
|
||||
blocksAmd64AVX2(&x[0], &in[0], &out[0], uint(nrBlocks))
|
||||
} else {
|
||||
blocksAmd64SSE2(&x[0], &in[0], &out[0], uint(nrBlocks))
|
||||
}
|
||||
}
|
||||
|
||||
func supportsAVX2() bool {
|
||||
// https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
|
||||
const (
|
||||
osXsaveBit = 1 << 27
|
||||
avx2Bit = 1 << 5
|
||||
)
|
||||
|
||||
// Check to see if CPUID actually supports the leaf that indicates AVX2.
|
||||
// CPUID.(EAX=0H, ECX=0H) >= 7
|
||||
regs := [4]uint32{0x00}
|
||||
cpuidAmd64(®s[0])
|
||||
if regs[0] < 7 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check to see if the OS knows how to save/restore XMM/YMM state.
|
||||
// CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1
|
||||
regs = [4]uint32{0x01}
|
||||
cpuidAmd64(®s[0])
|
||||
if regs[2]&osXsaveBit == 0 {
|
||||
return false
|
||||
}
|
||||
xcrRegs := [2]uint32{}
|
||||
xgetbv0Amd64(&xcrRegs[0])
|
||||
if xcrRegs[0]&6 != 6 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check for AVX2 support.
|
||||
// CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1
|
||||
regs = [4]uint32{0x07}
|
||||
cpuidAmd64(®s[0])
|
||||
return regs[1]&avx2Bit != 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
blocksFn = blocksAmd64
|
||||
usingVectors = true
|
||||
usingAVX2 = supportsAVX2()
|
||||
}
|
1303
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20_amd64.py
generated
vendored
Normal file
1303
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20_amd64.py
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1187
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20_amd64.s
generated
vendored
Normal file
1187
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
392
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20_ref.go
generated
vendored
Normal file
392
cmd/gost/vendor/github.com/Yawning/chacha20/chacha20_ref.go
generated
vendored
Normal file
@ -0,0 +1,392 @@
|
||||
// chacha20_ref.go - Reference ChaCha20.
|
||||
//
|
||||
// To the extent possible under law, Yawning Angel has waived all copyright
|
||||
// and related or neighboring rights to chacha20, using the Creative
|
||||
// Commons "CC0" public domain dedication. See LICENSE or
|
||||
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func blocksRef(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) {
|
||||
if isIetf {
|
||||
var totalBlocks uint64
|
||||
totalBlocks = uint64(x[8]) + uint64(nrBlocks)
|
||||
if totalBlocks > math.MaxUint32 {
|
||||
panic("chacha20: Exceeded keystream per nonce limit")
|
||||
}
|
||||
}
|
||||
|
||||
// This routine ignores x[0]...x[4] in favor the const values since it's
|
||||
// ever so slightly faster.
|
||||
|
||||
for n := 0; n < nrBlocks; n++ {
|
||||
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
|
||||
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
|
||||
|
||||
for i := chachaRounds; i > 0; i -= 2 {
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ^= x0
|
||||
x12 = (x12 << 16) | (x12 >> 16)
|
||||
x8 += x12
|
||||
x4 ^= x8
|
||||
x4 = (x4 << 12) | (x4 >> 20)
|
||||
x0 += x4
|
||||
x12 ^= x0
|
||||
x12 = (x12 << 8) | (x12 >> 24)
|
||||
x8 += x12
|
||||
x4 ^= x8
|
||||
x4 = (x4 << 7) | (x4 >> 25)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ^= x1
|
||||
x13 = (x13 << 16) | (x13 >> 16)
|
||||
x9 += x13
|
||||
x5 ^= x9
|
||||
x5 = (x5 << 12) | (x5 >> 20)
|
||||
x1 += x5
|
||||
x13 ^= x1
|
||||
x13 = (x13 << 8) | (x13 >> 24)
|
||||
x9 += x13
|
||||
x5 ^= x9
|
||||
x5 = (x5 << 7) | (x5 >> 25)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ^= x2
|
||||
x14 = (x14 << 16) | (x14 >> 16)
|
||||
x10 += x14
|
||||
x6 ^= x10
|
||||
x6 = (x6 << 12) | (x6 >> 20)
|
||||
x2 += x6
|
||||
x14 ^= x2
|
||||
x14 = (x14 << 8) | (x14 >> 24)
|
||||
x10 += x14
|
||||
x6 ^= x10
|
||||
x6 = (x6 << 7) | (x6 >> 25)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ^= x3
|
||||
x15 = (x15 << 16) | (x15 >> 16)
|
||||
x11 += x15
|
||||
x7 ^= x11
|
||||
x7 = (x7 << 12) | (x7 >> 20)
|
||||
x3 += x7
|
||||
x15 ^= x3
|
||||
x15 = (x15 << 8) | (x15 >> 24)
|
||||
x11 += x15
|
||||
x7 ^= x11
|
||||
x7 = (x7 << 7) | (x7 >> 25)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ^= x0
|
||||
x15 = (x15 << 16) | (x15 >> 16)
|
||||
x10 += x15
|
||||
x5 ^= x10
|
||||
x5 = (x5 << 12) | (x5 >> 20)
|
||||
x0 += x5
|
||||
x15 ^= x0
|
||||
x15 = (x15 << 8) | (x15 >> 24)
|
||||
x10 += x15
|
||||
x5 ^= x10
|
||||
x5 = (x5 << 7) | (x5 >> 25)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ^= x1
|
||||
x12 = (x12 << 16) | (x12 >> 16)
|
||||
x11 += x12
|
||||
x6 ^= x11
|
||||
x6 = (x6 << 12) | (x6 >> 20)
|
||||
x1 += x6
|
||||
x12 ^= x1
|
||||
x12 = (x12 << 8) | (x12 >> 24)
|
||||
x11 += x12
|
||||
x6 ^= x11
|
||||
x6 = (x6 << 7) | (x6 >> 25)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ^= x2
|
||||
x13 = (x13 << 16) | (x13 >> 16)
|
||||
x8 += x13
|
||||
x7 ^= x8
|
||||
x7 = (x7 << 12) | (x7 >> 20)
|
||||
x2 += x7
|
||||
x13 ^= x2
|
||||
x13 = (x13 << 8) | (x13 >> 24)
|
||||
x8 += x13
|
||||
x7 ^= x8
|
||||
x7 = (x7 << 7) | (x7 >> 25)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ^= x3
|
||||
x14 = (x14 << 16) | (x14 >> 16)
|
||||
x9 += x14
|
||||
x4 ^= x9
|
||||
x4 = (x4 << 12) | (x4 >> 20)
|
||||
x3 += x4
|
||||
x14 ^= x3
|
||||
x14 = (x14 << 8) | (x14 >> 24)
|
||||
x9 += x14
|
||||
x4 ^= x9
|
||||
x4 = (x4 << 7) | (x4 >> 25)
|
||||
}
|
||||
|
||||
// On amd64 at least, this is a rather big boost.
|
||||
if useUnsafe {
|
||||
if in != nil {
|
||||
inArr := (*[16]uint32)(unsafe.Pointer(&in[n*BlockSize]))
|
||||
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
|
||||
outArr[0] = inArr[0] ^ (x0 + sigma0)
|
||||
outArr[1] = inArr[1] ^ (x1 + sigma1)
|
||||
outArr[2] = inArr[2] ^ (x2 + sigma2)
|
||||
outArr[3] = inArr[3] ^ (x3 + sigma3)
|
||||
outArr[4] = inArr[4] ^ (x4 + x[4])
|
||||
outArr[5] = inArr[5] ^ (x5 + x[5])
|
||||
outArr[6] = inArr[6] ^ (x6 + x[6])
|
||||
outArr[7] = inArr[7] ^ (x7 + x[7])
|
||||
outArr[8] = inArr[8] ^ (x8 + x[8])
|
||||
outArr[9] = inArr[9] ^ (x9 + x[9])
|
||||
outArr[10] = inArr[10] ^ (x10 + x[10])
|
||||
outArr[11] = inArr[11] ^ (x11 + x[11])
|
||||
outArr[12] = inArr[12] ^ (x12 + x[12])
|
||||
outArr[13] = inArr[13] ^ (x13 + x[13])
|
||||
outArr[14] = inArr[14] ^ (x14 + x[14])
|
||||
outArr[15] = inArr[15] ^ (x15 + x[15])
|
||||
} else {
|
||||
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
|
||||
outArr[0] = x0 + sigma0
|
||||
outArr[1] = x1 + sigma1
|
||||
outArr[2] = x2 + sigma2
|
||||
outArr[3] = x3 + sigma3
|
||||
outArr[4] = x4 + x[4]
|
||||
outArr[5] = x5 + x[5]
|
||||
outArr[6] = x6 + x[6]
|
||||
outArr[7] = x7 + x[7]
|
||||
outArr[8] = x8 + x[8]
|
||||
outArr[9] = x9 + x[9]
|
||||
outArr[10] = x10 + x[10]
|
||||
outArr[11] = x11 + x[11]
|
||||
outArr[12] = x12 + x[12]
|
||||
outArr[13] = x13 + x[13]
|
||||
outArr[14] = x14 + x[14]
|
||||
outArr[15] = x15 + x[15]
|
||||
}
|
||||
} else {
|
||||
// Slow path, either the architecture cares about alignment, or is not little endian.
|
||||
x0 += sigma0
|
||||
x1 += sigma1
|
||||
x2 += sigma2
|
||||
x3 += sigma3
|
||||
x4 += x[4]
|
||||
x5 += x[5]
|
||||
x6 += x[6]
|
||||
x7 += x[7]
|
||||
x8 += x[8]
|
||||
x9 += x[9]
|
||||
x10 += x[10]
|
||||
x11 += x[11]
|
||||
x12 += x[12]
|
||||
x13 += x[13]
|
||||
x14 += x[14]
|
||||
x15 += x[15]
|
||||
if in != nil {
|
||||
binary.LittleEndian.PutUint32(out[0:4], binary.LittleEndian.Uint32(in[0:4])^x0)
|
||||
binary.LittleEndian.PutUint32(out[4:8], binary.LittleEndian.Uint32(in[4:8])^x1)
|
||||
binary.LittleEndian.PutUint32(out[8:12], binary.LittleEndian.Uint32(in[8:12])^x2)
|
||||
binary.LittleEndian.PutUint32(out[12:16], binary.LittleEndian.Uint32(in[12:16])^x3)
|
||||
binary.LittleEndian.PutUint32(out[16:20], binary.LittleEndian.Uint32(in[16:20])^x4)
|
||||
binary.LittleEndian.PutUint32(out[20:24], binary.LittleEndian.Uint32(in[20:24])^x5)
|
||||
binary.LittleEndian.PutUint32(out[24:28], binary.LittleEndian.Uint32(in[24:28])^x6)
|
||||
binary.LittleEndian.PutUint32(out[28:32], binary.LittleEndian.Uint32(in[28:32])^x7)
|
||||
binary.LittleEndian.PutUint32(out[32:36], binary.LittleEndian.Uint32(in[32:36])^x8)
|
||||
binary.LittleEndian.PutUint32(out[36:40], binary.LittleEndian.Uint32(in[36:40])^x9)
|
||||
binary.LittleEndian.PutUint32(out[40:44], binary.LittleEndian.Uint32(in[40:44])^x10)
|
||||
binary.LittleEndian.PutUint32(out[44:48], binary.LittleEndian.Uint32(in[44:48])^x11)
|
||||
binary.LittleEndian.PutUint32(out[48:52], binary.LittleEndian.Uint32(in[48:52])^x12)
|
||||
binary.LittleEndian.PutUint32(out[52:56], binary.LittleEndian.Uint32(in[52:56])^x13)
|
||||
binary.LittleEndian.PutUint32(out[56:60], binary.LittleEndian.Uint32(in[56:60])^x14)
|
||||
binary.LittleEndian.PutUint32(out[60:64], binary.LittleEndian.Uint32(in[60:64])^x15)
|
||||
in = in[BlockSize:]
|
||||
} else {
|
||||
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||
binary.LittleEndian.PutUint32(out[16:20], x4)
|
||||
binary.LittleEndian.PutUint32(out[20:24], x5)
|
||||
binary.LittleEndian.PutUint32(out[24:28], x6)
|
||||
binary.LittleEndian.PutUint32(out[28:32], x7)
|
||||
binary.LittleEndian.PutUint32(out[32:36], x8)
|
||||
binary.LittleEndian.PutUint32(out[36:40], x9)
|
||||
binary.LittleEndian.PutUint32(out[40:44], x10)
|
||||
binary.LittleEndian.PutUint32(out[44:48], x11)
|
||||
binary.LittleEndian.PutUint32(out[48:52], x12)
|
||||
binary.LittleEndian.PutUint32(out[52:56], x13)
|
||||
binary.LittleEndian.PutUint32(out[56:60], x14)
|
||||
binary.LittleEndian.PutUint32(out[60:64], x15)
|
||||
}
|
||||
out = out[BlockSize:]
|
||||
}
|
||||
|
||||
// Stoping at 2^70 bytes per nonce is the user's responsibility.
|
||||
ctr := uint64(x[13])<<32 | uint64(x[12])
|
||||
ctr++
|
||||
x[12] = uint32(ctr)
|
||||
x[13] = uint32(ctr >> 32)
|
||||
}
|
||||
}
|
||||
|
||||
func hChaChaRef(x *[stateSize]uint32, out *[32]byte) {
|
||||
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
|
||||
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11]
|
||||
|
||||
for i := chachaRounds; i > 0; i -= 2 {
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ^= x0
|
||||
x12 = (x12 << 16) | (x12 >> 16)
|
||||
x8 += x12
|
||||
x4 ^= x8
|
||||
x4 = (x4 << 12) | (x4 >> 20)
|
||||
x0 += x4
|
||||
x12 ^= x0
|
||||
x12 = (x12 << 8) | (x12 >> 24)
|
||||
x8 += x12
|
||||
x4 ^= x8
|
||||
x4 = (x4 << 7) | (x4 >> 25)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ^= x1
|
||||
x13 = (x13 << 16) | (x13 >> 16)
|
||||
x9 += x13
|
||||
x5 ^= x9
|
||||
x5 = (x5 << 12) | (x5 >> 20)
|
||||
x1 += x5
|
||||
x13 ^= x1
|
||||
x13 = (x13 << 8) | (x13 >> 24)
|
||||
x9 += x13
|
||||
x5 ^= x9
|
||||
x5 = (x5 << 7) | (x5 >> 25)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ^= x2
|
||||
x14 = (x14 << 16) | (x14 >> 16)
|
||||
x10 += x14
|
||||
x6 ^= x10
|
||||
x6 = (x6 << 12) | (x6 >> 20)
|
||||
x2 += x6
|
||||
x14 ^= x2
|
||||
x14 = (x14 << 8) | (x14 >> 24)
|
||||
x10 += x14
|
||||
x6 ^= x10
|
||||
x6 = (x6 << 7) | (x6 >> 25)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ^= x3
|
||||
x15 = (x15 << 16) | (x15 >> 16)
|
||||
x11 += x15
|
||||
x7 ^= x11
|
||||
x7 = (x7 << 12) | (x7 >> 20)
|
||||
x3 += x7
|
||||
x15 ^= x3
|
||||
x15 = (x15 << 8) | (x15 >> 24)
|
||||
x11 += x15
|
||||
x7 ^= x11
|
||||
x7 = (x7 << 7) | (x7 >> 25)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ^= x0
|
||||
x15 = (x15 << 16) | (x15 >> 16)
|
||||
x10 += x15
|
||||
x5 ^= x10
|
||||
x5 = (x5 << 12) | (x5 >> 20)
|
||||
x0 += x5
|
||||
x15 ^= x0
|
||||
x15 = (x15 << 8) | (x15 >> 24)
|
||||
x10 += x15
|
||||
x5 ^= x10
|
||||
x5 = (x5 << 7) | (x5 >> 25)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ^= x1
|
||||
x12 = (x12 << 16) | (x12 >> 16)
|
||||
x11 += x12
|
||||
x6 ^= x11
|
||||
x6 = (x6 << 12) | (x6 >> 20)
|
||||
x1 += x6
|
||||
x12 ^= x1
|
||||
x12 = (x12 << 8) | (x12 >> 24)
|
||||
x11 += x12
|
||||
x6 ^= x11
|
||||
x6 = (x6 << 7) | (x6 >> 25)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ^= x2
|
||||
x13 = (x13 << 16) | (x13 >> 16)
|
||||
x8 += x13
|
||||
x7 ^= x8
|
||||
x7 = (x7 << 12) | (x7 >> 20)
|
||||
x2 += x7
|
||||
x13 ^= x2
|
||||
x13 = (x13 << 8) | (x13 >> 24)
|
||||
x8 += x13
|
||||
x7 ^= x8
|
||||
x7 = (x7 << 7) | (x7 >> 25)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ^= x3
|
||||
x14 = (x14 << 16) | (x14 >> 16)
|
||||
x9 += x14
|
||||
x4 ^= x9
|
||||
x4 = (x4 << 12) | (x4 >> 20)
|
||||
x3 += x4
|
||||
x14 ^= x3
|
||||
x14 = (x14 << 8) | (x14 >> 24)
|
||||
x9 += x14
|
||||
x4 ^= x9
|
||||
x4 = (x4 << 7) | (x4 >> 25)
|
||||
}
|
||||
|
||||
// HChaCha returns x0...x3 | x12...x15, which corresponds to the
|
||||
// indexes of the ChaCha constant and the indexes of the IV.
|
||||
if useUnsafe {
|
||||
outArr := (*[16]uint32)(unsafe.Pointer(&out[0]))
|
||||
outArr[0] = x0
|
||||
outArr[1] = x1
|
||||
outArr[2] = x2
|
||||
outArr[3] = x3
|
||||
outArr[4] = x12
|
||||
outArr[5] = x13
|
||||
outArr[6] = x14
|
||||
outArr[7] = x15
|
||||
} else {
|
||||
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||
binary.LittleEndian.PutUint32(out[16:20], x12)
|
||||
binary.LittleEndian.PutUint32(out[20:24], x13)
|
||||
binary.LittleEndian.PutUint32(out[24:28], x14)
|
||||
binary.LittleEndian.PutUint32(out[28:32], x15)
|
||||
}
|
||||
return
|
||||
}
|
41
cmd/gost/vendor/github.com/ginuerzh/gost/forward.go
generated
vendored
41
cmd/gost/vendor/github.com/ginuerzh/gost/forward.go
generated
vendored
@ -63,15 +63,15 @@ func (s *TcpForwardServer) handleTcpForward(conn net.Conn, raddr net.Addr) {
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
srcAddr *net.UDPAddr // src address
|
||||
dstAddr *net.UDPAddr // dest address
|
||||
srcAddr string // src address
|
||||
dstAddr string // dest address
|
||||
data []byte
|
||||
}
|
||||
|
||||
type cnode struct {
|
||||
chain *ProxyChain
|
||||
conn net.Conn
|
||||
srcAddr, dstAddr *net.UDPAddr
|
||||
srcAddr, dstAddr string
|
||||
rChan, wChan chan *packet
|
||||
err error
|
||||
ttl time.Duration
|
||||
@ -146,13 +146,9 @@ func (node *cnode) run() {
|
||||
timer.Reset(node.ttl)
|
||||
glog.V(LDEBUG).Infof("[udp] %s <<< %s : length %d", node.srcAddr, addr, n)
|
||||
|
||||
if node.dstAddr.String() != addr.String() {
|
||||
glog.V(LWARNING).Infof("[udp] %s <- %s : dst-addr mismatch (%s)", node.srcAddr, node.dstAddr, addr)
|
||||
break
|
||||
}
|
||||
select {
|
||||
// swap srcAddr with dstAddr
|
||||
case node.rChan <- &packet{srcAddr: node.dstAddr, dstAddr: node.srcAddr, data: b[:n]}:
|
||||
case node.rChan <- &packet{srcAddr: addr.String(), dstAddr: node.srcAddr, data: b[:n]}:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", node.srcAddr, node.dstAddr, "recv queue is full, discard")
|
||||
}
|
||||
@ -169,13 +165,9 @@ func (node *cnode) run() {
|
||||
timer.Reset(node.ttl)
|
||||
glog.V(LDEBUG).Infof("[udp-tun] %s <<< %s : length %d", node.srcAddr, dgram.Header.Addr.String(), len(dgram.Data))
|
||||
|
||||
if dgram.Header.Addr.String() != node.dstAddr.String() {
|
||||
glog.V(LWARNING).Infof("[udp-tun] %s <- %s : dst-addr mismatch (%s)", node.srcAddr, node.dstAddr, dgram.Header.Addr)
|
||||
break
|
||||
}
|
||||
select {
|
||||
// swap srcAddr with dstAddr
|
||||
case node.rChan <- &packet{srcAddr: node.dstAddr, dstAddr: node.srcAddr, data: dgram.Data}:
|
||||
case node.rChan <- &packet{srcAddr: dgram.Header.Addr.String(), dstAddr: node.srcAddr, data: dgram.Data}:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[udp-tun] %s <- %s : %s", node.srcAddr, node.dstAddr, "recv queue is full, discard")
|
||||
}
|
||||
@ -187,9 +179,15 @@ func (node *cnode) run() {
|
||||
for pkt := range node.wChan {
|
||||
timer.Reset(node.ttl)
|
||||
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", pkt.dstAddr)
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
switch c := node.conn.(type) {
|
||||
case *net.UDPConn:
|
||||
if _, err := c.WriteToUDP(pkt.data, pkt.dstAddr); err != nil {
|
||||
if _, err := c.WriteToUDP(pkt.data, dstAddr); err != nil {
|
||||
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||
node.err = err
|
||||
errChan <- err
|
||||
@ -198,7 +196,7 @@ func (node *cnode) run() {
|
||||
glog.V(LDEBUG).Infof("[udp] %s >>> %s : length %d", pkt.srcAddr, pkt.dstAddr, len(pkt.data))
|
||||
|
||||
default:
|
||||
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(len(pkt.data)), 0, ToSocksAddr(pkt.dstAddr)), pkt.data)
|
||||
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(len(pkt.data)), 0, ToSocksAddr(dstAddr)), pkt.data)
|
||||
if err := dgram.Write(c); err != nil {
|
||||
glog.V(LWARNING).Infof("[udp-tun] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||
node.err = err
|
||||
@ -255,7 +253,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- &packet{srcAddr: addr, dstAddr: raddr, data: b[:n]}:
|
||||
case ch <- &packet{srcAddr: addr.String(), dstAddr: raddr.String(), data: b[:n]}:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", addr, raddr, "send queue is full, discard")
|
||||
}
|
||||
@ -264,7 +262,12 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
||||
// start recv queue
|
||||
go func(ch <-chan *packet) {
|
||||
for pkt := range ch {
|
||||
if _, err := conn.WriteToUDP(pkt.data, pkt.dstAddr); err != nil {
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", pkt.dstAddr)
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||
continue
|
||||
}
|
||||
if _, err := conn.WriteToUDP(pkt.data, dstAddr); err != nil {
|
||||
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||
return
|
||||
}
|
||||
@ -285,7 +288,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
||||
}
|
||||
}
|
||||
|
||||
node, ok := m[pkt.srcAddr.String()]
|
||||
node, ok := m[pkt.srcAddr]
|
||||
if !ok {
|
||||
node = &cnode{
|
||||
chain: s.Base.Chain,
|
||||
@ -295,7 +298,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
||||
wChan: make(chan *packet, 32),
|
||||
ttl: time.Duration(s.TTL) * time.Second,
|
||||
}
|
||||
m[pkt.srcAddr.String()] = node
|
||||
m[pkt.srcAddr] = node
|
||||
go node.run()
|
||||
glog.V(LINFO).Infof("[udp] %s -> %s : new client (%d)", pkt.srcAddr, pkt.dstAddr, len(m))
|
||||
}
|
||||
|
2
cmd/gost/vendor/github.com/ginuerzh/gost/gost.go
generated
vendored
2
cmd/gost/vendor/github.com/ginuerzh/gost/gost.go
generated
vendored
@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Version = "2.3"
|
||||
Version = "2.4-dev"
|
||||
)
|
||||
|
||||
// Log level for glog
|
||||
|
2
cmd/gost/vendor/github.com/ginuerzh/gost/node.go
generated
vendored
2
cmd/gost/vendor/github.com/ginuerzh/gost/node.go
generated
vendored
@ -71,7 +71,7 @@ func ParseProxyNode(s string) (node ProxyNode, err error) {
|
||||
}
|
||||
|
||||
switch node.Transport {
|
||||
case "ws", "wss", "tls", "http2", "ssu", "quic", "kcp", "redirect":
|
||||
case "ws", "wss", "tls", "http2", "quic", "kcp", "redirect", "ssu":
|
||||
case "https":
|
||||
node.Protocol = "http"
|
||||
node.Transport = "tls"
|
||||
|
10
cmd/gost/vendor/github.com/ginuerzh/gost/server.go
generated
vendored
10
cmd/gost/vendor/github.com/ginuerzh/gost/server.go
generated
vendored
@ -32,7 +32,7 @@ func NewProxyServer(node ProxyNode, chain *ProxyChain, config *tls.Config) *Prox
|
||||
|
||||
var cipher *ss.Cipher
|
||||
var ota bool
|
||||
if node.Protocol == "ss" {
|
||||
if node.Protocol == "ss" || node.Transport == "ssu" {
|
||||
var err error
|
||||
var method, password string
|
||||
|
||||
@ -98,8 +98,6 @@ func (s *ProxyServer) Serve() error {
|
||||
return NewRTcpForwardServer(s).Serve()
|
||||
case "rudp": // Remote UDP port forwarding
|
||||
return NewRUdpForwardServer(s).Serve()
|
||||
case "ssu": // TODO: shadowsocks udp relay
|
||||
return NewShadowUdpServer(s).ListenAndServe()
|
||||
case "quic":
|
||||
return NewQuicServer(s).ListenAndServeTLS(s.TLSConfig)
|
||||
case "kcp":
|
||||
@ -118,6 +116,12 @@ func (s *ProxyServer) Serve() error {
|
||||
return NewKCPServer(s, config).ListenAndServe()
|
||||
case "redirect":
|
||||
return NewRedsocksTCPServer(s).ListenAndServe()
|
||||
case "ssu": // shadowsocks udp relay
|
||||
ttl, _ := strconv.Atoi(s.Node.Get("ttl"))
|
||||
if ttl <= 0 {
|
||||
ttl = DefaultTTL
|
||||
}
|
||||
return NewShadowUdpServer(s, ttl).ListenAndServe()
|
||||
default:
|
||||
ln, err = net.Listen("tcp", node.Addr)
|
||||
}
|
||||
|
148
cmd/gost/vendor/github.com/ginuerzh/gost/ss.go
generated
vendored
148
cmd/gost/vendor/github.com/ginuerzh/gost/ss.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
"github.com/golang/glog"
|
||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||
"io"
|
||||
@ -65,47 +66,6 @@ func (s *ShadowServer) Serve() {
|
||||
glog.V(LINFO).Infof("[ss] %s >-< %s", s.conn.RemoteAddr(), addr)
|
||||
}
|
||||
|
||||
type ShadowUdpServer struct {
|
||||
Base *ProxyServer
|
||||
Handler func(conn *net.UDPConn, addr *net.UDPAddr, data []byte)
|
||||
}
|
||||
|
||||
func NewShadowUdpServer(base *ProxyServer) *ShadowUdpServer {
|
||||
return &ShadowUdpServer{Base: base}
|
||||
}
|
||||
|
||||
func (s *ShadowUdpServer) ListenAndServe() error {
|
||||
laddr, err := net.ResolveUDPAddr("udp", s.Base.Node.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lconn, err := net.ListenUDP("udp", laddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lconn.Close()
|
||||
|
||||
if s.Handler == nil {
|
||||
s.Handler = s.HandleConn
|
||||
}
|
||||
|
||||
for {
|
||||
b := make([]byte, LargeBufferSize)
|
||||
n, addr, err := lconn.ReadFromUDP(b)
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infoln(err)
|
||||
continue
|
||||
}
|
||||
|
||||
go s.Handler(lconn, addr, b[:n])
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: shadowsocks udp relay handler
|
||||
func (s *ShadowUdpServer) HandleConn(conn *net.UDPConn, addr *net.UDPAddr, data []byte) {
|
||||
|
||||
}
|
||||
|
||||
// This function is copied from shadowsocks library with some modification.
|
||||
func (s *ShadowServer) getRequest() (host string, ota bool, err error) {
|
||||
// buf size should at least have the same size with the largest possible
|
||||
@ -276,3 +236,109 @@ func (c *shadowConn) SetReadDeadline(t time.Time) error {
|
||||
func (c *shadowConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
type ShadowUdpServer struct {
|
||||
Base *ProxyServer
|
||||
TTL int
|
||||
}
|
||||
|
||||
func NewShadowUdpServer(base *ProxyServer, ttl int) *ShadowUdpServer {
|
||||
return &ShadowUdpServer{Base: base, TTL: ttl}
|
||||
}
|
||||
|
||||
func (s *ShadowUdpServer) ListenAndServe() error {
|
||||
laddr, err := net.ResolveUDPAddr("udp", s.Base.Node.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lconn, err := net.ListenUDP("udp", laddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lconn.Close()
|
||||
|
||||
conn := ss.NewSecurePacketConn(lconn, s.Base.cipher.Copy(), true) // force OTA on
|
||||
|
||||
rChan, wChan := make(chan *packet, 128), make(chan *packet, 128)
|
||||
// start send queue
|
||||
go func(ch chan<- *packet) {
|
||||
for {
|
||||
b := make([]byte, MediumBufferSize)
|
||||
n, addr, err := conn.ReadFrom(b[3:]) // add rsv and frag fields to make it the standard SOCKS5 UDP datagram
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : %s", addr, laddr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if b[3]&ss.OneTimeAuthMask > 0 {
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : client does not support OTA", addr, laddr)
|
||||
continue
|
||||
}
|
||||
b[3] &= ss.AddrMask
|
||||
|
||||
dgram, err := gosocks5.ReadUDPDatagram(bytes.NewReader(b[:n+3]))
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : %s", addr, laddr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- &packet{srcAddr: addr.String(), dstAddr: dgram.Header.Addr.String(), data: b[:n+3]}:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : %s", addr, dgram.Header.Addr.String(), "send queue is full, discard")
|
||||
}
|
||||
}
|
||||
}(wChan)
|
||||
// start recv queue
|
||||
go func(ch <-chan *packet) {
|
||||
for pkt := range ch {
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", pkt.dstAddr)
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[ssu] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||
continue
|
||||
}
|
||||
if _, err := conn.WriteTo(pkt.data, dstAddr); err != nil {
|
||||
glog.V(LWARNING).Infof("[ssu] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}(rChan)
|
||||
|
||||
// mapping client to node
|
||||
m := make(map[string]*cnode)
|
||||
|
||||
// start dispatcher
|
||||
for pkt := range wChan {
|
||||
// clear obsolete nodes
|
||||
for k, node := range m {
|
||||
if node != nil && node.err != nil {
|
||||
close(node.wChan)
|
||||
delete(m, k)
|
||||
glog.V(LINFO).Infof("[ssu] clear node %s", k)
|
||||
}
|
||||
}
|
||||
|
||||
node, ok := m[pkt.srcAddr]
|
||||
if !ok {
|
||||
node = &cnode{
|
||||
chain: s.Base.Chain,
|
||||
srcAddr: pkt.srcAddr,
|
||||
dstAddr: pkt.dstAddr,
|
||||
rChan: rChan,
|
||||
wChan: make(chan *packet, 32),
|
||||
ttl: time.Duration(s.TTL) * time.Second,
|
||||
}
|
||||
m[pkt.srcAddr] = node
|
||||
go node.run()
|
||||
glog.V(LINFO).Infof("[ssu] %s -> %s : new client (%d)", pkt.srcAddr, pkt.dstAddr, len(m))
|
||||
}
|
||||
|
||||
select {
|
||||
case node.wChan <- pkt:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, "node send queue is full, discard")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
28
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/encrypt.go
generated
vendored
28
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/encrypt.go
generated
vendored
@ -12,7 +12,7 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/codahale/chacha20"
|
||||
"github.com/Yawning/chacha20"
|
||||
"golang.org/x/crypto/blowfish"
|
||||
"golang.org/x/crypto/cast5"
|
||||
"golang.org/x/crypto/salsa20/salsa"
|
||||
@ -65,11 +65,19 @@ func newStream(block cipher.Block, err error, key, iv []byte,
|
||||
}
|
||||
}
|
||||
|
||||
func newAESStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
func newAESCFBStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
return newStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newAESCTRStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cipher.NewCTR(block, iv), nil
|
||||
}
|
||||
|
||||
func newDESStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := des.NewCipher(key)
|
||||
return newStream(block, err, key, iv, doe)
|
||||
@ -95,7 +103,11 @@ func newRC4MD5Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||
}
|
||||
|
||||
func newChaCha20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||
return chacha20.New(key, iv)
|
||||
return chacha20.NewCipher(key, iv)
|
||||
}
|
||||
|
||||
func newChaCha20IETFStream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||
return chacha20.NewCipher(key, iv)
|
||||
}
|
||||
|
||||
type salsaStreamCipher struct {
|
||||
@ -145,14 +157,18 @@ type cipherInfo struct {
|
||||
}
|
||||
|
||||
var cipherMethod = map[string]*cipherInfo{
|
||||
"aes-128-cfb": {16, 16, newAESStream},
|
||||
"aes-192-cfb": {24, 16, newAESStream},
|
||||
"aes-256-cfb": {32, 16, newAESStream},
|
||||
"aes-128-cfb": {16, 16, newAESCFBStream},
|
||||
"aes-192-cfb": {24, 16, newAESCFBStream},
|
||||
"aes-256-cfb": {32, 16, newAESCFBStream},
|
||||
"aes-128-ctr": {16, 16, newAESCTRStream},
|
||||
"aes-192-ctr": {24, 16, newAESCTRStream},
|
||||
"aes-256-ctr": {32, 16, newAESCTRStream},
|
||||
"des-cfb": {8, 8, newDESStream},
|
||||
"bf-cfb": {16, 8, newBlowFishStream},
|
||||
"cast5-cfb": {16, 8, newCast5Stream},
|
||||
"rc4-md5": {16, 16, newRC4MD5Stream},
|
||||
"chacha20": {32, 8, newChaCha20Stream},
|
||||
"chacha20-ietf": {32, 12, newChaCha20IETFStream},
|
||||
"salsa20": {32, 8, newSalsa20Stream},
|
||||
}
|
||||
|
||||
|
135
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/udp.go
generated
vendored
Normal file
135
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/udp.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
package shadowsocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
maxPacketSize = 4096 // increase it if error occurs
|
||||
)
|
||||
|
||||
var (
|
||||
errPacketTooSmall = fmt.Errorf("[udp]read error: cannot decrypt, received packet is smaller than ivLen")
|
||||
errPacketTooLarge = fmt.Errorf("[udp]read error: received packet is latger than maxPacketSize(%d)", maxPacketSize)
|
||||
errBufferTooSmall = fmt.Errorf("[udp]read error: given buffer is too small to hold data")
|
||||
errPacketOtaFailed = fmt.Errorf("[udp]read error: received packet has invalid ota")
|
||||
)
|
||||
|
||||
type SecurePacketConn struct {
|
||||
net.PacketConn
|
||||
*Cipher
|
||||
ota bool
|
||||
}
|
||||
|
||||
func NewSecurePacketConn(c net.PacketConn, cipher *Cipher, ota bool) *SecurePacketConn {
|
||||
return &SecurePacketConn{
|
||||
PacketConn: c,
|
||||
Cipher: cipher,
|
||||
ota: ota,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) Close() error {
|
||||
return c.PacketConn.Close()
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) ReadFrom(b []byte) (n int, src net.Addr, err error) {
|
||||
ota := false
|
||||
cipher := c.Copy()
|
||||
buf := make([]byte, 4096)
|
||||
n, src, err = c.PacketConn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n < c.info.ivLen {
|
||||
return 0, nil, errPacketTooSmall
|
||||
}
|
||||
|
||||
if len(b) < n-c.info.ivLen {
|
||||
err = errBufferTooSmall // just a warning
|
||||
}
|
||||
|
||||
iv := make([]byte, c.info.ivLen)
|
||||
copy(iv, buf[:c.info.ivLen])
|
||||
|
||||
if err = cipher.initDecrypt(iv); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cipher.decrypt(b[0:], buf[c.info.ivLen:n])
|
||||
n -= c.info.ivLen
|
||||
if b[idType]&OneTimeAuthMask > 0 {
|
||||
ota = true
|
||||
}
|
||||
|
||||
if c.ota && !ota {
|
||||
return 0, src, errPacketOtaFailed
|
||||
}
|
||||
|
||||
if ota {
|
||||
key := cipher.key
|
||||
actualHmacSha1Buf := HmacSha1(append(iv, key...), b[:n-lenHmacSha1])
|
||||
if !bytes.Equal(b[n-lenHmacSha1:n], actualHmacSha1Buf) {
|
||||
Debug.Printf("verify one time auth failed, iv=%v key=%v data=%v", iv, key, b)
|
||||
return 0, src, errPacketOtaFailed
|
||||
}
|
||||
n -= lenHmacSha1
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) WriteTo(b []byte, dst net.Addr) (n int, err error) {
|
||||
cipher := c.Copy()
|
||||
iv, err := cipher.initEncrypt()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
packetLen := len(b) + len(iv)
|
||||
|
||||
if c.ota {
|
||||
b[idType] |= OneTimeAuthMask
|
||||
packetLen += lenHmacSha1
|
||||
key := cipher.key
|
||||
actualHmacSha1Buf := HmacSha1(append(iv, key...), b)
|
||||
b = append(b, actualHmacSha1Buf...)
|
||||
}
|
||||
|
||||
cipherData := make([]byte, packetLen)
|
||||
copy(cipherData, iv)
|
||||
|
||||
cipher.encrypt(cipherData[len(iv):], b)
|
||||
n, err = c.PacketConn.WriteTo(cipherData, dst)
|
||||
if c.ota {
|
||||
n -= lenHmacSha1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) LocalAddr() net.Addr {
|
||||
return c.PacketConn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) SetDeadline(t time.Time) error {
|
||||
return c.PacketConn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) SetReadDeadline(t time.Time) error {
|
||||
return c.PacketConn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.PacketConn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) IsOta() bool {
|
||||
return c.ota
|
||||
}
|
||||
|
||||
func (c *SecurePacketConn) ForceOTA() net.PacketConn {
|
||||
return NewSecurePacketConn(c.PacketConn, c.Cipher.Copy(), true)
|
||||
}
|
265
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/udprelay.go
generated
vendored
Normal file
265
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/udprelay.go
generated
vendored
Normal file
@ -0,0 +1,265 @@
|
||||
package shadowsocks
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
idType = 0 // address type index
|
||||
idIP0 = 1 // ip addres start index
|
||||
idDmLen = 1 // domain address length index
|
||||
idDm0 = 2 // domain address start index
|
||||
|
||||
typeIPv4 = 1 // type is ipv4 address
|
||||
typeDm = 3 // type is domain address
|
||||
typeIPv6 = 4 // type is ipv6 address
|
||||
|
||||
lenIPv4 = 1 + net.IPv4len + 2 // 1addrType + ipv4 + 2port
|
||||
lenIPv6 = 1 + net.IPv6len + 2 // 1addrType + ipv6 + 2port
|
||||
lenDmBase = 1 + 1 + 2 // 1addrType + 1addrLen + 2port, plus addrLen
|
||||
lenHmacSha1 = 10
|
||||
)
|
||||
|
||||
var (
|
||||
reqList = newReqList()
|
||||
natlist = newNatTable()
|
||||
udpTimeout = 30 * time.Second
|
||||
reqListRefreshTime = 5 * time.Minute
|
||||
)
|
||||
|
||||
type natTable struct {
|
||||
sync.Mutex
|
||||
conns map[string]net.PacketConn
|
||||
}
|
||||
|
||||
func newNatTable() *natTable {
|
||||
return &natTable{conns: map[string]net.PacketConn{}}
|
||||
}
|
||||
|
||||
func (table *natTable) Delete(index string) net.PacketConn {
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
c, ok := table.conns[index]
|
||||
if ok {
|
||||
delete(table.conns, index)
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (table *natTable) Get(index string) (c net.PacketConn, ok bool, err error) {
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
c, ok = table.conns[index]
|
||||
if !ok {
|
||||
c, err = net.ListenPacket("udp", "")
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
table.conns[index] = c
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type requestHeaderList struct {
|
||||
sync.Mutex
|
||||
List map[string]([]byte)
|
||||
}
|
||||
|
||||
func newReqList() *requestHeaderList {
|
||||
ret := &requestHeaderList{List: map[string]([]byte){}}
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(reqListRefreshTime)
|
||||
ret.Refresh()
|
||||
}
|
||||
}()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *requestHeaderList) Refresh() {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
for k, _ := range r.List {
|
||||
delete(r.List, k)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *requestHeaderList) Get(dstaddr string) (req []byte, ok bool) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
req, ok = r.List[dstaddr]
|
||||
return
|
||||
}
|
||||
|
||||
func (r *requestHeaderList) Put(dstaddr string, req []byte) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
r.List[dstaddr] = req
|
||||
return
|
||||
}
|
||||
|
||||
func parseHeaderFromAddr(addr net.Addr) ([]byte, int) {
|
||||
// if the request address type is domain, it cannot be reverselookuped
|
||||
ip, port, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
return nil, 0
|
||||
}
|
||||
buf := make([]byte, 20)
|
||||
IP := net.ParseIP(ip)
|
||||
b1 := IP.To4()
|
||||
iplen := 0
|
||||
if b1 == nil { //ipv6
|
||||
b1 = IP.To16()
|
||||
buf[0] = typeIPv6
|
||||
iplen = net.IPv6len
|
||||
} else { //ipv4
|
||||
buf[0] = typeIPv4
|
||||
iplen = net.IPv4len
|
||||
}
|
||||
copy(buf[1:], b1)
|
||||
port_i, _ := strconv.Atoi(port)
|
||||
binary.BigEndian.PutUint16(buf[1+iplen:], uint16(port_i))
|
||||
return buf[:1+iplen+2], 1 + iplen + 2
|
||||
}
|
||||
|
||||
func Pipeloop(write net.PacketConn, writeAddr net.Addr, readClose net.PacketConn) {
|
||||
buf := leakyBuf.Get()
|
||||
defer leakyBuf.Put(buf)
|
||||
defer readClose.Close()
|
||||
for {
|
||||
readClose.SetDeadline(time.Now().Add(udpTimeout))
|
||||
n, raddr, err := readClose.ReadFrom(buf)
|
||||
if err != nil {
|
||||
if ne, ok := err.(*net.OpError); ok {
|
||||
if ne.Err == syscall.EMFILE || ne.Err == syscall.ENFILE {
|
||||
// log too many open file error
|
||||
// EMFILE is process reaches open file limits, ENFILE is system limit
|
||||
Debug.Println("[udp]read error:", err)
|
||||
}
|
||||
}
|
||||
Debug.Printf("[udp]closed pipe %s<-%s\n", writeAddr, readClose.LocalAddr())
|
||||
return
|
||||
}
|
||||
// need improvement here
|
||||
if req, ok := reqList.Get(raddr.String()); ok {
|
||||
write.WriteTo(append(req, buf[:n]...), writeAddr)
|
||||
} else {
|
||||
header, hlen := parseHeaderFromAddr(raddr)
|
||||
write.WriteTo(append(header[:hlen], buf[:n]...), writeAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleUDPConnection(handle *SecurePacketConn, n int, src net.Addr, receive []byte) {
|
||||
var dstIP net.IP
|
||||
var reqLen int
|
||||
var ota bool
|
||||
addrType := receive[idType]
|
||||
defer leakyBuf.Put(receive)
|
||||
|
||||
if addrType&OneTimeAuthMask > 0 {
|
||||
ota = true
|
||||
}
|
||||
receive[idType] &= ^OneTimeAuthMask
|
||||
compatiblemode := !handle.IsOta() && ota
|
||||
|
||||
switch addrType & AddrMask {
|
||||
case typeIPv4:
|
||||
reqLen = lenIPv4
|
||||
if len(receive) < reqLen {
|
||||
Debug.Println("[udp]invalid received message.")
|
||||
}
|
||||
dstIP = net.IP(receive[idIP0 : idIP0+net.IPv4len])
|
||||
case typeIPv6:
|
||||
reqLen = lenIPv6
|
||||
if len(receive) < reqLen {
|
||||
Debug.Println("[udp]invalid received message.")
|
||||
}
|
||||
dstIP = net.IP(receive[idIP0 : idIP0+net.IPv6len])
|
||||
case typeDm:
|
||||
reqLen = int(receive[idDmLen]) + lenDmBase
|
||||
if len(receive) < reqLen {
|
||||
Debug.Println("[udp]invalid received message.")
|
||||
}
|
||||
name := string(receive[idDm0 : idDm0+int(receive[idDmLen])])
|
||||
// avoid panic: syscall: string with NUL passed to StringToUTF16 on windows.
|
||||
if strings.ContainsRune(name, 0x00) {
|
||||
fmt.Println("[udp]invalid domain name.")
|
||||
return
|
||||
}
|
||||
dIP, err := net.ResolveIPAddr("ip", name) // carefully with const type
|
||||
if err != nil {
|
||||
Debug.Printf("[udp]failed to resolve domain name: %s\n", string(receive[idDm0:idDm0+receive[idDmLen]]))
|
||||
return
|
||||
}
|
||||
dstIP = dIP.IP
|
||||
default:
|
||||
Debug.Printf("[udp]addrType %d not supported", addrType)
|
||||
return
|
||||
}
|
||||
dst := &net.UDPAddr{
|
||||
IP: dstIP,
|
||||
Port: int(binary.BigEndian.Uint16(receive[reqLen-2 : reqLen])),
|
||||
}
|
||||
if _, ok := reqList.Get(dst.String()); !ok {
|
||||
req := make([]byte, reqLen)
|
||||
copy(req, receive)
|
||||
reqList.Put(dst.String(), req)
|
||||
}
|
||||
|
||||
remote, exist, err := natlist.Get(src.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
Debug.Printf("[udp]new client %s->%s via %s ota=%v\n", src, dst, remote.LocalAddr(), ota)
|
||||
go func() {
|
||||
if compatiblemode {
|
||||
Pipeloop(handle.ForceOTA(), src, remote)
|
||||
} else {
|
||||
Pipeloop(handle, src, remote)
|
||||
}
|
||||
|
||||
natlist.Delete(src.String())
|
||||
}()
|
||||
} else {
|
||||
Debug.Printf("[udp]using cached client %s->%s via %s ota=%v\n", src, dst, remote.LocalAddr(), ota)
|
||||
}
|
||||
if remote == nil {
|
||||
fmt.Println("WTF")
|
||||
}
|
||||
remote.SetDeadline(time.Now().Add(udpTimeout))
|
||||
_, err = remote.WriteTo(receive[reqLen:n], dst)
|
||||
if err != nil {
|
||||
if ne, ok := err.(*net.OpError); ok && (ne.Err == syscall.EMFILE || ne.Err == syscall.ENFILE) {
|
||||
// log too many open file error
|
||||
// EMFILE is process reaches open file limits, ENFILE is system limit
|
||||
Debug.Println("[udp]write error:", err)
|
||||
} else {
|
||||
Debug.Println("[udp]error connecting to:", dst, err)
|
||||
}
|
||||
if conn := natlist.Delete(src.String()); conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
// Pipeloop
|
||||
return
|
||||
}
|
||||
|
||||
func ReadAndHandleUDPReq(c *SecurePacketConn) error {
|
||||
buf := leakyBuf.Get()
|
||||
n, src, err := c.ReadFrom(buf[0:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go handleUDPConnection(c, n, src, buf)
|
||||
return nil
|
||||
}
|
8
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/util.go
generated
vendored
8
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/util.go
generated
vendored
@ -1,16 +1,16 @@
|
||||
package shadowsocks
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func PrintVersion() {
|
||||
const version = "1.1.5"
|
||||
const version = "1.2.0"
|
||||
fmt.Println("shadowsocks-go version", version)
|
||||
}
|
||||
|
||||
|
18
cmd/gost/vendor/vendor.json
vendored
18
cmd/gost/vendor/vendor.json
vendored
@ -2,6 +2,12 @@
|
||||
"comment": "",
|
||||
"ignore": "test",
|
||||
"package": [
|
||||
{
|
||||
"checksumSHA1": "IFJyJgPCjumDG37lEb0lyRBBGZE=",
|
||||
"path": "github.com/Yawning/chacha20",
|
||||
"revision": "c91e78db502ff629614837aacb7aa4efa61c651a",
|
||||
"revisionTime": "2016-04-30T09:49:23Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "QPs3L3mjPoi+a9GJCjW8HhyJczM=",
|
||||
"path": "github.com/codahale/chacha20",
|
||||
@ -15,10 +21,10 @@
|
||||
"revisionTime": "2017-01-19T05:34:58Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "b0uHAM/lCGCJ9GeKfClvrMMWXQM=",
|
||||
"checksumSHA1": "idpL1fpHpfntk74IVfWtkP1PMZs=",
|
||||
"path": "github.com/ginuerzh/gost",
|
||||
"revision": "358f57add6087d77b1d978e92e2f7c8073c2f544",
|
||||
"revisionTime": "2017-01-21T03:14:59Z"
|
||||
"revision": "321b03712af504981d35a47c50c2cfe4dd788a9d",
|
||||
"revisionTime": "2017-01-21T03:16:33Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "URsJa4y/sUUw/STmbeYx9EKqaYE=",
|
||||
@ -153,10 +159,10 @@
|
||||
"revisionTime": "2016-10-02T05:25:12Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "o0WHRL8mNIhfsoWlzhdJ8du6+C8=",
|
||||
"checksumSHA1": "MRsfMrdZwnnCTfIzT3czcj0lb0s=",
|
||||
"path": "github.com/shadowsocks/shadowsocks-go/shadowsocks",
|
||||
"revision": "5c9897ecdf623f385ccb8c2c78e32c5256961b41",
|
||||
"revisionTime": "2016-06-15T15:25:08Z"
|
||||
"revision": "97a5c71f80ba5f5b3e549f14a619fe557ff4f3c9",
|
||||
"revisionTime": "2017-01-21T20:35:16Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "JsJdKXhz87gWenMwBeejTOeNE7k=",
|
||||
|
41
forward.go
41
forward.go
@ -63,15 +63,15 @@ func (s *TcpForwardServer) handleTcpForward(conn net.Conn, raddr net.Addr) {
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
srcAddr *net.UDPAddr // src address
|
||||
dstAddr *net.UDPAddr // dest address
|
||||
srcAddr string // src address
|
||||
dstAddr string // dest address
|
||||
data []byte
|
||||
}
|
||||
|
||||
type cnode struct {
|
||||
chain *ProxyChain
|
||||
conn net.Conn
|
||||
srcAddr, dstAddr *net.UDPAddr
|
||||
srcAddr, dstAddr string
|
||||
rChan, wChan chan *packet
|
||||
err error
|
||||
ttl time.Duration
|
||||
@ -146,13 +146,9 @@ func (node *cnode) run() {
|
||||
timer.Reset(node.ttl)
|
||||
glog.V(LDEBUG).Infof("[udp] %s <<< %s : length %d", node.srcAddr, addr, n)
|
||||
|
||||
if node.dstAddr.String() != addr.String() {
|
||||
glog.V(LWARNING).Infof("[udp] %s <- %s : dst-addr mismatch (%s)", node.srcAddr, node.dstAddr, addr)
|
||||
break
|
||||
}
|
||||
select {
|
||||
// swap srcAddr with dstAddr
|
||||
case node.rChan <- &packet{srcAddr: node.dstAddr, dstAddr: node.srcAddr, data: b[:n]}:
|
||||
case node.rChan <- &packet{srcAddr: addr.String(), dstAddr: node.srcAddr, data: b[:n]}:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", node.srcAddr, node.dstAddr, "recv queue is full, discard")
|
||||
}
|
||||
@ -169,13 +165,9 @@ func (node *cnode) run() {
|
||||
timer.Reset(node.ttl)
|
||||
glog.V(LDEBUG).Infof("[udp-tun] %s <<< %s : length %d", node.srcAddr, dgram.Header.Addr.String(), len(dgram.Data))
|
||||
|
||||
if dgram.Header.Addr.String() != node.dstAddr.String() {
|
||||
glog.V(LWARNING).Infof("[udp-tun] %s <- %s : dst-addr mismatch (%s)", node.srcAddr, node.dstAddr, dgram.Header.Addr)
|
||||
break
|
||||
}
|
||||
select {
|
||||
// swap srcAddr with dstAddr
|
||||
case node.rChan <- &packet{srcAddr: node.dstAddr, dstAddr: node.srcAddr, data: dgram.Data}:
|
||||
case node.rChan <- &packet{srcAddr: dgram.Header.Addr.String(), dstAddr: node.srcAddr, data: dgram.Data}:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[udp-tun] %s <- %s : %s", node.srcAddr, node.dstAddr, "recv queue is full, discard")
|
||||
}
|
||||
@ -187,9 +179,15 @@ func (node *cnode) run() {
|
||||
for pkt := range node.wChan {
|
||||
timer.Reset(node.ttl)
|
||||
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", pkt.dstAddr)
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
switch c := node.conn.(type) {
|
||||
case *net.UDPConn:
|
||||
if _, err := c.WriteToUDP(pkt.data, pkt.dstAddr); err != nil {
|
||||
if _, err := c.WriteToUDP(pkt.data, dstAddr); err != nil {
|
||||
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||
node.err = err
|
||||
errChan <- err
|
||||
@ -198,7 +196,7 @@ func (node *cnode) run() {
|
||||
glog.V(LDEBUG).Infof("[udp] %s >>> %s : length %d", pkt.srcAddr, pkt.dstAddr, len(pkt.data))
|
||||
|
||||
default:
|
||||
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(len(pkt.data)), 0, ToSocksAddr(pkt.dstAddr)), pkt.data)
|
||||
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(len(pkt.data)), 0, ToSocksAddr(dstAddr)), pkt.data)
|
||||
if err := dgram.Write(c); err != nil {
|
||||
glog.V(LWARNING).Infof("[udp-tun] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||
node.err = err
|
||||
@ -255,7 +253,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- &packet{srcAddr: addr, dstAddr: raddr, data: b[:n]}:
|
||||
case ch <- &packet{srcAddr: addr.String(), dstAddr: raddr.String(), data: b[:n]}:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", addr, raddr, "send queue is full, discard")
|
||||
}
|
||||
@ -264,7 +262,12 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
||||
// start recv queue
|
||||
go func(ch <-chan *packet) {
|
||||
for pkt := range ch {
|
||||
if _, err := conn.WriteToUDP(pkt.data, pkt.dstAddr); err != nil {
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", pkt.dstAddr)
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||
continue
|
||||
}
|
||||
if _, err := conn.WriteToUDP(pkt.data, dstAddr); err != nil {
|
||||
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||
return
|
||||
}
|
||||
@ -285,7 +288,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
||||
}
|
||||
}
|
||||
|
||||
node, ok := m[pkt.srcAddr.String()]
|
||||
node, ok := m[pkt.srcAddr]
|
||||
if !ok {
|
||||
node = &cnode{
|
||||
chain: s.Base.Chain,
|
||||
@ -295,7 +298,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
||||
wChan: make(chan *packet, 32),
|
||||
ttl: time.Duration(s.TTL) * time.Second,
|
||||
}
|
||||
m[pkt.srcAddr.String()] = node
|
||||
m[pkt.srcAddr] = node
|
||||
go node.run()
|
||||
glog.V(LINFO).Infof("[udp] %s -> %s : new client (%d)", pkt.srcAddr, pkt.dstAddr, len(m))
|
||||
}
|
||||
|
2
gost.go
2
gost.go
@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Version = "2.3"
|
||||
Version = "2.4-dev"
|
||||
)
|
||||
|
||||
// Log level for glog
|
||||
|
2
node.go
2
node.go
@ -71,7 +71,7 @@ func ParseProxyNode(s string) (node ProxyNode, err error) {
|
||||
}
|
||||
|
||||
switch node.Transport {
|
||||
case "ws", "wss", "tls", "http2", "ssu", "quic", "kcp", "redirect":
|
||||
case "ws", "wss", "tls", "http2", "quic", "kcp", "redirect", "ssu":
|
||||
case "https":
|
||||
node.Protocol = "http"
|
||||
node.Transport = "tls"
|
||||
|
10
server.go
10
server.go
@ -32,7 +32,7 @@ func NewProxyServer(node ProxyNode, chain *ProxyChain, config *tls.Config) *Prox
|
||||
|
||||
var cipher *ss.Cipher
|
||||
var ota bool
|
||||
if node.Protocol == "ss" {
|
||||
if node.Protocol == "ss" || node.Transport == "ssu" {
|
||||
var err error
|
||||
var method, password string
|
||||
|
||||
@ -98,8 +98,6 @@ func (s *ProxyServer) Serve() error {
|
||||
return NewRTcpForwardServer(s).Serve()
|
||||
case "rudp": // Remote UDP port forwarding
|
||||
return NewRUdpForwardServer(s).Serve()
|
||||
case "ssu": // TODO: shadowsocks udp relay
|
||||
return NewShadowUdpServer(s).ListenAndServe()
|
||||
case "quic":
|
||||
return NewQuicServer(s).ListenAndServeTLS(s.TLSConfig)
|
||||
case "kcp":
|
||||
@ -118,6 +116,12 @@ func (s *ProxyServer) Serve() error {
|
||||
return NewKCPServer(s, config).ListenAndServe()
|
||||
case "redirect":
|
||||
return NewRedsocksTCPServer(s).ListenAndServe()
|
||||
case "ssu": // shadowsocks udp relay
|
||||
ttl, _ := strconv.Atoi(s.Node.Get("ttl"))
|
||||
if ttl <= 0 {
|
||||
ttl = DefaultTTL
|
||||
}
|
||||
return NewShadowUdpServer(s, ttl).ListenAndServe()
|
||||
default:
|
||||
ln, err = net.Listen("tcp", node.Addr)
|
||||
}
|
||||
|
148
ss.go
148
ss.go
@ -5,6 +5,7 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
"github.com/golang/glog"
|
||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||
"io"
|
||||
@ -65,47 +66,6 @@ func (s *ShadowServer) Serve() {
|
||||
glog.V(LINFO).Infof("[ss] %s >-< %s", s.conn.RemoteAddr(), addr)
|
||||
}
|
||||
|
||||
type ShadowUdpServer struct {
|
||||
Base *ProxyServer
|
||||
Handler func(conn *net.UDPConn, addr *net.UDPAddr, data []byte)
|
||||
}
|
||||
|
||||
func NewShadowUdpServer(base *ProxyServer) *ShadowUdpServer {
|
||||
return &ShadowUdpServer{Base: base}
|
||||
}
|
||||
|
||||
func (s *ShadowUdpServer) ListenAndServe() error {
|
||||
laddr, err := net.ResolveUDPAddr("udp", s.Base.Node.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lconn, err := net.ListenUDP("udp", laddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lconn.Close()
|
||||
|
||||
if s.Handler == nil {
|
||||
s.Handler = s.HandleConn
|
||||
}
|
||||
|
||||
for {
|
||||
b := make([]byte, LargeBufferSize)
|
||||
n, addr, err := lconn.ReadFromUDP(b)
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infoln(err)
|
||||
continue
|
||||
}
|
||||
|
||||
go s.Handler(lconn, addr, b[:n])
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: shadowsocks udp relay handler
|
||||
func (s *ShadowUdpServer) HandleConn(conn *net.UDPConn, addr *net.UDPAddr, data []byte) {
|
||||
|
||||
}
|
||||
|
||||
// This function is copied from shadowsocks library with some modification.
|
||||
func (s *ShadowServer) getRequest() (host string, ota bool, err error) {
|
||||
// buf size should at least have the same size with the largest possible
|
||||
@ -276,3 +236,109 @@ func (c *shadowConn) SetReadDeadline(t time.Time) error {
|
||||
func (c *shadowConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
type ShadowUdpServer struct {
|
||||
Base *ProxyServer
|
||||
TTL int
|
||||
}
|
||||
|
||||
func NewShadowUdpServer(base *ProxyServer, ttl int) *ShadowUdpServer {
|
||||
return &ShadowUdpServer{Base: base, TTL: ttl}
|
||||
}
|
||||
|
||||
func (s *ShadowUdpServer) ListenAndServe() error {
|
||||
laddr, err := net.ResolveUDPAddr("udp", s.Base.Node.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lconn, err := net.ListenUDP("udp", laddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lconn.Close()
|
||||
|
||||
conn := ss.NewSecurePacketConn(lconn, s.Base.cipher.Copy(), true) // force OTA on
|
||||
|
||||
rChan, wChan := make(chan *packet, 128), make(chan *packet, 128)
|
||||
// start send queue
|
||||
go func(ch chan<- *packet) {
|
||||
for {
|
||||
b := make([]byte, MediumBufferSize)
|
||||
n, addr, err := conn.ReadFrom(b[3:]) // add rsv and frag fields to make it the standard SOCKS5 UDP datagram
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : %s", addr, laddr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if b[3]&ss.OneTimeAuthMask > 0 {
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : client does not support OTA", addr, laddr)
|
||||
continue
|
||||
}
|
||||
b[3] &= ss.AddrMask
|
||||
|
||||
dgram, err := gosocks5.ReadUDPDatagram(bytes.NewReader(b[:n+3]))
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : %s", addr, laddr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- &packet{srcAddr: addr.String(), dstAddr: dgram.Header.Addr.String(), data: b[:n+3]}:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : %s", addr, dgram.Header.Addr.String(), "send queue is full, discard")
|
||||
}
|
||||
}
|
||||
}(wChan)
|
||||
// start recv queue
|
||||
go func(ch <-chan *packet) {
|
||||
for pkt := range ch {
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", pkt.dstAddr)
|
||||
if err != nil {
|
||||
glog.V(LWARNING).Infof("[ssu] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||
continue
|
||||
}
|
||||
if _, err := conn.WriteTo(pkt.data, dstAddr); err != nil {
|
||||
glog.V(LWARNING).Infof("[ssu] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}(rChan)
|
||||
|
||||
// mapping client to node
|
||||
m := make(map[string]*cnode)
|
||||
|
||||
// start dispatcher
|
||||
for pkt := range wChan {
|
||||
// clear obsolete nodes
|
||||
for k, node := range m {
|
||||
if node != nil && node.err != nil {
|
||||
close(node.wChan)
|
||||
delete(m, k)
|
||||
glog.V(LINFO).Infof("[ssu] clear node %s", k)
|
||||
}
|
||||
}
|
||||
|
||||
node, ok := m[pkt.srcAddr]
|
||||
if !ok {
|
||||
node = &cnode{
|
||||
chain: s.Base.Chain,
|
||||
srcAddr: pkt.srcAddr,
|
||||
dstAddr: pkt.dstAddr,
|
||||
rChan: rChan,
|
||||
wChan: make(chan *packet, 32),
|
||||
ttl: time.Duration(s.TTL) * time.Second,
|
||||
}
|
||||
m[pkt.srcAddr] = node
|
||||
go node.run()
|
||||
glog.V(LINFO).Infof("[ssu] %s -> %s : new client (%d)", pkt.srcAddr, pkt.dstAddr, len(m))
|
||||
}
|
||||
|
||||
select {
|
||||
case node.wChan <- pkt:
|
||||
case <-time.After(time.Second * 3):
|
||||
glog.V(LWARNING).Infof("[ssu] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, "node send queue is full, discard")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user