Code Monkey home page Code Monkey logo

bonjour-reflector's Introduction

bonjour-reflector

About this project

Bonjour-reflector makes Bonjour devices such as printers, Chromecasts or Spotify Connect speakers, discoverable and usable by other devices located on different VLANs.

Compared to other tools such as avahi-reflector, Bonjour-reflector allows a more fine-grained control of how Bonjour traffic is reflected across VLANs.

How it works

Bonjour-reflector works by intercepting all mDNS traffic and rewriting layers 2 and 3 of the packets to reflect them across the appropriate VLANs.

A configuration file lists, for each Bonjour device (defined by its MAC address), which VLANs should have access to this device. mDNS packets will only be forwarded if the configuration file says so.

The interface on which Bonjour-reflector runs should be configured so that it receives each VLAN's traffic, tagged.

In detail, here is what happens when Bonjour-reflector runs:

  • a device searching for Bonjour devices sends mDNS packets on his VLAN.
  • bonjour-reflector receives these mDNS packets, tagged with the original VLAN.
  • bonjour-reflector looks up in its configuration to which VLANs it should forward the mDNS request, and send new packets tagged with these new VLANs.
  • one Bonjour device receives the packet and sends a response which is also intercepted by bonjour-reflector.
  • bonjour-reflector reads the source MAC of the mDNS response, looks up in its configuration which VLANs are shared with this Bonjour device, and reflects the mDNS response on each of these VLANs.

Installation

A Golang version more recent than Go 1.16 is recommended to build bonjour-reflector. Checkout https://golang.org/doc/install for instructions on how to install a recent version of Golang.

To build the binary, run:

go build

One of the dependencies of the project (gopacket/pcap) also needs the libpcap header files to work properly. On Linux-based distributions, you can do this by installing the development version of libpcap (package: libpcap-dev).

App setup

First, indicate in the config.toml file which of your network interfaces you want to listen to.

Then run

./bonjour-reflector -config=./config.toml

(you may need to run this line with administrator privileges to listen to your interface).

You may use any configuration file you want (following the same structure as the template ./config.toml file provided) by specifying its path with the -config option.

Contribution

Help on this project is very welcomed. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:

  • The master branch contains the latest stable version of the project. All development should be done in dedicated branches.
  • Try to name your branch in a clear way, for example by following this pattern: username/what-i-am-fixing.
  • Do not check in any compiled binaries in the commits.
  • It's okay to have multiple small commits as you work on the PR - we will squash them before merging.
  • Make sure all test cases pass (using go test).
  • When fixing a bug:
    • Prefix your PR with Fix:, and add references to the issues linked to your PR (if they exist),
    • Add test coverage if applicable.
  • When adding a new feature:
    • Prefix your PR with Feature:,
    • Add a description of your feature and reasons to add this feature,
    • Add test cases for this feature.

Debugging & Profiling

A pprof server will listen on port 6060 if the you use the -debug flag.

More information on pprof is available here

License

MIT

bonjour-reflector's People

Contributors

anatolebeuzon avatar gandem avatar kserrania avatar oxlay avatar remicalixte avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bonjour-reflector's Issues

Multiple interfaces

Hi. This is more of a question than an issue:

Will this work on a bridge between two different network interfaces? I'm not using vlans, just looking for a way to have a one-way bonjour reflector (e.g. devices on wlan0 showing up on eth0 but not the other way around).

Thanks :)

Restrict clients by MAC address

I'm wondering if it would be possible to amend this software to facilitate MAC address restrictions on clients as well. Such a config file could look like this:

net_interface = "wls1" # Put here the network interface you want to use.

[devices]

    [devices."AA:BB:CC:DD:EE:FF"]    # A shared bonjour device
    description = "Test Chromecast"
    origin_pool = 1078               # Tag of the VLAN the device is in
    shared_pools = [1234, 3597]      # Tags of the VLANs which can use this device
    shared_devices = ["AA:BB:CC:DD:EE:FA","AA:BB:CC:DD:EE:FB"]   # Mac addresses of devices that can use this device

So in this example, device AA:BB:CC:DD:EE:FB (VLAN 1234) would be able to access AA:BB:CC:DD:EE:FF, but AA:BB:CC:DD:EE:FC (VLAN 1234) would not.

I'm not fluent in Go, so I'm asking if this seems feasible before I dive into it.

go build errors

I get these errors when trying to run 'go build':

~/go/src/bonjour-reflector $ go build
bonjour-reflector/vendor/github.com/google/gopacket/pcap
vendor/github.com/google/gopacket/pcap/pcap.go:202:7: identifier "_Ctype_struct_bpf_program" may conflict with identifiers generated by cgo
vendor/github.com/google/gopacket/pcap/pcap.go:482:13: identifier "_Ctype_struct_pcap_stat" may conflict with identifiers generated by cgo
vendor/github.com/google/gopacket/pcap/pcap.go:527:49: identifier "_Ctype_struct_bpf_program" may conflict with identifiers generated by cgo
vendor/github.com/google/gopacket/pcap/pcap.go:550:10: identifier "_Ctype_struct_bpf_program" may conflict with identifiers generated by cgo
vendor/github.com/google/gopacket/pcap/pcap.go:583:41: identifier "_Ctype_struct_bpf_insn" may conflict with identifiers generated by cgo
vendor/github.com/google/gopacket/pcap/pcap.go:655:66: identifier "_Ctype_struct_bpf_program" may conflict with identifiers generated by cgo
vendor/github.com/google/gopacket/pcap/pcap.go:668:19: identifier "_Ctype_struct_bpf_insn" may conflict with identifiers generated by cgo
vendor/github.com/google/gopacket/pcap/pcap.go:795:34: identifier "_Ctype_struct_pcap_addr" may conflict with identifiers generated by cgo
vendor/github.com/google/gopacket/pcap/pcap.go:798:56: identifier "_Ctype_struct_pcap_addr" may conflict with identifiers generated by cgo

This may be due to my being a newcomer to GO, so in case this rules in/out user error:
1.) Installed and configured vlans & network switch & router firewall rules using this tutorial:
https://www.sbprojects.net/projects/raspberrypi/vlan.php
Verified desired vlan connections by:
hostname -I

2.) Installed GO Raspberry Pi 3B running Stretch:
$mkdir -p $HOME/go/src $HOME/go/bin
$ InstallFile='go1.12.9.linux-armv6l.tar.gz'
$ wget https://dl.google.com/go/$InstallFile
$ sudo tar -C /usr/local -xvf $InstallFile
$ echo 'export GOPATH=$HOME/go' >> ~/.profile
$ echo 'export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin' >> ~/.profile
$ source ~/.profile

3.) Create, build & run, and install & run test GO program:
$ mkdir ~/go/src/hellotest && vi ~/go/src/hellotest/hello.go
hello.go contents:
package main
`import "fmt"`
func main() {
fmt.Printf("hello, world, Version 2\n")
}
Build and run:
$ cd ~/go/src/hellotest
$ go build
$ ./hellotest
hello, world Version 2
Install and run:
$ cd ~/go/src/hellotest
$ go install
$ cd ~
$ hellotest
hello, world Version 2

4.) Install git & dep & libpcap-dev
$ sudo apt-get update && sudo apt-get install git -y
$ wget https://raw.githubusercontent.com/golang/dep/master/install.sh
$ chmod 755 install.sh
$ ./install.sh
# (no error msgs)
$ ln -s $HOME/go/bin/dep /usr/bin/
$ \ls -1 ~/go/bin
dep
hellov2
$ sudo apt-get install libpcap-dev -y
$ cd ~/go/src
$ git clone https://github.com/Gandem/bonjour-reflector.git
$ cd ~/go/src/bonjour-reflector
# CONFIGURED config.toml
$ vi config.toml
$ dep ensure
# (no error msgs)
$ go build

Then got the error messages at beginning of this issue/post and no generated file called ~/go/src/bonjour-reflector/bonjour-reflector

No response from clients

I've just set up this reflector and configured it to reflect my Google Home Mini located in VLAN200 to VLANS 100, 300 and 400. The query packets from these VLANs are successfully reflected to VLAN200, however there's no response from Google Home Mini (I'm using MikroTik's sniffer to check the VLAN200 packets). When a device sends an mDNS query on the same VLAN, the Home Mini responds correctly. I've disabled all firewall rules as to not interfere, but I did not help.

I can provide a pcap file if that would help resolve my issue, thanks in advance.

EDIT: Seems like the issue is that this reflector does not replace the source IP of the packets when reflecting them and the devices do not respond since it's not the same network

Howto install

As I'm completely new to Go and no programmer, I am wondering howto get started ?
I would use a standard Ubuntu VM.

Running but not reflecting

OS: 20.04.3 LTS
GO version: 1.19.3 arm64
Platform Raspberry Pi4

Compiled bonjour-reflector and built a simple config to allow access to a chrome-cast from another vlan:

netplan config (not sure it matters):

network:
        version: 2
        ethernets:
                eth0:
                        dhcp4: false
        vlans:
                vlan1000:
                        id: 1000
                        addresses: [10.16.191.14/24]
                        gateway4: 10.16.191.1
                        nameservers:
                                addresses: [8.8.8.8,8.8.4.4]
                        link: eth0

config.toml:

net_interface = "eth0"
[devices]
        [devices."A4:77:33:89:20:E6"]
        description = "Chromecast in Lab"
        origin_pool = 702
        shared_pools = [701]

excuting: ./bonjour-reflector -config=./config.toml

Output snippet.

PACKET: 86 bytes, wire length 86 cap length 86 @ 2022-11-03 10:30:45.739136 +0000 UTC
- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..72..] SrcMAC=a4:77:33:89:20:e6 DstMAC=01:00:5e:00:00:fb EthernetType=Dot1Q Length=0}
- Layer 2 (04 bytes) = Dot1Q    {Contents=[2, 190, 8, 0] Payload=[..68..] Priority=0 DropEligible=false VLANIdentifier=702 Type=IPv4}
- Layer 3 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..48..] Version=4 IHL=5 TOS=0 Length=68 Id=0 Flags=DF FragOffset=0 TTL=255 Protocol=UDP Checksum=35723 SrcIP=10.16.5.18 DstIP=224.0.0.251 Options=[] Padding=[]}
- Layer 4 (08 bytes) = UDP      {Contents=[..8..] Payload=[..40..] SrcPort=5353(mdns) DstPort=5353(mdns) Length=48 Checksum=39814}
- Layer 5 (40 bytes) = Payload  40 byte(s)

PACKET: 398 bytes, wire length 398 cap length 398 @ 2022-11-03 10:30:45.739454 +0000 UTC
- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..384..] SrcMAC=a4:77:33:89:20:e6 DstMAC=01:00:5e:00:00:fb EthernetType=Dot1Q Length=0}
- Layer 2 (04 bytes) = Dot1Q    {Contents=[2, 190, 8, 0] Payload=[..380..] Priority=0 DropEligible=false VLANIdentifier=702 Type=IPv4}
- Layer 3 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..360..] Version=4 IHL=5 TOS=0 Length=380 Id=0 Flags=DF FragOffset=0 TTL=255 Protocol=UDP Checksum=35411 SrcIP=10.16.5.18 DstIP=224.0.0.251 Options=[] Padding=[]}
- Layer 4 (08 bytes) = UDP      {Contents=[..8..] Payload=[..352..] SrcPort=5353(mdns) DstPort=5353(mdns) Length=360 Checksum=5335}
- Layer 5 (352 bytes) = Payload 352 byte(s)

PACKET: 107 bytes, wire length 107 cap length 107 @ 2022-11-03 10:30:54.06189 +0000 UTC
- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..93..] SrcMAC=46:63:7e:ea:a5:49 DstMAC=01:00:5e:00:00:fb EthernetType=Dot1Q Length=0}
- Layer 2 (04 bytes) = Dot1Q    {Contents=[2, 189, 8, 0] Payload=[..89..] Priority=0 DropEligible=false VLANIdentifier=701 Type=IPv4}
- Layer 3 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..69..] Version=4 IHL=5 TOS=0 Length=89 Id=41119 Flags= FragOffset=0 TTL=2 Protocol=UDP Checksum=12221 SrcIP=10.16.253.44 DstIP=224.0.0.251 Options=[] Padding=[]}
- Layer 4 (08 bytes) = UDP      {Contents=[..8..] Payload=[..61..] SrcPort=5353(mdns) DstPort=5353(mdns) Length=69 Checksum=51551}
- Layer 5 (61 bytes) = Payload  61 byte(s)

PACKET: 107 bytes, wire length 107 cap length 107 @ 2022-11-03 10:30:55.064249 +0000 UTC
- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..93..] SrcMAC=46:63:7e:ea:a5:49 DstMAC=01:00:5e:00:00:fb EthernetType=Dot1Q Length=0}
- Layer 2 (04 bytes) = Dot1Q    {Contents=[2, 189, 8, 0] Payload=[..89..] Priority=0 DropEligible=false VLANIdentifier=701 Type=IPv4}
- Layer 3 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..69..] Version=4 IHL=5 TOS=0 Length=89 Id=41127 Flags= FragOffset=0 TTL=2 Protocol=UDP Checksum=12213 SrcIP=10.16.253.44 DstIP=224.0.0.251 Options=[] Padding=[]}
- Layer 4 (08 bytes) = UDP      {Contents=[..8..] Payload=[..61..] SrcPort=5353(mdns) DstPort=5353(mdns) Length=69 Checksum=51551}
- Layer 5 (61 bytes) = Payload  61 byte(s)

PACKET: 86 bytes, wire length 86 cap length 86 @ 2022-11-03 10:31:14.24797 +0000 UTC
- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..72..] SrcMAC=a4:77:33:89:20:e6 DstMAC=01:00:5e:00:00:fb EthernetType=Dot1Q Length=0}
- Layer 2 (04 bytes) = Dot1Q    {Contents=[2, 190, 8, 0] Payload=[..68..] Priority=0 DropEligible=false VLANIdentifier=702 Type=IPv4}
- Layer 3 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..48..] Version=4 IHL=5 TOS=0 Length=68 Id=0 Flags=DF FragOffset=0 TTL=255 Protocol=UDP Checksum=35723 SrcIP=10.16.5.18 DstIP=224.0.0.251 Options=[] Padding=[]}
- Layer 4 (08 bytes) = UDP      {Contents=[..8..] Payload=[..40..] SrcPort=5353(mdns) DstPort=5353(mdns) Length=48 Checksum=35207}
- Layer 5 (40 bytes) = Payload  40 byte(s)

A capture on the interface shows mDNS packets are forwarded out the port for the host running bonjour-reflector, but nothing comes back.

I have avahi running fine, i obviously disable it before running bonjour-reflector.

What am i doing wrong and once i get that sorted is there a process for demonizing the process?

Can I use this to expose Docker traffic to host and vice versa?

I have a use-case that this could be the perfect fit for but I don’t understand enough about networking to know.

On MacOS, setting Docker to use the “host” network is a no-op - docker will simply ignore this and isolate the network anyway.

I’m using a software called Home Assistant, which integrates with Apple’s HomeKit, and there’s a section for this integration specifically dealing with Docker, where usage of avahi-daemon is recommended, in reflector mode (so the HomeKit app can find the HA instance running inside docker). See Docker network isolation here: https://www.home-assistant.io/integrations/homekit

avahi-daemon is unfortunately not available for MacOS, and this library looks like it could provide similar functionality. However, at least for a networking dummy like me, its fine-grained control is a bit intimidating.

For starters I couldn’t get it to run due to some Go installation problems, but even if I did manage to run it, what would I include in the toml file? Do the devices I want to repeat mDNS for have to be defined in both sides? Where would I find their interface? And how do I know the name/ID of the VLAN they’re running on? Mind you, HA isn’t an actual device, it only emulates one.

High CPU usage

CPU usage seems to be quite high, I compiled bonjour-reflector on MIPS architecture and I get 100% load (of course it's not a very powerful CPU to start with...). I'm wondering if packet processing could be threaded, source VLANs filtered earlier or something.

Wildcard support when specifying mac addresses

Is there any wildcard support when listing devices in the config.toml?

For example:
[devices."*"] = "any device"
[devices."ab:cd:ef:*"] or [devices."ab:cd:ef"] = "any device with a mac that starts with ab:cd:ef

I've tried various approaches, including *, .*, 00:00:00:00:00:00, FF:FF:FF:FF:FF:FF without success.

Not strong in go but I didn't see anything in the code that looked like it handled wildcard values.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.