Skip to content

Commit

Permalink
feat(crit): add crit x sk for sockets
Browse files Browse the repository at this point in the history
Signed-off-by: Prajwal S N <prajwalnadig21@gmail.com>
  • Loading branch information
snprajwal committed Jul 27, 2023
1 parent 90a7a27 commit 74a5040
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 10 deletions.
8 changes: 5 additions & 3 deletions crit/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ var infoCmd = &cobra.Command{

// The `crit x` command
var xCmd = &cobra.Command{
Use: "x DIR {ps|fd|mem|rss}",
Use: "x DIR {ps|fd|mem|rss|sk}",
Short: "Explore the image directory",
Long: "Explore the image directory with one of (ps, fd, mem, rss) options",
Long: "Explore the image directory with one of (ps, fd, mem, rss, sk) options",
// Exactly two arguments are required:
// * Path of the input directory
// * Explore type
Expand All @@ -248,8 +248,10 @@ var xCmd = &cobra.Command{
xData, err = c.ExploreMems()
case "rss":
xData, err = c.ExploreRss()
case "sk":
xData, err = c.ExploreSk()
default:
err = errors.New("invalid explore type (supported: {ps|fd|mem|rss})")
err = errors.New("invalid explore type (supported: {ps|fd|mem|rss|sk})")

Check warning on line 254 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L254

Added line #L254 was not covered by tests
}
if err != nil {
log.Fatal(fmt.Errorf("error exploring directory: %w", err))
Expand Down
1 change: 1 addition & 0 deletions crit/crit.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Critter interface {
ExploreFds() ([]*Fd, error)
ExploreMems() ([]*MemMap, error)
ExploreRss() ([]*RssMap, error)
ExploreSk() ([]*Sk, error)
}

// crit implements the Critter interface. It contains:
Expand Down
119 changes: 119 additions & 0 deletions crit/explore.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,122 @@ func (c *crit) ExploreRss() ([]*RssMap, error) {

return rssMaps, nil
}

// Sk represents the sockets associated with a single process
type Sk struct {
PId uint32 `json:"pId"`
Sockets []*Socket `json:"sockets"`
}

// Socket represents a single socket
type Socket struct {
Fd uint32 `json:"fd"`
Type string `json:"type"`
Family string `json:"family,omitempty"`
Protocol string `json:"protocol,omitempty"`
State string `json:"state,omitempty"`
SourceAddr string `json:"sourceAddr,omitempty"`
SourcePort uint32 `json:"sourcePort,omitempty"`
DestAddr string `json:"destAddr,omitempty"`
DestPort uint32 `json:"destPort,omitempty"`
SendBuf string `json:"sendBuf,omitempty"`
RecvBuf string `json:"recvBuf,omitempty"`
}

// ExploreSk searches the process tree for sockets
// and returns a list of PIDs with the associated sockets
func (c *crit) ExploreSk() ([]*Sk, error) {
psTreeImg, err := getImg(filepath.Join(c.inputDirPath, "pstree.img"), &pstree.PstreeEntry{})
if err != nil {
return nil, err
}

Check warning on line 404 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L403-L404

Added lines #L403 - L404 were not covered by tests

sks := make([]*Sk, 0)
for _, entry := range psTreeImg.Entries {
process := entry.Message.(*pstree.PstreeEntry)
pID := process.GetPid()
// Get file with object IDs
idsImg, err := getImg(filepath.Join(c.inputDirPath, fmt.Sprintf("ids-%d.img", pID)), &criu_core.TaskKobjIdsEntry{})
if err != nil {
return nil, err
}

Check warning on line 414 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L413-L414

Added lines #L413 - L414 were not covered by tests
filesID := idsImg.Entries[0].Message.(*criu_core.TaskKobjIdsEntry).GetFilesId()
// Get open file descriptors
fdInfoImg, err := getImg(filepath.Join(c.inputDirPath, fmt.Sprintf("fdinfo-%d.img", filesID)), &fdinfo.FdinfoEntry{})
if err != nil {
return nil, err
}

Check warning on line 420 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L419-L420

Added lines #L419 - L420 were not covered by tests
skEntry := Sk{PId: pID}
for _, fdInfoEntry := range fdInfoImg.Entries {
fdInfo := fdInfoEntry.Message.(*fdinfo.FdinfoEntry)
socket := Socket{
Fd: fdInfo.GetFd(),
Type: fdInfo.GetType().String(),
}
switch fdInfo.GetType() {
case fdinfo.FdTypes_INETSK:
file, err := getFile(c.inputDirPath, fdInfo.GetId())
if err != nil {
return nil, err
}
if isk := file.GetIsk(); isk != nil {
socket.State = getSkState(isk.GetState())
socket.Family = getSkFamily(isk.GetFamily())
socket.Protocol = getSkProtocol(isk.GetType())
socket.SourceAddr = processIP(isk.GetSrcAddr())
socket.SourcePort = isk.GetSrcPort()
socket.DestAddr = processIP(isk.GetDstAddr())
socket.DestPort = isk.GetDstPort()
socket.SendBuf = countBytes(int64(isk.GetOpts().GetSoSndbuf()))
socket.RecvBuf = countBytes(int64(isk.GetOpts().GetSoRcvbuf()))
}
case fdinfo.FdTypes_UNIXSK:
file, err := getFile(c.inputDirPath, fdInfo.GetId())
if err != nil {
return nil, err
}
if usk := file.GetUsk(); usk != nil {
socket.State = getSkState(usk.GetState())
socket.Protocol = getSkProtocol(usk.GetType())
socket.SourceAddr = string(usk.GetName())
socket.SendBuf = countBytes(int64(usk.GetOpts().GetSoSndbuf()))
socket.RecvBuf = countBytes(int64(usk.GetOpts().GetSoRcvbuf()))
}
case fdinfo.FdTypes_PACKETSK:
file, err := getFile(c.inputDirPath, fdInfo.GetId())
if err != nil {
return nil, err
}
if psk := file.GetPsk(); psk != nil {
socket.Protocol = getSkProtocol(psk.GetProtocol())
socket.SendBuf = countBytes(int64(psk.GetOpts().GetSoSndbuf()))
socket.RecvBuf = countBytes(int64(psk.GetOpts().GetSoRcvbuf()))
}
case fdinfo.FdTypes_NETLINKSK:
file, err := getFile(c.inputDirPath, fdInfo.GetId())
if err != nil {
return nil, err
}
if nlsk := file.GetNlsk(); nlsk != nil {
socket.State = getSkState(nlsk.GetState())
socket.Protocol = getSkProtocol(nlsk.GetProtocol())
socket.SendBuf = countBytes(int64(nlsk.GetOpts().GetSoSndbuf()))
socket.RecvBuf = countBytes(int64(nlsk.GetOpts().GetSoRcvbuf()))
}

Check warning on line 477 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L429-L477

Added lines #L429 - L477 were not covered by tests
default:
continue
}

skEntry.Sockets = append(skEntry.Sockets, &socket)

Check warning on line 482 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L482

Added line #L482 was not covered by tests
}

// Omit if the process has no associated sockets
if len(skEntry.Sockets) == 0 {
continue
}

sks = append(sks, &skEntry)

Check warning on line 490 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L490

Added line #L490 was not covered by tests
}

return sks, nil
}
116 changes: 109 additions & 7 deletions crit/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/binary"
"fmt"
"io"
"net"
"os"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -110,27 +111,37 @@ var (
filesImg, regImg, pipeImg, unixSkImg *CriuImage
)

// Helper to get file path for exploring file descriptors
func getFilePath(dir string, fID uint32, fType fdinfo.FdTypes) (string, error) {
var filePath string
// Helper to fetch a file if it exists in files.img
func getFile(dir string, fID uint32) (*fdinfo.FileEntry, error) {
var err error
// Get open files
if filesImg == nil {
filesImg, err = getImg(filepath.Join(dir, "files.img"), &fdinfo.FileEntry{})
if err != nil {
return "", err
return nil, err

Check warning on line 120 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L120

Added line #L120 was not covered by tests
}
}

// Check if file entry is present
var file *fdinfo.FileEntry
for _, entry := range filesImg.Entries {
file = entry.Message.(*fdinfo.FileEntry)
if file.GetId() == fID {
break
return file, nil
}
}

return nil, nil

Check warning on line 132 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L132

Added line #L132 was not covered by tests
}

// Helper to get file path for exploring file descriptors
func getFilePath(dir string, fID uint32, fType fdinfo.FdTypes) (string, error) {
var filePath string
var err error
// Fetch the file, if it exists in file.img
file, err := getFile(dir, fID)
if err != nil {
return "", err
}

Check warning on line 143 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L142-L143

Added lines #L142 - L143 were not covered by tests

switch fType {
case fdinfo.FdTypes_REG:
filePath, err = getRegFilePath(dir, file, fID)
Expand Down Expand Up @@ -232,3 +243,94 @@ func getUnixSkFilePath(dir string, file *fdinfo.FileEntry, fID uint32) (string,

return "unix[?]", nil
}

// Helper to convert slice of uint32 into IP address string
func processIP(parts []uint32) string {
// IPv4
if len(parts) == 1 {
ip := make(net.IP, net.IPv4len)
binary.LittleEndian.PutUint32(ip, parts[0])
return ip.String()
}

Check warning on line 254 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L248-L254

Added lines #L248 - L254 were not covered by tests
// IPv6
if len(parts) == 4 {
ip := make(net.IP, net.IPv6len)
for _, part := range parts {
binary.LittleEndian.PutUint32(ip, part)
}
return ip.String()

Check warning on line 261 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L256-L261

Added lines #L256 - L261 were not covered by tests
}
// Invalid
return ""

Check warning on line 264 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L264

Added line #L264 was not covered by tests
}

// Helper to identify socket state
func getSkState(state uint32) string {
switch state {
case 0:
return "ESTABLISHED"
case 1:
return "SYN_SENT"
case 2:
return "SYN_RECV"
case 3:
return "FIN_WAIT1"
case 4:
return "FIN_WAIT2"
case 5:
return "TIME_WAIT"
case 6:
return "CLOSE"
case 7:
return "CLOSE_WAIT"
case 8:
return "LAST_ACK"
case 9:
return "LISTEN"
case 10:
return "CLOSING"
default:
// State cannot be empty, hence we use unknown
return "UNKNOWN"

Check warning on line 294 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L268-L294

Added lines #L268 - L294 were not covered by tests
}
}

// Helper to identify socket family
func getSkFamily(family uint32) string {
switch family {
case 0:
return "UNIX"
case 1:
return "BRIDGE"
case 2:
return "KEY"
case 3:
return "PACKET"
default:
return ""

Check warning on line 310 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L299-L310

Added lines #L299 - L310 were not covered by tests
}
}

// Helper to identify socket protocol
func getSkProtocol(protocol uint32) string {
switch protocol {
case 0:
return "IP"
case 1:
return "IGMP"
case 2:
return "TCP"
case 3:
return "UDP"
case 4:
return "IPV6"
case 5:
return "GRE"
case 6:
return "AH"
case 7:
return "RAW"
default:
return ""

Check warning on line 334 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L315-L334

Added lines #L315 - L334 were not covered by tests
}
}
1 change: 1 addition & 0 deletions test/crit/crit-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ function command_test {
$CRIT x "$TEST_IMG_DIR" fd || exit 1
$CRIT x "$TEST_IMG_DIR" mem || exit 1
$CRIT x "$TEST_IMG_DIR" rss || exit 1
$CRIT x "$TEST_IMG_DIR" sk || exit 1
}

echo "Generating image list..."
Expand Down

0 comments on commit 74a5040

Please sign in to comment.