Packet formats complete
This commit is contained in:
parent
3d66d67713
commit
56d69309ea
2 changed files with 235 additions and 29 deletions
45
aurp/aurp.go
45
aurp/aurp.go
|
@ -4,7 +4,6 @@ package aurp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
@ -214,7 +213,7 @@ func ParsePacket(p []byte) (Packet, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch sc {
|
switch sc {
|
||||||
case CmdSubcodeZoneInfoReq:
|
case SubcodeZoneInfoReq:
|
||||||
zir, err := parseZIReqPacket(p)
|
zir, err := parseZIReqPacket(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -222,11 +221,21 @@ func ParsePacket(p []byte) (Packet, error) {
|
||||||
zir.Header = h
|
zir.Header = h
|
||||||
return zir, nil
|
return zir, nil
|
||||||
|
|
||||||
case CmdSubcodeGetDomainZoneList:
|
case SubcodeGetDomainZoneList:
|
||||||
// TODO
|
gdzl, err := parseGDZLReqPacket(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gdzl.Header = h
|
||||||
|
return gdzl, nil
|
||||||
|
|
||||||
case CmdSubcodeGetZonesNet:
|
case SubcodeGetZonesNet:
|
||||||
// TODO
|
gzn, err := parseGZNReqPacket(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gzn.Header = h
|
||||||
|
return gzn, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown subcode %d", sc)
|
return nil, fmt.Errorf("unknown subcode %d", sc)
|
||||||
|
@ -238,20 +247,30 @@ func ParsePacket(p []byte) (Packet, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch sc {
|
switch sc {
|
||||||
case CmdSubcodeZoneInfoNonExt, CmdSubcodeZoneInfoExt:
|
case SubcodeZoneInfoNonExt, SubcodeZoneInfoExt:
|
||||||
zir, err := parseZIRspPacket(p)
|
zir, err := parseZIRspPacket(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
zir.Header = h
|
zir.Header = h
|
||||||
zir.Subcode = sc
|
zir.Subcode = sc // 1 or 2, only known at this layer
|
||||||
return zir, nil
|
return zir, nil
|
||||||
|
|
||||||
case CmdSubcodeGetDomainZoneList:
|
case SubcodeGetDomainZoneList:
|
||||||
// TODO
|
gdzl, err := parseGDZLRspPacket(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gdzl.Header = h
|
||||||
|
return gdzl, nil
|
||||||
|
|
||||||
case CmdSubcodeGetZonesNet:
|
case SubcodeGetZonesNet:
|
||||||
// TODO
|
gzn, err := parseGZNRspPacket(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gzn.Header = h
|
||||||
|
return gzn, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown subcode %d", sc)
|
return nil, fmt.Errorf("unknown subcode %d", sc)
|
||||||
|
@ -274,6 +293,4 @@ func ParsePacket(p []byte) (Packet, error) {
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported domain header packet type %d", dh.PacketType)
|
return nil, fmt.Errorf("unsupported domain header packet type %d", dh.PacketType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("unimplemented packet handling")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,29 +6,28 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdSubcode is used to distinguish types of zone request/response.
|
// Subcode is used to distinguish types of zone request/response.
|
||||||
type CmdSubcode uint16
|
type Subcode uint16
|
||||||
|
|
||||||
// Various subcodes.
|
// Various subcodes.
|
||||||
const (
|
const (
|
||||||
CmdSubcodeZoneInfoReq CmdSubcode = 0x0001
|
SubcodeZoneInfoReq Subcode = 0x0001
|
||||||
CmdSubcodeZoneInfoNonExt CmdSubcode = 0x0001
|
SubcodeZoneInfoNonExt Subcode = 0x0001
|
||||||
CmdSubcodeZoneInfoExt CmdSubcode = 0x0002
|
SubcodeZoneInfoExt Subcode = 0x0002
|
||||||
CmdSubcodeGetZonesNet CmdSubcode = 0x0003
|
SubcodeGetZonesNet Subcode = 0x0003
|
||||||
CmdSubcodeGetDomainZoneList CmdSubcode = 0x0004
|
SubcodeGetDomainZoneList Subcode = 0x0004
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseSubcode(p []byte) (CmdSubcode, []byte, error) {
|
func parseSubcode(p []byte) (Subcode, []byte, error) {
|
||||||
if len(p) < 2 {
|
if len(p) < 2 {
|
||||||
return 0, p, fmt.Errorf("insufficient input length %d for subcode", len(p))
|
return 0, p, fmt.Errorf("insufficient input length %d for subcode", len(p))
|
||||||
}
|
}
|
||||||
return CmdSubcode(binary.BigEndian.Uint16(p[:2])), p[2:], nil
|
return Subcode(binary.BigEndian.Uint16(p[:2])), p[2:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ZIReqPacket struct {
|
type ZIReqPacket struct {
|
||||||
Header
|
Header
|
||||||
|
Subcode
|
||||||
Subcode CmdSubcode
|
|
||||||
Networks []uint16
|
Networks []uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ func (p *ZIReqPacket) WriteTo(w io.Writer) (int64, error) {
|
||||||
p.Sequence = 0
|
p.Sequence = 0
|
||||||
p.CommandCode = CmdCodeZoneReq
|
p.CommandCode = CmdCodeZoneReq
|
||||||
p.Flags = 0
|
p.Flags = 0
|
||||||
p.Subcode = CmdSubcodeZoneInfoReq
|
p.Subcode = SubcodeZoneInfoReq
|
||||||
|
|
||||||
a := acc(w)
|
a := acc(w)
|
||||||
a.writeTo(&p.Header)
|
a.writeTo(&p.Header)
|
||||||
|
@ -57,7 +56,7 @@ func parseZIReqPacket(p []byte) (*ZIReqPacket, error) {
|
||||||
ns[i] = binary.BigEndian.Uint16(p[i*2:][:2])
|
ns[i] = binary.BigEndian.Uint16(p[i*2:][:2])
|
||||||
}
|
}
|
||||||
return &ZIReqPacket{
|
return &ZIReqPacket{
|
||||||
Subcode: CmdSubcodeZoneInfoReq,
|
Subcode: SubcodeZoneInfoReq,
|
||||||
Networks: ns,
|
Networks: ns,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -75,7 +74,7 @@ func parseZIReqPacket(p []byte) (*ZIReqPacket, error) {
|
||||||
// "Duplicate zone names never exist in extended ZI-Rsp packets"
|
// "Duplicate zone names never exist in extended ZI-Rsp packets"
|
||||||
type ZIRspPacket struct {
|
type ZIRspPacket struct {
|
||||||
Header
|
Header
|
||||||
Subcode CmdSubcode
|
Subcode
|
||||||
Zones ZoneTuples
|
Zones ZoneTuples
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +102,196 @@ func parseZIRspPacket(p []byte) (*ZIRspPacket, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GDZLReqPacket struct {
|
||||||
|
Header
|
||||||
|
Subcode
|
||||||
|
StartIndex uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *GDZLReqPacket) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
p.Sequence = 0
|
||||||
|
p.CommandCode = CmdCodeZoneReq
|
||||||
|
p.Flags = 0
|
||||||
|
p.Subcode = SubcodeGetDomainZoneList
|
||||||
|
|
||||||
|
a := acc(w)
|
||||||
|
a.writeTo(&p.Header)
|
||||||
|
a.write16(uint16(p.Subcode))
|
||||||
|
a.write16(p.StartIndex)
|
||||||
|
return a.ret()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGDZLReqPacket(p []byte) (*GDZLReqPacket, error) {
|
||||||
|
if len(p) < 2 {
|
||||||
|
return nil, fmt.Errorf("insufficient input length %d for GDZL-Req packet", len(p))
|
||||||
|
}
|
||||||
|
return &GDZLReqPacket{
|
||||||
|
Subcode: SubcodeGetDomainZoneList,
|
||||||
|
StartIndex: binary.BigEndian.Uint16(p[:2]),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GDZLRspPacket struct {
|
||||||
|
Header
|
||||||
|
Subcode
|
||||||
|
StartIndex int16
|
||||||
|
ZoneNames []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *GDZLRspPacket) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
for _, zn := range p.ZoneNames {
|
||||||
|
if len(zn) > 127 {
|
||||||
|
return 0, fmt.Errorf("zone name %q too long", zn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Sequence = 0
|
||||||
|
p.CommandCode = CmdCodeZoneRsp
|
||||||
|
// Flags is used to distinguish the final response packet, so leave alone
|
||||||
|
p.Subcode = SubcodeGetDomainZoneList
|
||||||
|
|
||||||
|
a := acc(w)
|
||||||
|
a.writeTo(&p.Header)
|
||||||
|
a.write16(uint16(p.Subcode))
|
||||||
|
a.write16(uint16(p.StartIndex))
|
||||||
|
if p.StartIndex == -1 {
|
||||||
|
return a.ret()
|
||||||
|
}
|
||||||
|
for _, zn := range p.ZoneNames {
|
||||||
|
// The spec is not clear what format these take, and Apple's example
|
||||||
|
// implementation always returns -1 (not supported), and I have no
|
||||||
|
// packet captures of this subcode.
|
||||||
|
// I'm guessing they're Pascal-style (length-prefixed) since that's used
|
||||||
|
// in the ZI-Rsp long tuples as well as throughout all the ancient Mac
|
||||||
|
// code.
|
||||||
|
a.write8(uint8(len(zn)))
|
||||||
|
a.write([]byte(zn))
|
||||||
|
}
|
||||||
|
return a.ret()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGDZLRspPacket(p []byte) (*GDZLRspPacket, error) {
|
||||||
|
if len(p) < 2 {
|
||||||
|
return nil, fmt.Errorf("insufficient input length %d for GDZL-Rsp packet", len(p))
|
||||||
|
}
|
||||||
|
gdzl := &GDZLRspPacket{
|
||||||
|
Subcode: SubcodeGetDomainZoneList,
|
||||||
|
StartIndex: int16(binary.BigEndian.Uint16(p[:2])),
|
||||||
|
}
|
||||||
|
if gdzl.StartIndex == -1 {
|
||||||
|
return gdzl, nil
|
||||||
|
}
|
||||||
|
// See comment in GDZLRspPacket.WriteTo about the assumption here.
|
||||||
|
p = p[2:]
|
||||||
|
for len(p) > 0 {
|
||||||
|
strLen := p[0]
|
||||||
|
p = p[1:]
|
||||||
|
if len(p) < int(strLen) {
|
||||||
|
return nil, fmt.Errorf("insufficient remaining input length %d for zone name with length prefix %d", len(p), strLen)
|
||||||
|
}
|
||||||
|
gdzl.ZoneNames = append(gdzl.ZoneNames, string(p[:strLen]))
|
||||||
|
p = p[strLen:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return gdzl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GZNReqPacket struct {
|
||||||
|
Header
|
||||||
|
Subcode
|
||||||
|
ZoneName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *GZNReqPacket) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
if len(p.ZoneName) > 127 {
|
||||||
|
return 0, fmt.Errorf("zone name %q too long", p.ZoneName)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Sequence = 0
|
||||||
|
p.CommandCode = CmdCodeZoneReq
|
||||||
|
p.Flags = 0
|
||||||
|
p.Subcode = SubcodeGetZonesNet
|
||||||
|
|
||||||
|
a := acc(w)
|
||||||
|
a.writeTo(&p.Header)
|
||||||
|
a.write16(uint16(p.Subcode))
|
||||||
|
a.write8(uint8(len(p.ZoneName)))
|
||||||
|
a.write([]byte(p.ZoneName))
|
||||||
|
return a.ret()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGZNReqPacket(p []byte) (*GZNReqPacket, error) {
|
||||||
|
if len(p) < 1 {
|
||||||
|
return nil, fmt.Errorf("insufficient input length %d for GZN-Req packet", len(p))
|
||||||
|
}
|
||||||
|
strLen := p[0]
|
||||||
|
p = p[1:]
|
||||||
|
if len(p) < int(strLen) {
|
||||||
|
return nil, fmt.Errorf("insufficient remaining input length %d for zone name with length prefix %d", len(p), strLen)
|
||||||
|
}
|
||||||
|
return &GZNReqPacket{
|
||||||
|
Subcode: SubcodeGetZonesNet,
|
||||||
|
ZoneName: string(p[:strLen]),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GZNRspPacket struct {
|
||||||
|
Header
|
||||||
|
Subcode
|
||||||
|
ZoneName string
|
||||||
|
NotSupported bool
|
||||||
|
Networks NetworkTuples
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *GZNRspPacket) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
if len(p.ZoneName) > 127 {
|
||||||
|
return 0, fmt.Errorf("zone name %q too long", p.ZoneName)
|
||||||
|
}
|
||||||
|
|
||||||
|
a := acc(w)
|
||||||
|
a.writeTo(&p.Header)
|
||||||
|
a.write16(uint16(p.Subcode))
|
||||||
|
a.write8(uint8(len(p.ZoneName)))
|
||||||
|
if p.NotSupported {
|
||||||
|
a.write16(0xffff) // -1
|
||||||
|
return a.ret()
|
||||||
|
}
|
||||||
|
a.writeTo(p.Networks)
|
||||||
|
return a.ret()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGZNRspPacket(p []byte) (*GZNRspPacket, error) {
|
||||||
|
if len(p) < 1 {
|
||||||
|
return nil, fmt.Errorf("insufficient input length %d for GZN-Rsp packet", len(p))
|
||||||
|
}
|
||||||
|
gzn := &GZNRspPacket{
|
||||||
|
Subcode: SubcodeGetZonesNet,
|
||||||
|
}
|
||||||
|
|
||||||
|
strLen := p[0]
|
||||||
|
p = p[1:]
|
||||||
|
if len(p) < int(strLen) {
|
||||||
|
return nil, fmt.Errorf("insufficient remaining input length %d for zone name with length prefix %d", len(p), strLen)
|
||||||
|
}
|
||||||
|
gzn.ZoneName = string(p[:strLen])
|
||||||
|
p = p[strLen:]
|
||||||
|
|
||||||
|
if len(p) < 2 {
|
||||||
|
return nil, fmt.Errorf("insufficient remaining input length %d for GZN-Rsp packet", len(p))
|
||||||
|
}
|
||||||
|
gzn.NotSupported = p[0] == 0xff && p[1] == 0xff
|
||||||
|
if gzn.NotSupported {
|
||||||
|
return gzn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ns, err := parseNetworkTuples(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gzn.Networks = ns
|
||||||
|
return gzn, nil
|
||||||
|
}
|
||||||
|
|
||||||
type ZoneTuples []ZoneTuple
|
type ZoneTuples []ZoneTuple
|
||||||
|
|
||||||
type ZoneTuple struct {
|
type ZoneTuple struct {
|
||||||
|
|
Loading…
Reference in a new issue