Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: change src ip in mdns query (#32) #33

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type macAddress string
type brconfig struct {
NetInterface string `toml:"net_interface"`
Devices map[macAddress]bonjourDevice `toml:"devices"`
SpoofAddr string `toml:"cc_subnet_ip"`
}

type bonjourDevice struct {
Expand Down
1 change: 1 addition & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestReadConfig(t *testing.T) {
expectedCfg := brconfig{
NetInterface: "test0",
Devices: devices,
SpoofAddr: "192.168.1.1",
}

if err != nil {
Expand Down
1 change: 1 addition & 0 deletions config_test.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# This is a test config file used by config_test.go
net_interface = "test0"
cc_subnet_ip = "192.168.1.1"

[devices]

Expand Down
10 changes: 8 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ func main() {
if err != nil {
log.Fatalf("Could not find network interface: %v", cfg.NetInterface)
}

// Parse IP use to relay queries to chromecasts
spoofAddr := net.ParseIP(cfg.SpoofAddr)
if spoofAddr == nil {
log.Fatalf("Could not parse cc_subnet_ip")
}

// Get the local MAC address, to filter out Bonjour packet generated locally
intf, err := net.InterfaceByName(cfg.NetInterface)
Expand Down Expand Up @@ -66,15 +72,15 @@ func main() {
continue
}
for _, tag := range tags {
sendBonjourPacket(rawTraffic, &bonjourPacket, tag, brMACAddress)
sendBonjourPacket(rawTraffic, &bonjourPacket, tag, brMACAddress, spoofAddr, true)
}
} else {
device, ok := cfg.Devices[macAddress(bonjourPacket.srcMAC.String())]
if !ok {
continue
}
for _, tag := range device.SharedPools {
sendBonjourPacket(rawTraffic, &bonjourPacket, tag, brMACAddress)
sendBonjourPacket(rawTraffic, &bonjourPacket, tag, brMACAddress, spoofAddr, false)
}
}
}
Expand Down
40 changes: 30 additions & 10 deletions packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type bonjourPacket struct {
srcMAC *net.HardwareAddr
dstMAC *net.HardwareAddr
isIPv6 bool
srcIP *net.IP
vlanTag *uint16
isDNSQuery bool
}
Expand All @@ -30,22 +31,23 @@ func parsePacketsLazily(source *gopacket.PacketSource) chan bonjourPacket {

// Get source and destination mac addresses
srcMAC, dstMAC := parseEthernetLayer(packet)

// Check IP protocol version
isIPv6 := parseIPLayer(packet)

// Check IP protocol version and get srcIP
isIPv6, srcIP := parseIPLayer(packet)
// Get UDP payload
payload := parseUDPLayer(packet)

isDNSQuery := parseDNSPayload(payload)

// Pass on the packet for its next adventure
packetChan <- bonjourPacket{
packet: packet,
packet: packet,
vlanTag: tag,
srcMAC: srcMAC,
dstMAC: dstMAC,
isIPv6: isIPv6,
srcIP: srcIP,
isDNSQuery: isDNSQuery,
}
}
Expand All @@ -69,12 +71,14 @@ func parseVLANTag(packet gopacket.Packet) (tag *uint16) {
return
}

func parseIPLayer(packet gopacket.Packet) (isIPv6 bool) {
func parseIPLayer(packet gopacket.Packet) (isIPv6 bool, srcIP *net.IP) {
if parsedIP := packet.Layer(layers.LayerTypeIPv4); parsedIP != nil {
isIPv6 = false
srcIP = &parsedIP.(*layers.IPv4).SrcIP
}
if parsedIP := packet.Layer(layers.LayerTypeIPv6); parsedIP != nil {
isIPv6 = true
srcIP = &parsedIP.(*layers.IPv6).SrcIP
}
return
}
Expand All @@ -98,19 +102,35 @@ type packetWriter interface {
WritePacketData([]byte) error
}

func sendBonjourPacket(handle packetWriter, bonjourPacket *bonjourPacket, tag uint16, brMACAddress net.HardwareAddr) {
func sendBonjourPacket(handle packetWriter, bonjourPacket *bonjourPacket, tag uint16, brMACAddress net.HardwareAddr, spoofAddr net.IP, spoof bool) {
*bonjourPacket.vlanTag = tag
*bonjourPacket.srcMAC = brMACAddress

// Network devices may set dstMAC to the local MAC address
// Rewrite dstMAC to ensure that it is set to the appropriate multicast MAC address
if bonjourPacket.isIPv6 {
*bonjourPacket.dstMAC = net.HardwareAddr{0x33, 0x33, 0x00, 0x00, 0x00, 0xFB}
} else {
*bonjourPacket.dstMAC = net.HardwareAddr{0x01, 0x00, 0x5E, 0x00, 0x00, 0xFB}
}



buf := gopacket.NewSerializeBuffer()
gopacket.SerializePacket(buf, gopacket.SerializeOptions{}, bonjourPacket.packet)
serializeOptions := gopacket.SerializeOptions{}

// We change the Source IP address of the mDNS query since Chromecasts ignore
// packets coming from outside their subnet.
if spoof && bonjourPacket.isIPv6 == false {
serializeOptions = gopacket.SerializeOptions{ComputeChecksums: true}
*bonjourPacket.srcIP = spoofAddr
// We recalculate the checksum since the IP was modified
if parsedIP := bonjourPacket.packet.Layer(layers.LayerTypeIPv4); parsedIP != nil {
if parsedUDP := bonjourPacket.packet.Layer(layers.LayerTypeUDP); parsedUDP != nil {
parsedUDP.(*layers.UDP).SetNetworkLayerForChecksum(parsedIP.(*layers.IPv4))
}
}
}

gopacket.SerializePacket(buf, serializeOptions, bonjourPacket.packet)
handle.WritePacketData(buf.Bytes())
}
27 changes: 19 additions & 8 deletions packet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var (
dstUDPPortTest = layers.UDPPort(5353)
questionPayloadTest = []byte{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 101, 120, 97,
109, 112, 108, 101, 3, 99, 111, 109, 0, 0, 1, 0, 1}
spoofAddrTest = net.IP{192, 168, 1, 1}
)

func createMockmDNSPacket(isIPv4 bool, isDNSQuery bool) []byte {
Expand Down Expand Up @@ -150,16 +151,16 @@ func TestParseIPLayer(t *testing.T) {
isIPv4 := true
ipv4Packet := gopacket.NewPacket(createMockmDNSPacket(isIPv4, true), decoder, options)

computedIsIPv6 := parseIPLayer(ipv4Packet)
if computedIsIPv6 == true {
computedIsIPv6, srcIP := parseIPLayer(ipv4Packet)
if computedIsIPv6 == true || srcIP == nil {
t.Error("Error in parseIPLayer() for IPv4 addresses")
}

isIPv4 = false
ipv6Packet := gopacket.NewPacket(createMockmDNSPacket(isIPv4, true), decoder, options)

computedIsIPv6 = parseIPLayer(ipv6Packet)
if computedIsIPv6 == false {
computedIsIPv6, srcIP = parseIPLayer(ipv6Packet)
if computedIsIPv6 == false || srcIP == nil {
t.Error("Error in parseIPLayer() for IPv6 addresses")
}
}
Expand Down Expand Up @@ -284,23 +285,27 @@ func TestSendBonjourPacket(t *testing.T) {
initialPacketIPv6 := gopacket.NewPacket(initialDataIPv6, decoder, gopacket.DecodeOptions{Lazy: true})

srcMACv4, dstMACv4 := parseEthernetLayer(initialPacketIPv4)
isIPv6, srcIP := parseIPLayer(initialPacketIPv4)
bonjourTestPacketIPv4 := bonjourPacket{
packet: initialPacketIPv4,
vlanTag: parseVLANTag(initialPacketIPv4),
srcMAC: srcMACv4,
dstMAC: dstMACv4,
srcIP: srcIP,
isDNSQuery: true,
isIPv6: false,
isIPv6: isIPv6,
}

srcMACv6, dstMACv6 := parseEthernetLayer(initialPacketIPv6)
isIPv6, srcIP = parseIPLayer(initialPacketIPv6)
bonjourTestPacketIPv6 := bonjourPacket{
packet: initialPacketIPv6,
vlanTag: parseVLANTag(initialPacketIPv6),
srcMAC: srcMACv6,
dstMAC: dstMACv6,
srcIP: srcIP,
isDNSQuery: true,
isIPv6: true,
isIPv6: isIPv6,
}

newVlanTag := uint16(29)
Expand All @@ -315,12 +320,18 @@ func TestSendBonjourPacket(t *testing.T) {

pw := &mockPacketWriter{packet: nil}

sendBonjourPacket(pw, &bonjourTestPacketIPv4, newVlanTag, brMACTest)
sendBonjourPacket(pw, &bonjourTestPacketIPv4, newVlanTag, brMACTest, spoofAddrTest, false)
if !reflect.DeepEqual(expectedPacketIPv4.Layers(), pw.packet.Layers()) {
t.Error("Error in sendBonjourPacket() for IPv4")
}

// When we change the src IP address of mDNS Query we expect the IPv4 layer to be different
sendBonjourPacket(pw, &bonjourTestPacketIPv4, newVlanTag, brMACTest, spoofAddrTest, true)
if reflect.DeepEqual(expectedPacketIPv4.Layers(), pw.packet.Layers()) {
t.Error("Error in sendBonjourPacket() for IPv4 with spoof address")
}

sendBonjourPacket(pw, &bonjourTestPacketIPv6, newVlanTag, brMACTest)
sendBonjourPacket(pw, &bonjourTestPacketIPv6, newVlanTag, brMACTest, spoofAddrTest, false)
if !reflect.DeepEqual(expectedPacketIPv6.Layers(), pw.packet.Layers()) {
t.Error("Error in sendBonjourPacket() for IPv6")
}
Expand Down