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
|
// DDP type = 6
|
||||||
// ---
|
// ---
|
||||||
// ZIP command = 6
|
// ZIP command = 6
|
||||||
ZoneInvalid bool // 0x80
|
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
|
UseBroadcast bool // 0x40 - "set for data links that do not support multicast"
|
||||||
OnlyOneZone bool // 0x20
|
OnlyOneZone bool // 0x20 - "set if the network's zone list contains only one zone name"
|
||||||
// Remainder of flags reserved
|
// Remainder of flags reserved
|
||||||
NetStart ddp.Network
|
NetStart ddp.Network
|
||||||
NetEnd ddp.Network
|
NetEnd ddp.Network
|
||||||
|
|
3
main.go
3
main.go
|
@ -205,6 +205,9 @@ func main() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: filter ethFrame.Dst to myHWAddr, the broadcast address,
|
||||||
|
// or the relevant zone multicast address
|
||||||
|
|
||||||
switch ethFrame.SNAPProto {
|
switch ethFrame.SNAPProto {
|
||||||
case ethertalk.AARPProto:
|
case ethertalk.AARPProto:
|
||||||
// log.Print("Got an AARP frame")
|
// 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:
|
case nbp.FunctionBrRq:
|
||||||
// There must be 1!
|
// There must be 1!
|
||||||
tuple := &nbpkt.Tuples[0]
|
tuple := &nbpkt.Tuples[0]
|
||||||
|
ethDst := ethertalk.AppleTalkBroadcast
|
||||||
|
if tuple.Zone != "*" && tuple.Zone != "" {
|
||||||
|
ethDst = atalk.MulticastAddr(tuple.Zone)
|
||||||
|
}
|
||||||
|
|
||||||
zones := zoneTable.LookupName(tuple.Zone)
|
zones := zoneTable.LookupName(tuple.Zone)
|
||||||
for _, z := range zones {
|
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
|
// lookups in their own zone will receive LkUp packets from themselves
|
||||||
// (actually sent by a router). The node's NBP process should expect to
|
// (actually sent by a router). The node's NBP process should expect to
|
||||||
// receive these packets and must reply to them."
|
// receive these packets and must reply to them."
|
||||||
// TODO: use zone-specific multicast
|
|
||||||
nbpkt.Function = nbp.FunctionLkUp
|
nbpkt.Function = nbp.FunctionLkUp
|
||||||
nbpRaw, err := nbpkt.Marshal()
|
nbpRaw, err := nbpkt.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -128,6 +131,7 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
outFrame.Dst = ethDst
|
||||||
outFrameRaw, err := ethertalk.Marshal(*outFrame)
|
outFrameRaw, err := ethertalk.Marshal(*outFrame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"gitea.drjosh.dev/josh/jrouter/atalk"
|
||||||
"gitea.drjosh.dev/josh/jrouter/atalk/nbp"
|
"gitea.drjosh.dev/josh/jrouter/atalk/nbp"
|
||||||
"github.com/google/gopacket/pcap"
|
"github.com/google/gopacket/pcap"
|
||||||
"github.com/sfiera/multitalk/pkg/ddp"
|
"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 {
|
if len(nbpkt.Tuples) < 1 {
|
||||||
return fmt.Errorf("no tuples in NBP packet")
|
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
|
// Convert it to a LkUp and broadcast on EtherTalk
|
||||||
// TODO: use zone-specific multicast
|
|
||||||
nbpkt.Function = nbp.FunctionLkUp
|
nbpkt.Function = nbp.FunctionLkUp
|
||||||
nbpRaw, err := nbpkt.Marshal()
|
nbpRaw, err := nbpkt.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -66,7 +67,9 @@ func handleNBPInAURP(pcapHandle *pcap.Handle, myHWAddr ethernet.Addr, ddpkt *ddp
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
outFrameRaw, err := ethertalk.Marshal(*outFrame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// Only running a network with one zone for now.
|
||||||
gnir := &zip.GetNetInfoReplyPacket{
|
gnir := &zip.GetNetInfoReplyPacket{
|
||||||
ZoneInvalid: zipkt.ZoneName != cfg.EtherTalk.ZoneName,
|
ZoneInvalid: zipkt.ZoneName != cfg.EtherTalk.ZoneName,
|
||||||
UseBroadcast: true, // TODO: add multicast addr computation
|
UseBroadcast: false,
|
||||||
OnlyOneZone: true,
|
OnlyOneZone: true,
|
||||||
NetStart: cfg.EtherTalk.NetStart,
|
NetStart: cfg.EtherTalk.NetStart,
|
||||||
NetEnd: cfg.EtherTalk.NetEnd,
|
NetEnd: cfg.EtherTalk.NetEnd,
|
||||||
ZoneName: zipkt.ZoneName, // has to match request
|
ZoneName: zipkt.ZoneName, // has to match request
|
||||||
MulticastAddr: ethertalk.AppleTalkBroadcast,
|
MulticastAddr: atalk.MulticastAddr(cfg.EtherTalk.ZoneName),
|
||||||
DefaultZoneName: cfg.EtherTalk.ZoneName,
|
DefaultZoneName: cfg.EtherTalk.ZoneName,
|
||||||
}
|
}
|
||||||
log.Printf("ZIP: Replying with GetNetInfo-Reply: %+v", gnir)
|
log.Printf("ZIP: Replying with GetNetInfo-Reply: %+v", gnir)
|
||||||
|
|
Loading…
Reference in a new issue