214 lines
4.9 KiB
Go
214 lines
4.9 KiB
Go
|
package socks5
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"io"
|
||
|
"log"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
// ErrBadReply is the error when read reply
|
||
|
ErrBadReply = errors.New("Bad Reply")
|
||
|
)
|
||
|
|
||
|
// NewNegotiationRequest return negotiation request packet can be writed into server
|
||
|
func NewNegotiationRequest(methods []byte) *NegotiationRequest {
|
||
|
return &NegotiationRequest{
|
||
|
Ver: Ver,
|
||
|
NMethods: byte(len(methods)),
|
||
|
Methods: methods,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// WriteTo write negotiation request packet into server
|
||
|
func (r *NegotiationRequest) WriteTo(w io.Writer) (int64, error) {
|
||
|
var n int
|
||
|
i, err := w.Write([]byte{r.Ver})
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
i, err = w.Write([]byte{r.NMethods})
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
i, err = w.Write(r.Methods)
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
if Debug {
|
||
|
log.Printf("Sent NegotiationRequest: %#v %#v %#v\n", r.Ver, r.NMethods, r.Methods)
|
||
|
}
|
||
|
return int64(n), nil
|
||
|
}
|
||
|
|
||
|
// NewNegotiationReplyFrom read negotiation reply packet from server
|
||
|
func NewNegotiationReplyFrom(r io.Reader) (*NegotiationReply, error) {
|
||
|
bb := make([]byte, 2)
|
||
|
if _, err := io.ReadFull(r, bb); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if bb[0] != Ver {
|
||
|
return nil, ErrVersion
|
||
|
}
|
||
|
if Debug {
|
||
|
log.Printf("Got NegotiationReply: %#v %#v\n", bb[0], bb[1])
|
||
|
}
|
||
|
return &NegotiationReply{
|
||
|
Ver: bb[0],
|
||
|
Method: bb[1],
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// NewUserPassNegotiationRequest return user password negotiation request packet can be writed into server
|
||
|
func NewUserPassNegotiationRequest(username []byte, password []byte) *UserPassNegotiationRequest {
|
||
|
return &UserPassNegotiationRequest{
|
||
|
Ver: UserPassVer,
|
||
|
Ulen: byte(len(username)),
|
||
|
Uname: username,
|
||
|
Plen: byte(len(password)),
|
||
|
Passwd: password,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// WriteTo write user password negotiation request packet into server
|
||
|
func (r *UserPassNegotiationRequest) WriteTo(w io.Writer) (int64, error) {
|
||
|
var n int
|
||
|
i, err := w.Write([]byte{r.Ver, r.Ulen})
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
i, err = w.Write(r.Uname)
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
i, err = w.Write([]byte{r.Plen})
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
i, err = w.Write(r.Passwd)
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
if Debug {
|
||
|
log.Printf("Sent UserNameNegotiationRequest: %#v %#v %#v %#v %#v\n", r.Ver, r.Ulen, r.Uname, r.Plen, r.Passwd)
|
||
|
}
|
||
|
return int64(n), nil
|
||
|
}
|
||
|
|
||
|
// NewUserPassNegotiationReplyFrom read user password negotiation reply packet from server
|
||
|
func NewUserPassNegotiationReplyFrom(r io.Reader) (*UserPassNegotiationReply, error) {
|
||
|
bb := make([]byte, 2)
|
||
|
if _, err := io.ReadFull(r, bb); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if bb[0] != UserPassVer {
|
||
|
return nil, ErrUserPassVersion
|
||
|
}
|
||
|
if Debug {
|
||
|
log.Printf("Got UserPassNegotiationReply: %#v %#v \n", bb[0], bb[1])
|
||
|
}
|
||
|
return &UserPassNegotiationReply{
|
||
|
Ver: bb[0],
|
||
|
Status: bb[1],
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// NewRequest return request packet can be writed into server, dstaddr should not have domain length
|
||
|
func NewRequest(cmd byte, atyp byte, dstaddr []byte, dstport []byte) *Request {
|
||
|
if atyp == ATYPDomain {
|
||
|
dstaddr = append([]byte{byte(len(dstaddr))}, dstaddr...)
|
||
|
}
|
||
|
return &Request{
|
||
|
Ver: Ver,
|
||
|
Cmd: cmd,
|
||
|
Rsv: 0x00,
|
||
|
Atyp: atyp,
|
||
|
DstAddr: dstaddr,
|
||
|
DstPort: dstport,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// WriteTo write request packet into server
|
||
|
func (r *Request) WriteTo(w io.Writer) (int64, error) {
|
||
|
var n int
|
||
|
i, err := w.Write([]byte{r.Ver, r.Cmd, r.Rsv, r.Atyp})
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
i, err = w.Write(r.DstAddr)
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
i, err = w.Write(r.DstPort)
|
||
|
n = n + i
|
||
|
if err != nil {
|
||
|
return int64(n), err
|
||
|
}
|
||
|
if Debug {
|
||
|
log.Printf("Sent Request: %#v %#v %#v %#v %#v %#v\n", r.Ver, r.Cmd, r.Rsv, r.Atyp, r.DstAddr, r.DstPort)
|
||
|
}
|
||
|
return int64(n), nil
|
||
|
}
|
||
|
|
||
|
// NewReplyFrom read reply packet from server
|
||
|
func NewReplyFrom(r io.Reader) (*Reply, error) {
|
||
|
bb := make([]byte, 4)
|
||
|
if _, err := io.ReadFull(r, bb); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if bb[0] != Ver {
|
||
|
return nil, ErrVersion
|
||
|
}
|
||
|
var addr []byte
|
||
|
if bb[3] == ATYPIPv4 {
|
||
|
addr = make([]byte, 4)
|
||
|
if _, err := io.ReadFull(r, addr); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
} else if bb[3] == ATYPIPv6 {
|
||
|
addr = make([]byte, 16)
|
||
|
if _, err := io.ReadFull(r, addr); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
} else if bb[3] == ATYPDomain {
|
||
|
dal := make([]byte, 1)
|
||
|
if _, err := io.ReadFull(r, dal); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if dal[0] == 0 {
|
||
|
return nil, ErrBadReply
|
||
|
}
|
||
|
addr = make([]byte, int(dal[0]))
|
||
|
if _, err := io.ReadFull(r, addr); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
addr = append(dal, addr...)
|
||
|
} else {
|
||
|
return nil, ErrBadReply
|
||
|
}
|
||
|
port := make([]byte, 2)
|
||
|
if _, err := io.ReadFull(r, port); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if Debug {
|
||
|
log.Printf("Got Reply: %#v %#v %#v %#v %#v %#v\n", bb[0], bb[1], bb[2], bb[3], addr, port)
|
||
|
}
|
||
|
return &Reply{
|
||
|
Ver: bb[0],
|
||
|
Rep: bb[1],
|
||
|
Rsv: bb[2],
|
||
|
Atyp: bb[3],
|
||
|
BndAddr: addr,
|
||
|
BndPort: port,
|
||
|
}, nil
|
||
|
}
|