| // Copyright 2018 The gVisor Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // Package hash contains utility functions for hashing. |
| package hash |
| |
| import ( |
| "encoding/binary" |
| |
| "gvisor.dev/gvisor/pkg/rand" |
| "gvisor.dev/gvisor/pkg/tcpip/header" |
| ) |
| |
| var hashIV = RandN32(1)[0] |
| |
| // RandN32 generates a slice of n cryptographic random 32-bit numbers. |
| func RandN32(n int) []uint32 { |
| b := make([]byte, 4*n) |
| if _, err := rand.Read(b); err != nil { |
| panic("unable to get random numbers: " + err.Error()) |
| } |
| r := make([]uint32, n) |
| for i := range r { |
| r[i] = binary.LittleEndian.Uint32(b[4*i : (4*i + 4)]) |
| } |
| return r |
| } |
| |
| // Hash3Words calculates the Jenkins hash of 3 32-bit words. This is adapted |
| // from linux. |
| func Hash3Words(a, b, c, initval uint32) uint32 { |
| const iv = 0xdeadbeef + (3 << 2) |
| initval += iv |
| |
| a += initval |
| b += initval |
| c += initval |
| |
| c ^= b |
| c -= rol32(b, 14) |
| a ^= c |
| a -= rol32(c, 11) |
| b ^= a |
| b -= rol32(a, 25) |
| c ^= b |
| c -= rol32(b, 16) |
| a ^= c |
| a -= rol32(c, 4) |
| b ^= a |
| b -= rol32(a, 14) |
| c ^= b |
| c -= rol32(b, 24) |
| |
| return c |
| } |
| |
| // IPv4FragmentHash computes the hash of the IPv4 fragment as suggested in RFC 791. |
| func IPv4FragmentHash(h header.IPv4) uint32 { |
| x := uint32(h.ID())<<16 | uint32(h.Protocol()) |
| t := h.SourceAddress() |
| y := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 |
| t = h.DestinationAddress() |
| z := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 |
| return Hash3Words(x, y, z, hashIV) |
| } |
| |
| // IPv6FragmentHash computes the hash of the ipv6 fragment. |
| // Unlike IPv4, the protocol is not used to compute the hash. |
| // RFC 2640 (sec 4.5) is not very sharp on this aspect. |
| // As a reference, also Linux ignores the protocol to compute |
| // the hash (inet6_hash_frag). |
| func IPv6FragmentHash(h header.IPv6, id uint32) uint32 { |
| t := h.SourceAddress() |
| y := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 |
| t = h.DestinationAddress() |
| z := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 |
| return Hash3Words(id, y, z, hashIV) |
| } |
| |
| func rol32(v, shift uint32) uint32 { |
| return (v << shift) | (v >> ((-shift) & 31)) |
| } |