github.com/yggdrasil-network/yggdrasil-go@v0.5.6/contrib/mobile/mobile.go (about) 1 package mobile 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 "net" 7 "regexp" 8 9 "github.com/gologme/log" 10 11 "github.com/yggdrasil-network/yggdrasil-go/src/address" 12 "github.com/yggdrasil-network/yggdrasil-go/src/config" 13 "github.com/yggdrasil-network/yggdrasil-go/src/core" 14 "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" 15 "github.com/yggdrasil-network/yggdrasil-go/src/multicast" 16 "github.com/yggdrasil-network/yggdrasil-go/src/tun" 17 "github.com/yggdrasil-network/yggdrasil-go/src/version" 18 19 _ "golang.org/x/mobile/bind" 20 ) 21 22 // Yggdrasil mobile package is meant to "plug the gap" for mobile support, as 23 // Gomobile will not create headers for Swift/Obj-C etc if they have complex 24 // (non-native) types. Therefore for iOS we will expose some nice simple 25 // functions. Note that in the case of iOS we handle reading/writing to/from TUN 26 // in Swift therefore we use the "dummy" TUN interface instead. 27 type Yggdrasil struct { 28 core *core.Core 29 iprwc *ipv6rwc.ReadWriteCloser 30 config *config.NodeConfig 31 multicast *multicast.Multicast 32 tun *tun.TunAdapter // optional 33 log MobileLogger 34 logger *log.Logger 35 } 36 37 // StartAutoconfigure starts a node with a randomly generated config 38 func (m *Yggdrasil) StartAutoconfigure() error { 39 return m.StartJSON([]byte("{}")) 40 } 41 42 // StartJSON starts a node with the given JSON config. You can get JSON config 43 // (rather than HJSON) by using the GenerateConfigJSON() function 44 func (m *Yggdrasil) StartJSON(configjson []byte) error { 45 setMemLimitIfPossible() 46 47 logger := log.New(m.log, "", 0) 48 logger.EnableLevel("error") 49 logger.EnableLevel("warn") 50 logger.EnableLevel("info") 51 m.logger = logger 52 m.config = config.GenerateConfig() 53 if err := m.config.UnmarshalHJSON(configjson); err != nil { 54 return err 55 } 56 // Set up the Yggdrasil node itself. 57 { 58 options := []core.SetupOption{} 59 for _, peer := range m.config.Peers { 60 options = append(options, core.Peer{URI: peer}) 61 } 62 for intf, peers := range m.config.InterfacePeers { 63 for _, peer := range peers { 64 options = append(options, core.Peer{URI: peer, SourceInterface: intf}) 65 } 66 } 67 for _, allowed := range m.config.AllowedPublicKeys { 68 k, err := hex.DecodeString(allowed) 69 if err != nil { 70 panic(err) 71 } 72 options = append(options, core.AllowedPublicKey(k[:])) 73 } 74 for _, lAddr := range m.config.Listen { 75 options = append(options, core.ListenAddress(lAddr)) 76 } 77 var err error 78 m.core, err = core.New(m.config.Certificate, logger, options...) 79 if err != nil { 80 panic(err) 81 } 82 address, subnet := m.core.Address(), m.core.Subnet() 83 logger.Infof("Your public key is %s", hex.EncodeToString(m.core.PublicKey())) 84 logger.Infof("Your IPv6 address is %s", address.String()) 85 logger.Infof("Your IPv6 subnet is %s", subnet.String()) 86 } 87 88 // Set up the multicast module. 89 if len(m.config.MulticastInterfaces) > 0 { 90 var err error 91 logger.Infof("Initializing multicast %s", "") 92 options := []multicast.SetupOption{} 93 for _, intf := range m.config.MulticastInterfaces { 94 options = append(options, multicast.MulticastInterface{ 95 Regex: regexp.MustCompile(intf.Regex), 96 Beacon: intf.Beacon, 97 Listen: intf.Listen, 98 Port: intf.Port, 99 Priority: uint8(intf.Priority), 100 Password: intf.Password, 101 }) 102 } 103 logger.Infof("Starting multicast %s", "") 104 m.multicast, err = multicast.New(m.core, m.logger, options...) 105 if err != nil { 106 logger.Errorln("An error occurred starting multicast:", err) 107 } 108 } 109 110 mtu := m.config.IfMTU 111 m.iprwc = ipv6rwc.NewReadWriteCloser(m.core) 112 if m.iprwc.MaxMTU() < mtu { 113 mtu = m.iprwc.MaxMTU() 114 } 115 m.iprwc.SetMTU(mtu) 116 return nil 117 } 118 119 // Send sends a packet to Yggdrasil. It should be a fully formed 120 // IPv6 packet 121 func (m *Yggdrasil) Send(p []byte) error { 122 if m.iprwc == nil { 123 return nil 124 } 125 _, _ = m.iprwc.Write(p) 126 return nil 127 } 128 129 // Send sends a packet from given buffer to Yggdrasil. From first byte up to length. 130 func (m *Yggdrasil) SendBuffer(p []byte, length int) error { 131 if m.iprwc == nil { 132 return nil 133 } 134 if len(p) < length { 135 return nil 136 } 137 _, _ = m.iprwc.Write(p[:length]) 138 return nil 139 } 140 141 // Recv waits for and reads a packet coming from Yggdrasil. It 142 // will be a fully formed IPv6 packet 143 func (m *Yggdrasil) Recv() ([]byte, error) { 144 if m.iprwc == nil { 145 return nil, nil 146 } 147 var buf [65535]byte 148 n, _ := m.iprwc.Read(buf[:]) 149 return buf[:n], nil 150 } 151 152 // Recv waits for and reads a packet coming from Yggdrasil to given buffer, returning size of packet 153 func (m *Yggdrasil) RecvBuffer(buf []byte) (int, error) { 154 if m.iprwc == nil { 155 return 0, nil 156 } 157 n, _ := m.iprwc.Read(buf) 158 return n, nil 159 } 160 161 // Stop the mobile Yggdrasil instance 162 func (m *Yggdrasil) Stop() error { 163 logger := log.New(m.log, "", 0) 164 logger.EnableLevel("info") 165 logger.Infof("Stopping the mobile Yggdrasil instance %s", "") 166 if m.multicast != nil { 167 logger.Infof("Stopping multicast %s", "") 168 if err := m.multicast.Stop(); err != nil { 169 return err 170 } 171 } 172 logger.Infof("Stopping TUN device %s", "") 173 if m.tun != nil { 174 if err := m.tun.Stop(); err != nil { 175 return err 176 } 177 } 178 logger.Infof("Stopping Yggdrasil core %s", "") 179 m.core.Stop() 180 return nil 181 } 182 183 // Retry resets the peer connection timer and tries to dial them immediately. 184 func (m *Yggdrasil) RetryPeersNow() { 185 m.core.RetryPeersNow() 186 } 187 188 // GenerateConfigJSON generates mobile-friendly configuration in JSON format 189 func GenerateConfigJSON() []byte { 190 nc := config.GenerateConfig() 191 nc.IfName = "none" 192 if json, err := json.Marshal(nc); err == nil { 193 return json 194 } 195 return nil 196 } 197 198 // GetAddressString gets the node's IPv6 address 199 func (m *Yggdrasil) GetAddressString() string { 200 ip := m.core.Address() 201 return ip.String() 202 } 203 204 // GetSubnetString gets the node's IPv6 subnet in CIDR notation 205 func (m *Yggdrasil) GetSubnetString() string { 206 subnet := m.core.Subnet() 207 return subnet.String() 208 } 209 210 // GetPublicKeyString gets the node's public key in hex form 211 func (m *Yggdrasil) GetPublicKeyString() string { 212 return hex.EncodeToString(m.core.GetSelf().Key) 213 } 214 215 // GetRoutingEntries gets the number of entries in the routing table 216 func (m *Yggdrasil) GetRoutingEntries() int { 217 return int(m.core.GetSelf().RoutingEntries) 218 } 219 220 func (m *Yggdrasil) GetPeersJSON() (result string) { 221 peers := []struct { 222 core.PeerInfo 223 IP string 224 }{} 225 for _, v := range m.core.GetPeers() { 226 var ip string 227 if v.Key != nil { 228 a := address.AddrForKey(v.Key) 229 ip = net.IP(a[:]).String() 230 } 231 peers = append(peers, struct { 232 core.PeerInfo 233 IP string 234 }{ 235 PeerInfo: v, 236 IP: ip, 237 }) 238 } 239 if res, err := json.Marshal(peers); err == nil { 240 return string(res) 241 } else { 242 return "{}" 243 } 244 } 245 246 func (m *Yggdrasil) GetPathsJSON() (result string) { 247 if res, err := json.Marshal(m.core.GetPaths()); err == nil { 248 return string(res) 249 } else { 250 return "{}" 251 } 252 } 253 254 func (m *Yggdrasil) GetTreeJSON() (result string) { 255 if res, err := json.Marshal(m.core.GetTree()); err == nil { 256 return string(res) 257 } else { 258 return "{}" 259 } 260 } 261 262 // GetMTU returns the configured node MTU. This must be called AFTER Start. 263 func (m *Yggdrasil) GetMTU() int { 264 return int(m.core.MTU()) 265 } 266 267 func GetVersion() string { 268 return version.BuildVersion() 269 }