github.com/pawelgaczynski/gain@v0.4.0-alpha.0.20230821120126-41f1e60a18da/pkg/socket/socktoaddr.go (about) 1 // Copyright (c) 2023 Paweł Gaczyński 2 // Copyright (c) 2019 Andy Pan 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package socket 17 18 import ( 19 "net" 20 "syscall" 21 "unsafe" 22 23 bsPool "github.com/pawelgaczynski/gain/pkg/pool/byteslice" 24 ) 25 26 var ipv4InIPv6Prefix = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff} 27 28 const ( 29 netIPBytesSize = 16 30 sockAddrPortBitOffset = 8 31 decimalBase = 10 32 int32size = 32 33 ) 34 35 func RawAnyToSockaddrInet4(rsa *syscall.RawSockaddrAny) (*syscall.SockaddrInet4, error) { 36 if rsa == nil { 37 return nil, syscall.EINVAL 38 } 39 40 if rsa.Addr.Family != syscall.AF_INET { 41 return nil, syscall.EAFNOSUPPORT 42 } 43 44 rsaPointer := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa)) 45 sockAddr := new(syscall.SockaddrInet4) 46 p := (*[2]byte)(unsafe.Pointer(&rsaPointer.Port)) 47 48 sockAddr.Port = int(p[0])<<sockAddrPortBitOffset + int(p[1]) 49 for i := 0; i < len(sockAddr.Addr); i++ { 50 sockAddr.Addr[i] = rsaPointer.Addr[i] 51 } 52 53 return sockAddr, nil 54 } 55 56 // SockaddrToTCPOrUnixAddr converts a Sockaddr to a net.TCPAddr or net.UnixAddr. 57 // Returns nil if conversion fails. 58 func SockaddrToTCPOrUnixAddr(sysSockAddr syscall.Sockaddr) net.Addr { 59 switch sockAddr := sysSockAddr.(type) { 60 case *syscall.SockaddrInet4: 61 ip := sockaddrInet4ToIP(sockAddr) 62 63 return &net.TCPAddr{IP: ip, Port: sockAddr.Port} 64 65 case *syscall.SockaddrInet6: 66 ip, zone := sockaddrInet6ToIPAndZone(sockAddr) 67 68 return &net.TCPAddr{IP: ip, Port: sockAddr.Port, Zone: zone} 69 70 case *syscall.SockaddrUnix: 71 return &net.UnixAddr{Name: sockAddr.Name, Net: "unix"} 72 } 73 74 return nil 75 } 76 77 // SockaddrToUDPAddr converts a Sockaddr to a net.UDPAddr 78 // Returns nil if conversion fails. 79 func SockaddrToUDPAddr(sysSockAddr syscall.Sockaddr) net.Addr { 80 switch sockAddr := sysSockAddr.(type) { 81 case *syscall.SockaddrInet4: 82 ip := sockaddrInet4ToIP(sockAddr) 83 84 return &net.UDPAddr{IP: ip, Port: sockAddr.Port} 85 86 case *syscall.SockaddrInet6: 87 ip, zone := sockaddrInet6ToIPAndZone(sockAddr) 88 89 return &net.UDPAddr{IP: ip, Port: sockAddr.Port, Zone: zone} 90 } 91 92 return nil 93 } 94 95 // sockaddrInet4ToIPAndZone converts a SockaddrInet4 to a net.IP. 96 // It returns nil if conversion fails. 97 func sockaddrInet4ToIP(sa *syscall.SockaddrInet4) net.IP { 98 ip := bsPool.Get(netIPBytesSize) 99 // ipv4InIPv6Prefix 100 copy(ip[0:12], ipv4InIPv6Prefix) 101 copy(ip[12:16], sa.Addr[:]) 102 103 return ip 104 } 105 106 // sockaddrInet6ToIPAndZone converts a SockaddrInet6 to a net.IP with IPv6 Zone. 107 // It returns nil if conversion fails. 108 func sockaddrInet6ToIPAndZone(sa *syscall.SockaddrInet6) (net.IP, string) { 109 ip := bsPool.Get(netIPBytesSize) 110 copy(ip, sa.Addr[:]) 111 112 return ip, ip6ZoneToString(int(sa.ZoneId)) 113 } 114 115 // ip6ZoneToString converts an IP6 Zone unix int to a net string 116 // returns "" if zone is 0. 117 func ip6ZoneToString(zone int) string { 118 if zone == 0 { 119 return "" 120 } 121 122 if ifi, err := net.InterfaceByIndex(zone); err == nil { 123 return ifi.Name 124 } 125 126 return int2decimal(uint(zone)) 127 } 128 129 // BytesToString converts byte slice to a string without memory allocation. 130 // 131 // Note it may break if the implementation of string or slice header changes in the future go versions. 132 func BytesToString(b []byte) string { 133 /* #nosec G103 */ 134 return *(*string)(unsafe.Pointer(&b)) 135 } 136 137 // Convert int to decimal string. 138 func int2decimal(value uint) string { 139 if value == 0 { 140 return "0" 141 } 142 143 // Assemble decimal in reverse order. 144 byteSlice := bsPool.Get(int32size) 145 bytesSliceLen := len(byteSlice) 146 147 for ; value > 0; value /= 10 { 148 bytesSliceLen-- 149 byteSlice[bytesSliceLen] = byte(value%decimalBase) + '0' 150 } 151 152 return BytesToString(byteSlice[bytesSliceLen:]) 153 }