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)