go-multiaddr/net/convert.go

190 lines
3.9 KiB
Go
Raw Normal View History

2014-11-05 00:38:21 -08:00
package manet
2014-09-13 04:48:56 -07:00
import (
2014-11-05 01:47:02 -08:00
"bytes"
2014-09-13 04:48:56 -07:00
"fmt"
"net"
"strings"
2014-10-10 23:56:35 -07:00
ma "github.com/jbenet/go-multiaddr"
2014-09-13 04:48:56 -07:00
)
2014-11-05 00:04:30 -08:00
var (
// IP4Loopback is the ip4 loopback multiaddr
IP4Loopback = ma.StringCast("/ip4/127.0.0.1")
// IP6Loopback is the ip6 loopback multiaddr
IP6Loopback = ma.StringCast("/ip6/::1")
2014-11-05 01:47:02 -08:00
// IP6LinkLocalLoopback is the ip6 link-local loopback multiaddr
IP6LinkLocalLoopback = ma.StringCast("/ip6/fe80::1")
2014-11-05 00:04:30 -08:00
)
2014-09-13 04:48:56 -07:00
var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion")
// FromNetAddr converts a net.Addr type to a Multiaddr.
2014-10-10 23:56:35 -07:00
func FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
2014-09-13 04:48:56 -07:00
switch a.Network() {
case "tcp", "tcp4", "tcp6":
ac, ok := a.(*net.TCPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
// Get IP Addr
ipm, err := FromIP(ac.IP)
if err != nil {
return nil, errIncorrectNetAddr
}
// Get TCP Addr
2014-10-10 23:56:35 -07:00
tcpm, err := ma.NewMultiaddr(fmt.Sprintf("/tcp/%d", ac.Port))
2014-09-13 04:48:56 -07:00
if err != nil {
return nil, errIncorrectNetAddr
}
// Encapsulate
return ipm.Encapsulate(tcpm), nil
case "udp", "upd4", "udp6":
ac, ok := a.(*net.UDPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
// Get IP Addr
ipm, err := FromIP(ac.IP)
if err != nil {
return nil, errIncorrectNetAddr
}
// Get UDP Addr
2014-10-10 23:56:35 -07:00
udpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d", ac.Port))
2014-09-13 04:48:56 -07:00
if err != nil {
return nil, errIncorrectNetAddr
}
// Encapsulate
return ipm.Encapsulate(udpm), nil
case "ip", "ip4", "ip6":
ac, ok := a.(*net.IPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIP(ac.IP)
2014-11-05 00:38:21 -08:00
case "ip+net":
ac, ok := a.(*net.IPNet)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIP(ac.IP)
2014-09-13 04:48:56 -07:00
default:
return nil, fmt.Errorf("unknown network %v", a.Network())
}
}
2014-10-10 20:31:19 -07:00
// ToNetAddr converts a Multiaddr to a net.Addr
// Must be ThinWaist. acceptable protocol stacks are:
// /ip{4,6}/{tcp, udp}
2014-10-10 23:56:35 -07:00
func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
network, host, err := DialArgs(maddr)
2014-10-10 20:31:19 -07:00
if err != nil {
return nil, err
}
switch network {
case "tcp":
return net.ResolveTCPAddr(network, host)
case "udp":
return net.ResolveUDPAddr(network, host)
case "ip":
return net.ResolveIPAddr(network, host)
}
return nil, fmt.Errorf("network not supported: %s", network)
}
2014-09-13 04:48:56 -07:00
// FromIP converts a net.IP type to a Multiaddr.
2014-10-10 23:56:35 -07:00
func FromIP(ip net.IP) (ma.Multiaddr, error) {
2014-09-13 04:48:56 -07:00
switch {
case ip.To4() != nil:
2014-10-10 23:56:35 -07:00
return ma.NewMultiaddr("/ip4/" + ip.String())
2014-09-13 04:48:56 -07:00
case ip.To16() != nil:
2014-10-10 23:56:35 -07:00
return ma.NewMultiaddr("/ip6/" + ip.String())
2014-09-13 04:48:56 -07:00
default:
return nil, errIncorrectNetAddr
}
}
// DialArgs is a convenience function returning arguments for use in net.Dial
2014-10-10 23:56:35 -07:00
func DialArgs(m ma.Multiaddr) (string, string, error) {
if !IsThinWaist(m) {
return "", "", fmt.Errorf("%s is not a 'thin waist' address", m)
}
str := m.String()
parts := strings.Split(str, "/")[1:]
2014-10-10 20:31:19 -07:00
if len(parts) == 2 { // only IP
return parts[0], parts[1], nil
}
network := parts[2]
var host string
switch parts[0] {
case "ip4":
host = strings.Join([]string{parts[1], parts[3]}, ":")
case "ip6":
host = fmt.Sprintf("[%s]:%s", parts[1], parts[3])
}
return network, host, nil
}
// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols.
2014-10-10 20:31:19 -07:00
// This means: /{IP4, IP6}[/{TCP, UDP}]
2014-10-10 23:56:35 -07:00
func IsThinWaist(m ma.Multiaddr) bool {
p := m.Protocols()
2014-10-10 20:31:19 -07:00
// nothing? not even a waist.
if len(p) == 0 {
return false
}
2014-10-10 23:56:35 -07:00
if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 {
return false
}
2014-10-10 20:31:19 -07:00
// only IP? still counts.
if len(p) == 1 {
return true
}
switch p[1].Code {
2014-10-10 23:56:35 -07:00
case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6:
2014-10-10 20:31:19 -07:00
return true
default:
return false
}
}
2014-11-05 00:04:30 -08:00
// IsIPLoopback returns whether a Multiaddr is a "Loopback" IP address
// This means either /ip4/127.0.0.1 or /ip6/::1
func IsIPLoopback(m ma.Multiaddr) bool {
2014-11-05 01:47:02 -08:00
b := m.Bytes()
// /ip4/127 prefix (_entire_ /8 is loopback...)
if bytes.HasPrefix(b, []byte{4, 127}) {
return true
}
// /ip6/::1
if IP6Loopback.Equal(m) || IP6LinkLocalLoopback.Equal(m) {
return true
}
return false
2014-11-05 00:04:30 -08:00
}