bep40.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package torrent
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "hash/crc32"
  8. "net"
  9. )
  10. var table = crc32.MakeTable(crc32.Castagnoli)
  11. type peerPriority = uint32
  12. func sameSubnet(ones, bits int, a, b net.IP) bool {
  13. mask := net.CIDRMask(ones, bits)
  14. return a.Mask(mask).Equal(b.Mask(mask))
  15. }
  16. func ipv4Mask(a, b net.IP) net.IPMask {
  17. if !sameSubnet(16, 32, a, b) {
  18. return net.IPv4Mask(0xff, 0xff, 0x55, 0x55)
  19. }
  20. if !sameSubnet(24, 32, a, b) {
  21. return net.IPv4Mask(0xff, 0xff, 0xff, 0x55)
  22. }
  23. return net.IPv4Mask(0xff, 0xff, 0xff, 0xff)
  24. }
  25. func mask(prefix, bytes int) net.IPMask {
  26. ret := make(net.IPMask, bytes)
  27. for i := range ret {
  28. ret[i] = 0x55
  29. }
  30. for i := 0; i < prefix; i++ {
  31. ret[i] = 0xff
  32. }
  33. return ret
  34. }
  35. func ipv6Mask(a, b net.IP) net.IPMask {
  36. for i := 6; i <= 16; i++ {
  37. if !sameSubnet(i*8, 128, a, b) {
  38. return mask(i, 16)
  39. }
  40. }
  41. panic(fmt.Sprintf("%s %s", a, b))
  42. }
  43. func bep40PriorityBytes(a, b IpPort) ([]byte, error) {
  44. if a.IP.Equal(b.IP) {
  45. var ret [4]byte
  46. binary.BigEndian.PutUint16(ret[0:2], a.Port)
  47. binary.BigEndian.PutUint16(ret[2:4], b.Port)
  48. return ret[:], nil
  49. }
  50. if a4, b4 := a.IP.To4(), b.IP.To4(); a4 != nil && b4 != nil {
  51. m := ipv4Mask(a.IP, b.IP)
  52. return append(a4.Mask(m), b4.Mask(m)...), nil
  53. }
  54. if a6, b6 := a.IP.To16(), b.IP.To16(); a6 != nil && b6 != nil {
  55. m := ipv6Mask(a.IP, b.IP)
  56. return append(a6.Mask(m), b6.Mask(m)...), nil
  57. }
  58. return nil, errors.New("incomparable IPs")
  59. }
  60. func bep40Priority(a, b IpPort) (peerPriority, error) {
  61. bs, err := bep40PriorityBytes(a, b)
  62. if err != nil {
  63. return 0, err
  64. }
  65. i := len(bs) / 2
  66. _a, _b := bs[:i], bs[i:]
  67. if bytes.Compare(_a, _b) > 0 {
  68. bs = append(_b, _a...)
  69. }
  70. return crc32.Checksum(bs, table), nil
  71. }
  72. func bep40PriorityIgnoreError(a, b IpPort) peerPriority {
  73. prio, _ := bep40Priority(a, b)
  74. return prio
  75. }