mirror of https://github.com/v2ray/v2ray-core
				
				
				
			move sniffer to their own directory
							parent
							
								
									eafe580be4
								
							
						
					
					
						commit
						8912e4eb90
					
				| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
package bittorrent
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"v2ray.com/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SniffHeader struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SniffHeader) Protocol() string {
 | 
			
		||||
	return "bittorrent"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SniffHeader) Domain() string {
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errNotBittorrent = errors.New("not bittorrent header")
 | 
			
		||||
 | 
			
		||||
func SniffBittorrent(b []byte) (*SniffHeader, error) {
 | 
			
		||||
	if len(b) < 20 {
 | 
			
		||||
		return nil, core.ErrNoClue
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b[0] == 19 && string(b[1:20]) == "BitTorrent protocol" {
 | 
			
		||||
		return &SniffHeader{}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errNotBittorrent
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
package http
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"v2ray.com/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type version byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	HTTP1 version = iota
 | 
			
		||||
	HTTP2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SniffHeader struct {
 | 
			
		||||
	version version
 | 
			
		||||
	host    string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SniffHeader) Protocol() string {
 | 
			
		||||
	switch h.version {
 | 
			
		||||
	case HTTP1:
 | 
			
		||||
		return "http1"
 | 
			
		||||
	case HTTP2:
 | 
			
		||||
		return "http2"
 | 
			
		||||
	default:
 | 
			
		||||
		return "unknown"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SniffHeader) Domain() string {
 | 
			
		||||
	return h.host
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	methods = [...]string{"get", "post", "head", "put", "delete", "options", "connect"}
 | 
			
		||||
 | 
			
		||||
	errNotHTTPMethod = errors.New("not an HTTP method")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func beginWithHTTPMethod(b []byte) error {
 | 
			
		||||
	for _, m := range methods {
 | 
			
		||||
		if len(b) >= len(m) && strings.ToLower(string(b[:len(m)])) == m {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(b) < len(m) {
 | 
			
		||||
			return core.ErrNoClue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return errNotHTTPMethod
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SniffHTTP(b []byte) (*SniffHeader, error) {
 | 
			
		||||
	if err := beginWithHTTPMethod(b); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sh := &SniffHeader{
 | 
			
		||||
		version: HTTP1,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	headers := bytes.Split(b, []byte{'\n'})
 | 
			
		||||
	for i := 1; i < len(headers); i++ {
 | 
			
		||||
		header := headers[i]
 | 
			
		||||
		if len(header) == 0 {
 | 
			
		||||
			return nil, core.ErrNoClue
 | 
			
		||||
		}
 | 
			
		||||
		parts := bytes.SplitN(header, []byte{':'}, 2)
 | 
			
		||||
		if len(parts) != 2 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		key := strings.ToLower(string(parts[0]))
 | 
			
		||||
		value := strings.ToLower(string(bytes.Trim(parts[1], " ")))
 | 
			
		||||
		if key == "host" {
 | 
			
		||||
			domain := strings.Split(value, ":")
 | 
			
		||||
			sh.host = strings.TrimSpace(domain[0])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(sh.host) > 0 {
 | 
			
		||||
		return sh, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, core.ErrNoClue
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,106 @@
 | 
			
		|||
package http_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"v2ray.com/core/common/compare"
 | 
			
		||||
	. "v2ray.com/core/common/protocol/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestHTTPHeaders(t *testing.T) {
 | 
			
		||||
	cases := []struct {
 | 
			
		||||
		input  string
 | 
			
		||||
		domain string
 | 
			
		||||
		err    bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			input: `GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1
 | 
			
		||||
Host: net.tutsplus.com
 | 
			
		||||
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
 | 
			
		||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
 | 
			
		||||
Accept-Language: en-us,en;q=0.5
 | 
			
		||||
Accept-Encoding: gzip,deflate
 | 
			
		||||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
 | 
			
		||||
Keep-Alive: 300
 | 
			
		||||
Connection: keep-alive
 | 
			
		||||
Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120
 | 
			
		||||
Pragma: no-cache
 | 
			
		||||
Cache-Control: no-cache`,
 | 
			
		||||
			domain: "net.tutsplus.com",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			input: `POST /foo.php HTTP/1.1
 | 
			
		||||
Host: localhost
 | 
			
		||||
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
 | 
			
		||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
 | 
			
		||||
Accept-Language: en-us,en;q=0.5
 | 
			
		||||
Accept-Encoding: gzip,deflate
 | 
			
		||||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
 | 
			
		||||
Keep-Alive: 300
 | 
			
		||||
Connection: keep-alive
 | 
			
		||||
Referer: http://localhost/test.php
 | 
			
		||||
Content-Type: application/x-www-form-urlencoded
 | 
			
		||||
Content-Length: 43
 | 
			
		||||
 
 | 
			
		||||
first_name=John&last_name=Doe&action=Submit`,
 | 
			
		||||
			domain: "localhost",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			input: `X /foo.php HTTP/1.1
 | 
			
		||||
Host: localhost
 | 
			
		||||
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
 | 
			
		||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
 | 
			
		||||
Accept-Language: en-us,en;q=0.5
 | 
			
		||||
Accept-Encoding: gzip,deflate
 | 
			
		||||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
 | 
			
		||||
Keep-Alive: 300
 | 
			
		||||
Connection: keep-alive
 | 
			
		||||
Referer: http://localhost/test.php
 | 
			
		||||
Content-Type: application/x-www-form-urlencoded
 | 
			
		||||
Content-Length: 43
 | 
			
		||||
 
 | 
			
		||||
first_name=John&last_name=Doe&action=Submit`,
 | 
			
		||||
			domain: "",
 | 
			
		||||
			err:    true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			input: `GET /foo.php HTTP/1.1
 | 
			
		||||
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
 | 
			
		||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
 | 
			
		||||
Accept-Language: en-us,en;q=0.5
 | 
			
		||||
Accept-Encoding: gzip,deflate
 | 
			
		||||
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
 | 
			
		||||
Keep-Alive: 300
 | 
			
		||||
Connection: keep-alive
 | 
			
		||||
Referer: http://localhost/test.php
 | 
			
		||||
Content-Type: application/x-www-form-urlencoded
 | 
			
		||||
Content-Length: 43
 | 
			
		||||
 | 
			
		||||
Host: localhost
 | 
			
		||||
first_name=John&last_name=Doe&action=Submit`,
 | 
			
		||||
			domain: "",
 | 
			
		||||
			err:    true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			input:  `GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1`,
 | 
			
		||||
			domain: "",
 | 
			
		||||
			err:    true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range cases {
 | 
			
		||||
		header, err := SniffHTTP([]byte(test.input))
 | 
			
		||||
		if test.err {
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				t.Errorf("Expect error but nil, in test: %v", test)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Errorf("Expect no error but actually %s in test %v", err.Error(), test)
 | 
			
		||||
			}
 | 
			
		||||
			if err := compare.StringEqualWithDetail(header.Domain(), test.domain); err != nil {
 | 
			
		||||
				t.Error(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,147 @@
 | 
			
		|||
package tls
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"v2ray.com/core"
 | 
			
		||||
	"v2ray.com/core/common/serial"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SniffHeader struct {
 | 
			
		||||
	domain string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SniffHeader) Protocol() string {
 | 
			
		||||
	return "tls"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *SniffHeader) Domain() string {
 | 
			
		||||
	return h.domain
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errNotTLS = errors.New("not TLS header")
 | 
			
		||||
var errNotClientHello = errors.New("not client hello")
 | 
			
		||||
 | 
			
		||||
func IsValidTLSVersion(major, minor byte) bool {
 | 
			
		||||
	return major == 3
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadClientHello returns server name (if any) from TLS client hello message.
 | 
			
		||||
// https://github.com/golang/go/blob/master/src/crypto/tls/handshake_messages.go#L300
 | 
			
		||||
func ReadClientHello(data []byte, h *SniffHeader) error {
 | 
			
		||||
	if len(data) < 42 {
 | 
			
		||||
		return core.ErrNoClue
 | 
			
		||||
	}
 | 
			
		||||
	sessionIDLen := int(data[38])
 | 
			
		||||
	if sessionIDLen > 32 || len(data) < 39+sessionIDLen {
 | 
			
		||||
		return core.ErrNoClue
 | 
			
		||||
	}
 | 
			
		||||
	data = data[39+sessionIDLen:]
 | 
			
		||||
	if len(data) < 2 {
 | 
			
		||||
		return core.ErrNoClue
 | 
			
		||||
	}
 | 
			
		||||
	// cipherSuiteLen is the number of bytes of cipher suite numbers. Since
 | 
			
		||||
	// they are uint16s, the number must be even.
 | 
			
		||||
	cipherSuiteLen := int(data[0])<<8 | int(data[1])
 | 
			
		||||
	if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
 | 
			
		||||
		return errNotClientHello
 | 
			
		||||
	}
 | 
			
		||||
	data = data[2+cipherSuiteLen:]
 | 
			
		||||
	if len(data) < 1 {
 | 
			
		||||
		return core.ErrNoClue
 | 
			
		||||
	}
 | 
			
		||||
	compressionMethodsLen := int(data[0])
 | 
			
		||||
	if len(data) < 1+compressionMethodsLen {
 | 
			
		||||
		return core.ErrNoClue
 | 
			
		||||
	}
 | 
			
		||||
	data = data[1+compressionMethodsLen:]
 | 
			
		||||
 | 
			
		||||
	if len(data) == 0 {
 | 
			
		||||
		return errNotClientHello
 | 
			
		||||
	}
 | 
			
		||||
	if len(data) < 2 {
 | 
			
		||||
		return errNotClientHello
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	extensionsLength := int(data[0])<<8 | int(data[1])
 | 
			
		||||
	data = data[2:]
 | 
			
		||||
	if extensionsLength != len(data) {
 | 
			
		||||
		return errNotClientHello
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for len(data) != 0 {
 | 
			
		||||
		if len(data) < 4 {
 | 
			
		||||
			return errNotClientHello
 | 
			
		||||
		}
 | 
			
		||||
		extension := uint16(data[0])<<8 | uint16(data[1])
 | 
			
		||||
		length := int(data[2])<<8 | int(data[3])
 | 
			
		||||
		data = data[4:]
 | 
			
		||||
		if len(data) < length {
 | 
			
		||||
			return errNotClientHello
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch extension {
 | 
			
		||||
		case 0x00: /* extensionServerName */
 | 
			
		||||
			d := data[:length]
 | 
			
		||||
			if len(d) < 2 {
 | 
			
		||||
				return errNotClientHello
 | 
			
		||||
			}
 | 
			
		||||
			namesLen := int(d[0])<<8 | int(d[1])
 | 
			
		||||
			d = d[2:]
 | 
			
		||||
			if len(d) != namesLen {
 | 
			
		||||
				return errNotClientHello
 | 
			
		||||
			}
 | 
			
		||||
			for len(d) > 0 {
 | 
			
		||||
				if len(d) < 3 {
 | 
			
		||||
					return errNotClientHello
 | 
			
		||||
				}
 | 
			
		||||
				nameType := d[0]
 | 
			
		||||
				nameLen := int(d[1])<<8 | int(d[2])
 | 
			
		||||
				d = d[3:]
 | 
			
		||||
				if len(d) < nameLen {
 | 
			
		||||
					return errNotClientHello
 | 
			
		||||
				}
 | 
			
		||||
				if nameType == 0 {
 | 
			
		||||
					serverName := string(d[:nameLen])
 | 
			
		||||
					// An SNI value may not include a
 | 
			
		||||
					// trailing dot. See
 | 
			
		||||
					// https://tools.ietf.org/html/rfc6066#section-3.
 | 
			
		||||
					if strings.HasSuffix(serverName, ".") {
 | 
			
		||||
						return errNotClientHello
 | 
			
		||||
					}
 | 
			
		||||
					h.domain = serverName
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
				d = d[nameLen:]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		data = data[length:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return errNotTLS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SniffTLS(b []byte) (*SniffHeader, error) {
 | 
			
		||||
	if len(b) < 5 {
 | 
			
		||||
		return nil, core.ErrNoClue
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b[0] != 0x16 /* TLS Handshake */ {
 | 
			
		||||
		return nil, errNotTLS
 | 
			
		||||
	}
 | 
			
		||||
	if !IsValidTLSVersion(b[1], b[2]) {
 | 
			
		||||
		return nil, errNotTLS
 | 
			
		||||
	}
 | 
			
		||||
	headerLen := int(serial.BytesToUint16(b[3:5]))
 | 
			
		||||
	if 5+headerLen > len(b) {
 | 
			
		||||
		return nil, core.ErrNoClue
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h := &SniffHeader{}
 | 
			
		||||
	err := ReadClientHello(b[5:5+headerLen], h)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return h, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, err
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,102 @@
 | 
			
		|||
package tls_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"v2ray.com/core/common/compare"
 | 
			
		||||
	. "v2ray.com/core/common/protocol/tls"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestTLSHeaders(t *testing.T) {
 | 
			
		||||
	cases := []struct {
 | 
			
		||||
		input  []byte
 | 
			
		||||
		domain string
 | 
			
		||||
		err    bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			input: []byte{
 | 
			
		||||
				0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00,
 | 
			
		||||
				0xc4, 0x03, 0x03, 0x1a, 0xac, 0xb2, 0xa8, 0xfe,
 | 
			
		||||
				0xb4, 0x96, 0x04, 0x5b, 0xca, 0xf7, 0xc1, 0xf4,
 | 
			
		||||
				0x2e, 0x53, 0x24, 0x6e, 0x34, 0x0c, 0x58, 0x36,
 | 
			
		||||
				0x71, 0x97, 0x59, 0xe9, 0x41, 0x66, 0xe2, 0x43,
 | 
			
		||||
				0xa0, 0x13, 0xb6, 0x00, 0x00, 0x20, 0x1a, 0x1a,
 | 
			
		||||
				0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30,
 | 
			
		||||
				0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13,
 | 
			
		||||
				0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d,
 | 
			
		||||
				0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00,
 | 
			
		||||
				0x00, 0x7b, 0xba, 0xba, 0x00, 0x00, 0xff, 0x01,
 | 
			
		||||
				0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00,
 | 
			
		||||
				0x14, 0x00, 0x00, 0x11, 0x63, 0x2e, 0x73, 0x2d,
 | 
			
		||||
				0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66,
 | 
			
		||||
				0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x17, 0x00,
 | 
			
		||||
				0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00,
 | 
			
		||||
				0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04,
 | 
			
		||||
				0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08,
 | 
			
		||||
				0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x05, 0x00,
 | 
			
		||||
				0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
 | 
			
		||||
				0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c,
 | 
			
		||||
				0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70,
 | 
			
		||||
				0x2f, 0x31, 0x2e, 0x31, 0x00, 0x0b, 0x00, 0x02,
 | 
			
		||||
				0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08,
 | 
			
		||||
				0xaa, 0xaa, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
 | 
			
		||||
				0xaa, 0xaa, 0x00, 0x01, 0x00,
 | 
			
		||||
			},
 | 
			
		||||
			domain: "c.s-microsoft.com",
 | 
			
		||||
			err:    false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			input: []byte{
 | 
			
		||||
				0x16, 0x03, 0x01, 0x00, 0xee, 0x01, 0x00, 0x00,
 | 
			
		||||
				0xea, 0x03, 0x03, 0xe7, 0x91, 0x9e, 0x93, 0xca,
 | 
			
		||||
				0x78, 0x1b, 0x3c, 0xe0, 0x65, 0x25, 0x58, 0xb5,
 | 
			
		||||
				0x93, 0xe1, 0x0f, 0x85, 0xec, 0x9a, 0x66, 0x8e,
 | 
			
		||||
				0x61, 0x82, 0x88, 0xc8, 0xfc, 0xae, 0x1e, 0xca,
 | 
			
		||||
				0xd7, 0xa5, 0x63, 0x20, 0xbd, 0x1c, 0x00, 0x00,
 | 
			
		||||
				0x8b, 0xee, 0x09, 0xe3, 0x47, 0x6a, 0x0e, 0x74,
 | 
			
		||||
				0xb0, 0xbc, 0xa3, 0x02, 0xa7, 0x35, 0xe8, 0x85,
 | 
			
		||||
				0x70, 0x7c, 0x7a, 0xf0, 0x00, 0xdf, 0x4a, 0xea,
 | 
			
		||||
				0x87, 0x01, 0x14, 0x91, 0x00, 0x20, 0xea, 0xea,
 | 
			
		||||
				0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30,
 | 
			
		||||
				0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13,
 | 
			
		||||
				0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d,
 | 
			
		||||
				0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00,
 | 
			
		||||
				0x00, 0x81, 0x9a, 0x9a, 0x00, 0x00, 0xff, 0x01,
 | 
			
		||||
				0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
 | 
			
		||||
				0x16, 0x00, 0x00, 0x13, 0x77, 0x77, 0x77, 0x30,
 | 
			
		||||
				0x37, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x74,
 | 
			
		||||
				0x61, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x00,
 | 
			
		||||
				0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
 | 
			
		||||
				0x0d, 0x00, 0x14, 0x00, 0x12, 0x04, 0x03, 0x08,
 | 
			
		||||
				0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05,
 | 
			
		||||
				0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00,
 | 
			
		||||
				0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
				0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e,
 | 
			
		||||
				0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74,
 | 
			
		||||
				0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x75, 0x50,
 | 
			
		||||
				0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
 | 
			
		||||
				0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x9a, 0x9a,
 | 
			
		||||
				0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x8a, 0x8a,
 | 
			
		||||
				0x00, 0x01, 0x00,
 | 
			
		||||
			},
 | 
			
		||||
			domain: "www07.clicktale.net",
 | 
			
		||||
			err:    false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range cases {
 | 
			
		||||
		header, err := SniffTLS(test.input)
 | 
			
		||||
		if test.err {
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				t.Errorf("Exepct error but nil in test %v", test)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Errorf("Expect no error but actually %s in test %v", err.Error(), test)
 | 
			
		||||
			}
 | 
			
		||||
			if err := compare.StringEqualWithDetail(header.Domain(), test.domain); err != nil {
 | 
			
		||||
				t.Error(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue