github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/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/ttpreport/gvisor-ligolo/pkg/rand"
    22  	"github.com/ttpreport/gvisor-ligolo/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  }