-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add incoming records sorting buffer, handshake encoder/decoder
- Loading branch information
1 parent
3bd8b2d
commit a56125f
Showing
10 changed files
with
3,031 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package dtls | ||
|
||
import "strconv" | ||
|
||
type alert uint8 | ||
|
||
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6 | ||
const ( | ||
alertCloseNotify alert = 0 | ||
alertUnexpectedMessage alert = 10 | ||
alertBadRecordMAC alert = 20 | ||
alertDecryptionFailed alert = 21 | ||
alertRecordOverflow alert = 22 | ||
alertDecompressionFailure alert = 30 | ||
alertHandshakeFailure alert = 40 | ||
alertBadCertificate alert = 42 | ||
alertUnsupportedCertificate alert = 43 | ||
alertCertificateRevoked alert = 44 | ||
alertCertificateExpired alert = 45 | ||
alertCertificateUnknown alert = 46 | ||
alertIllegalParameter alert = 47 | ||
alertUnknownCA alert = 48 | ||
alertAccessDenied alert = 49 | ||
alertDecodeError alert = 50 | ||
alertDecryptError alert = 51 | ||
alertProtocolVersion alert = 70 | ||
alertInsufficientSecurity alert = 71 | ||
alertInternalError alert = 80 | ||
alertInappropriateFallback alert = 86 | ||
alertUserCanceled alert = 90 | ||
alertNoRenegotiation alert = 100 | ||
alertUnsupportedExtension alert = 110 | ||
alertCertificateUnobtainable alert = 111 | ||
alertUnrecognizedName alert = 112 | ||
alertBadCertificateStatusResponse alert = 113 | ||
alertBadCertificateHashValue alert = 114 | ||
alertUnknownPSKIdentity alert = 115 | ||
) | ||
|
||
var alertText = map[alert]string{ | ||
alertCloseNotify: "close notify", | ||
alertUnexpectedMessage: "unexpected message", | ||
alertBadRecordMAC: "bad record MAC", | ||
alertDecryptionFailed: "decryption failed", | ||
alertRecordOverflow: "record overflow", | ||
alertDecompressionFailure: "decompression failure", | ||
alertHandshakeFailure: "handshake failure", | ||
alertBadCertificate: "bad certificate", | ||
alertUnsupportedCertificate: "unsupported certificate", | ||
alertCertificateRevoked: "revoked certificate", | ||
alertCertificateExpired: "expired certificate", | ||
alertCertificateUnknown: "unknown certificate", | ||
alertIllegalParameter: "illegal parameter", | ||
alertUnknownCA: "unknown certificate authority", | ||
alertAccessDenied: "access denied", | ||
alertDecodeError: "error decoding message", | ||
alertDecryptError: "error decrypting message", | ||
alertProtocolVersion: "protocol version not supported", | ||
alertInsufficientSecurity: "insufficient security level", | ||
alertInternalError: "internal error", | ||
alertInappropriateFallback: "inappropriate fallback", | ||
alertUserCanceled: "user canceled", | ||
alertNoRenegotiation: "no renegotiation", | ||
alertUnsupportedExtension: "unsupported extension", | ||
alertCertificateUnobtainable: "certificate unobtainable", | ||
alertUnrecognizedName: "unrecognized name", | ||
alertBadCertificateStatusResponse: "bad certificate status response", | ||
alertBadCertificateHashValue: "bad certificate hash value", | ||
alertUnknownPSKIdentity: "unknown PSK identity", | ||
} | ||
|
||
func (e alert) String() string { | ||
s, ok := alertText[e] | ||
if ok { | ||
return "dtls: " + s | ||
} | ||
return "dtls: alert(" + strconv.Itoa(int(e)) + ")" | ||
} | ||
|
||
func (e alert) Error() string { | ||
return e.String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
package dtls | ||
|
||
import ( | ||
"encoding/hex" | ||
"errors" | ||
"io" | ||
"log" | ||
"sort" | ||
"strconv" | ||
) | ||
|
||
var ErrFormat = errors.New("dtls: incorrect format") | ||
|
||
type reader interface { | ||
Next(n int) ([]byte, error) | ||
Len() int | ||
} | ||
|
||
const ( | ||
maxPacketSize = 4096 | ||
maxUnreadRecords = 64 | ||
) | ||
|
||
type bufferReader struct { | ||
buf []byte | ||
pos int | ||
} | ||
|
||
func (r *bufferReader) Next(n int) ([]byte, error) { | ||
p := r.pos + n | ||
if len(r.buf) < r.pos+n { | ||
return nil, io.EOF | ||
} | ||
off := r.pos | ||
r.pos = p | ||
return r.buf[off:p], nil | ||
} | ||
|
||
func (r *bufferReader) Len() int { | ||
return len(r.buf) - r.pos | ||
} | ||
|
||
type receiver struct { | ||
inner io.Reader | ||
buf [maxPacketSize]byte | ||
records recordSeq | ||
epoch uint16 | ||
seq uint64 | ||
} | ||
|
||
func (r *receiver) Read() (*record, error) { | ||
for { | ||
if len(r.records) > 0 { | ||
if rec := r.records[0]; rec.seq == r.seq { | ||
r.records = r.records[1:] | ||
r.seq++ | ||
return rec, nil | ||
} | ||
} | ||
n, err := r.inner.Read(r.buf[:]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
r.fill(r.buf[:n]) | ||
} | ||
} | ||
|
||
func (r *receiver) fill(b []byte) (err error) { | ||
log.Printf("RECV %s", hex.Dump(b)) | ||
rec := new(record) | ||
if err = rec.read(b); err != nil { | ||
return err | ||
} | ||
if rec.seq < r.seq { | ||
return nil | ||
} | ||
r.records = append(r.records, rec) | ||
n := 0 | ||
for _, it := range r.records { | ||
it.age++ | ||
if it.seq < r.seq || it.seq > r.seq+maxUnreadRecords || it.age > maxUnreadRecords { | ||
continue | ||
} | ||
r.records[n] = it | ||
n++ | ||
} | ||
r.records = r.records[:n] | ||
sort.Sort(r.records) | ||
return | ||
} | ||
|
||
type handshakeDecoder struct { | ||
*receiver | ||
ver uint16 | ||
mseq uint16 | ||
} | ||
|
||
func (r *handshakeDecoder) ReadMessage() (msg handshakeMsg, err error) { | ||
var rec *record | ||
var buf []byte | ||
var off int | ||
for { | ||
if rec, err = r.Read(); err != nil { | ||
return | ||
} | ||
f := new(fragment) | ||
if err = f.read(rec.buf); err != nil { | ||
return | ||
} | ||
if f.off != off { | ||
return nil, ErrFormat | ||
} | ||
if buf == nil { | ||
buf = make([]byte, f.sum) | ||
} | ||
if off += copy(buf[off:], f.buf); off < len(buf) { | ||
continue | ||
} | ||
msg = newMessage(f.typ) | ||
if msg == nil { | ||
return nil, errors.New("dtls: unsupported handshake message: " + strconv.Itoa(int(f.typ))) | ||
} | ||
if err = msg.Unmarshal(&bufferReader{buf: buf}); err != nil { | ||
return nil, err | ||
} | ||
return | ||
} | ||
} | ||
|
||
func getInt24(b []byte) int { | ||
return int(b[0])<<16 | int(b[1])<<8 | int(b[2]) | ||
} | ||
|
||
func getSlice16(r reader) (v []uint16, err error) { | ||
var b []byte | ||
if b, err = r.Next(2); err != nil { | ||
return | ||
} | ||
n := int(be.Uint16(b)) | ||
if b, err = r.Next(n); err != nil { | ||
return | ||
} | ||
for i, s := 0, n-1; i < s; i += 2 { | ||
v = append(v, be.Uint16(b[i:])) | ||
} | ||
return | ||
} | ||
|
||
func getSlice8(r reader) (v []uint8, err error) { | ||
var b []byte | ||
if b, err = r.Next(1); err != nil { | ||
return | ||
} | ||
n := int(b[0]) | ||
if n > 0 { | ||
v, err = r.Next(n) | ||
} | ||
return | ||
} | ||
|
||
func getExtensions(r reader) (v map[uint16]Extension, err error) { | ||
var b []byte | ||
if b, err = r.Next(2); err != nil { | ||
return | ||
} | ||
n := int(be.Uint16(b)) | ||
v = make(map[uint16]Extension) | ||
for n > 0 { | ||
if b, err = r.Next(4); err != nil { | ||
return | ||
} | ||
typ, s := be.Uint16(b), int(be.Uint16(b[2:])) | ||
if b, err = r.Next(s); err != nil { | ||
return | ||
} | ||
v[typ] = rawExtension(b) | ||
n -= 4 + s | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package dtls | ||
|
||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
"log" | ||
"testing" | ||
) | ||
|
||
func TestDecoder(t *testing.T) { | ||
t.Parallel() | ||
data, _ := hex.DecodeString("16feff000000000000000000980100008c000000000000008cfefded6b5094c6c428fc41606dc37b295f51392b1033fc9549775e457ffbeac3ea6e00000022c02bc02f009ecca9cca8cc14cc13c009c0130033c00ac0140039009c002f0035000a01000040ff010001000017000000230000000d0012001006010603050105030401040302010203000e000700040002000100000b00020100000a00080006001d00170018") | ||
dec := &handshakeDecoder{ | ||
receiver: &receiver{ | ||
inner: bytes.NewReader(data), | ||
}, | ||
} | ||
msg, err := dec.ReadMessage() | ||
if err != nil { | ||
t.Fatal("read", err) | ||
} | ||
hello := msg.(*clientHello) | ||
if hello == nil { | ||
t.Fatal("message type error") | ||
} | ||
if hello.Version != VersionDTLS12 { | ||
t.Fatal("handshake version") | ||
} | ||
random, _ := hex.DecodeString("ed6b5094c6c428fc41606dc37b295f51392b1033fc9549775e457ffbeac3ea6e") | ||
if !bytes.Equal(hello.RandomBytes, random) { | ||
t.Fatal("random") | ||
} | ||
if hello.Session != nil { | ||
t.Fatal("session") | ||
} | ||
if hello.Cookie != nil { | ||
t.Fatal("cookie") | ||
} | ||
log.Printf("%#v", msg) | ||
} |
Oops, something went wrong.