mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-03 20:17:36 +03:00
uTLS: initial commit
This commit is contained in:
parent
e8bc3d6d4f
commit
cd3d1c4656
31 changed files with 4004 additions and 4 deletions
224
examples/examples.go
Normal file
224
examples/examples.go
Normal file
|
@ -0,0 +1,224 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
tls "github.com/Jigsaw-Code/utls"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
dialTimeout = time.Duration(15) * time.Second
|
||||
sessionTicket = []uint8(`Here goes phony session ticket: phony enough to get into ASCII range
|
||||
Ticket could be of any length, but for camouflage purposes it's better to use uniformly random contents
|
||||
and standard length such as 228`)
|
||||
)
|
||||
|
||||
func HttpGetDefault(hostname string, addr string) (string, error) {
|
||||
config := tls.Config{ServerName: hostname}
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
tlsConn := tls.Client(dialConn, &config)
|
||||
defer tlsConn.Close()
|
||||
|
||||
err = tlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("tlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
tlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
tlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func HttpGetByHelloID(hostname string, addr string, helloID tls.ClientHelloID) (string, error) {
|
||||
config := tls.Config{ServerName: hostname}
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
uTlsConn := tls.UClient(dialConn, &config, helloID)
|
||||
defer uTlsConn.Close()
|
||||
|
||||
err = uTlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
uTlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
uTlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func HttpGetExplicitRandom(hostname string, addr string) (string, error) {
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
uTlsConn := tls.UClient(dialConn, nil, tls.HelloGolang)
|
||||
defer uTlsConn.Close()
|
||||
|
||||
uTlsConn.SetSNI(hostname) // have to set SNI, if config was nil
|
||||
err = uTlsConn.BuildHandshakeState()
|
||||
if err != nil {
|
||||
// have to call BuildHandshakeState() first, when using default UClient, to avoid settings' overwriting
|
||||
return "", fmt.Errorf("uTlsConn.BuildHandshakeState() error: %+v", err)
|
||||
}
|
||||
|
||||
cRandom := []byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
||||
110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
|
||||
130, 131}
|
||||
uTlsConn.SetClientRandom(cRandom)
|
||||
err = uTlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
// These fields are accessible regardless of setting client hello explicitly
|
||||
fmt.Printf("#> MasterSecret:\n%s", hex.Dump(uTlsConn.HandshakeState.MasterSecret))
|
||||
fmt.Printf("#> ClientHello Random:\n%s", hex.Dump(uTlsConn.HandshakeState.Hello.Random))
|
||||
fmt.Printf("#> ServerHello Random:\n%s", hex.Dump(uTlsConn.HandshakeState.ServerHello.Random))
|
||||
|
||||
uTlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
uTlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// Note that the server will reject the fake ticket(unless you set up your server to accept them) and do full handshake
|
||||
func HttpGetTicket(hostname string, addr string) (string, error) {
|
||||
config := tls.Config{ServerName: hostname}
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
uTlsConn := tls.UClient(dialConn, &config, tls.HelloGolang)
|
||||
defer uTlsConn.Close()
|
||||
|
||||
err = uTlsConn.BuildHandshakeState()
|
||||
if err != nil {
|
||||
// have to call BuildHandshakeState() first, when using default UClient, to avoid settings' overwriting
|
||||
return "", fmt.Errorf("uTlsConn.BuildHandshakeState() error: %+v", err)
|
||||
}
|
||||
|
||||
masterSecret := make([]byte, 48)
|
||||
copy(masterSecret, []byte("masterSecret is NOT sent over the wire")) // you may use it for real security
|
||||
|
||||
// Create a session ticket that wasn't actually issued by the server.
|
||||
sessionState := tls.MakeClientSessionState(sessionTicket, uint16(tls.VersionTLS12),
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
masterSecret,
|
||||
nil, nil)
|
||||
|
||||
uTlsConn.SetSessionState(sessionState)
|
||||
|
||||
err = uTlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
fmt.Println("#> This is how client hello with session ticket looked:")
|
||||
fmt.Print(hex.Dump(uTlsConn.HandshakeState.Hello.Raw))
|
||||
|
||||
uTlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
uTlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// Note that the server will reject the fake ticket(unless you set up your server to accept them) and do full handshake
|
||||
func HttpGetTicketHelloID(hostname string, addr string, helloID tls.ClientHelloID) (string, error) {
|
||||
config := tls.Config{ServerName: hostname}
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
uTlsConn := tls.UClient(dialConn, &config, helloID)
|
||||
defer uTlsConn.Close()
|
||||
|
||||
masterSecret := make([]byte, 48)
|
||||
copy(masterSecret, []byte("masterSecret is NOT sent over the wire")) // you may use it for real security
|
||||
|
||||
// Create a session ticket that wasn't actually issued by the server.
|
||||
sessionState := tls.MakeClientSessionState(sessionTicket, uint16(tls.VersionTLS12),
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
masterSecret,
|
||||
nil, nil)
|
||||
|
||||
uTlsConn.SetSessionState(sessionState)
|
||||
err = uTlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
|
||||
fmt.Println("#> This is how client hello with session ticket looked:")
|
||||
fmt.Print(hex.Dump(uTlsConn.HandshakeState.Hello.Raw))
|
||||
|
||||
uTlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
uTlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var response string
|
||||
var err error
|
||||
requestHostname := "www.google.com"
|
||||
requestAddr := "172.217.11.46:443"
|
||||
|
||||
response, err = HttpGetDefault(requestHostname, requestAddr)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetDefault failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetDefault response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetByHelloID(requestHostname, requestAddr, tls.HelloAndroid_5_1_Browser)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetByHelloID(Android_5_1) failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetByHelloID(Android_5_1) response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetByHelloID(requestHostname, requestAddr, tls.HelloRandomizedNoALPN)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetByHelloID(Randomized) failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetByHelloID(Randomized) response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetExplicitRandom(requestHostname, requestAddr)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetExplicitRandom failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetExplicitRandom response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetTicket(requestHostname, requestAddr)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetTicket failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetTicket response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetTicketHelloID(requestHostname, requestAddr, tls.HelloAndroid_5_1_Browser)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetTicketHelloID(Android_5_1) failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetTicketHelloID(Android_5_1) response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getFirstLine(s string) string {
|
||||
ss := strings.Split(s, "\r\n")
|
||||
if len(ss) == 0 {
|
||||
return ""
|
||||
} else {
|
||||
return ss[0]
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue