procfs icon indicating copy to clipboard operation
procfs copied to clipboard

procfs has data consistency issues when reading /proc/net/tcp

Open shaohk opened this issue 2 years ago • 2 comments

https://github.com/prometheus/procfs/blob/ff0ad85f7e8bcd5c677d99143f14a2a3aab533aa/net_tcp.go#L28

I read tcp connections by procfs like this

package main

import (
	"fmt"

	"github.com/prometheus/procfs"
)

func main() {
	fs, _ := procfs.NewDefaultFS()

	tcps, _ := fs.NetTCP()
	for _, tcp := range tcps {
		fmt.Println(tcp.LocalAddr, tcp.LocalPort, tcp.RemAddr, tcp.RemPort, tcp.Inode)
	}
}

When I execute multiple times, I find that the same TCP connection appears twice. eg:

Tue Sep 26 18:48 [root@host ~]# ./nettcp | sort | uniq -c | grep '2 '
      ......
      1 192.168.0.2 22815 127.0.0.1 8181 4157386808
      2 192.168.0.2 24219 127.0.0.1 8300 4192187746
      1 192.168.0.2 29727 127.0.0.1 5002 4185948034
      ......

But, When I execute multiple netstat command, there won't be the phenomenon mentioned above. eg:

Tue Sep 26 18:50 [root@host ~]# netstat -npta | awk '{print $1, $4, $5, $7}' | sort | uniq -c
      ......
      1 tcp 192.168.0.2:11609 127.0.0.1:8300 138167/python
      1 tcp 192.168.0.2:12385 127.0.0.1:8300 138188/python
      1 tcp 192.168.0.2:12465 127.0.0.1:8035 266462/agent
      ......

And I find netstat source code, find the code that

FILE *proc_fopen(const char *name)
{
    static char *buffer;
    static size_t pagesz;
    FILE *fd = fopen(name, "r");

    if (fd == NULL)
      return NULL;

    if (!buffer) {
      pagesz = getpagesize();
      buffer = malloc(pagesz);
    }

    setvbuf(fd, buffer, _IOFBF, pagesz);

    return fd;
}

netstat sets the setvbuf to _IOFBF mode when opening the net/tcp file. But golang procfs doesn't set this.

How can we ensure consistency when reading net/tcp in Golang?

shaohk avatar Sep 26 '23 11:09 shaohk

We essentially just parse net/tcp, can you provide the relevant /proc/net/tcp content in this situation?

discordianfish avatar Oct 13 '23 09:10 discordianfish

@shaohk Are you implying that you suspect the contents of /proc/netstat are changing mid-flight when procfs reads that file? I would be skeptical of that, since it is read with io.ReadAll (limited to 1 MiB) via the internal/util.ReadFileNoStat function.

dswarbrick avatar Nov 02 '23 14:11 dswarbrick

I couldn't reproduce this with the aforementioned snippet running for a thousand times. @shaohk Are you still able to reproduce this with the latest release?

rexagod avatar Mar 21 '24 16:03 rexagod