mirror of
https://github.com/nadoo/glider.git
synced 2026-06-26 16:40:12 +08:00
98 lines
2.0 KiB
Go
98 lines
2.0 KiB
Go
package anytls
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"crypto/subtle"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
const (
|
|
cmdWaste byte = iota
|
|
cmdSYN
|
|
cmdPSH
|
|
cmdFIN
|
|
cmdSettings
|
|
cmdAlert
|
|
cmdUpdatePaddingScheme
|
|
cmdSYNACK
|
|
cmdHeartRequest
|
|
cmdHeartResponse
|
|
cmdServerSettings
|
|
)
|
|
|
|
const (
|
|
protocolVersion = 2
|
|
maxFrameData = 65535
|
|
)
|
|
|
|
type frame struct {
|
|
command byte
|
|
streamID uint32
|
|
data []byte
|
|
}
|
|
|
|
func passwordHash(password string) [32]byte {
|
|
return sha256.Sum256([]byte(password))
|
|
}
|
|
|
|
func readAuth(r io.Reader, password string) error {
|
|
var head [34]byte
|
|
if _, err := io.ReadFull(r, head[:]); err != nil {
|
|
return err
|
|
}
|
|
want := passwordHash(password)
|
|
if subtle.ConstantTimeCompare(head[:32], want[:]) != 1 {
|
|
return errors.New("authentication failed")
|
|
}
|
|
paddingLen := binary.BigEndian.Uint16(head[32:34])
|
|
if paddingLen > 0 {
|
|
_, err := io.CopyN(io.Discard, r, int64(paddingLen))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeAuth(w io.Writer, password string, paddingLen int) error {
|
|
if paddingLen < 0 || paddingLen > 65535 {
|
|
return fmt.Errorf("invalid auth padding length %d", paddingLen)
|
|
}
|
|
hash := passwordHash(password)
|
|
buf := make([]byte, 34+paddingLen)
|
|
copy(buf, hash[:])
|
|
binary.BigEndian.PutUint16(buf[32:34], uint16(paddingLen))
|
|
_, err := w.Write(buf)
|
|
return err
|
|
}
|
|
|
|
func readFrame(r io.Reader) (frame, error) {
|
|
var head [7]byte
|
|
if _, err := io.ReadFull(r, head[:]); err != nil {
|
|
return frame{}, err
|
|
}
|
|
n := binary.BigEndian.Uint16(head[5:7])
|
|
var data []byte
|
|
if n > 0 {
|
|
data = make([]byte, n)
|
|
if _, err := io.ReadFull(r, data); err != nil {
|
|
return frame{}, err
|
|
}
|
|
}
|
|
return frame{command: head[0], streamID: binary.BigEndian.Uint32(head[1:5]), data: data}, nil
|
|
}
|
|
|
|
func writeFrame(w io.Writer, f frame) error {
|
|
if len(f.data) > maxFrameData {
|
|
return errors.New("frame data too large")
|
|
}
|
|
buf := make([]byte, 7+len(f.data))
|
|
buf[0] = f.command
|
|
binary.BigEndian.PutUint32(buf[1:5], f.streamID)
|
|
binary.BigEndian.PutUint16(buf[5:7], uint16(len(f.data)))
|
|
copy(buf[7:], f.data)
|
|
_, err := w.Write(buf)
|
|
return err
|
|
}
|