github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/tcpip/network/hash/hash.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package hash contains utility functions for hashing. 16 package hash 17 18 import ( 19 "encoding/binary" 20 21 "github.com/metacubex/gvisor/pkg/rand" 22 "github.com/metacubex/gvisor/pkg/tcpip/header" 23 ) 24 25 var hashIV = RandN32(1)[0] 26 27 // RandN32 generates a slice of n cryptographic random 32-bit numbers. 28 func RandN32(n int) []uint32 { 29 b := make([]byte, 4*n) 30 if _, err := rand.Read(b); err != nil { 31 panic("unable to get random numbers: " + err.Error()) 32 } 33 r := make([]uint32, n) 34 for i := range r { 35 r[i] = binary.LittleEndian.Uint32(b[4*i : (4*i + 4)]) 36 } 37 return r 38 } 39 40 // Hash3Words calculates the Jenkins hash of 3 32-bit words. This is adapted 41 // from linux. 42 func Hash3Words(a, b, c, initval uint32) uint32 { 43 const iv = 0xdeadbeef + (3 << 2) 44 initval += iv 45 46 a += initval 47 b += initval 48 c += initval 49 50 c ^= b 51 c -= rol32(b, 14) 52 a ^= c 53 a -= rol32(c, 11) 54 b ^= a 55 b -= rol32(a, 25) 56 c ^= b 57 c -= rol32(b, 16) 58 a ^= c 59 a -= rol32(c, 4) 60 b ^= a 61 b -= rol32(a, 14) 62 c ^= b 63 c -= rol32(b, 24) 64 65 return c 66 } 67 68 // IPv4FragmentHash computes the hash of the IPv4 fragment as suggested in RFC 791. 69 func IPv4FragmentHash(h header.IPv4) uint32 { 70 x := uint32(h.ID())<<16 | uint32(h.Protocol()) 71 t := h.SourceAddress().As4() 72 y := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 73 t = h.DestinationAddress().As4() 74 z := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 75 return Hash3Words(x, y, z, hashIV) 76 } 77 78 // IPv6FragmentHash computes the hash of the ipv6 fragment. 79 // Unlike IPv4, the protocol is not used to compute the hash. 80 // RFC 2640 (sec 4.5) is not very sharp on this aspect. 81 // As a reference, also Linux ignores the protocol to compute 82 // the hash (inet6_hash_frag). 83 func IPv6FragmentHash(h header.IPv6, id uint32) uint32 { 84 t := h.SourceAddress().As16() 85 y := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 86 t = h.DestinationAddress().As16() 87 z := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 88 return Hash3Words(id, y, z, hashIV) 89 } 90 91 func rol32(v, shift uint32) uint32 { 92 return (v << shift) | (v >> ((-shift) & 31)) 93 }