main.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package main
  7. import (
  8. "context"
  9. "crypto/rand"
  10. "encoding/binary"
  11. "flag"
  12. "log"
  13. "strings"
  14. "time"
  15. "google.golang.org/protobuf/proto"
  16. "github.com/syncthing/syncthing/internal/gen/discoproto"
  17. _ "github.com/syncthing/syncthing/lib/automaxprocs"
  18. "github.com/syncthing/syncthing/lib/beacon"
  19. "github.com/syncthing/syncthing/lib/discover"
  20. "github.com/syncthing/syncthing/lib/protocol"
  21. )
  22. var (
  23. all = false // print all packets, not just first from each device/source
  24. fake = false // send fake packets to lure out other devices faster
  25. mc = "[ff12::8384]:21027"
  26. bc = 21027
  27. )
  28. var (
  29. // Static prefix that we use when generating fake device IDs, so that we
  30. // can recognize them ourselves. Also makes the device ID start with
  31. // "STPROBE-" which is humanly recognizable.
  32. randomPrefix = []byte{148, 223, 23, 4, 148}
  33. // Our random, fake, device ID that we use when sending announcements.
  34. myID = randomDeviceID()
  35. )
  36. func main() {
  37. flag.BoolVar(&all, "all", all, "Print all received announcements (not only first)")
  38. flag.BoolVar(&fake, "fake", fake, "Send fake announcements")
  39. flag.StringVar(&mc, "mc", mc, "IPv6 multicast address")
  40. flag.IntVar(&bc, "bc", bc, "IPv4 broadcast port number")
  41. flag.Parse()
  42. if fake {
  43. log.Println("My ID:", myID)
  44. }
  45. ctx := context.Background()
  46. runbeacon(ctx, beacon.NewMulticast(mc), fake)
  47. runbeacon(ctx, beacon.NewBroadcast(bc), fake)
  48. select {}
  49. }
  50. func runbeacon(ctx context.Context, bc beacon.Interface, fake bool) {
  51. go bc.Serve(ctx)
  52. go recv(bc)
  53. if fake {
  54. go send(bc)
  55. }
  56. }
  57. // receives and prints discovery announcements
  58. func recv(bc beacon.Interface) {
  59. seen := make(map[string]bool)
  60. for {
  61. data, src := bc.Recv()
  62. if m := binary.BigEndian.Uint32(data); m != discover.Magic {
  63. log.Printf("Incorrect magic %x in announcement from %v", m, src)
  64. continue
  65. }
  66. var ann discoproto.Announce
  67. proto.Unmarshal(data[4:], &ann)
  68. id, _ := protocol.DeviceIDFromBytes(ann.Id)
  69. if id == myID {
  70. // This is one of our own fake packets, don't print it.
  71. continue
  72. }
  73. // Print announcement details for the first packet from a given
  74. // device ID and source address, or if -all was given.
  75. key := id.String() + src.String()
  76. if all || !seen[key] {
  77. log.Printf("Announcement from %v\n", src)
  78. log.Printf(" %v at %s\n", id, strings.Join(ann.Addresses, ", "))
  79. seen[key] = true
  80. }
  81. }
  82. }
  83. // sends fake discovery announcements once every second
  84. func send(bc beacon.Interface) {
  85. ann := &discoproto.Announce{
  86. Id: myID[:],
  87. Addresses: []string{"tcp://fake.example.com:12345"},
  88. }
  89. bs, _ := proto.Marshal(ann)
  90. for {
  91. bc.Send(bs)
  92. time.Sleep(time.Second)
  93. }
  94. }
  95. // returns a random but recognizable device ID
  96. func randomDeviceID() protocol.DeviceID {
  97. var id protocol.DeviceID
  98. copy(id[:], randomPrefix)
  99. rand.Read(id[len(randomPrefix):])
  100. return id
  101. }