ZI-Req, ZI-Rsp
This commit is contained in:
parent
e18614bfec
commit
3d66d67713
7 changed files with 322 additions and 13 deletions
73
aurp/aurp.go
73
aurp/aurp.go
|
@ -4,6 +4,7 @@ package aurp
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
@ -82,17 +83,6 @@ const (
|
|||
CmdCodeTickleAck CmdCode = 0x000f
|
||||
)
|
||||
|
||||
// CmdSubcode is used to distinguish types of zone request/response.
|
||||
type CmdSubcode uint16
|
||||
|
||||
// Various subcodes.
|
||||
const (
|
||||
CmdSubcodeZoneInfo1 CmdSubcode = 0x0001
|
||||
CmdSubcodeZoneInfo2 CmdSubcode = 0x0002 // only for responses
|
||||
CmdSubcodeGetZonesNet CmdSubcode = 0x0003
|
||||
CmdSubcodeGetDomainZoneList CmdSubcode = 0x0004
|
||||
)
|
||||
|
||||
// RoutingFlag is used in the flags field
|
||||
type RoutingFlag uint16
|
||||
|
||||
|
@ -218,6 +208,65 @@ func ParsePacket(p []byte) (Packet, error) {
|
|||
rd.Header = h
|
||||
return rd, nil
|
||||
|
||||
case CmdCodeZoneReq:
|
||||
sc, p, err := parseSubcode(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch sc {
|
||||
case CmdSubcodeZoneInfoReq:
|
||||
zir, err := parseZIReqPacket(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zir.Header = h
|
||||
return zir, nil
|
||||
|
||||
case CmdSubcodeGetDomainZoneList:
|
||||
// TODO
|
||||
|
||||
case CmdSubcodeGetZonesNet:
|
||||
// TODO
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown subcode %d", sc)
|
||||
}
|
||||
|
||||
case CmdCodeZoneRsp:
|
||||
sc, p, err := parseSubcode(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch sc {
|
||||
case CmdSubcodeZoneInfoNonExt, CmdSubcodeZoneInfoExt:
|
||||
zir, err := parseZIRspPacket(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zir.Header = h
|
||||
zir.Subcode = sc
|
||||
return zir, nil
|
||||
|
||||
case CmdSubcodeGetDomainZoneList:
|
||||
// TODO
|
||||
|
||||
case CmdSubcodeGetZonesNet:
|
||||
// TODO
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown subcode %d", sc)
|
||||
}
|
||||
|
||||
case CmdCodeTickle:
|
||||
return &TicklePacket{
|
||||
Header: h,
|
||||
}, nil
|
||||
|
||||
case CmdCodeTickleAck:
|
||||
return &TickleAckPacket{
|
||||
Header: h,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown routing packet command code %d", h.CommandCode)
|
||||
}
|
||||
|
@ -225,4 +274,6 @@ func ParsePacket(p []byte) (Packet, error) {
|
|||
default:
|
||||
return nil, fmt.Errorf("unsupported domain header packet type %d", dh.PacketType)
|
||||
}
|
||||
|
||||
return nil, errors.New("unimplemented packet handling")
|
||||
}
|
||||
|
|
14
aurp/errors.go
Normal file
14
aurp/errors.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package aurp
|
||||
|
||||
type ErrorCode int16
|
||||
|
||||
// Various error codes.
|
||||
const (
|
||||
ErrCodeNormalClose ErrorCode = -1
|
||||
ErrCodeRoutingLoop ErrorCode = -2
|
||||
ErrCodeOutOfSync ErrorCode = -3
|
||||
ErrCodeOptionNegotiation ErrorCode = -4
|
||||
ErrCodeInvalidVersion ErrorCode = -5
|
||||
ErrCodeInsufficientResources ErrorCode = -6
|
||||
ErrCodeAuthentication ErrorCode = -7
|
||||
)
|
|
@ -15,6 +15,9 @@ type OpenReqPacket struct {
|
|||
}
|
||||
|
||||
func (p *OpenReqPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.Sequence = 0
|
||||
p.CommandCode = CmdCodeOpenReq
|
||||
|
||||
a := acc(w)
|
||||
a.writeTo(&p.Header)
|
||||
a.write16(p.Version)
|
||||
|
@ -45,6 +48,9 @@ type OpenRspPacket struct {
|
|||
}
|
||||
|
||||
func (p *OpenRspPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.Sequence = 0
|
||||
p.CommandCode = CmdCodeOpenRsp
|
||||
|
||||
a := acc(w)
|
||||
a.writeTo(&p.Header)
|
||||
a.write16(uint16(p.RateOrErrCode))
|
||||
|
|
|
@ -9,10 +9,12 @@ import (
|
|||
type RDPacket struct {
|
||||
Header
|
||||
|
||||
ErrorCode int16
|
||||
ErrorCode ErrorCode
|
||||
}
|
||||
|
||||
func (p *RDPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.CommandCode = CmdCodeRD
|
||||
|
||||
a := acc(w)
|
||||
a.writeTo(&p.Header)
|
||||
a.write16(uint16(p.ErrorCode))
|
||||
|
@ -24,6 +26,6 @@ func parseRD(p []byte) (*RDPacket, error) {
|
|||
return nil, fmt.Errorf("insufficient input length %d for router down packet", len(p))
|
||||
}
|
||||
return &RDPacket{
|
||||
ErrorCode: int16(binary.BigEndian.Uint16(p[:2])),
|
||||
ErrorCode: ErrorCode(binary.BigEndian.Uint16(p[:2])),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -10,6 +10,12 @@ type RIReqPacket struct {
|
|||
Header
|
||||
}
|
||||
|
||||
func (p *RIReqPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.Sequence = 0
|
||||
p.CommandCode = CmdCodeRIReq
|
||||
return p.Header.WriteTo(w)
|
||||
}
|
||||
|
||||
type RIRspPacket struct {
|
||||
Header
|
||||
|
||||
|
@ -17,6 +23,8 @@ type RIRspPacket struct {
|
|||
}
|
||||
|
||||
func (p *RIRspPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.CommandCode = CmdCodeRIRsp
|
||||
|
||||
a := acc(w)
|
||||
a.writeTo(&p.Header)
|
||||
a.writeTo(p.Networks)
|
||||
|
@ -37,6 +45,11 @@ type RIAckPacket struct {
|
|||
Header
|
||||
}
|
||||
|
||||
func (p *RIAckPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.CommandCode = CmdCodeRIAck
|
||||
return p.Header.WriteTo(w)
|
||||
}
|
||||
|
||||
type RIUpdPacket struct {
|
||||
Header
|
||||
|
||||
|
@ -44,6 +57,8 @@ type RIUpdPacket struct {
|
|||
}
|
||||
|
||||
func (p *RIUpdPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.CommandCode = CmdCodeRIUpd
|
||||
|
||||
a := acc(w)
|
||||
a.writeTo(&p.Header)
|
||||
a.writeTo(p.Events)
|
25
aurp/tickle.go
Normal file
25
aurp/tickle.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package aurp
|
||||
|
||||
import "io"
|
||||
|
||||
type TicklePacket struct {
|
||||
Header
|
||||
}
|
||||
|
||||
func (p *TicklePacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.Sequence = 0
|
||||
p.CommandCode = CmdCodeTickle
|
||||
p.Flags = 0
|
||||
return p.Header.WriteTo(w)
|
||||
}
|
||||
|
||||
type TickleAckPacket struct {
|
||||
Header
|
||||
}
|
||||
|
||||
func (p *TickleAckPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.Sequence = 0
|
||||
p.CommandCode = CmdCodeTickleAck
|
||||
p.Flags = 0
|
||||
return p.Header.WriteTo(w)
|
||||
}
|
196
aurp/zone_info.go
Normal file
196
aurp/zone_info.go
Normal file
|
@ -0,0 +1,196 @@
|
|||
package aurp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// CmdSubcode is used to distinguish types of zone request/response.
|
||||
type CmdSubcode uint16
|
||||
|
||||
// Various subcodes.
|
||||
const (
|
||||
CmdSubcodeZoneInfoReq CmdSubcode = 0x0001
|
||||
CmdSubcodeZoneInfoNonExt CmdSubcode = 0x0001
|
||||
CmdSubcodeZoneInfoExt CmdSubcode = 0x0002
|
||||
CmdSubcodeGetZonesNet CmdSubcode = 0x0003
|
||||
CmdSubcodeGetDomainZoneList CmdSubcode = 0x0004
|
||||
)
|
||||
|
||||
func parseSubcode(p []byte) (CmdSubcode, []byte, error) {
|
||||
if len(p) < 2 {
|
||||
return 0, p, fmt.Errorf("insufficient input length %d for subcode", len(p))
|
||||
}
|
||||
return CmdSubcode(binary.BigEndian.Uint16(p[:2])), p[2:], nil
|
||||
}
|
||||
|
||||
type ZIReqPacket struct {
|
||||
Header
|
||||
|
||||
Subcode CmdSubcode
|
||||
Networks []uint16
|
||||
}
|
||||
|
||||
func (p *ZIReqPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.Sequence = 0
|
||||
p.CommandCode = CmdCodeZoneReq
|
||||
p.Flags = 0
|
||||
p.Subcode = CmdSubcodeZoneInfoReq
|
||||
|
||||
a := acc(w)
|
||||
a.writeTo(&p.Header)
|
||||
a.write16(uint16(p.Subcode))
|
||||
for _, n := range p.Networks {
|
||||
a.write16(n)
|
||||
}
|
||||
return a.ret()
|
||||
}
|
||||
|
||||
func parseZIReqPacket(p []byte) (*ZIReqPacket, error) {
|
||||
if len(p)%2 != 0 {
|
||||
return nil, fmt.Errorf("odd number of bytes %d for networks", len(p))
|
||||
}
|
||||
c := len(p) / 2
|
||||
ns := make([]uint16, 0, c)
|
||||
for i := range c {
|
||||
ns[i] = binary.BigEndian.Uint16(p[i*2:][:2])
|
||||
}
|
||||
return &ZIReqPacket{
|
||||
Subcode: CmdSubcodeZoneInfoReq,
|
||||
Networks: ns,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ZIRspPacket represents a ZI-Rsp: a response packet to a ZI-Req.
|
||||
//
|
||||
// "When the data sender receives a ZI-Req and the zone list for the network or
|
||||
// networks for which that ZI-Req requested zone information fits in one ZI-Rsp
|
||||
// packet, it sends a nonextended ZI-Rsp."
|
||||
// "When the data sender receives a ZI-Req and the zone list for a network about
|
||||
// which that ZI-Req requested zone information does not fit in a single ZI-Rsp
|
||||
// packet, it sends a sequence of extended ZI-Rsp packets."
|
||||
// "All tuples in a single extended ZI-Rsp packet must contain the same network
|
||||
// number"
|
||||
// "Duplicate zone names never exist in extended ZI-Rsp packets"
|
||||
type ZIRspPacket struct {
|
||||
Header
|
||||
Subcode CmdSubcode
|
||||
Zones ZoneTuples
|
||||
}
|
||||
|
||||
func (p *ZIRspPacket) WriteTo(w io.Writer) (int64, error) {
|
||||
p.Sequence = 0
|
||||
p.CommandCode = CmdCodeZoneRsp
|
||||
p.Flags = 0
|
||||
// Subcode can vary for this packet type: it's either 1 or 2
|
||||
|
||||
a := acc(w)
|
||||
a.writeTo(&p.Header)
|
||||
a.write16(uint16(p.Subcode))
|
||||
a.writeTo(p.Zones)
|
||||
return a.ret()
|
||||
}
|
||||
|
||||
func parseZIRspPacket(p []byte) (*ZIRspPacket, error) {
|
||||
zs, err := parseZoneTuples(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ZIRspPacket{
|
||||
// Subcode needs to be provided by layer above
|
||||
Zones: zs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ZoneTuples []ZoneTuple
|
||||
|
||||
type ZoneTuple struct {
|
||||
Network uint16
|
||||
Name string
|
||||
}
|
||||
|
||||
func (zs ZoneTuples) WriteTo(w io.Writer) (int64, error) {
|
||||
if len(zs) > 65535 {
|
||||
return 0, fmt.Errorf("too many zone tuples [%d > 65535]", len(zs))
|
||||
}
|
||||
for _, zt := range zs {
|
||||
if len(zt.Name) > 127 {
|
||||
return 0, fmt.Errorf("zone name %q too long", zt.Name)
|
||||
}
|
||||
}
|
||||
|
||||
a := acc(w)
|
||||
a.write16(uint16(len(zs)))
|
||||
offsets := make(map[string]uint16)
|
||||
|
||||
for _, zt := range zs {
|
||||
a.write16(zt.Network)
|
||||
|
||||
if offset, wrote := offsets[zt.Name]; wrote {
|
||||
// Optimised tuple
|
||||
a.write16(0x8000 | offset)
|
||||
continue
|
||||
}
|
||||
// Long tuple
|
||||
offsets[zt.Name] = uint16(a.n - 4) // 4 = sizeof(zone count) + sizeof(first network number)
|
||||
a.write8(uint8(len(zt.Name)))
|
||||
a.write([]byte(zt.Name))
|
||||
}
|
||||
|
||||
return a.ret()
|
||||
}
|
||||
|
||||
func parseZoneTuples(p []byte) (ZoneTuples, error) {
|
||||
if len(p) < 2 {
|
||||
return nil, fmt.Errorf("insufficient input length %d for zone tuples", len(p))
|
||||
}
|
||||
count := binary.BigEndian.Uint16(p[:2])
|
||||
p = p[2:]
|
||||
|
||||
if len(p) < int(3*count) {
|
||||
return nil, fmt.Errorf("insufficient remaining input length %d for %d zone tuples", len(p), count)
|
||||
}
|
||||
|
||||
zs := make(ZoneTuples, 0, count)
|
||||
var fromFirst []byte
|
||||
for range count {
|
||||
if len(p) < 3 {
|
||||
return nil, fmt.Errorf("insufficient remaining input length %d for another zone tuple", len(p))
|
||||
}
|
||||
var zt ZoneTuple
|
||||
zt.Network = binary.BigEndian.Uint16(p[:2])
|
||||
p = p[2:]
|
||||
if nameLen := p[0]; nameLen&0x80 == 0 {
|
||||
// Long tuple
|
||||
if fromFirst == nil {
|
||||
fromFirst = p
|
||||
}
|
||||
p = p[1:]
|
||||
if len(p) < int(nameLen) {
|
||||
return nil, fmt.Errorf("insufficient remaining input length %d for zone name of length %d", len(p), nameLen)
|
||||
}
|
||||
zt.Name = string(p[:nameLen])
|
||||
p = p[nameLen:]
|
||||
} else {
|
||||
// Optimised tuple
|
||||
if len(p) < 2 {
|
||||
return nil, fmt.Errorf("insufficient remaining input length %d for offset", len(p))
|
||||
}
|
||||
offset := binary.BigEndian.Uint16(p[:2])
|
||||
offset &^= 0x8000
|
||||
p = p[2:]
|
||||
if int(offset) >= len(fromFirst) {
|
||||
return nil, fmt.Errorf("optimized zone tuple offset %d out of range", offset)
|
||||
}
|
||||
nameLen := fromFirst[offset]
|
||||
if len(fromFirst) < int(nameLen) {
|
||||
return nil, fmt.Errorf("insufficient remaining input length %d for zone name of length %d", len(p), nameLen)
|
||||
}
|
||||
zt.Name = string(fromFirst[offset+1:][:nameLen])
|
||||
}
|
||||
|
||||
zs = append(zs, zt)
|
||||
}
|
||||
return zs, nil
|
||||
}
|
Loading…
Reference in a new issue