#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 {
|
type packet struct {
|
||||||
srcAddr *net.UDPAddr // src address
|
srcAddr string // src address
|
||||||
dstAddr *net.UDPAddr // dest address
|
dstAddr string // dest address
|
||||||
data []byte
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type cnode struct {
|
type cnode struct {
|
||||||
chain *ProxyChain
|
chain *ProxyChain
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
srcAddr, dstAddr *net.UDPAddr
|
srcAddr, dstAddr string
|
||||||
rChan, wChan chan *packet
|
rChan, wChan chan *packet
|
||||||
err error
|
err error
|
||||||
ttl time.Duration
|
ttl time.Duration
|
||||||
@ -146,13 +146,9 @@ func (node *cnode) run() {
|
|||||||
timer.Reset(node.ttl)
|
timer.Reset(node.ttl)
|
||||||
glog.V(LDEBUG).Infof("[udp] %s <<< %s : length %d", node.srcAddr, addr, n)
|
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 {
|
select {
|
||||||
// swap srcAddr with dstAddr
|
// 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):
|
case <-time.After(time.Second * 3):
|
||||||
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", node.srcAddr, node.dstAddr, "recv queue is full, discard")
|
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)
|
timer.Reset(node.ttl)
|
||||||
glog.V(LDEBUG).Infof("[udp-tun] %s <<< %s : length %d", node.srcAddr, dgram.Header.Addr.String(), len(dgram.Data))
|
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 {
|
select {
|
||||||
// swap srcAddr with dstAddr
|
// 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):
|
case <-time.After(time.Second * 3):
|
||||||
glog.V(LWARNING).Infof("[udp-tun] %s <- %s : %s", node.srcAddr, node.dstAddr, "recv queue is full, discard")
|
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 {
|
for pkt := range node.wChan {
|
||||||
timer.Reset(node.ttl)
|
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) {
|
switch c := node.conn.(type) {
|
||||||
case *net.UDPConn:
|
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)
|
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||||
node.err = err
|
node.err = err
|
||||||
errChan <- 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))
|
glog.V(LDEBUG).Infof("[udp] %s >>> %s : length %d", pkt.srcAddr, pkt.dstAddr, len(pkt.data))
|
||||||
|
|
||||||
default:
|
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 {
|
if err := dgram.Write(c); err != nil {
|
||||||
glog.V(LWARNING).Infof("[udp-tun] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
glog.V(LWARNING).Infof("[udp-tun] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||||
node.err = err
|
node.err = err
|
||||||
@ -255,7 +253,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
select {
|
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):
|
case <-time.After(time.Second * 3):
|
||||||
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", addr, raddr, "send queue is full, discard")
|
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
|
// start recv queue
|
||||||
go func(ch <-chan *packet) {
|
go func(ch <-chan *packet) {
|
||||||
for pkt := range ch {
|
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)
|
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -285,7 +288,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node, ok := m[pkt.srcAddr.String()]
|
node, ok := m[pkt.srcAddr]
|
||||||
if !ok {
|
if !ok {
|
||||||
node = &cnode{
|
node = &cnode{
|
||||||
chain: s.Base.Chain,
|
chain: s.Base.Chain,
|
||||||
@ -295,7 +298,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
|||||||
wChan: make(chan *packet, 32),
|
wChan: make(chan *packet, 32),
|
||||||
ttl: time.Duration(s.TTL) * time.Second,
|
ttl: time.Duration(s.TTL) * time.Second,
|
||||||
}
|
}
|
||||||
m[pkt.srcAddr.String()] = node
|
m[pkt.srcAddr] = node
|
||||||
go node.run()
|
go node.run()
|
||||||
glog.V(LINFO).Infof("[udp] %s -> %s : new client (%d)", pkt.srcAddr, pkt.dstAddr, len(m))
|
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 (
|
const (
|
||||||
Version = "2.3"
|
Version = "2.4-dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Log level for glog
|
// 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 {
|
switch node.Transport {
|
||||||
case "ws", "wss", "tls", "http2", "ssu", "quic", "kcp", "redirect":
|
case "ws", "wss", "tls", "http2", "quic", "kcp", "redirect", "ssu":
|
||||||
case "https":
|
case "https":
|
||||||
node.Protocol = "http"
|
node.Protocol = "http"
|
||||||
node.Transport = "tls"
|
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 cipher *ss.Cipher
|
||||||
var ota bool
|
var ota bool
|
||||||
if node.Protocol == "ss" {
|
if node.Protocol == "ss" || node.Transport == "ssu" {
|
||||||
var err error
|
var err error
|
||||||
var method, password string
|
var method, password string
|
||||||
|
|
||||||
@ -98,8 +98,6 @@ func (s *ProxyServer) Serve() error {
|
|||||||
return NewRTcpForwardServer(s).Serve()
|
return NewRTcpForwardServer(s).Serve()
|
||||||
case "rudp": // Remote UDP port forwarding
|
case "rudp": // Remote UDP port forwarding
|
||||||
return NewRUdpForwardServer(s).Serve()
|
return NewRUdpForwardServer(s).Serve()
|
||||||
case "ssu": // TODO: shadowsocks udp relay
|
|
||||||
return NewShadowUdpServer(s).ListenAndServe()
|
|
||||||
case "quic":
|
case "quic":
|
||||||
return NewQuicServer(s).ListenAndServeTLS(s.TLSConfig)
|
return NewQuicServer(s).ListenAndServeTLS(s.TLSConfig)
|
||||||
case "kcp":
|
case "kcp":
|
||||||
@ -118,6 +116,12 @@ func (s *ProxyServer) Serve() error {
|
|||||||
return NewKCPServer(s, config).ListenAndServe()
|
return NewKCPServer(s, config).ListenAndServe()
|
||||||
case "redirect":
|
case "redirect":
|
||||||
return NewRedsocksTCPServer(s).ListenAndServe()
|
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:
|
default:
|
||||||
ln, err = net.Listen("tcp", node.Addr)
|
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"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ginuerzh/gosocks5"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
"io"
|
"io"
|
||||||
@ -65,47 +66,6 @@ func (s *ShadowServer) Serve() {
|
|||||||
glog.V(LINFO).Infof("[ss] %s >-< %s", s.conn.RemoteAddr(), addr)
|
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.
|
// This function is copied from shadowsocks library with some modification.
|
||||||
func (s *ShadowServer) getRequest() (host string, ota bool, err error) {
|
func (s *ShadowServer) getRequest() (host string, ota bool, err error) {
|
||||||
// buf size should at least have the same size with the largest possible
|
// 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 {
|
func (c *shadowConn) SetWriteDeadline(t time.Time) error {
|
||||||
return c.conn.SetWriteDeadline(t)
|
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
|
||||||
|
}
|
||||||
|
40
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/encrypt.go
generated
vendored
40
cmd/gost/vendor/github.com/shadowsocks/shadowsocks-go/shadowsocks/encrypt.go
generated
vendored
@ -12,7 +12,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/codahale/chacha20"
|
"github.com/Yawning/chacha20"
|
||||||
"golang.org/x/crypto/blowfish"
|
"golang.org/x/crypto/blowfish"
|
||||||
"golang.org/x/crypto/cast5"
|
"golang.org/x/crypto/cast5"
|
||||||
"golang.org/x/crypto/salsa20/salsa"
|
"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)
|
block, err := aes.NewCipher(key)
|
||||||
return newStream(block, err, key, iv, doe)
|
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) {
|
func newDESStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||||
block, err := des.NewCipher(key)
|
block, err := des.NewCipher(key)
|
||||||
return newStream(block, err, key, iv, doe)
|
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) {
|
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 {
|
type salsaStreamCipher struct {
|
||||||
@ -145,15 +157,19 @@ type cipherInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cipherMethod = map[string]*cipherInfo{
|
var cipherMethod = map[string]*cipherInfo{
|
||||||
"aes-128-cfb": {16, 16, newAESStream},
|
"aes-128-cfb": {16, 16, newAESCFBStream},
|
||||||
"aes-192-cfb": {24, 16, newAESStream},
|
"aes-192-cfb": {24, 16, newAESCFBStream},
|
||||||
"aes-256-cfb": {32, 16, newAESStream},
|
"aes-256-cfb": {32, 16, newAESCFBStream},
|
||||||
"des-cfb": {8, 8, newDESStream},
|
"aes-128-ctr": {16, 16, newAESCTRStream},
|
||||||
"bf-cfb": {16, 8, newBlowFishStream},
|
"aes-192-ctr": {24, 16, newAESCTRStream},
|
||||||
"cast5-cfb": {16, 8, newCast5Stream},
|
"aes-256-ctr": {32, 16, newAESCTRStream},
|
||||||
"rc4-md5": {16, 16, newRC4MD5Stream},
|
"des-cfb": {8, 8, newDESStream},
|
||||||
"chacha20": {32, 8, newChaCha20Stream},
|
"bf-cfb": {16, 8, newBlowFishStream},
|
||||||
"salsa20": {32, 8, newSalsa20Stream},
|
"cast5-cfb": {16, 8, newCast5Stream},
|
||||||
|
"rc4-md5": {16, 16, newRC4MD5Stream},
|
||||||
|
"chacha20": {32, 8, newChaCha20Stream},
|
||||||
|
"chacha20-ietf": {32, 12, newChaCha20IETFStream},
|
||||||
|
"salsa20": {32, 8, newSalsa20Stream},
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckCipherMethod(method string) error {
|
func CheckCipherMethod(method string) error {
|
||||||
|
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
|
package shadowsocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PrintVersion() {
|
func PrintVersion() {
|
||||||
const version = "1.1.5"
|
const version = "1.2.0"
|
||||||
fmt.Println("shadowsocks-go version", version)
|
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": "",
|
"comment": "",
|
||||||
"ignore": "test",
|
"ignore": "test",
|
||||||
"package": [
|
"package": [
|
||||||
|
{
|
||||||
|
"checksumSHA1": "IFJyJgPCjumDG37lEb0lyRBBGZE=",
|
||||||
|
"path": "github.com/Yawning/chacha20",
|
||||||
|
"revision": "c91e78db502ff629614837aacb7aa4efa61c651a",
|
||||||
|
"revisionTime": "2016-04-30T09:49:23Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "QPs3L3mjPoi+a9GJCjW8HhyJczM=",
|
"checksumSHA1": "QPs3L3mjPoi+a9GJCjW8HhyJczM=",
|
||||||
"path": "github.com/codahale/chacha20",
|
"path": "github.com/codahale/chacha20",
|
||||||
@ -15,10 +21,10 @@
|
|||||||
"revisionTime": "2017-01-19T05:34:58Z"
|
"revisionTime": "2017-01-19T05:34:58Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "b0uHAM/lCGCJ9GeKfClvrMMWXQM=",
|
"checksumSHA1": "idpL1fpHpfntk74IVfWtkP1PMZs=",
|
||||||
"path": "github.com/ginuerzh/gost",
|
"path": "github.com/ginuerzh/gost",
|
||||||
"revision": "358f57add6087d77b1d978e92e2f7c8073c2f544",
|
"revision": "321b03712af504981d35a47c50c2cfe4dd788a9d",
|
||||||
"revisionTime": "2017-01-21T03:14:59Z"
|
"revisionTime": "2017-01-21T03:16:33Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "URsJa4y/sUUw/STmbeYx9EKqaYE=",
|
"checksumSHA1": "URsJa4y/sUUw/STmbeYx9EKqaYE=",
|
||||||
@ -153,10 +159,10 @@
|
|||||||
"revisionTime": "2016-10-02T05:25:12Z"
|
"revisionTime": "2016-10-02T05:25:12Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "o0WHRL8mNIhfsoWlzhdJ8du6+C8=",
|
"checksumSHA1": "MRsfMrdZwnnCTfIzT3czcj0lb0s=",
|
||||||
"path": "github.com/shadowsocks/shadowsocks-go/shadowsocks",
|
"path": "github.com/shadowsocks/shadowsocks-go/shadowsocks",
|
||||||
"revision": "5c9897ecdf623f385ccb8c2c78e32c5256961b41",
|
"revision": "97a5c71f80ba5f5b3e549f14a619fe557ff4f3c9",
|
||||||
"revisionTime": "2016-06-15T15:25:08Z"
|
"revisionTime": "2017-01-21T20:35:16Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "JsJdKXhz87gWenMwBeejTOeNE7k=",
|
"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 {
|
type packet struct {
|
||||||
srcAddr *net.UDPAddr // src address
|
srcAddr string // src address
|
||||||
dstAddr *net.UDPAddr // dest address
|
dstAddr string // dest address
|
||||||
data []byte
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type cnode struct {
|
type cnode struct {
|
||||||
chain *ProxyChain
|
chain *ProxyChain
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
srcAddr, dstAddr *net.UDPAddr
|
srcAddr, dstAddr string
|
||||||
rChan, wChan chan *packet
|
rChan, wChan chan *packet
|
||||||
err error
|
err error
|
||||||
ttl time.Duration
|
ttl time.Duration
|
||||||
@ -146,13 +146,9 @@ func (node *cnode) run() {
|
|||||||
timer.Reset(node.ttl)
|
timer.Reset(node.ttl)
|
||||||
glog.V(LDEBUG).Infof("[udp] %s <<< %s : length %d", node.srcAddr, addr, n)
|
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 {
|
select {
|
||||||
// swap srcAddr with dstAddr
|
// 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):
|
case <-time.After(time.Second * 3):
|
||||||
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", node.srcAddr, node.dstAddr, "recv queue is full, discard")
|
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)
|
timer.Reset(node.ttl)
|
||||||
glog.V(LDEBUG).Infof("[udp-tun] %s <<< %s : length %d", node.srcAddr, dgram.Header.Addr.String(), len(dgram.Data))
|
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 {
|
select {
|
||||||
// swap srcAddr with dstAddr
|
// 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):
|
case <-time.After(time.Second * 3):
|
||||||
glog.V(LWARNING).Infof("[udp-tun] %s <- %s : %s", node.srcAddr, node.dstAddr, "recv queue is full, discard")
|
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 {
|
for pkt := range node.wChan {
|
||||||
timer.Reset(node.ttl)
|
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) {
|
switch c := node.conn.(type) {
|
||||||
case *net.UDPConn:
|
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)
|
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||||
node.err = err
|
node.err = err
|
||||||
errChan <- 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))
|
glog.V(LDEBUG).Infof("[udp] %s >>> %s : length %d", pkt.srcAddr, pkt.dstAddr, len(pkt.data))
|
||||||
|
|
||||||
default:
|
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 {
|
if err := dgram.Write(c); err != nil {
|
||||||
glog.V(LWARNING).Infof("[udp-tun] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
glog.V(LWARNING).Infof("[udp-tun] %s -> %s : %s", pkt.srcAddr, pkt.dstAddr, err)
|
||||||
node.err = err
|
node.err = err
|
||||||
@ -255,7 +253,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
select {
|
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):
|
case <-time.After(time.Second * 3):
|
||||||
glog.V(LWARNING).Infof("[udp] %s -> %s : %s", addr, raddr, "send queue is full, discard")
|
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
|
// start recv queue
|
||||||
go func(ch <-chan *packet) {
|
go func(ch <-chan *packet) {
|
||||||
for pkt := range ch {
|
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)
|
glog.V(LWARNING).Infof("[udp] %s <- %s : %s", pkt.dstAddr, pkt.srcAddr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -285,7 +288,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node, ok := m[pkt.srcAddr.String()]
|
node, ok := m[pkt.srcAddr]
|
||||||
if !ok {
|
if !ok {
|
||||||
node = &cnode{
|
node = &cnode{
|
||||||
chain: s.Base.Chain,
|
chain: s.Base.Chain,
|
||||||
@ -295,7 +298,7 @@ func (s *UdpForwardServer) ListenAndServe() error {
|
|||||||
wChan: make(chan *packet, 32),
|
wChan: make(chan *packet, 32),
|
||||||
ttl: time.Duration(s.TTL) * time.Second,
|
ttl: time.Duration(s.TTL) * time.Second,
|
||||||
}
|
}
|
||||||
m[pkt.srcAddr.String()] = node
|
m[pkt.srcAddr] = node
|
||||||
go node.run()
|
go node.run()
|
||||||
glog.V(LINFO).Infof("[udp] %s -> %s : new client (%d)", pkt.srcAddr, pkt.dstAddr, len(m))
|
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 (
|
const (
|
||||||
Version = "2.3"
|
Version = "2.4-dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Log level for glog
|
// 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 {
|
switch node.Transport {
|
||||||
case "ws", "wss", "tls", "http2", "ssu", "quic", "kcp", "redirect":
|
case "ws", "wss", "tls", "http2", "quic", "kcp", "redirect", "ssu":
|
||||||
case "https":
|
case "https":
|
||||||
node.Protocol = "http"
|
node.Protocol = "http"
|
||||||
node.Transport = "tls"
|
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 cipher *ss.Cipher
|
||||||
var ota bool
|
var ota bool
|
||||||
if node.Protocol == "ss" {
|
if node.Protocol == "ss" || node.Transport == "ssu" {
|
||||||
var err error
|
var err error
|
||||||
var method, password string
|
var method, password string
|
||||||
|
|
||||||
@ -98,8 +98,6 @@ func (s *ProxyServer) Serve() error {
|
|||||||
return NewRTcpForwardServer(s).Serve()
|
return NewRTcpForwardServer(s).Serve()
|
||||||
case "rudp": // Remote UDP port forwarding
|
case "rudp": // Remote UDP port forwarding
|
||||||
return NewRUdpForwardServer(s).Serve()
|
return NewRUdpForwardServer(s).Serve()
|
||||||
case "ssu": // TODO: shadowsocks udp relay
|
|
||||||
return NewShadowUdpServer(s).ListenAndServe()
|
|
||||||
case "quic":
|
case "quic":
|
||||||
return NewQuicServer(s).ListenAndServeTLS(s.TLSConfig)
|
return NewQuicServer(s).ListenAndServeTLS(s.TLSConfig)
|
||||||
case "kcp":
|
case "kcp":
|
||||||
@ -118,6 +116,12 @@ func (s *ProxyServer) Serve() error {
|
|||||||
return NewKCPServer(s, config).ListenAndServe()
|
return NewKCPServer(s, config).ListenAndServe()
|
||||||
case "redirect":
|
case "redirect":
|
||||||
return NewRedsocksTCPServer(s).ListenAndServe()
|
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:
|
default:
|
||||||
ln, err = net.Listen("tcp", node.Addr)
|
ln, err = net.Listen("tcp", node.Addr)
|
||||||
}
|
}
|
||||||
|
148
ss.go
148
ss.go
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ginuerzh/gosocks5"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
"io"
|
"io"
|
||||||
@ -65,47 +66,6 @@ func (s *ShadowServer) Serve() {
|
|||||||
glog.V(LINFO).Infof("[ss] %s >-< %s", s.conn.RemoteAddr(), addr)
|
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.
|
// This function is copied from shadowsocks library with some modification.
|
||||||
func (s *ShadowServer) getRequest() (host string, ota bool, err error) {
|
func (s *ShadowServer) getRequest() (host string, ota bool, err error) {
|
||||||
// buf size should at least have the same size with the largest possible
|
// 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 {
|
func (c *shadowConn) SetWriteDeadline(t time.Time) error {
|
||||||
return c.conn.SetWriteDeadline(t)
|
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