socks5/password_negotiation.go

115 lines
2.9 KiB
Go

package socks5
import (
"io"
)
// PasswordNegotiationRequest is the password negotiation reqeust packet
type PasswordNegotiationRequest struct {
UsernameLen byte
Username string
PasswordLen byte
Password string
}
// NewPasswordNegotiationRequest returns new password negotiation request packet
func NewPasswordNegotiationRequest(username string, password string) *PasswordNegotiationRequest {
return &PasswordNegotiationRequest{
UsernameLen: byte(len(username)),
Username: username,
PasswordLen: byte(len(password)),
Password: password,
}
}
// NewPasswordNegotiationRequestFrom reads password negotiation request packet from reader
func NewPasswordNegotiationRequestFrom(r io.Reader) (*PasswordNegotiationRequest, error) {
buf := make([]byte, 2)
if _, err := io.ReadFull(r, buf); err != nil {
return nil, err
}
if buf[0] != PasswordVersion {
return nil, ErrPasswordAuthVersion
}
if buf[1] == 0 {
return nil, ErrBadRequest
}
usernameBuf := make([]byte, int(buf[1])+1)
if _, err := io.ReadFull(r, usernameBuf); err != nil {
return nil, err
}
var passwordBuf []byte
if usernameBuf[int(buf[1])] != 0 {
passwordBuf = make([]byte, int(usernameBuf[int(buf[1])]))
if _, err := io.ReadFull(r, passwordBuf); err != nil {
return nil, err
}
}
return &PasswordNegotiationRequest{
UsernameLen: buf[1],
Username: string(usernameBuf[:int(buf[1])]),
PasswordLen: usernameBuf[int(buf[1])],
Password: string(passwordBuf),
}, nil
}
// WriteTo writes password negotiation request packet
func (s *PasswordNegotiationRequest) WriteTo(w io.Writer) (int64, error) {
buf := []byte{PasswordVersion, s.UsernameLen}
buf = append(buf, []byte(s.Username)...)
buf = append(buf, s.PasswordLen)
buf = append(buf, []byte(s.Password)...)
n, err := w.Write(buf)
if err != nil {
return int64(n), err
}
return int64(n), nil
}
// PasswordNegotiationReply is the password negotiation reply packet
type PasswordNegotiationReply struct {
Status PasswordStatus
}
// NewPasswordNegotiationReply returns password negotiation reply packet
func NewPasswordNegotiationReply(status PasswordStatus) *PasswordNegotiationReply {
return &PasswordNegotiationReply{
Status: status,
}
}
// NewPasswordNegotiationReplyFrom reads password negotiation reply packet from reader
func NewPasswordNegotiationReplyFrom(r io.Reader) (*PasswordNegotiationReply, error) {
buf := make([]byte, 2)
if _, err := io.ReadFull(r, buf); err != nil {
return nil, err
}
if buf[0] != PasswordVersion {
return nil, ErrPasswordAuthVersion
}
rep := &PasswordNegotiationReply{
Status: PasswordStatus(buf[1]),
}
return rep, nil
}
// WriteTo writes password negotiation reply packet
func (s *PasswordNegotiationReply) WriteTo(w io.Writer) (int64, error) {
n, err := w.Write([]byte{PasswordVersion, byte(s.Status)})
if err != nil {
return int64(n), err
}
return int64(n), nil
}