mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-09 14:50:56 +00:00
External discover
This commit is contained in:
parent
31ea72dbb3
commit
f2d8b68278
1
discover/cmd/discosrv/.gitignore
vendored
Normal file
1
discover/cmd/discosrv/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
discosrv
|
74
discover/cmd/discosrv/main.go
Normal file
74
discover/cmd/discosrv/main.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/calmh/syncthing/discover"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
IP []byte
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
nodes = make(map[string]Node)
|
||||||
|
lock sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
addr, _ := net.ResolveUDPAddr("udp", ":22025")
|
||||||
|
conn, err := net.ListenUDP("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf = make([]byte, 1024)
|
||||||
|
for {
|
||||||
|
n, addr, err := conn.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
pkt, err := discover.DecodePacket(buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Warning:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch pkt.Magic {
|
||||||
|
case 0x20121025:
|
||||||
|
// Announcement
|
||||||
|
//lock.Lock()
|
||||||
|
ip := addr.IP.To4()
|
||||||
|
if ip == nil {
|
||||||
|
ip = addr.IP.To16()
|
||||||
|
}
|
||||||
|
node := Node{ip, uint16(pkt.Port)}
|
||||||
|
log.Println("<-", pkt.ID, node)
|
||||||
|
nodes[pkt.ID] = node
|
||||||
|
//lock.Unlock()
|
||||||
|
case 0x19760309:
|
||||||
|
// Query
|
||||||
|
//lock.Lock()
|
||||||
|
node, ok := nodes[pkt.ID]
|
||||||
|
//lock.Unlock()
|
||||||
|
if ok {
|
||||||
|
pkt := discover.Packet{
|
||||||
|
Magic: 0x20121025,
|
||||||
|
ID: pkt.ID,
|
||||||
|
Port: node.Port,
|
||||||
|
IP: node.IP,
|
||||||
|
}
|
||||||
|
_, _, err = conn.WriteMsgUDP(discover.EncodePacket(pkt), nil, addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Warning:", err)
|
||||||
|
} else {
|
||||||
|
log.Println("->", pkt.ID, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -146,22 +146,19 @@ func NewDiscoverer(id string, port int, extPort int, extServer string) (*Discove
|
|||||||
func (d *Discoverer) sendAnnouncements() {
|
func (d *Discoverer) sendAnnouncements() {
|
||||||
remote4 := &net.UDPAddr{IP: net.IP{255, 255, 255, 255}, Port: AnnouncementPort}
|
remote4 := &net.UDPAddr{IP: net.IP{255, 255, 255, 255}, Port: AnnouncementPort}
|
||||||
|
|
||||||
buf := encodePacket(packet{AnnouncementMagic, uint16(d.ListenPort), d.MyID, nil})
|
buf := EncodePacket(Packet{AnnouncementMagic, uint16(d.ListenPort), d.MyID, nil})
|
||||||
go d.writeAnnouncements(buf, remote4, d.BroadcastIntv)
|
go d.writeAnnouncements(buf, remote4, d.BroadcastIntv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Discoverer) sendExtAnnouncements() {
|
func (d *Discoverer) sendExtAnnouncements() {
|
||||||
extIPs, err := net.LookupIP(d.extServer)
|
extIP, err := net.ResolveUDPAddr("udp", d.extServer+":22025")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("discover/external: %v; no external announcements", err)
|
log.Printf("discover/external: %v; no external announcements", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := encodePacket(packet{AnnouncementMagic, uint16(d.ExtListenPort), d.MyID, nil})
|
buf := EncodePacket(Packet{AnnouncementMagic, uint16(d.ExtListenPort), d.MyID, nil})
|
||||||
for _, extIP := range extIPs {
|
go d.writeAnnouncements(buf, extIP, d.ExtBroadcastIntv)
|
||||||
remote4 := &net.UDPAddr{IP: extIP, Port: AnnouncementPort}
|
|
||||||
go d.writeAnnouncements(buf, remote4, d.ExtBroadcastIntv)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Discoverer) writeAnnouncements(buf []byte, remote *net.UDPAddr, intv time.Duration) {
|
func (d *Discoverer) writeAnnouncements(buf []byte, remote *net.UDPAddr, intv time.Duration) {
|
||||||
@ -170,6 +167,7 @@ func (d *Discoverer) writeAnnouncements(buf []byte, remote *net.UDPAddr, intv ti
|
|||||||
for errCounter < maxErrors {
|
for errCounter < maxErrors {
|
||||||
_, _, err = d.conn.WriteMsgUDP(buf, nil, remote)
|
_, _, err = d.conn.WriteMsgUDP(buf, nil, remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("discover/write: warning:", err)
|
||||||
errCounter++
|
errCounter++
|
||||||
} else {
|
} else {
|
||||||
errCounter = 0
|
errCounter = 0
|
||||||
@ -191,8 +189,8 @@ func (d *Discoverer) recvAnnouncements() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt, err := decodePacket(buf[:n])
|
pkt, err := DecodePacket(buf[:n])
|
||||||
if err != nil || pkt.magic != AnnouncementMagic {
|
if err != nil || pkt.Magic != AnnouncementMagic {
|
||||||
errCounter++
|
errCounter++
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
continue
|
continue
|
||||||
@ -200,11 +198,11 @@ func (d *Discoverer) recvAnnouncements() {
|
|||||||
|
|
||||||
errCounter = 0
|
errCounter = 0
|
||||||
|
|
||||||
if pkt.id != d.MyID {
|
if pkt.ID != d.MyID {
|
||||||
nodeAddr := fmt.Sprintf("%s:%d", addr.IP.String(), pkt.port)
|
nodeAddr := fmt.Sprintf("%s:%d", addr.IP.String(), pkt.Port)
|
||||||
d.registryLock.Lock()
|
d.registryLock.Lock()
|
||||||
if d.registry[pkt.id] != nodeAddr {
|
if d.registry[pkt.ID] != nodeAddr {
|
||||||
d.registry[pkt.id] = nodeAddr
|
d.registry[pkt.ID] = nodeAddr
|
||||||
}
|
}
|
||||||
d.registryLock.Unlock()
|
d.registryLock.Unlock()
|
||||||
}
|
}
|
||||||
@ -213,58 +211,48 @@ func (d *Discoverer) recvAnnouncements() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Discoverer) externalLookup(node string) (string, bool) {
|
func (d *Discoverer) externalLookup(node string) (string, bool) {
|
||||||
extIPs, err := net.LookupIP(d.extServer)
|
extIP, err := net.ResolveUDPAddr("udp", d.extServer+":22025")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("discover/external: %v; no external lookup", err)
|
log.Printf("discover/external: %v; no external lookup", err)
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = make(chan string, len(extIPs))
|
var res = make(chan string, 1)
|
||||||
var failed = 0
|
conn, err := net.DialUDP("udp", nil, extIP)
|
||||||
for _, extIP := range extIPs {
|
if err != nil {
|
||||||
remote := &net.UDPAddr{IP: extIP, Port: AnnouncementPort}
|
log.Printf("discover/external: %v; no external lookup", err)
|
||||||
conn, err := net.DialUDP("udp", nil, remote)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("discover/external: %v; no external lookup", err)
|
|
||||||
failed++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.Write(encodePacket(packet{QueryMagic, 0, node, nil}))
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("discover/external: %v; no external lookup", err)
|
|
||||||
failed++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
var buf = make([]byte, 1024)
|
|
||||||
_, err = conn.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("discover/external/read: %v; no external lookup", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt, err := decodePacket(buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("discover/external/read: %v; no external lookup", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if pkt.magic != AnnouncementMagic {
|
|
||||||
log.Printf("discover/external/read: bad magic; no external lookup", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res <- fmt.Sprintf("%s:%d", ipStr(pkt.ip), pkt.port)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
if failed == len(extIPs) {
|
|
||||||
// no point in waiting
|
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = conn.Write(EncodePacket(Packet{QueryMagic, 0, node, nil}))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("discover/external: %v; no external lookup", err)
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
log.Println("query", extIP)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var buf = make([]byte, 1024)
|
||||||
|
n, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("discover/external/read: %v; no external lookup", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt, err := DecodePacket(buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("discover/external/read: %v; no external lookup", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkt.Magic != AnnouncementMagic {
|
||||||
|
log.Printf("discover/external/read: bad magic; no external lookup", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res <- fmt.Sprintf("%s:%d", ipStr(pkt.IP), pkt.Port)
|
||||||
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case r := <-res:
|
case r := <-res:
|
||||||
return r, true
|
return r, true
|
||||||
|
@ -6,11 +6,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type packet struct {
|
type Packet struct {
|
||||||
magic uint32 // AnnouncementMagic or QueryMagic
|
Magic uint32 // AnnouncementMagic or QueryMagic
|
||||||
port uint16 // unset if magic == QueryMagic
|
Port uint16 // unset if magic == QueryMagic
|
||||||
id string
|
ID string
|
||||||
ip []byte // zero length in local announcements
|
IP []byte // zero length in local announcements
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -18,26 +18,26 @@ var (
|
|||||||
errFormat = errors.New("incorrect packet format")
|
errFormat = errors.New("incorrect packet format")
|
||||||
)
|
)
|
||||||
|
|
||||||
func encodePacket(pkt packet) []byte {
|
func EncodePacket(pkt Packet) []byte {
|
||||||
if l := len(pkt.ip); l != 0 && l != 4 && l != 16 {
|
if l := len(pkt.IP); l != 0 && l != 4 && l != 16 {
|
||||||
// bad ip format
|
// bad ip format
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var idbs = []byte(pkt.id)
|
var idbs = []byte(pkt.ID)
|
||||||
var l = 4 + 4 + len(idbs) + pad(len(idbs))
|
var l = 4 + 4 + len(idbs) + pad(len(idbs))
|
||||||
if pkt.magic == AnnouncementMagic {
|
if pkt.Magic == AnnouncementMagic {
|
||||||
l += 4 + 4 + len(pkt.ip)
|
l += 4 + 4 + len(pkt.IP)
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf = make([]byte, l)
|
var buf = make([]byte, l)
|
||||||
var offset = 0
|
var offset = 0
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(buf[offset:], pkt.magic)
|
binary.BigEndian.PutUint32(buf[offset:], pkt.Magic)
|
||||||
offset += 4
|
offset += 4
|
||||||
|
|
||||||
if pkt.magic == AnnouncementMagic {
|
if pkt.Magic == AnnouncementMagic {
|
||||||
binary.BigEndian.PutUint16(buf[offset:], uint16(pkt.port))
|
binary.BigEndian.PutUint16(buf[offset:], uint16(pkt.Port))
|
||||||
offset += 4
|
offset += 4
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,39 +46,39 @@ func encodePacket(pkt packet) []byte {
|
|||||||
copy(buf[offset:], idbs)
|
copy(buf[offset:], idbs)
|
||||||
offset += len(idbs) + pad(len(idbs))
|
offset += len(idbs) + pad(len(idbs))
|
||||||
|
|
||||||
if pkt.magic == AnnouncementMagic {
|
if pkt.Magic == AnnouncementMagic {
|
||||||
binary.BigEndian.PutUint32(buf[offset:], uint32(len(pkt.ip)))
|
binary.BigEndian.PutUint32(buf[offset:], uint32(len(pkt.IP)))
|
||||||
offset += 4
|
offset += 4
|
||||||
copy(buf[offset:], pkt.ip)
|
copy(buf[offset:], pkt.IP)
|
||||||
offset += len(pkt.ip)
|
offset += len(pkt.IP)
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodePacket(buf []byte) (*packet, error) {
|
func DecodePacket(buf []byte) (*Packet, error) {
|
||||||
var p packet
|
var p Packet
|
||||||
var offset int
|
var offset int
|
||||||
|
|
||||||
if len(buf) < 4 {
|
if len(buf) < 4 {
|
||||||
// short packet
|
// short packet
|
||||||
return nil, errFormat
|
return nil, errFormat
|
||||||
}
|
}
|
||||||
p.magic = binary.BigEndian.Uint32(buf[offset:])
|
p.Magic = binary.BigEndian.Uint32(buf[offset:])
|
||||||
offset += 4
|
offset += 4
|
||||||
|
|
||||||
if p.magic != AnnouncementMagic && p.magic != QueryMagic {
|
if p.Magic != AnnouncementMagic && p.Magic != QueryMagic {
|
||||||
return nil, errBadMagic
|
return nil, errBadMagic
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.magic == AnnouncementMagic {
|
if p.Magic == AnnouncementMagic {
|
||||||
// Port Number
|
// Port Number
|
||||||
|
|
||||||
if len(buf) < offset+4 {
|
if len(buf) < offset+4 {
|
||||||
// short packet
|
// short packet
|
||||||
return nil, errFormat
|
return nil, errFormat
|
||||||
}
|
}
|
||||||
p.port = binary.BigEndian.Uint16(buf[offset:])
|
p.Port = binary.BigEndian.Uint16(buf[offset:])
|
||||||
offset += 2
|
offset += 2
|
||||||
reserved := binary.BigEndian.Uint16(buf[offset:])
|
reserved := binary.BigEndian.Uint16(buf[offset:])
|
||||||
if reserved != 0 {
|
if reserved != 0 {
|
||||||
@ -101,10 +101,10 @@ func decodePacket(buf []byte) (*packet, error) {
|
|||||||
return nil, errFormat
|
return nil, errFormat
|
||||||
}
|
}
|
||||||
idbs := buf[offset : offset+int(l)]
|
idbs := buf[offset : offset+int(l)]
|
||||||
p.id = string(idbs)
|
p.ID = string(idbs)
|
||||||
offset += int(l) + pad(int(l))
|
offset += int(l) + pad(int(l))
|
||||||
|
|
||||||
if p.magic == AnnouncementMagic {
|
if p.Magic == AnnouncementMagic {
|
||||||
// IP
|
// IP
|
||||||
|
|
||||||
if len(buf) < offset+4 {
|
if len(buf) < offset+4 {
|
||||||
@ -123,7 +123,7 @@ func decodePacket(buf []byte) (*packet, error) {
|
|||||||
return nil, errFormat
|
return nil, errFormat
|
||||||
}
|
}
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
p.ip = buf[offset : offset+int(l)]
|
p.IP = buf[offset : offset+int(l)]
|
||||||
offset += int(l)
|
offset += int(l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
var testdata = []struct {
|
var testdata = []struct {
|
||||||
data []byte
|
data []byte
|
||||||
packet *packet
|
packet *Packet
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -17,10 +17,10 @@ var testdata = []struct {
|
|||||||
0x00, 0x00, 0x00, 0x05,
|
0x00, 0x00, 0x00, 0x05,
|
||||||
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x00, 0x00,
|
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00},
|
0x00, 0x00, 0x00, 0x00},
|
||||||
&packet{
|
&Packet{
|
||||||
magic: 0x20121025,
|
Magic: 0x20121025,
|
||||||
port: 0x1234,
|
Port: 0x1234,
|
||||||
id: "hello",
|
ID: "hello",
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -31,11 +31,11 @@ var testdata = []struct {
|
|||||||
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x21, 0x21,
|
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x21, 0x21,
|
||||||
0x00, 0x00, 0x00, 0x04,
|
0x00, 0x00, 0x00, 0x04,
|
||||||
0x01, 0x02, 0x03, 0x04},
|
0x01, 0x02, 0x03, 0x04},
|
||||||
&packet{
|
&Packet{
|
||||||
magic: 0x20121025,
|
Magic: 0x20121025,
|
||||||
port: 0x3456,
|
Port: 0x3456,
|
||||||
id: "hello!!!",
|
ID: "hello!!!",
|
||||||
ip: []byte{1, 2, 3, 4},
|
IP: []byte{1, 2, 3, 4},
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -43,9 +43,9 @@ var testdata = []struct {
|
|||||||
[]byte{0x19, 0x76, 0x03, 0x09,
|
[]byte{0x19, 0x76, 0x03, 0x09,
|
||||||
0x00, 0x00, 0x00, 0x06,
|
0x00, 0x00, 0x00, 0x06,
|
||||||
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00},
|
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00},
|
||||||
&packet{
|
&Packet{
|
||||||
magic: 0x19760309,
|
Magic: 0x19760309,
|
||||||
id: "hello!",
|
ID: "hello!",
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -68,7 +68,7 @@ var testdata = []struct {
|
|||||||
errFormat,
|
errFormat,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[]byte{0x19, 0x77, 0x03, 0x09, // incorrect magic
|
[]byte{0x19, 0x77, 0x03, 0x09, // incorrect Magic
|
||||||
0x00, 0x00, 0x00, 0x06,
|
0x00, 0x00, 0x00, 0x06,
|
||||||
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00},
|
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00},
|
||||||
nil,
|
nil,
|
||||||
@ -93,7 +93,7 @@ var testdata = []struct {
|
|||||||
|
|
||||||
func TestDecodePacket(t *testing.T) {
|
func TestDecodePacket(t *testing.T) {
|
||||||
for i, test := range testdata {
|
for i, test := range testdata {
|
||||||
p, err := decodePacket(test.data)
|
p, err := DecodePacket(test.data)
|
||||||
if err != test.err {
|
if err != test.err {
|
||||||
t.Errorf("%d: unexpected error %v", i, err)
|
t.Errorf("%d: unexpected error %v", i, err)
|
||||||
} else {
|
} else {
|
||||||
@ -109,7 +109,7 @@ func TestEncodePacket(t *testing.T) {
|
|||||||
if test.err != nil {
|
if test.err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf := encodePacket(*test.packet)
|
buf := EncodePacket(*test.packet)
|
||||||
if bytes.Compare(buf, test.data) != 0 {
|
if bytes.Compare(buf, test.data) != 0 {
|
||||||
t.Errorf("%d: incorrect encoded packet\n% x\n% 0x", i, test.data, buf)
|
t.Errorf("%d: incorrect encoded packet\n% x\n% 0x", i, test.data, buf)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user