github.com/iDigitalFlame/xmt@v0.5.4/com/c_comapt13.go (about) 1 //go:build !go1.13 2 // +build !go1.13 3 4 // Copyright (C) 2020 - 2023 iDigitalFlame 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 // 19 20 package com 21 22 import ( 23 "bytes" 24 "context" 25 "net" 26 "syscall" 27 "time" 28 29 // Importing unsafe to use linkname 30 _ "unsafe" 31 ) 32 33 type netConfig struct{} 34 35 //go:linkname parseIPv4 net.parseIPv4 36 func parseIPv4(s string) net.IP 37 38 func newListenConfig(_ time.Duration) netConfig { 39 return netConfig{} 40 } 41 42 //go:linkname parseIPv6 net.parseIPv6 43 func parseIPv6(s string, a bool) (net.IP, string) 44 func resolveAddrList(x context.Context, n, s string) ([]net.Addr, error) { 45 a, _, err := parseNetwork(x, n, true) 46 if err != nil { 47 return nil, err 48 } 49 if len(a) == 0 { 50 return nil, syscall.EINVAL 51 } 52 if (a[0] == 'u' || a[0] == 'U') && len(a) >= 4 && (a[3] == 'x' || a[3] == 'X') { 53 v, err := net.ResolveUnixAddr(a, s) 54 if err != nil { 55 return nil, err 56 } 57 return []net.Addr{v}, nil 58 } 59 return internetAddrList(x, a, s) 60 } 61 func internetAddrList(x context.Context, n, a string) ([]net.Addr, error) { 62 var ( 63 v int 64 err error 65 h, p string 66 ) 67 switch n[0] { 68 case 'i', 'I': 69 if len(a) == 0 { 70 break 71 } 72 h = a 73 case 't', 'T', 'u', 'U': 74 if len(a) == 0 { 75 break 76 } 77 if h, p, err = net.SplitHostPort(a); err != nil { 78 return nil, err 79 } 80 if v, err = net.DefaultResolver.LookupPort(x, n, p); err != nil { 81 return nil, err 82 } 83 default: 84 return nil, syscall.EINVAL 85 } 86 if len(h) == 0 { 87 switch n[0] { 88 case 't', 'T': 89 return []net.Addr{&net.TCPAddr{Port: v}}, nil 90 case 'u', 'U': 91 return []net.Addr{&net.UDPAddr{Port: v}}, nil 92 case 'i', 'I': 93 return []net.Addr{&net.IPAddr{}}, nil 94 } 95 return nil, syscall.EINVAL 96 } 97 var i []net.IPAddr 98 if k := parseIPv4(h); k != nil { 99 i = []net.IPAddr{{IP: k}} 100 } else if k, z := parseIPv6(h, true); k != nil { 101 if i = []net.IPAddr{{IP: k, Zone: z}}; len(k) == len(net.IPv6unspecified) && bytes.Compare(net.IPv6unspecified, k) == 0 { 102 i = append(i, net.IPAddr{IP: net.IPv4zero}) 103 } 104 } else if i, err = net.DefaultResolver.LookupIPAddr(x, h); err != nil { 105 return nil, err 106 } 107 var ( 108 o = make([]net.Addr, 0, len(i)) 109 y, u = n[len(n)-1] == '4', n[len(n)-1] == '6' 110 ) 111 loop: 112 for r := range i { 113 switch { 114 case !y && !u: 115 case i[r].IP.To4() != nil: 116 case len(i[r].IP) == net.IPv6len && i[r].IP.To4() == nil: 117 default: 118 continue loop 119 } 120 switch n[0] { 121 case 't', 'T': 122 o = append(o, &net.TCPAddr{IP: i[r].IP, Port: v, Zone: i[r].Zone}) 123 case 'u', 'U': 124 o = append(o, &net.UDPAddr{IP: i[r].IP, Port: v, Zone: i[r].Zone}) 125 case 'i', 'I': 126 o = append(o, &net.IPAddr{IP: i[r].IP, Zone: i[r].Zone}) 127 default: 128 return nil, syscall.EINVAL 129 } 130 } 131 if len(o) == 0 { 132 return nil, syscall.EADDRNOTAVAIL 133 } 134 return o, nil 135 } 136 137 //go:linkname parseNetwork net.parseNetwork 138 func parseNetwork(x context.Context, n string, p bool) (string, int, error) 139 func (netConfig) Listen(x context.Context, n, a string) (net.Listener, error) { 140 v, err := resolveAddrList(x, n, a) 141 if err != nil { 142 return nil, err 143 } 144 for i := range v { 145 switch k := v[i].(type) { 146 case *net.TCPAddr: 147 switch { 148 case len(n) == 3 && (n[0] == 't' || n[0] == 'T') && (n[1] == 'c' || n[1] == 'C') && (n[2] == 'p' || n[2] == 'P'): 149 case len(n) == 4 && (n[0] == 't' || n[0] == 'T') && (n[1] == 'c' || n[1] == 'C') && (n[2] == 'p' || n[2] == 'P') && (n[3] == '4' || n[3] == '6'): 150 default: 151 return nil, syscall.EINVAL 152 } 153 l, err := listenTCP(x, n, k) 154 if err != nil { 155 return nil, err 156 } 157 return l, nil 158 case *net.UnixAddr: 159 switch { 160 case len(n) == 4 && (n[0] == 'u' || n[0] == 'U') && (n[3] == 'x' || n[3] == 'X'): 161 case len(n) == 8 && (n[0] == 'u' || n[0] == 'U') && (n[7] == 'm' || n[7] == 'M'): 162 default: 163 return nil, syscall.EINVAL 164 } 165 l, err := listenUnix(x, n, k) 166 if err != nil { 167 return nil, err 168 } 169 return l, nil 170 } 171 } 172 return nil, syscall.EADDRNOTAVAIL 173 } 174 175 //go:linkname listenIP net.listenIP 176 func listenIP(x context.Context, n string, a *net.IPAddr) (*net.IPConn, error) 177 178 //go:linkname listenUDP net.listenUDP 179 func listenUDP(x context.Context, n string, a *net.UDPAddr) (*net.UDPConn, error) 180 181 //go:linkname listenTCP net.listenTCP 182 func listenTCP(x context.Context, n string, a *net.TCPAddr) (*net.TCPListener, error) 183 func (netConfig) ListenPacket(x context.Context, n, a string) (net.PacketConn, error) { 184 v, err := resolveAddrList(x, n, a) 185 if err != nil { 186 return nil, err 187 } 188 for i := range v { 189 switch k := v[i].(type) { 190 case *net.IPAddr: 191 l, err := listenIP(x, n, k) 192 if err != nil { 193 return nil, err 194 } 195 return l, nil 196 case *net.UDPAddr: 197 switch { 198 case len(n) == 3 && (n[0] == 'u' || n[0] == 'U') && (n[1] == 'd' || n[1] == 'D') && (n[2] == 'p' || n[2] == 'P'): 199 case len(n) == 4 && (n[0] == 'u' || n[0] == 'U') && (n[1] == 'd' || n[1] == 'D') && (n[2] == 'p' || n[2] == 'P') && (n[3] == '4' || n[3] == '6'): 200 default: 201 return nil, syscall.EINVAL 202 } 203 l, err := listenUDP(x, n, k) 204 if err != nil { 205 return nil, err 206 } 207 return l, nil 208 case *net.UnixAddr: 209 if len(n) != 8 || (n[0] != 'u' && n[0] != 'U') || (n[7] != 'm' && n[7] != 'M') { 210 return nil, syscall.EINVAL 211 } 212 l, err := listenUnixgram(x, n, k) 213 if err != nil { 214 return nil, err 215 } 216 return l, nil 217 } 218 } 219 return nil, syscall.EADDRNOTAVAIL 220 } 221 222 //go:linkname listenUnix net.listenUnix 223 func listenUnix(x context.Context, n string, a *net.UnixAddr) (*net.UnixListener, error) 224 225 //go:linkname listenUnixgram net.listenUnixgram 226 func listenUnixgram(x context.Context, n string, a *net.UnixAddr) (*net.UnixConn, error)