Implement zone multicast
This commit is contained in:
parent
0d12b55735
commit
ed233b3f3e
6 changed files with 121 additions and 9 deletions
102
atalk/strings.go
Normal file
102
atalk/strings.go
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Copyright 2024 Josh Deprez
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package atalk
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
|
||||
"github.com/sfiera/multitalk/pkg/ethernet"
|
||||
)
|
||||
|
||||
// Inside AppleTalk, appendix D
|
||||
var toUpperMap = []byte{
|
||||
// The alphabet
|
||||
0x61: 0x41,
|
||||
0x62: 0x42,
|
||||
0x63: 0x43,
|
||||
0x64: 0x44,
|
||||
0x65: 0x45,
|
||||
0x66: 0x46,
|
||||
0x67: 0x47,
|
||||
0x68: 0x48,
|
||||
0x69: 0x49,
|
||||
0x6A: 0x4A,
|
||||
0x6B: 0x4B,
|
||||
0x6C: 0x4C,
|
||||
0x6D: 0x4D,
|
||||
0x6E: 0x4E,
|
||||
0x6F: 0x4F,
|
||||
0x70: 0x50,
|
||||
0x71: 0x51,
|
||||
0x72: 0x52,
|
||||
0x73: 0x53,
|
||||
0x74: 0x54,
|
||||
0x75: 0x55,
|
||||
0x76: 0x56,
|
||||
0x77: 0x57,
|
||||
0x78: 0x58,
|
||||
0x79: 0x59,
|
||||
0x7A: 0x5A,
|
||||
|
||||
// Letters with diacritics, etc
|
||||
0x88: 0xCB,
|
||||
0x8A: 0x80,
|
||||
0x8B: 0xCC,
|
||||
0x8C: 0x81,
|
||||
0x8D: 0x82,
|
||||
0x8E: 0x83,
|
||||
0x96: 0x84,
|
||||
0x9A: 0x85,
|
||||
0x9B: 0xCD,
|
||||
0x9F: 0x86,
|
||||
0xBE: 0xAE,
|
||||
0xBF: 0xAF,
|
||||
0xCF: 0xCE,
|
||||
}
|
||||
|
||||
func Checksum(s string) uint16 {
|
||||
// Inside AppleTalk, pp 4-17 and pp 8-18
|
||||
var cksum uint16
|
||||
for _, b := range []byte(s) {
|
||||
cksum += uint16(b)
|
||||
cksum = bits.RotateLeft16(cksum, -1)
|
||||
}
|
||||
if cksum == 0 {
|
||||
cksum = 0xFFFF
|
||||
}
|
||||
return cksum
|
||||
}
|
||||
|
||||
func ToUpper(s string) string {
|
||||
// Inside Appletalk, appendix D
|
||||
sb := []byte(s)
|
||||
out := make([]byte, len(sb))
|
||||
for i, b := range sb {
|
||||
if u := toUpperMap[b]; u != 0 {
|
||||
out[i] = u
|
||||
} else {
|
||||
out[i] = b
|
||||
}
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func MulticastAddr(zone string) ethernet.Addr {
|
||||
// Inside AppleTalk, pp 3-10 and pp 8-18
|
||||
h := Checksum(ToUpper(zone))
|
||||
return ethernet.Addr{0x09, 0x00, 0x07, 0x00, 0x00, byte(h % 0xFD)}
|
||||
}
|
|
@ -57,9 +57,9 @@ type GetNetInfoReplyPacket struct {
|
|||
// DDP type = 6
|
||||
// ---
|
||||
// ZIP command = 6
|
||||
ZoneInvalid bool // 0x80
|
||||
UseBroadcast bool // 0x40
|
||||
OnlyOneZone bool // 0x20
|
||||
ZoneInvalid bool // 0x80 - "set if the zone name in the request is invalid for the network from which the request was sent"
|
||||
UseBroadcast bool // 0x40 - "set for data links that do not support multicast"
|
||||
OnlyOneZone bool // 0x20 - "set if the network's zone list contains only one zone name"
|
||||
// Remainder of flags reserved
|
||||
NetStart ddp.Network
|
||||
NetEnd ddp.Network
|
||||
|
|
3
main.go
3
main.go
|
@ -205,6 +205,9 @@ func main() {
|
|||
continue
|
||||
}
|
||||
|
||||
// TODO: filter ethFrame.Dst to myHWAddr, the broadcast address,
|
||||
// or the relevant zone multicast address
|
||||
|
||||
switch ethFrame.SNAPProto {
|
||||
case ethertalk.AARPProto:
|
||||
// log.Print("Got an AARP frame")
|
||||
|
|
6
nbp.go
6
nbp.go
|
@ -100,6 +100,10 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd
|
|||
case nbp.FunctionBrRq:
|
||||
// There must be 1!
|
||||
tuple := &nbpkt.Tuples[0]
|
||||
ethDst := ethertalk.AppleTalkBroadcast
|
||||
if tuple.Zone != "*" && tuple.Zone != "" {
|
||||
ethDst = atalk.MulticastAddr(tuple.Zone)
|
||||
}
|
||||
|
||||
zones := zoneTable.LookupName(tuple.Zone)
|
||||
for _, z := range zones {
|
||||
|
@ -112,7 +116,6 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd
|
|||
// lookups in their own zone will receive LkUp packets from themselves
|
||||
// (actually sent by a router). The node's NBP process should expect to
|
||||
// receive these packets and must reply to them."
|
||||
// TODO: use zone-specific multicast
|
||||
nbpkt.Function = nbp.FunctionLkUp
|
||||
nbpRaw, err := nbpkt.Marshal()
|
||||
if err != nil {
|
||||
|
@ -128,6 +131,7 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outFrame.Dst = ethDst
|
||||
outFrameRaw, err := ethertalk.Marshal(*outFrame)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"gitea.drjosh.dev/josh/jrouter/atalk"
|
||||
"gitea.drjosh.dev/josh/jrouter/atalk/nbp"
|
||||
"github.com/google/gopacket/pcap"
|
||||
"github.com/sfiera/multitalk/pkg/ddp"
|
||||
|
@ -43,11 +44,11 @@ func handleNBPInAURP(pcapHandle *pcap.Handle, myHWAddr ethernet.Addr, ddpkt *ddp
|
|||
if len(nbpkt.Tuples) < 1 {
|
||||
return fmt.Errorf("no tuples in NBP packet")
|
||||
}
|
||||
tuple := &nbpkt.Tuples[0]
|
||||
|
||||
log.Printf("NBP/DDP/AURP: Converting FwdReq to LkUp (%v)", nbpkt.Tuples[0])
|
||||
log.Printf("NBP/DDP/AURP: Converting FwdReq to LkUp (%v)", tuple)
|
||||
|
||||
// Convert it to a LkUp and broadcast on EtherTalk
|
||||
// TODO: use zone-specific multicast
|
||||
nbpkt.Function = nbp.FunctionLkUp
|
||||
nbpRaw, err := nbpkt.Marshal()
|
||||
if err != nil {
|
||||
|
@ -66,7 +67,9 @@ func handleNBPInAURP(pcapHandle *pcap.Handle, myHWAddr ethernet.Addr, ddpkt *ddp
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: outFrame.Dst = zone-specific multicast address
|
||||
if tuple.Zone != "*" && tuple.Zone != "" {
|
||||
outFrame.Dst = atalk.MulticastAddr(tuple.Zone)
|
||||
}
|
||||
outFrameRaw, err := ethertalk.Marshal(*outFrame)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
4
zip.go
4
zip.go
|
@ -126,12 +126,12 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd
|
|||
// Only running a network with one zone for now.
|
||||
gnir := &zip.GetNetInfoReplyPacket{
|
||||
ZoneInvalid: zipkt.ZoneName != cfg.EtherTalk.ZoneName,
|
||||
UseBroadcast: true, // TODO: add multicast addr computation
|
||||
UseBroadcast: false,
|
||||
OnlyOneZone: true,
|
||||
NetStart: cfg.EtherTalk.NetStart,
|
||||
NetEnd: cfg.EtherTalk.NetEnd,
|
||||
ZoneName: zipkt.ZoneName, // has to match request
|
||||
MulticastAddr: ethertalk.AppleTalkBroadcast,
|
||||
MulticastAddr: atalk.MulticastAddr(cfg.EtherTalk.ZoneName),
|
||||
DefaultZoneName: cfg.EtherTalk.ZoneName,
|
||||
}
|
||||
log.Printf("ZIP: Replying with GetNetInfo-Reply: %+v", gnir)
|
||||
|
|
Loading…
Reference in a new issue