github.com/decred/dcrlnd@v0.7.6/channeldb/addr.go (about) 1 package channeldb 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "fmt" 7 "io" 8 "net" 9 10 "github.com/decred/dcrlnd/tor" 11 ) 12 13 // addressType specifies the network protocol and version that should be used 14 // when connecting to a node at a particular address. 15 type addressType uint8 16 17 const ( 18 // tcp4Addr denotes an IPv4 TCP address. 19 tcp4Addr addressType = 0 20 21 // tcp6Addr denotes an IPv6 TCP address. 22 tcp6Addr addressType = 1 23 24 // v2OnionAddr denotes a version 2 Tor onion service address. 25 v2OnionAddr addressType = 2 26 27 // v3OnionAddr denotes a version 3 Tor (prop224) onion service address. 28 v3OnionAddr addressType = 3 29 ) 30 31 // encodeTCPAddr serializes a TCP address into its compact raw bytes 32 // representation. 33 func encodeTCPAddr(w io.Writer, addr *net.TCPAddr) error { 34 var ( 35 addrType byte 36 ip []byte 37 ) 38 39 if addr.IP.To4() != nil { 40 addrType = byte(tcp4Addr) 41 ip = addr.IP.To4() 42 } else { 43 addrType = byte(tcp6Addr) 44 ip = addr.IP.To16() 45 } 46 47 if ip == nil { 48 return fmt.Errorf("unable to encode IP %v", addr.IP) 49 } 50 51 if _, err := w.Write([]byte{addrType}); err != nil { 52 return err 53 } 54 55 if _, err := w.Write(ip); err != nil { 56 return err 57 } 58 59 var port [2]byte 60 byteOrder.PutUint16(port[:], uint16(addr.Port)) 61 if _, err := w.Write(port[:]); err != nil { 62 return err 63 } 64 65 return nil 66 } 67 68 // encodeOnionAddr serializes an onion address into its compact raw bytes 69 // representation. 70 func encodeOnionAddr(w io.Writer, addr *tor.OnionAddr) error { 71 var suffixIndex int 72 hostLen := len(addr.OnionService) 73 switch hostLen { 74 case tor.V2Len: 75 if _, err := w.Write([]byte{byte(v2OnionAddr)}); err != nil { 76 return err 77 } 78 suffixIndex = tor.V2Len - tor.OnionSuffixLen 79 case tor.V3Len: 80 if _, err := w.Write([]byte{byte(v3OnionAddr)}); err != nil { 81 return err 82 } 83 suffixIndex = tor.V3Len - tor.OnionSuffixLen 84 default: 85 return errors.New("unknown onion service length") 86 } 87 88 suffix := addr.OnionService[suffixIndex:] 89 if suffix != tor.OnionSuffix { 90 return fmt.Errorf("invalid suffix \"%v\"", suffix) 91 } 92 93 host, err := tor.Base32Encoding.DecodeString( 94 addr.OnionService[:suffixIndex], 95 ) 96 if err != nil { 97 return err 98 } 99 100 // Sanity check the decoded length. 101 switch { 102 case hostLen == tor.V2Len && len(host) != tor.V2DecodedLen: 103 return fmt.Errorf("onion service %v decoded to invalid host %x", 104 addr.OnionService, host) 105 106 case hostLen == tor.V3Len && len(host) != tor.V3DecodedLen: 107 return fmt.Errorf("onion service %v decoded to invalid host %x", 108 addr.OnionService, host) 109 } 110 111 if _, err := w.Write(host); err != nil { 112 return err 113 } 114 115 var port [2]byte 116 byteOrder.PutUint16(port[:], uint16(addr.Port)) 117 if _, err := w.Write(port[:]); err != nil { 118 return err 119 } 120 121 return nil 122 } 123 124 // deserializeAddr reads the serialized raw representation of an address and 125 // deserializes it into the actual address. This allows us to avoid address 126 // resolution within the channeldb package. 127 func deserializeAddr(r io.Reader) (net.Addr, error) { 128 var addrType [1]byte 129 if _, err := r.Read(addrType[:]); err != nil { 130 return nil, err 131 } 132 133 var address net.Addr 134 switch addressType(addrType[0]) { 135 case tcp4Addr: 136 var ip [4]byte 137 if _, err := r.Read(ip[:]); err != nil { 138 return nil, err 139 } 140 141 var port [2]byte 142 if _, err := r.Read(port[:]); err != nil { 143 return nil, err 144 } 145 146 address = &net.TCPAddr{ 147 IP: net.IP(ip[:]), 148 Port: int(binary.BigEndian.Uint16(port[:])), 149 } 150 case tcp6Addr: 151 var ip [16]byte 152 if _, err := r.Read(ip[:]); err != nil { 153 return nil, err 154 } 155 156 var port [2]byte 157 if _, err := r.Read(port[:]); err != nil { 158 return nil, err 159 } 160 161 address = &net.TCPAddr{ 162 IP: net.IP(ip[:]), 163 Port: int(binary.BigEndian.Uint16(port[:])), 164 } 165 case v2OnionAddr: 166 var h [tor.V2DecodedLen]byte 167 if _, err := r.Read(h[:]); err != nil { 168 return nil, err 169 } 170 171 var p [2]byte 172 if _, err := r.Read(p[:]); err != nil { 173 return nil, err 174 } 175 176 onionService := tor.Base32Encoding.EncodeToString(h[:]) 177 onionService += tor.OnionSuffix 178 port := int(binary.BigEndian.Uint16(p[:])) 179 180 address = &tor.OnionAddr{ 181 OnionService: onionService, 182 Port: port, 183 } 184 case v3OnionAddr: 185 var h [tor.V3DecodedLen]byte 186 if _, err := r.Read(h[:]); err != nil { 187 return nil, err 188 } 189 190 var p [2]byte 191 if _, err := r.Read(p[:]); err != nil { 192 return nil, err 193 } 194 195 onionService := tor.Base32Encoding.EncodeToString(h[:]) 196 onionService += tor.OnionSuffix 197 port := int(binary.BigEndian.Uint16(p[:])) 198 199 address = &tor.OnionAddr{ 200 OnionService: onionService, 201 Port: port, 202 } 203 default: 204 return nil, ErrUnknownAddressType 205 } 206 207 return address, nil 208 } 209 210 // serializeAddr serializes an address into its raw bytes representation so that 211 // it can be deserialized without requiring address resolution. 212 func serializeAddr(w io.Writer, address net.Addr) error { 213 switch addr := address.(type) { 214 case *net.TCPAddr: 215 return encodeTCPAddr(w, addr) 216 case *tor.OnionAddr: 217 return encodeOnionAddr(w, addr) 218 default: 219 return ErrUnknownAddressType 220 } 221 }