Perform external queries
This commit is contained in:
parent
e48222ada0
commit
31ea72dbb3
3
build.sh
3
build.sh
@ -2,8 +2,11 @@
|
|||||||
|
|
||||||
version=$(git describe --always)
|
version=$(git describe --always)
|
||||||
|
|
||||||
|
go test ./... || exit 1
|
||||||
|
|
||||||
for goos in darwin linux freebsd ; do
|
for goos in darwin linux freebsd ; do
|
||||||
for goarch in amd64 386 ; do
|
for goarch in amd64 386 ; do
|
||||||
|
echo "$goos-$goarch"
|
||||||
export GOOS="$goos"
|
export GOOS="$goos"
|
||||||
export GOARCH="$goarch"
|
export GOARCH="$goarch"
|
||||||
go build -ldflags "-X main.Version $version" \
|
go build -ldflags "-X main.Version $version" \
|
||||||
|
|||||||
@ -20,6 +20,12 @@ following format:
|
|||||||
\ NodeID (variable length) \
|
\ NodeID (variable length) \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| Length of IP |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
/ /
|
||||||
|
\ IP (variable length) \
|
||||||
|
/ /
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
This is the XDR encoding of:
|
This is the XDR encoding of:
|
||||||
|
|
||||||
@ -31,11 +37,15 @@ struct Announcement {
|
|||||||
|
|
||||||
(Hence NodeID is padded to a multiple of 32 bits)
|
(Hence NodeID is padded to a multiple of 32 bits)
|
||||||
|
|
||||||
The sending node's address is not encoded -- it is taken to be the source
|
The sending node's address is not encoded in local announcement -- the Length
|
||||||
address of the announcement. Every time such a packet is received, a local
|
of IP field is set to zero and the address is taken to be the source address of
|
||||||
table that maps NodeID to Address is updated. When the local node wants to
|
the announcement. In announcement packets sent by a discovery server in
|
||||||
connect to another node with the address specification 'dynamic', this table is
|
response to a query, the IP is present and the length is either 4 (IPv4) or 16
|
||||||
consulted.
|
(IPv6).
|
||||||
|
|
||||||
|
Every time such a packet is received, a local table that maps NodeID to Address
|
||||||
|
is updated. When the local node wants to connect to another node with the
|
||||||
|
address specification 'dynamic', this table is consulted.
|
||||||
|
|
||||||
For external discovery, an identical packet is sent every 30 minutes to the
|
For external discovery, an identical packet is sent every 30 minutes to the
|
||||||
external discovery server. The server keeps information for up to 60 minutes.
|
external discovery server. The server keeps information for up to 60 minutes.
|
||||||
@ -71,8 +81,6 @@ server from being used as an amplifier in a DDoS attack.)
|
|||||||
package discover
|
package discover
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -86,11 +94,6 @@ const (
|
|||||||
QueryMagic = 0x19760309
|
QueryMagic = 0x19760309
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errBadMagic = errors.New("bad magic")
|
|
||||||
errFormat = errors.New("incorrect packet format")
|
|
||||||
)
|
|
||||||
|
|
||||||
type Discoverer struct {
|
type Discoverer struct {
|
||||||
MyID string
|
MyID string
|
||||||
ListenPort int
|
ListenPort int
|
||||||
@ -104,13 +107,7 @@ type Discoverer struct {
|
|||||||
extServer string
|
extServer string
|
||||||
}
|
}
|
||||||
|
|
||||||
type packet struct {
|
// We tolerate a certain amount of errors because we might be running on
|
||||||
magic uint32 // AnnouncementMagic or QueryMagic
|
|
||||||
port uint16 // unset if magic == QueryMagic
|
|
||||||
id string
|
|
||||||
}
|
|
||||||
|
|
||||||
// We tolerate a certain amount of errors because we might be running in
|
|
||||||
// laptops that sleep and wake, have intermittent network connectivity, etc.
|
// laptops that sleep and wake, have intermittent network connectivity, etc.
|
||||||
// When we hit this many errors in succession, we stop.
|
// When we hit this many errors in succession, we stop.
|
||||||
const maxErrors = 30
|
const maxErrors = 30
|
||||||
@ -149,7 +146,7 @@ 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})
|
buf := encodePacket(packet{AnnouncementMagic, uint16(d.ListenPort), d.MyID, nil})
|
||||||
go d.writeAnnouncements(buf, remote4, d.BroadcastIntv)
|
go d.writeAnnouncements(buf, remote4, d.BroadcastIntv)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +157,7 @@ func (d *Discoverer) sendExtAnnouncements() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := encodePacket(packet{AnnouncementMagic, uint16(d.ExtListenPort), d.MyID})
|
buf := encodePacket(packet{AnnouncementMagic, uint16(d.ExtListenPort), d.MyID, nil})
|
||||||
for _, extIP := range extIPs {
|
for _, extIP := range extIPs {
|
||||||
remote4 := &net.UDPAddr{IP: extIP, Port: AnnouncementPort}
|
remote4 := &net.UDPAddr{IP: extIP, Port: AnnouncementPort}
|
||||||
go d.writeAnnouncements(buf, remote4, d.ExtBroadcastIntv)
|
go d.writeAnnouncements(buf, remote4, d.ExtBroadcastIntv)
|
||||||
@ -215,93 +212,77 @@ func (d *Discoverer) recvAnnouncements() {
|
|||||||
log.Println("discover/read: stopping due to too many errors:", err)
|
log.Println("discover/read: stopping due to too many errors:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Discoverer) externalLookup(node string) (string, bool) {
|
||||||
|
extIPs, err := net.LookupIP(d.extServer)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("discover/external: %v; no external lookup", err)
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
var res = make(chan string, len(extIPs))
|
||||||
|
var failed = 0
|
||||||
|
for _, extIP := range extIPs {
|
||||||
|
remote := &net.UDPAddr{IP: extIP, Port: AnnouncementPort}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case r := <-res:
|
||||||
|
return r, true
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Discoverer) Lookup(node string) (string, bool) {
|
func (d *Discoverer) Lookup(node string) (string, bool) {
|
||||||
d.registryLock.Lock()
|
d.registryLock.Lock()
|
||||||
defer d.registryLock.Unlock()
|
|
||||||
addr, ok := d.registry[node]
|
addr, ok := d.registry[node]
|
||||||
return addr, ok
|
d.registryLock.Unlock()
|
||||||
}
|
|
||||||
|
|
||||||
func encodePacket(pkt packet) []byte {
|
if ok {
|
||||||
var idbs = []byte(pkt.id)
|
return addr, true
|
||||||
var l = len(idbs) + pad(len(idbs)) + 4 + 4
|
} else if len(d.extServer) != 0 {
|
||||||
if pkt.magic == AnnouncementMagic {
|
// We might want to cache this, but not permanently so it needs some intelligence
|
||||||
l += 4
|
return d.externalLookup(node)
|
||||||
}
|
}
|
||||||
|
return "", false
|
||||||
var buf = make([]byte, l)
|
|
||||||
var offset = 0
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(buf[offset:], pkt.magic)
|
|
||||||
offset += 4
|
|
||||||
|
|
||||||
if pkt.magic == AnnouncementMagic {
|
|
||||||
binary.BigEndian.PutUint16(buf[offset:], uint16(pkt.port))
|
|
||||||
offset += 4
|
|
||||||
}
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(buf[offset:], uint32(len(idbs)))
|
|
||||||
offset += 4
|
|
||||||
copy(buf[offset:], idbs)
|
|
||||||
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodePacket(buf []byte) (*packet, error) {
|
|
||||||
var p packet
|
|
||||||
var offset int
|
|
||||||
|
|
||||||
if len(buf) < 4 {
|
|
||||||
// short packet
|
|
||||||
return nil, errFormat
|
|
||||||
}
|
|
||||||
p.magic = binary.BigEndian.Uint32(buf[offset:])
|
|
||||||
offset += 4
|
|
||||||
|
|
||||||
if p.magic != AnnouncementMagic && p.magic != QueryMagic {
|
|
||||||
return nil, errBadMagic
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.magic == AnnouncementMagic {
|
|
||||||
if len(buf) < offset+4 {
|
|
||||||
// short packet
|
|
||||||
return nil, errFormat
|
|
||||||
}
|
|
||||||
p.port = binary.BigEndian.Uint16(buf[offset:])
|
|
||||||
offset += 2
|
|
||||||
reserved := binary.BigEndian.Uint16(buf[offset:])
|
|
||||||
if reserved != 0 {
|
|
||||||
return nil, errFormat
|
|
||||||
}
|
|
||||||
offset += 2
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(buf) < offset+4 {
|
|
||||||
// short packet
|
|
||||||
return nil, errFormat
|
|
||||||
}
|
|
||||||
l := binary.BigEndian.Uint32(buf[offset:])
|
|
||||||
offset += 4
|
|
||||||
|
|
||||||
if len(buf) < offset+int(l)+pad(int(l)) {
|
|
||||||
// short packet
|
|
||||||
return nil, errFormat
|
|
||||||
}
|
|
||||||
idbs := buf[offset : offset+int(l)]
|
|
||||||
p.id = string(idbs)
|
|
||||||
offset += int(l) + pad(int(l))
|
|
||||||
if len(buf[offset:]) > 0 {
|
|
||||||
// extra data
|
|
||||||
return nil, errFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
return &p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func pad(l int) int {
|
|
||||||
d := l % 4
|
|
||||||
if d == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return 4 - d
|
|
||||||
}
|
}
|
||||||
|
|||||||
160
discover/encoding.go
Normal file
160
discover/encoding.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package discover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type packet struct {
|
||||||
|
magic uint32 // AnnouncementMagic or QueryMagic
|
||||||
|
port uint16 // unset if magic == QueryMagic
|
||||||
|
id string
|
||||||
|
ip []byte // zero length in local announcements
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errBadMagic = errors.New("bad magic")
|
||||||
|
errFormat = errors.New("incorrect packet format")
|
||||||
|
)
|
||||||
|
|
||||||
|
func encodePacket(pkt packet) []byte {
|
||||||
|
if l := len(pkt.ip); l != 0 && l != 4 && l != 16 {
|
||||||
|
// bad ip format
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var idbs = []byte(pkt.id)
|
||||||
|
var l = 4 + 4 + len(idbs) + pad(len(idbs))
|
||||||
|
if pkt.magic == AnnouncementMagic {
|
||||||
|
l += 4 + 4 + len(pkt.ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf = make([]byte, l)
|
||||||
|
var offset = 0
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(buf[offset:], pkt.magic)
|
||||||
|
offset += 4
|
||||||
|
|
||||||
|
if pkt.magic == AnnouncementMagic {
|
||||||
|
binary.BigEndian.PutUint16(buf[offset:], uint16(pkt.port))
|
||||||
|
offset += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(buf[offset:], uint32(len(idbs)))
|
||||||
|
offset += 4
|
||||||
|
copy(buf[offset:], idbs)
|
||||||
|
offset += len(idbs) + pad(len(idbs))
|
||||||
|
|
||||||
|
if pkt.magic == AnnouncementMagic {
|
||||||
|
binary.BigEndian.PutUint32(buf[offset:], uint32(len(pkt.ip)))
|
||||||
|
offset += 4
|
||||||
|
copy(buf[offset:], pkt.ip)
|
||||||
|
offset += len(pkt.ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodePacket(buf []byte) (*packet, error) {
|
||||||
|
var p packet
|
||||||
|
var offset int
|
||||||
|
|
||||||
|
if len(buf) < 4 {
|
||||||
|
// short packet
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
p.magic = binary.BigEndian.Uint32(buf[offset:])
|
||||||
|
offset += 4
|
||||||
|
|
||||||
|
if p.magic != AnnouncementMagic && p.magic != QueryMagic {
|
||||||
|
return nil, errBadMagic
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.magic == AnnouncementMagic {
|
||||||
|
// Port Number
|
||||||
|
|
||||||
|
if len(buf) < offset+4 {
|
||||||
|
// short packet
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
p.port = binary.BigEndian.Uint16(buf[offset:])
|
||||||
|
offset += 2
|
||||||
|
reserved := binary.BigEndian.Uint16(buf[offset:])
|
||||||
|
if reserved != 0 {
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
offset += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node ID
|
||||||
|
|
||||||
|
if len(buf) < offset+4 {
|
||||||
|
// short packet
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
l := binary.BigEndian.Uint32(buf[offset:])
|
||||||
|
offset += 4
|
||||||
|
|
||||||
|
if len(buf) < offset+int(l)+pad(int(l)) {
|
||||||
|
// short packet
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
idbs := buf[offset : offset+int(l)]
|
||||||
|
p.id = string(idbs)
|
||||||
|
offset += int(l) + pad(int(l))
|
||||||
|
|
||||||
|
if p.magic == AnnouncementMagic {
|
||||||
|
// IP
|
||||||
|
|
||||||
|
if len(buf) < offset+4 {
|
||||||
|
// short packet
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
l = binary.BigEndian.Uint32(buf[offset:])
|
||||||
|
offset += 4
|
||||||
|
|
||||||
|
if l != 0 && l != 4 && l != 16 {
|
||||||
|
// weird ip length
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
if len(buf) < offset+int(l) {
|
||||||
|
// short packet
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
if l > 0 {
|
||||||
|
p.ip = buf[offset : offset+int(l)]
|
||||||
|
offset += int(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(buf[offset:]) > 0 {
|
||||||
|
// extra data
|
||||||
|
return nil, errFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
return &p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func pad(l int) int {
|
||||||
|
d := l % 4
|
||||||
|
if d == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return 4 - d
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipStr(ip []byte) string {
|
||||||
|
switch len(ip) {
|
||||||
|
case 4:
|
||||||
|
return fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
|
||||||
|
case 16:
|
||||||
|
return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||||
|
ip[0], ip[1], ip[2], ip[3],
|
||||||
|
ip[4], ip[5], ip[6], ip[7],
|
||||||
|
ip[8], ip[9], ip[10], ip[11],
|
||||||
|
ip[12], ip[13], ip[14], ip[15])
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,7 +15,8 @@ var testdata = []struct {
|
|||||||
[]byte{0x20, 0x12, 0x10, 0x25,
|
[]byte{0x20, 0x12, 0x10, 0x25,
|
||||||
0x12, 0x34, 0x00, 0x00,
|
0x12, 0x34, 0x00, 0x00,
|
||||||
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},
|
||||||
&packet{
|
&packet{
|
||||||
magic: 0x20121025,
|
magic: 0x20121025,
|
||||||
port: 0x1234,
|
port: 0x1234,
|
||||||
@ -27,11 +28,14 @@ var testdata = []struct {
|
|||||||
[]byte{0x20, 0x12, 0x10, 0x25,
|
[]byte{0x20, 0x12, 0x10, 0x25,
|
||||||
0x34, 0x56, 0x00, 0x00,
|
0x34, 0x56, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x08,
|
0x00, 0x00, 0x00, 0x08,
|
||||||
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x21, 0x21},
|
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x21, 0x21,
|
||||||
|
0x00, 0x00, 0x00, 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},
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -49,7 +53,8 @@ var testdata = []struct {
|
|||||||
[]byte{0x20, 0x12, 0x10, 0x25,
|
[]byte{0x20, 0x12, 0x10, 0x25,
|
||||||
0x12, 0x34, 0x12, 0x34, // reserved bits not set to zero
|
0x12, 0x34, 0x12, 0x34, // reserved bits not set to zero
|
||||||
0x00, 0x00, 0x00, 0x06,
|
0x00, 0x00, 0x00, 0x06,
|
||||||
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00},
|
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00},
|
||||||
nil,
|
nil,
|
||||||
errFormat,
|
errFormat,
|
||||||
},
|
},
|
||||||
@ -57,7 +62,8 @@ var testdata = []struct {
|
|||||||
[]byte{0x20, 0x12, 0x10, 0x25,
|
[]byte{0x20, 0x12, 0x10, 0x25,
|
||||||
0x12, 0x34, 0x00, 0x00,
|
0x12, 0x34, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x06,
|
0x00, 0x00, 0x00, 0x06,
|
||||||
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21}, // missing padding
|
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, // missing padding
|
||||||
|
0x00, 0x00, 0x00, 0x00},
|
||||||
nil,
|
nil,
|
||||||
errFormat,
|
errFormat,
|
||||||
},
|
},
|
||||||
@ -109,3 +115,24 @@ func TestEncodePacket(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ipstrTests = []struct {
|
||||||
|
d []byte
|
||||||
|
s string
|
||||||
|
}{
|
||||||
|
{[]byte{192, 168, 34}, ""},
|
||||||
|
{[]byte{192, 168, 0, 34}, "192.168.0.34"},
|
||||||
|
{[]byte{0x20, 0x01, 0x12, 0x34,
|
||||||
|
0x34, 0x56, 0x56, 0x78,
|
||||||
|
0x78, 0x00, 0x00, 0xdc,
|
||||||
|
0x00, 0x00, 0x43, 0x54}, "2001:1234:3456:5678:7800:00dc:0000:4354"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPStr(t *testing.T) {
|
||||||
|
for _, tc := range ipstrTests {
|
||||||
|
s1 := ipStr(tc.d)
|
||||||
|
if s1 != tc.s {
|
||||||
|
t.Errorf("Incorrect ipstr %q != %q", tc.s, s1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user