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 }