github.com/cilium/cilium@v1.16.2/pkg/proxy/netstat.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package proxy
     5  
     6  import (
     7  	"bytes"
     8  	"os"
     9  	"regexp"
    10  	"strconv"
    11  
    12  	"github.com/cilium/cilium/pkg/logging/logfields"
    13  )
    14  
    15  var (
    16  	// procNetTCPFiles is the constant list of /proc/net files to read to get
    17  	// the same information about open TCP connections as output by netstat.
    18  	procNetTCPFiles = []string{
    19  		"/proc/net/tcp",
    20  		"/proc/net/tcp6",
    21  	}
    22  
    23  	// procNetUDPFiles is the constant list of /proc/net files to read to get
    24  	// the same information about open UDP connections as output by netstat.
    25  	procNetUDPFiles = []string{
    26  		"/proc/net/udp",
    27  		"/proc/net/udp6",
    28  	}
    29  
    30  	// procNetFileRegexp matches the first two columns of /proc/net/{tcp,udp}*
    31  	// files and submatches on the local port number.
    32  	procNetFileRegexp = regexp.MustCompile("^ *[[:digit:]]*: *[[:xdigit:]]*:([[:xdigit:]]*) ")
    33  )
    34  
    35  // readOpenLocalPorts returns the set of L4 ports currently open locally.
    36  // procNetFiles should be procNetTCPFiles or procNetUDPFiles (or both).
    37  func readOpenLocalPorts(procNetFiles []string) map[uint16]struct{} {
    38  	openLocalPorts := make(map[uint16]struct{}, 128)
    39  
    40  	for _, file := range procNetFiles {
    41  		b, err := os.ReadFile(file)
    42  		if err != nil {
    43  			log.WithError(err).WithField(logfields.Path, file).Errorf("cannot read proc file")
    44  			continue
    45  		}
    46  
    47  		lines := bytes.Split(b, []byte("\n"))
    48  
    49  		// Extract the local port number from the "local_address" column.
    50  		// The header line won't match and will be ignored.
    51  		for _, line := range lines {
    52  			groups := procNetFileRegexp.FindSubmatch(line)
    53  			if len(groups) != 2 { // no match
    54  				continue
    55  			}
    56  			// The port number is in hexadecimal.
    57  			localPort, err := strconv.ParseUint(string(groups[1]), 16, 16)
    58  			if err != nil {
    59  				log.WithError(err).WithField(logfields.Path, file).Errorf("cannot read proc file")
    60  				continue
    61  			}
    62  			openLocalPorts[uint16(localPort)] = struct{}{}
    63  		}
    64  	}
    65  
    66  	return openLocalPorts
    67  }
    68  
    69  // OpenLocalPorts returns the set of L4 ports currently open locally.
    70  func OpenLocalPorts() map[uint16]struct{} {
    71  	return readOpenLocalPorts(append(procNetTCPFiles, procNetUDPFiles...))
    72  }