Fix ZIP ATP replies
This commit is contained in:
parent
e95df3db20
commit
c1efd9f91b
5 changed files with 56 additions and 7 deletions
|
@ -22,8 +22,9 @@ Things I plan to fix Real Soon Now:
|
|||
interface. I haven't tested it with netatalk or tashrouter on the same
|
||||
host, but I think using a distinct Ethernet address would help them coexist.
|
||||
* It doesn't do any of the required packet splitting to keep packets under the
|
||||
AppleTalk size limits. In particular ZIP GetZoneList Replies are incorrect
|
||||
when the zone list would exceed the limit.
|
||||
AppleTalk size limits. ~~In particular ZIP GetZoneList Replies are incorrect
|
||||
when the zone list would exceed the limit.~~ GetZoneList is now fixed, but
|
||||
various others need fixing.
|
||||
* It logs a lot and has no other monitoring or observability capability. I plan
|
||||
to add a Prometheus metrics endpoint and at least add log levels / verbosity
|
||||
flag.
|
||||
|
|
|
@ -20,6 +20,13 @@ import (
|
|||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"gitea.drjosh.dev/josh/jrouter/atalk"
|
||||
)
|
||||
|
||||
const (
|
||||
HeaderSize = 8
|
||||
MaxDataSize = atalk.DDPMaxDataSize - HeaderSize // 578
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -50,6 +57,9 @@ func (p *TReq) Marshal() ([]byte, error) {
|
|||
if p.TRelTimeoutIndicator > 4 {
|
||||
return nil, fmt.Errorf("invalid TRel timeout indicator [%d > 4]", p.TRelTimeoutIndicator)
|
||||
}
|
||||
if len(p.Data) > MaxDataSize {
|
||||
return nil, fmt.Errorf("%w [%d > %d]", atalk.ErrDataTooBig, len(p.Data), MaxDataSize)
|
||||
}
|
||||
|
||||
b := bytes.NewBuffer(nil)
|
||||
ci := byte(ciFuncTReq)
|
||||
|
|
|
@ -16,4 +16,11 @@
|
|||
|
||||
package atalk
|
||||
|
||||
const DDPExtHeaderSize = 13
|
||||
import "errors"
|
||||
|
||||
const (
|
||||
DDPExtHeaderSize = 13
|
||||
DDPMaxDataSize = 586
|
||||
)
|
||||
|
||||
var ErrDataTooBig = errors.New("data too big")
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"gitea.drjosh.dev/josh/jrouter/atalk"
|
||||
"gitea.drjosh.dev/josh/jrouter/atalk/atp"
|
||||
)
|
||||
|
||||
|
@ -78,6 +79,9 @@ func (p *GetZonesReplyPacket) MarshalTResp() (*atp.TResp, error) {
|
|||
b.WriteString(z)
|
||||
}
|
||||
r.Data = b.Bytes()
|
||||
if len(r.Data) > atp.MaxDataSize {
|
||||
return nil, fmt.Errorf("%w [%d > %d]", atalk.ErrDataTooBig, len(r.Data), atp.MaxDataSize)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
|
|
35
zip.go
35
zip.go
|
@ -32,7 +32,7 @@ import (
|
|||
|
||||
func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAddr aarp.AddrPair, cfg *config, zones *ZoneTable, ddpkt *ddp.ExtPacket) error {
|
||||
switch ddpkt.Proto {
|
||||
case 3: // ATP
|
||||
case ddp.ProtoATP:
|
||||
atpkt, err := atp.UnmarshalPacket(ddpkt.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -43,11 +43,15 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: handle this in a more transactiony way
|
||||
if gzl.StartIndex == 0 {
|
||||
return fmt.Errorf("ZIP ATP: received request with StartIndex = 0 (invalid)")
|
||||
}
|
||||
|
||||
resp := &zip.GetZonesReplyPacket{
|
||||
TID: gzl.TID,
|
||||
LastFlag: true, // TODO: support multiple response packets
|
||||
LastFlag: true,
|
||||
}
|
||||
|
||||
switch gzl.Function {
|
||||
case zip.FunctionGetZoneList:
|
||||
resp.Zones = zones.AllNames()
|
||||
|
@ -59,6 +63,29 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd
|
|||
resp.Zones = []string{cfg.EtherTalk.ZoneName}
|
||||
}
|
||||
|
||||
// Inside AppleTalk SE, pp 8-8
|
||||
if int(gzl.StartIndex) > len(resp.Zones) {
|
||||
// "Note: A 0-byte response will be returned by a router if the
|
||||
// index specified in the request is greater than the index of
|
||||
// the last zone in the list (and the user bytes field will
|
||||
// indicate no more zones)."
|
||||
resp.Zones = nil
|
||||
} else {
|
||||
// Trim the zones list
|
||||
// "zone names in the router are assumed to be numbered starting
|
||||
// with 1"
|
||||
resp.Zones = resp.Zones[gzl.StartIndex-1:]
|
||||
size := 0
|
||||
for i, z := range resp.Zones {
|
||||
size += 1 + len(z) // length prefix plus string
|
||||
if size > atp.MaxDataSize {
|
||||
resp.LastFlag = false
|
||||
resp.Zones = resp.Zones[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
respATP, err := resp.MarshalTResp()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -99,7 +126,7 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd
|
|||
return fmt.Errorf("unsupported ATP packet type %T for ZIP", atpkt)
|
||||
}
|
||||
|
||||
case 6: // ZIP
|
||||
case ddp.ProtoZIP:
|
||||
zipkt, err := zip.UnmarshalPacket(ddpkt.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
Loading…
Reference in a new issue