github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/internal/x/net/lif/link.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build solaris
     6  
     7  package lif
     8  
     9  import "unsafe"
    10  
    11  // A Link represents logical data link information.
    12  //
    13  // It also represents base information for logical network interface.
    14  // On Solaris, each logical network interface represents network layer
    15  // adjacency information and the interface has a only single network
    16  // address or address pair for tunneling. It's usual that multiple
    17  // logical network interfaces share the same logical data link.
    18  type Link struct {
    19  	Name  string // name, equivalent to IP interface name
    20  	Index int    // index, equivalent to IP interface index
    21  	Type  int    // type
    22  	Flags int    // flags
    23  	MTU   int    // maximum transmission unit, basically link MTU but may differ between IP address families
    24  	Addr  []byte // address
    25  }
    26  
    27  func (ll *Link) fetch(s uintptr) {
    28  	var lifr lifreq
    29  	for i := 0; i < len(ll.Name); i++ {
    30  		lifr.Name[i] = int8(ll.Name[i])
    31  	}
    32  	ioc := int64(sysSIOCGLIFINDEX)
    33  	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
    34  		ll.Index = int(nativeEndian.Uint32(lifr.Lifru[:4]))
    35  	}
    36  	ioc = int64(sysSIOCGLIFFLAGS)
    37  	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
    38  		ll.Flags = int(nativeEndian.Uint64(lifr.Lifru[:8]))
    39  	}
    40  	ioc = int64(sysSIOCGLIFMTU)
    41  	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
    42  		ll.MTU = int(nativeEndian.Uint32(lifr.Lifru[:4]))
    43  	}
    44  	switch ll.Type {
    45  	case sysIFT_IPV4, sysIFT_IPV6, sysIFT_6TO4:
    46  	default:
    47  		ioc = int64(sysSIOCGLIFHWADDR)
    48  		if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
    49  			ll.Addr, _ = parseLinkAddr(lifr.Lifru[4:])
    50  		}
    51  	}
    52  }
    53  
    54  // Links returns a list of logical data links.
    55  //
    56  // The provided af must be an address family and name must be a data
    57  // link name. The zero value of af or name means a wildcard.
    58  func Links(af int, name string) ([]Link, error) {
    59  	eps, err := newEndpoints(af)
    60  	if len(eps) == 0 {
    61  		return nil, err
    62  	}
    63  	defer func() {
    64  		for _, ep := range eps {
    65  			ep.close()
    66  		}
    67  	}()
    68  	return links(eps, name)
    69  }
    70  
    71  func links(eps []endpoint, name string) ([]Link, error) {
    72  	var lls []Link
    73  	lifn := lifnum{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
    74  	lifc := lifconf{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
    75  	for _, ep := range eps {
    76  		lifn.Family = uint16(ep.af)
    77  		ioc := int64(sysSIOCGLIFNUM)
    78  		if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifn)); err != nil {
    79  			continue
    80  		}
    81  		if lifn.Count == 0 {
    82  			continue
    83  		}
    84  		b := make([]byte, lifn.Count*sizeofLifreq)
    85  		lifc.Family = uint16(ep.af)
    86  		lifc.Len = lifn.Count * sizeofLifreq
    87  		if len(lifc.Lifcu) == 8 {
    88  			nativeEndian.PutUint64(lifc.Lifcu[:], uint64(uintptr(unsafe.Pointer(&b[0]))))
    89  		} else {
    90  			nativeEndian.PutUint32(lifc.Lifcu[:], uint32(uintptr(unsafe.Pointer(&b[0]))))
    91  		}
    92  		ioc = int64(sysSIOCGLIFCONF)
    93  		if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifc)); err != nil {
    94  			continue
    95  		}
    96  		nb := make([]byte, 32) // see LIFNAMSIZ in net/if.h
    97  		for i := 0; i < int(lifn.Count); i++ {
    98  			lifr := (*lifreq)(unsafe.Pointer(&b[i*sizeofLifreq]))
    99  			for i := 0; i < 32; i++ {
   100  				if lifr.Name[i] == 0 {
   101  					nb = nb[:i]
   102  					break
   103  				}
   104  				nb[i] = byte(lifr.Name[i])
   105  			}
   106  			llname := string(nb)
   107  			nb = nb[:32]
   108  			if isDupLink(lls, llname) || name != "" && name != llname {
   109  				continue
   110  			}
   111  			ll := Link{Name: llname, Type: int(lifr.Type)}
   112  			ll.fetch(ep.s)
   113  			lls = append(lls, ll)
   114  		}
   115  	}
   116  	return lls, nil
   117  }
   118  
   119  func isDupLink(lls []Link, name string) bool {
   120  	for _, ll := range lls {
   121  		if ll.Name == name {
   122  			return true
   123  		}
   124  	}
   125  	return false
   126  }