mirror of https://github.com/bjdgyc/anylink.git
79 lines
1.9 KiB
Go
79 lines
1.9 KiB
Go
package extension
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/cryptobyte"
|
|
)
|
|
|
|
const serverNameTypeDNSHostName = 0
|
|
|
|
// ServerName allows the client to inform the server the specific
|
|
// name it wishs to contact. Useful if multiple DNS names resolve
|
|
// to one IP
|
|
//
|
|
// https://tools.ietf.org/html/rfc6066#section-3
|
|
type ServerName struct {
|
|
ServerName string
|
|
}
|
|
|
|
// TypeValue returns the extension TypeValue
|
|
func (s ServerName) TypeValue() TypeValue {
|
|
return ServerNameTypeValue
|
|
}
|
|
|
|
// Marshal encodes the extension
|
|
func (s *ServerName) Marshal() ([]byte, error) {
|
|
var b cryptobyte.Builder
|
|
b.AddUint16(uint16(s.TypeValue()))
|
|
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
|
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
|
b.AddUint8(serverNameTypeDNSHostName)
|
|
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
|
b.AddBytes([]byte(s.ServerName))
|
|
})
|
|
})
|
|
})
|
|
return b.Bytes()
|
|
}
|
|
|
|
// Unmarshal populates the extension from encoded data
|
|
func (s *ServerName) Unmarshal(data []byte) error {
|
|
val := cryptobyte.String(data)
|
|
var extension uint16
|
|
val.ReadUint16(&extension)
|
|
if TypeValue(extension) != s.TypeValue() {
|
|
return errInvalidExtensionType
|
|
}
|
|
|
|
var extData cryptobyte.String
|
|
val.ReadUint16LengthPrefixed(&extData)
|
|
|
|
var nameList cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
|
|
return errInvalidSNIFormat
|
|
}
|
|
for !nameList.Empty() {
|
|
var nameType uint8
|
|
var serverName cryptobyte.String
|
|
if !nameList.ReadUint8(&nameType) ||
|
|
!nameList.ReadUint16LengthPrefixed(&serverName) ||
|
|
serverName.Empty() {
|
|
return errInvalidSNIFormat
|
|
}
|
|
if nameType != serverNameTypeDNSHostName {
|
|
continue
|
|
}
|
|
if len(s.ServerName) != 0 {
|
|
// Multiple names of the same name_type are prohibited.
|
|
return errInvalidSNIFormat
|
|
}
|
|
s.ServerName = string(serverName)
|
|
// An SNI value may not include a trailing dot.
|
|
if strings.HasSuffix(s.ServerName, ".") {
|
|
return errInvalidSNIFormat
|
|
}
|
|
}
|
|
return nil
|
|
}
|