forked from pixelbender/go-stun
-
Notifications
You must be signed in to change notification settings - Fork 0
/
stun.go
73 lines (64 loc) · 2.08 KB
/
stun.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
package stun
import (
"crypto/md5"
"crypto/tls"
"errors"
"net"
"net/url"
"strings"
)
var ErrUnsupportedScheme = errors.New("stun: unsupported scheme")
var ErrNoAddressResponse = errors.New("stun: no mapped address")
// Lookup connects to the given STUN URI and makes the STUN binding request.
// Returns the server reflexive transport address (mapped address).
func Lookup(uri, username, password string) (*Addr, error) {
u, err := url.Parse(uri)
if err != nil {
return nil, err
}
var conn net.Conn
switch strings.ToLower(u.Scheme) {
case "stun":
conn, err = net.Dial("udp", GetServerAddress(u.Opaque, false))
case "stuns":
conn, err = tls.Dial("tcp", GetServerAddress(u.Opaque, true), nil)
default:
err = ErrUnsupportedScheme
}
if err != nil {
return nil, err
}
c := NewClient(conn, &Config{GetAuthKey: LongTermAuthKey(username, password)})
defer c.Close()
msg, err := c.RoundTrip(&Message{Method: MethodBinding})
if err != nil {
return nil, err
}
if addr, ok := msg.Attributes[AttrXorMappedAddress]; ok {
return addr.(*Addr), nil
} else if addr, ok := msg.Attributes[AttrMappedAddress]; ok {
return addr.(*Addr), nil
}
return nil, ErrNoAddressResponse
}
// ListenAndServe listens on the network address and calls handler to serve requests.
func ListenAndServe(network, addr string, handler Handler) error {
srv := &Server{Config: DefaultConfig, Handler: handler}
return srv.ListenAndServe(network, addr)
}
// ListenAndServeTLS listens on the network address secured by TLS and calls handler to serve requests.
func ListenAndServeTLS(network, addr string, certFile, keyFile string, handler Handler) error {
srv := &Server{Config: DefaultConfig, Handler: handler}
return srv.ListenAndServeTLS(network, addr, certFile, keyFile)
}
func LongTermAuthKey(username, password string) func(attrs Attributes) ([]byte, error) {
return func(attrs Attributes) ([]byte, error) {
if attrs.Has(AttrRealm) {
attrs[AttrUsername] = username
h := md5.New()
h.Write([]byte(username + ":" + attrs.String(AttrRealm) + ":" + password))
return h.Sum(nil), nil
}
return nil, nil
}
}