github.com/elastic/gosigar@v0.14.3/examples/ss/ss.go (about)

     1  // +build linux
     2  
     3  package main
     4  
     5  import (
     6  	"flag"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"log"
    11  	"os"
    12  	"strings"
    13  	"syscall"
    14  	"text/tabwriter"
    15  
    16  	"github.com/elastic/gosigar/sys/linux"
    17  )
    18  
    19  var (
    20  	fs    = flag.NewFlagSet("ss", flag.ExitOnError)
    21  	debug = fs.Bool("d", false, "enable debug output to stderr")
    22  	ipv6  = fs.Bool("6", false, "display only IP version 6 sockets")
    23  	v1    = fs.Bool("v1", false, "send inet_diag_msg v1 instead of v2")
    24  	diag  = fs.String("diag", "", "dump raw information about TCP sockets to FILE")
    25  )
    26  
    27  func main() {
    28  	log.SetFlags(0)
    29  	fs.Parse(os.Args[1:])
    30  
    31  	if !*debug {
    32  		log.SetOutput(ioutil.Discard)
    33  	}
    34  
    35  	if err := sockets(); err != nil {
    36  		fmt.Fprintf(os.Stderr, "error: %v\n", err)
    37  		os.Exit(1)
    38  	}
    39  }
    40  
    41  func sockets() error {
    42  	// Set address family based on flags. The requested address family only
    43  	// works with inet_diag_req_v2. v1 returns all tcp sockets.
    44  	af := linux.AF_INET
    45  	if *ipv6 {
    46  		af = linux.AF_INET6
    47  	}
    48  
    49  	// For debug purposes allow for sending either inet_diag_req and inet_diag_req_v2.
    50  	var req syscall.NetlinkMessage
    51  	if *v1 {
    52  		req = linux.NewInetDiagReq()
    53  	} else {
    54  		req = linux.NewInetDiagReqV2(af)
    55  	}
    56  
    57  	// Write netlink response to a file for further analysis or for writing
    58  	// tests cases.
    59  	var diagWriter io.Writer
    60  	if *diag != "" {
    61  		f, err := os.OpenFile(*diag, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
    62  		if err != nil {
    63  			return err
    64  		}
    65  		defer f.Close()
    66  		diagWriter = f
    67  	}
    68  
    69  	log.Println("sending netlink request")
    70  	msgs, err := linux.NetlinkInetDiagWithBuf(req, nil, diagWriter)
    71  	if err != nil {
    72  		return err
    73  	}
    74  	log.Printf("received %d inet_diag_msg responses", len(msgs))
    75  
    76  	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
    77  	fmt.Fprintln(w, strings.Join([]string{
    78  		"State",
    79  		"Recv-Q",
    80  		"Send-Q",
    81  		"Local Address:Port",
    82  		"Remote Address:Port",
    83  		"UID",
    84  		"Inode",
    85  		"PID/Program",
    86  	}, "\t"))
    87  	defer w.Flush()
    88  
    89  	for _, diag := range msgs {
    90  		// XXX: A real implementation of ss would find the process holding
    91  		// inode of the socket. It would read /proc/<pid>/fd and find all sockets.
    92  		pidProgram := "not implemented"
    93  
    94  		fmt.Fprintf(w, "%v\t%v\t%v\t%v:%v\t%v:%v\t%v\t%v\t%v\n",
    95  			linux.TCPState(diag.State), diag.RQueue, diag.WQueue,
    96  			diag.SrcIP().String(), diag.SrcPort(),
    97  			diag.DstIP().String(), diag.DstPort(),
    98  			diag.UID, diag.Inode, pidProgram)
    99  	}
   100  
   101  	return nil
   102  }