github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/utils/ss/util.go (about)

     1  package ss
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  	"net"
     8  	"strconv"
     9  
    10  	"github.com/AntonOrnatskyi/goproxy/utils"
    11  )
    12  
    13  const leakyBufSize = 4108 // data.len(2) + hmacsha1(10) + data(4096)
    14  const maxNBuf = 2048
    15  
    16  var leakyBuf = utils.NewLeakyBuf(maxNBuf, leakyBufSize)
    17  
    18  const (
    19  	idType  = 0 // address type index
    20  	idIP0   = 1 // ip addres start index
    21  	idDmLen = 1 // domain address length index
    22  	idDm0   = 2 // domain address start index
    23  
    24  	typeIPv4 = 1 // type is ipv4 address
    25  	typeDm   = 3 // type is domain address
    26  	typeIPv6 = 4 // type is ipv6 address
    27  
    28  	lenIPv4     = net.IPv4len + 2 // ipv4 + 2port
    29  	lenIPv6     = net.IPv6len + 2 // ipv6 + 2port
    30  	lenDmBase   = 2               // 1addrLen + 2port, plus addrLen
    31  	lenHmacSha1 = 10
    32  )
    33  
    34  func GetRequest(conn *Conn) (host string, err error) {
    35  
    36  	// buf size should at least have the same size with the largest possible
    37  	// request size (when addrType is 3, domain name has at most 256 bytes)
    38  	// 1(addrType) + 1(lenByte) + 255(max length address) + 2(port) + 10(hmac-sha1)
    39  	buf := make([]byte, 269)
    40  	// read till we get possible domain length field
    41  	if _, err = io.ReadFull(conn, buf[:idType+1]); err != nil {
    42  		return
    43  	}
    44  
    45  	var reqStart, reqEnd int
    46  	addrType := buf[idType]
    47  	switch addrType & AddrMask {
    48  	case typeIPv4:
    49  		reqStart, reqEnd = idIP0, idIP0+lenIPv4
    50  	case typeIPv6:
    51  		reqStart, reqEnd = idIP0, idIP0+lenIPv6
    52  	case typeDm:
    53  		if _, err = io.ReadFull(conn, buf[idType+1:idDmLen+1]); err != nil {
    54  			return
    55  		}
    56  		reqStart, reqEnd = idDm0, idDm0+int(buf[idDmLen])+lenDmBase
    57  	default:
    58  		err = fmt.Errorf("addr type %d not supported", addrType&AddrMask)
    59  		return
    60  	}
    61  
    62  	if _, err = io.ReadFull(conn, buf[reqStart:reqEnd]); err != nil {
    63  		return
    64  	}
    65  
    66  	// Return string for typeIP is not most efficient, but browsers (Chrome,
    67  	// Safari, Firefox) all seems using typeDm exclusively. So this is not a
    68  	// big problem.
    69  	switch addrType & AddrMask {
    70  	case typeIPv4:
    71  		host = net.IP(buf[idIP0 : idIP0+net.IPv4len]).String()
    72  	case typeIPv6:
    73  		host = net.IP(buf[idIP0 : idIP0+net.IPv6len]).String()
    74  	case typeDm:
    75  		host = string(buf[idDm0 : idDm0+int(buf[idDmLen])])
    76  	}
    77  	// parse port
    78  	port := binary.BigEndian.Uint16(buf[reqEnd-2 : reqEnd])
    79  	host = net.JoinHostPort(host, strconv.Itoa(int(port)))
    80  
    81  	return
    82  }