mirror of https://github.com/ginuerzh/gost
12 changed files with 6415 additions and 95 deletions
@ -0,0 +1,21 @@ |
|||||
|
MIT License |
||||
|
|
||||
|
Copyright (c) 2017 ginuerzh |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
||||
@ -0,0 +1,2 @@ |
|||||
|
# tls-dissector |
||||
|
Dissect TLS handshake messages |
||||
@ -0,0 +1,75 @@ |
|||||
|
package dissector |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"encoding/binary" |
||||
|
"io" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
ExtServerName uint16 = 0x0000 |
||||
|
) |
||||
|
|
||||
|
type Extension interface { |
||||
|
Type() uint16 |
||||
|
Bytes() []byte |
||||
|
} |
||||
|
|
||||
|
func ReadExtension(r io.Reader) (ext Extension, err error) { |
||||
|
b := make([]byte, 4) |
||||
|
if _, err = io.ReadFull(r, b); err != nil { |
||||
|
return |
||||
|
} |
||||
|
bb := make([]byte, int(binary.BigEndian.Uint16(b[2:4]))) |
||||
|
if _, err = io.ReadFull(r, bb); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
t := binary.BigEndian.Uint16(b[:2]) |
||||
|
switch t { |
||||
|
case ExtServerName: |
||||
|
ext = &ServerNameExtension{ |
||||
|
NameType: bb[2], |
||||
|
Name: string(bb[5:]), |
||||
|
} |
||||
|
|
||||
|
default: |
||||
|
ext = &unknownExtension{ |
||||
|
raw: append(b, bb...), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
type unknownExtension struct { |
||||
|
raw []byte |
||||
|
} |
||||
|
|
||||
|
func (ext *unknownExtension) Type() uint16 { |
||||
|
return binary.BigEndian.Uint16(ext.raw) |
||||
|
} |
||||
|
|
||||
|
func (ext *unknownExtension) Bytes() []byte { |
||||
|
return ext.raw |
||||
|
} |
||||
|
|
||||
|
type ServerNameExtension struct { |
||||
|
NameType uint8 |
||||
|
Name string |
||||
|
} |
||||
|
|
||||
|
func (ext *ServerNameExtension) Type() uint16 { |
||||
|
return ExtServerName |
||||
|
} |
||||
|
|
||||
|
func (ext *ServerNameExtension) Bytes() []byte { |
||||
|
buf := &bytes.Buffer{} |
||||
|
binary.Write(buf, binary.BigEndian, ExtServerName) |
||||
|
binary.Write(buf, binary.BigEndian, uint16(2+1+2+len(ext.Name))) |
||||
|
binary.Write(buf, binary.BigEndian, uint16(1+2+len(ext.Name))) |
||||
|
buf.WriteByte(ext.NameType) |
||||
|
binary.Write(buf, binary.BigEndian, uint16(len(ext.Name))) |
||||
|
buf.WriteString(ext.Name) |
||||
|
return buf.Bytes() |
||||
|
} |
||||
@ -0,0 +1,152 @@ |
|||||
|
package dissector |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"encoding/binary" |
||||
|
"io" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
handshakeHeaderLen = 4 |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
HelloRequest = 0 |
||||
|
ClientHello = 1 |
||||
|
ServerHello = 2 |
||||
|
) |
||||
|
|
||||
|
type Random struct { |
||||
|
Time uint32 |
||||
|
Opaque [28]byte |
||||
|
} |
||||
|
|
||||
|
type CipherSuite uint16 |
||||
|
|
||||
|
type CompressionMethod uint8 |
||||
|
|
||||
|
type ClientHelloHandshake struct { |
||||
|
Version Version |
||||
|
Random Random |
||||
|
SessionID []byte |
||||
|
CipherSuites []CipherSuite |
||||
|
CompressionMethods []CompressionMethod |
||||
|
Extensions []Extension |
||||
|
} |
||||
|
|
||||
|
func (h *ClientHelloHandshake) Encode() (data []byte, err error) { |
||||
|
buf := new(bytes.Buffer) |
||||
|
if _, err = h.WriteTo(buf); err != nil { |
||||
|
return |
||||
|
} |
||||
|
data = buf.Bytes() |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (h *ClientHelloHandshake) Decode(data []byte) (err error) { |
||||
|
_, err = h.ReadFrom(bytes.NewReader(data)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (h *ClientHelloHandshake) ReadFrom(r io.Reader) (n int64, err error) { |
||||
|
b := make([]byte, handshakeHeaderLen) |
||||
|
nn, err := io.ReadFull(r, b) |
||||
|
n += int64(nn) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if b[0] != ClientHello { |
||||
|
err = ErrBadType |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
length := int(b[1])<<16 | int(b[2])<<8 | int(b[3]) |
||||
|
b = make([]byte, length) |
||||
|
nn, err = io.ReadFull(r, b) |
||||
|
n += int64(nn) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
h.Version = Version(binary.BigEndian.Uint16(b[:2])) |
||||
|
|
||||
|
pos := 2 |
||||
|
h.Random.Time = binary.BigEndian.Uint32(b[pos : pos+4]) |
||||
|
pos += 4 |
||||
|
copy(h.Random.Opaque[:], b[pos:pos+28]) |
||||
|
pos += 28 |
||||
|
|
||||
|
sessionLen := int(b[pos]) |
||||
|
pos++ |
||||
|
h.SessionID = make([]byte, sessionLen) |
||||
|
copy(h.SessionID, b[pos:pos+sessionLen]) |
||||
|
pos += sessionLen |
||||
|
|
||||
|
cipherLen := int(binary.BigEndian.Uint16(b[pos : pos+2])) |
||||
|
pos += 2 |
||||
|
for i := 0; i < cipherLen/2; i++ { |
||||
|
h.CipherSuites = append(h.CipherSuites, CipherSuite(binary.BigEndian.Uint16(b[pos:pos+2]))) |
||||
|
pos += 2 |
||||
|
} |
||||
|
|
||||
|
compLen := int(b[pos]) |
||||
|
pos++ |
||||
|
for i := 0; i < compLen; i++ { |
||||
|
h.CompressionMethods = append(h.CompressionMethods, CompressionMethod(b[pos])) |
||||
|
pos++ |
||||
|
} |
||||
|
|
||||
|
// extLen := int(binary.BigEndian.Uint16(b[pos : pos+2]))
|
||||
|
pos += 2 |
||||
|
|
||||
|
br := bytes.NewReader(b[pos:]) |
||||
|
for br.Len() > 0 { |
||||
|
var ext Extension |
||||
|
ext, err = ReadExtension(br) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
h.Extensions = append(h.Extensions, ext) |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (h *ClientHelloHandshake) WriteTo(w io.Writer) (n int64, err error) { |
||||
|
buf := &bytes.Buffer{} |
||||
|
buf.WriteByte(ClientHello) |
||||
|
buf.Write([]byte{0, 0, 0}) // placeholder for payload length
|
||||
|
binary.Write(buf, binary.BigEndian, h.Version) |
||||
|
pos := 6 |
||||
|
binary.Write(buf, binary.BigEndian, h.Random.Time) |
||||
|
buf.Write(h.Random.Opaque[:]) |
||||
|
pos += 32 |
||||
|
buf.WriteByte(byte(len(h.SessionID))) |
||||
|
buf.Write(h.SessionID) |
||||
|
pos += (1 + len(h.SessionID)) |
||||
|
binary.Write(buf, binary.BigEndian, uint16(len(h.CipherSuites)*2)) |
||||
|
for _, cs := range h.CipherSuites { |
||||
|
binary.Write(buf, binary.BigEndian, cs) |
||||
|
} |
||||
|
pos += (2 + len(h.CipherSuites)*2) |
||||
|
buf.WriteByte(byte(len(h.CompressionMethods))) |
||||
|
for _, cm := range h.CompressionMethods { |
||||
|
buf.WriteByte(byte(cm)) |
||||
|
} |
||||
|
pos += (1 + len(h.CompressionMethods)) |
||||
|
buf.Write([]byte{0, 0}) // placeholder for extensions length
|
||||
|
|
||||
|
extLen := 0 |
||||
|
for _, ext := range h.Extensions { |
||||
|
nn, _ := buf.Write(ext.Bytes()) |
||||
|
extLen += nn |
||||
|
} |
||||
|
|
||||
|
b := buf.Bytes() |
||||
|
plen := len(b) - handshakeHeaderLen |
||||
|
b[1], b[2], b[3] = byte((plen>>16)&0xFF), byte((plen>>8)&0xFF), byte(plen&0xFF) // payload length
|
||||
|
b[pos], b[pos+1] = byte((extLen>>8)&0xFF), byte(extLen&0xFF) // extensions length
|
||||
|
|
||||
|
nn, err := w.Write(b) |
||||
|
n = int64(nn) |
||||
|
return |
||||
|
} |
||||
@ -0,0 +1,61 @@ |
|||||
|
package dissector |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"encoding/binary" |
||||
|
"errors" |
||||
|
"io" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
RecordHeaderLen = 5 |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
Handshake = 0x16 |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
ErrBadType = errors.New("bad type") |
||||
|
) |
||||
|
|
||||
|
type Version uint16 |
||||
|
|
||||
|
type Record struct { |
||||
|
Type uint8 |
||||
|
Version Version |
||||
|
Opaque []byte |
||||
|
} |
||||
|
|
||||
|
func ReadRecord(r io.Reader) (*Record, error) { |
||||
|
record := &Record{} |
||||
|
if _, err := record.ReadFrom(r); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return record, nil |
||||
|
} |
||||
|
|
||||
|
func (rec *Record) ReadFrom(r io.Reader) (n int64, err error) { |
||||
|
b := make([]byte, RecordHeaderLen) |
||||
|
nn, err := io.ReadFull(r, b) |
||||
|
n += int64(nn) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
rec.Type = b[0] |
||||
|
rec.Version = Version(binary.BigEndian.Uint16(b[1:3])) |
||||
|
length := int(binary.BigEndian.Uint16(b[3:5])) |
||||
|
rec.Opaque = make([]byte, length) |
||||
|
nn, err = io.ReadFull(r, rec.Opaque) |
||||
|
n += int64(nn) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (rec *Record) WriteTo(w io.Writer) (n int64, err error) { |
||||
|
buf := &bytes.Buffer{} |
||||
|
buf.WriteByte(rec.Type) |
||||
|
binary.Write(buf, binary.BigEndian, rec.Version) |
||||
|
binary.Write(buf, binary.BigEndian, uint16(len(rec.Opaque))) |
||||
|
buf.Write(rec.Opaque) |
||||
|
return buf.WriteTo(w) |
||||
|
} |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue