github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/swarm.go (about) 1 package commands 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "path" 9 "sort" 10 11 cmds "github.com/ipfs/go-ipfs/commands" 12 swarm "github.com/ipfs/go-ipfs/p2p/net/swarm" 13 peer "github.com/ipfs/go-ipfs/p2p/peer" 14 iaddr "github.com/ipfs/go-ipfs/util/ipfsaddr" 15 16 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 17 mafilter "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter" 18 ) 19 20 type stringList struct { 21 Strings []string 22 } 23 24 type addrMap struct { 25 Addrs map[string][]string 26 } 27 28 var SwarmCmd = &cmds.Command{ 29 Helptext: cmds.HelpText{ 30 Tagline: "swarm inspection tool", 31 Synopsis: ` 32 ipfs swarm peers - List peers with open connections 33 ipfs swarm addrs - List known addresses. Useful to debug. 34 ipfs swarm connect <address> - Open connection to a given address 35 ipfs swarm disconnect <address> - Close connection to a given address 36 ipfs swarm filters - Manipulate filters addresses 37 `, 38 ShortDescription: ` 39 ipfs swarm is a tool to manipulate the network swarm. The swarm is the 40 component that opens, listens for, and maintains connections to other 41 ipfs peers in the internet. 42 `, 43 }, 44 Subcommands: map[string]*cmds.Command{ 45 "peers": swarmPeersCmd, 46 "addrs": swarmAddrsCmd, 47 "connect": swarmConnectCmd, 48 "disconnect": swarmDisconnectCmd, 49 "filters": swarmFiltersCmd, 50 }, 51 } 52 53 var swarmPeersCmd = &cmds.Command{ 54 Helptext: cmds.HelpText{ 55 Tagline: "List peers with open connections", 56 ShortDescription: ` 57 ipfs swarm peers lists the set of peers this node is connected to. 58 `, 59 }, 60 Run: func(req cmds.Request, res cmds.Response) { 61 62 log.Debug("ipfs swarm peers") 63 n, err := req.InvocContext().GetNode() 64 if err != nil { 65 res.SetError(err, cmds.ErrNormal) 66 return 67 } 68 69 if n.PeerHost == nil { 70 res.SetError(errNotOnline, cmds.ErrClient) 71 return 72 } 73 74 conns := n.PeerHost.Network().Conns() 75 addrs := make([]string, len(conns)) 76 for i, c := range conns { 77 pid := c.RemotePeer() 78 addr := c.RemoteMultiaddr() 79 addrs[i] = fmt.Sprintf("%s/ipfs/%s", addr, pid.Pretty()) 80 } 81 82 sort.Sort(sort.StringSlice(addrs)) 83 res.SetOutput(&stringList{addrs}) 84 }, 85 Marshalers: cmds.MarshalerMap{ 86 cmds.Text: stringListMarshaler, 87 }, 88 Type: stringList{}, 89 } 90 91 var swarmAddrsCmd = &cmds.Command{ 92 Helptext: cmds.HelpText{ 93 Tagline: "List known addresses. Useful to debug.", 94 ShortDescription: ` 95 ipfs swarm addrs lists all addresses this node is aware of. 96 `, 97 }, 98 Subcommands: map[string]*cmds.Command{ 99 "local": swarmAddrsLocalCmd, 100 }, 101 Run: func(req cmds.Request, res cmds.Response) { 102 103 n, err := req.InvocContext().GetNode() 104 if err != nil { 105 res.SetError(err, cmds.ErrNormal) 106 return 107 } 108 109 if n.PeerHost == nil { 110 res.SetError(errNotOnline, cmds.ErrClient) 111 return 112 } 113 114 addrs := make(map[string][]string) 115 ps := n.PeerHost.Network().Peerstore() 116 for _, p := range ps.Peers() { 117 s := p.Pretty() 118 for _, a := range ps.Addrs(p) { 119 addrs[s] = append(addrs[s], a.String()) 120 } 121 sort.Sort(sort.StringSlice(addrs[s])) 122 } 123 124 res.SetOutput(&addrMap{Addrs: addrs}) 125 }, 126 Marshalers: cmds.MarshalerMap{ 127 cmds.Text: func(res cmds.Response) (io.Reader, error) { 128 m, ok := res.Output().(*addrMap) 129 if !ok { 130 return nil, errors.New("failed to cast map[string]string") 131 } 132 133 // sort the ids first 134 ids := make([]string, 0, len(m.Addrs)) 135 for p := range m.Addrs { 136 ids = append(ids, p) 137 } 138 sort.Sort(sort.StringSlice(ids)) 139 140 buf := new(bytes.Buffer) 141 for _, p := range ids { 142 paddrs := m.Addrs[p] 143 buf.WriteString(fmt.Sprintf("%s (%d)\n", p, len(paddrs))) 144 for _, addr := range paddrs { 145 buf.WriteString("\t" + addr + "\n") 146 } 147 } 148 return buf, nil 149 }, 150 }, 151 Type: addrMap{}, 152 } 153 154 var swarmAddrsLocalCmd = &cmds.Command{ 155 Helptext: cmds.HelpText{ 156 Tagline: "List local addresses.", 157 ShortDescription: ` 158 ipfs swarm addrs local lists all local addresses the node is listening on. 159 `, 160 }, 161 Options: []cmds.Option{ 162 cmds.BoolOption("id", "Show peer ID in addresses"), 163 }, 164 Run: func(req cmds.Request, res cmds.Response) { 165 166 n, err := req.InvocContext().GetNode() 167 if err != nil { 168 res.SetError(err, cmds.ErrNormal) 169 return 170 } 171 172 if n.PeerHost == nil { 173 res.SetError(errNotOnline, cmds.ErrClient) 174 return 175 } 176 177 showid, _, _ := req.Option("id").Bool() 178 id := n.Identity.Pretty() 179 180 var addrs []string 181 for _, addr := range n.PeerHost.Addrs() { 182 saddr := addr.String() 183 if showid { 184 saddr = path.Join(saddr, "ipfs", id) 185 } 186 addrs = append(addrs, saddr) 187 } 188 sort.Sort(sort.StringSlice(addrs)) 189 190 res.SetOutput(&stringList{addrs}) 191 }, 192 Type: stringList{}, 193 Marshalers: cmds.MarshalerMap{ 194 cmds.Text: stringListMarshaler, 195 }, 196 } 197 198 var swarmConnectCmd = &cmds.Command{ 199 Helptext: cmds.HelpText{ 200 Tagline: "Open connection to a given address", 201 ShortDescription: ` 202 'ipfs swarm connect' opens a new direct connection to a peer address. 203 204 The address format is an ipfs multiaddr: 205 206 ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ 207 `, 208 }, 209 Arguments: []cmds.Argument{ 210 cmds.StringArg("address", true, true, "address of peer to connect to").EnableStdin(), 211 }, 212 Run: func(req cmds.Request, res cmds.Response) { 213 ctx := req.Context() 214 215 n, err := req.InvocContext().GetNode() 216 if err != nil { 217 res.SetError(err, cmds.ErrNormal) 218 return 219 } 220 221 addrs := req.Arguments() 222 223 if n.PeerHost == nil { 224 res.SetError(errNotOnline, cmds.ErrClient) 225 return 226 } 227 228 pis, err := peersWithAddresses(addrs) 229 if err != nil { 230 res.SetError(err, cmds.ErrNormal) 231 return 232 } 233 234 output := make([]string, len(pis)) 235 for i, pi := range pis { 236 output[i] = "connect " + pi.ID.Pretty() 237 238 err := n.PeerHost.Connect(ctx, pi) 239 if err != nil { 240 output[i] += " failure: " + err.Error() 241 } else { 242 output[i] += " success" 243 } 244 } 245 246 res.SetOutput(&stringList{output}) 247 }, 248 Marshalers: cmds.MarshalerMap{ 249 cmds.Text: stringListMarshaler, 250 }, 251 Type: stringList{}, 252 } 253 254 var swarmDisconnectCmd = &cmds.Command{ 255 Helptext: cmds.HelpText{ 256 Tagline: "Close connection to a given address", 257 ShortDescription: ` 258 'ipfs swarm disconnect' closes a connection to a peer address. The address format 259 is an ipfs multiaddr: 260 261 ipfs swarm disconnect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ 262 `, 263 }, 264 Arguments: []cmds.Argument{ 265 cmds.StringArg("address", true, true, "address of peer to connect to").EnableStdin(), 266 }, 267 Run: func(req cmds.Request, res cmds.Response) { 268 n, err := req.InvocContext().GetNode() 269 if err != nil { 270 res.SetError(err, cmds.ErrNormal) 271 return 272 } 273 274 addrs := req.Arguments() 275 276 if n.PeerHost == nil { 277 res.SetError(errNotOnline, cmds.ErrClient) 278 return 279 } 280 281 iaddrs, err := parseAddresses(addrs) 282 if err != nil { 283 res.SetError(err, cmds.ErrNormal) 284 return 285 } 286 287 output := make([]string, len(iaddrs)) 288 for i, addr := range iaddrs { 289 taddr := addr.Transport() 290 output[i] = "disconnect " + addr.ID().Pretty() 291 292 found := false 293 conns := n.PeerHost.Network().ConnsToPeer(addr.ID()) 294 for _, conn := range conns { 295 if !conn.RemoteMultiaddr().Equal(taddr) { 296 log.Debug("it's not", conn.RemoteMultiaddr(), taddr) 297 continue 298 } 299 300 if err := conn.Close(); err != nil { 301 output[i] += " failure: " + err.Error() 302 } else { 303 output[i] += " success" 304 } 305 found = true 306 break 307 } 308 309 if !found { 310 output[i] += " failure: conn not found" 311 } 312 } 313 res.SetOutput(&stringList{output}) 314 }, 315 Marshalers: cmds.MarshalerMap{ 316 cmds.Text: stringListMarshaler, 317 }, 318 Type: stringList{}, 319 } 320 321 func stringListMarshaler(res cmds.Response) (io.Reader, error) { 322 list, ok := res.Output().(*stringList) 323 if !ok { 324 return nil, errors.New("failed to cast []string") 325 } 326 327 buf := new(bytes.Buffer) 328 for _, s := range list.Strings { 329 buf.WriteString(s) 330 buf.WriteString("\n") 331 } 332 return buf, nil 333 } 334 335 // parseAddresses is a function that takes in a slice of string peer addresses 336 // (multiaddr + peerid) and returns slices of multiaddrs and peerids. 337 func parseAddresses(addrs []string) (iaddrs []iaddr.IPFSAddr, err error) { 338 iaddrs = make([]iaddr.IPFSAddr, len(addrs)) 339 for i, saddr := range addrs { 340 iaddrs[i], err = iaddr.ParseString(saddr) 341 if err != nil { 342 return nil, cmds.ClientError("invalid peer address: " + err.Error()) 343 } 344 } 345 return 346 } 347 348 // peersWithAddresses is a function that takes in a slice of string peer addresses 349 // (multiaddr + peerid) and returns a slice of properly constructed peers 350 func peersWithAddresses(addrs []string) (pis []peer.PeerInfo, err error) { 351 iaddrs, err := parseAddresses(addrs) 352 if err != nil { 353 return nil, err 354 } 355 356 for _, iaddr := range iaddrs { 357 pis = append(pis, peer.PeerInfo{ 358 ID: iaddr.ID(), 359 Addrs: []ma.Multiaddr{iaddr.Transport()}, 360 }) 361 } 362 return pis, nil 363 } 364 365 var swarmFiltersCmd = &cmds.Command{ 366 Helptext: cmds.HelpText{ 367 Tagline: "Manipulate address filters", 368 ShortDescription: ` 369 'ipfs swarm filters' will list out currently applied filters. Its subcommands can be used 370 to add or remove said filters. Filters are specified using the multiaddr-filter format: 371 372 example: 373 374 /ip4/192.168.0.0/ipcidr/16 375 376 Where the above is equivalent to the standard CIDR: 377 378 192.168.0.0/16 379 380 Filters default to those specified under the "Swarm.AddrFilters" config key. 381 `, 382 }, 383 Subcommands: map[string]*cmds.Command{ 384 "add": swarmFiltersAddCmd, 385 "rm": swarmFiltersRmCmd, 386 }, 387 Run: func(req cmds.Request, res cmds.Response) { 388 n, err := req.InvocContext().GetNode() 389 if err != nil { 390 res.SetError(err, cmds.ErrNormal) 391 return 392 } 393 394 if n.PeerHost == nil { 395 res.SetError(errNotOnline, cmds.ErrNormal) 396 return 397 } 398 399 snet, ok := n.PeerHost.Network().(*swarm.Network) 400 if !ok { 401 res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal) 402 return 403 } 404 405 var output []string 406 for _, f := range snet.Filters.Filters() { 407 s, err := mafilter.ConvertIPNet(f) 408 if err != nil { 409 res.SetError(err, cmds.ErrNormal) 410 return 411 } 412 output = append(output, s) 413 } 414 res.SetOutput(&stringList{output}) 415 }, 416 Marshalers: cmds.MarshalerMap{ 417 cmds.Text: stringListMarshaler, 418 }, 419 Type: stringList{}, 420 } 421 422 var swarmFiltersAddCmd = &cmds.Command{ 423 Helptext: cmds.HelpText{ 424 Tagline: "add an address filter", 425 ShortDescription: ` 426 'ipfs swarm filters add' will add an address filter to the daemons swarm. 427 Filters applied this way will not persist daemon reboots, to acheive that, 428 add your filters to the ipfs config file. 429 `, 430 }, 431 Arguments: []cmds.Argument{ 432 cmds.StringArg("address", true, true, "multiaddr to filter").EnableStdin(), 433 }, 434 Run: func(req cmds.Request, res cmds.Response) { 435 n, err := req.InvocContext().GetNode() 436 if err != nil { 437 res.SetError(err, cmds.ErrNormal) 438 return 439 } 440 441 if n.PeerHost == nil { 442 res.SetError(errNotOnline, cmds.ErrNormal) 443 return 444 } 445 446 snet, ok := n.PeerHost.Network().(*swarm.Network) 447 if !ok { 448 res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal) 449 return 450 } 451 452 for _, arg := range req.Arguments() { 453 mask, err := mafilter.NewMask(arg) 454 if err != nil { 455 res.SetError(err, cmds.ErrNormal) 456 return 457 } 458 459 snet.Filters.AddDialFilter(mask) 460 } 461 }, 462 } 463 464 var swarmFiltersRmCmd = &cmds.Command{ 465 Helptext: cmds.HelpText{ 466 Tagline: "remove an address filter", 467 ShortDescription: ` 468 'ipfs swarm filters rm' will remove an address filter from the daemons swarm. 469 Filters removed this way will not persist daemon reboots, to acheive that, 470 remove your filters from the ipfs config file. 471 `, 472 }, 473 Arguments: []cmds.Argument{ 474 cmds.StringArg("address", true, true, "multiaddr filter to remove").EnableStdin(), 475 }, 476 Run: func(req cmds.Request, res cmds.Response) { 477 n, err := req.InvocContext().GetNode() 478 if err != nil { 479 res.SetError(err, cmds.ErrNormal) 480 return 481 } 482 483 if n.PeerHost == nil { 484 res.SetError(errNotOnline, cmds.ErrNormal) 485 return 486 } 487 488 snet, ok := n.PeerHost.Network().(*swarm.Network) 489 if !ok { 490 res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal) 491 return 492 } 493 494 if req.Arguments()[0] == "all" || req.Arguments()[0] == "*" { 495 fs := snet.Filters.Filters() 496 for _, f := range fs { 497 snet.Filters.Remove(f) 498 } 499 return 500 } 501 502 for _, arg := range req.Arguments() { 503 mask, err := mafilter.NewMask(arg) 504 if err != nil { 505 res.SetError(err, cmds.ErrNormal) 506 return 507 } 508 509 snet.Filters.Remove(mask) 510 } 511 }, 512 }