This repository has been archived by the owner on Apr 10, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
auth.go
95 lines (83 loc) · 2.63 KB
/
auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package gosocks5
import (
"fmt"
"github.com/pkg/errors"
"log"
"net"
)
type Authenticator interface {
Authenticate(conn net.Conn) error
}
type NoAuthAuthenticator struct{}
var _ Authenticator = &NoAuthAuthenticator{}
func (na *NoAuthAuthenticator) Authenticate(conn net.Conn) (finalErr error) {
_, err := conn.Write([]byte{socks5Version, noAuthMethod})
if err != nil {
return err
}
return nil
}
type UserPassAuthenticator struct {
// todo: Credentials should be filled somewhere
Credentials map[string]string
}
var _ Authenticator = &UserPassAuthenticator{}
func (up *UserPassAuthenticator) Authenticate(conn net.Conn) (finalErr error) {
defer func() {
if finalErr == nil {
if _, err := conn.Write([]byte{subnegotiationVersion, authStatusSuccess}); err != nil {
log.Printf("failed to write auth success response, err: %v", err)
}
} else {
if _, err := conn.Write([]byte{subnegotiationVersion, authStatusFailure}); err != nil {
log.Printf("failed to write auth failure response, err: %v", err)
}
}
}()
_, err := conn.Write([]byte{socks5Version, userPassMethod})
if err != nil {
return errors.Wrap(err, "failed to write selected auth method")
}
subnegotiationVersionBuf := make([]byte, 1)
if _, err = conn.Read(subnegotiationVersionBuf); err != nil {
return errors.Wrap(err, "failed to read subnegotiation version")
}
if int(subnegotiationVersionBuf[0]) != subnegotiationVersion {
return fmt.Errorf("unexpected subnegotitation version %d", subnegotiationVersionBuf[0])
}
usernameLenBuf := make([]byte, 1)
if _, err = conn.Read(usernameLenBuf); err != nil {
return errors.Wrap(err, "failed to read username len")
}
usernameBuf := make([]byte, int(usernameLenBuf[0]))
if _, err = conn.Read(usernameBuf); err != nil {
return errors.Wrap(err, "failed to read username")
}
username := string(usernameBuf)
storedPassword, ok := up.Credentials[username]
if !ok {
return fmt.Errorf("username %s doesn't exist", username)
}
passwordLenBuf := make([]byte, 1)
if _, err = conn.Read(passwordLenBuf); err != nil {
return errors.Wrap(err, "failed to read password len")
}
passwordBuf := make([]byte, int(passwordLenBuf[0]))
if _, err = conn.Read(passwordBuf); err != nil {
return errors.Wrap(err, "failed to read password")
}
if storedPassword != string(passwordBuf) {
return fmt.Errorf("password doesn't match for username %s", username)
}
return nil
}
func getAuthenticator(authMethod int) Authenticator {
authenticators := map[int]Authenticator{
0: &NoAuthAuthenticator{},
2: &UserPassAuthenticator{},
}
if authenticator, ok := authenticators[authMethod]; ok {
return authenticator
}
return nil
}