github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/proc/net.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package proc 16 17 import ( 18 "bytes" 19 "fmt" 20 "io" 21 "reflect" 22 "time" 23 24 "github.com/SagerNet/gvisor/pkg/abi/linux" 25 "github.com/SagerNet/gvisor/pkg/context" 26 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 27 "github.com/SagerNet/gvisor/pkg/hostarch" 28 "github.com/SagerNet/gvisor/pkg/log" 29 "github.com/SagerNet/gvisor/pkg/sentry/fs" 30 "github.com/SagerNet/gvisor/pkg/sentry/fs/proc/seqfile" 31 "github.com/SagerNet/gvisor/pkg/sentry/fs/ramfs" 32 "github.com/SagerNet/gvisor/pkg/sentry/inet" 33 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 34 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 35 "github.com/SagerNet/gvisor/pkg/sentry/socket" 36 "github.com/SagerNet/gvisor/pkg/sentry/socket/unix" 37 "github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport" 38 "github.com/SagerNet/gvisor/pkg/tcpip/header" 39 ) 40 41 // LINT.IfChange 42 43 // newNetDir creates a new proc net entry. 44 func newNetDir(ctx context.Context, t *kernel.Task, msrc *fs.MountSource) *fs.Inode { 45 k := t.Kernel() 46 47 var contents map[string]*fs.Inode 48 if s := t.NetworkNamespace().Stack(); s != nil { 49 // TODO(github.com/SagerNet/issue/1833): Make sure file contents reflect the task 50 // network namespace. 51 contents = map[string]*fs.Inode{ 52 "dev": seqfile.NewSeqFileInode(ctx, &netDev{s: s}, msrc), 53 "snmp": seqfile.NewSeqFileInode(ctx, &netSnmp{s: s}, msrc), 54 55 // The following files are simple stubs until they are 56 // implemented in netstack, if the file contains a 57 // header the stub is just the header otherwise it is 58 // an empty file. 59 "arp": newStaticProcInode(ctx, msrc, []byte("IP address HW type Flags HW address Mask Device\n")), 60 61 "netlink": newStaticProcInode(ctx, msrc, []byte("sk Eth Pid Groups Rmem Wmem Dump Locks Drops Inode\n")), 62 "netstat": newStaticProcInode(ctx, msrc, []byte("TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed EmbryonicRsts PruneCalled RcvPruned OfoPruned OutOfWindowIcmps LockDroppedIcmps ArpFilter TW TWRecycled TWKilled PAWSPassive PAWSActive PAWSEstab DelayedACKs DelayedACKLocked DelayedACKLost ListenOverflows ListenDrops TCPPrequeued TCPDirectCopyFromBacklog TCPDirectCopyFromPrequeue TCPPrequeueDropped TCPHPHits TCPHPHitsToUser TCPPureAcks TCPHPAcks TCPRenoRecovery TCPSackRecovery TCPSACKReneging TCPFACKReorder TCPSACKReorder TCPRenoReorder TCPTSReorder TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo TCPLostRetransmit TCPRenoFailures TCPSackFailures TCPLossFailures TCPFastRetrans TCPForwardRetrans TCPSlowStartRetrans TCPTimeouts TCPLossProbes TCPLossProbeRecovery TCPRenoRecoveryFail TCPSackRecoveryFail TCPSchedulerFailed TCPRcvCollapsed TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv TCPAbortOnData TCPAbortOnClose TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger TCPAbortFailed TCPMemoryPressures TCPSACKDiscard TCPDSACKIgnoredOld TCPDSACKIgnoredNoUndo TCPSpuriousRTOs TCPMD5NotFound TCPMD5Unexpected TCPMD5Failure TCPSackShifted TCPSackMerged TCPSackShiftFallback TCPBacklogDrop TCPMinTTLDrop TCPDeferAcceptDrop IPReversePathFilter TCPTimeWaitOverflow TCPReqQFullDoCookies TCPReqQFullDrop TCPRetransFail TCPRcvCoalesce TCPOFOQueue TCPOFODrop TCPOFOMerge TCPChallengeACK TCPSYNChallenge TCPFastOpenActive TCPFastOpenActiveFail TCPFastOpenPassive TCPFastOpenPassiveFail TCPFastOpenListenOverflow TCPFastOpenCookieReqd TCPSpuriousRtxHostQueues BusyPollRxPackets TCPAutoCorking TCPFromZeroWindowAdv TCPToZeroWindowAdv TCPWantZeroWindowAdv TCPSynRetrans TCPOrigDataSent TCPHystartTrainDetect TCPHystartTrainCwnd TCPHystartDelayDetect TCPHystartDelayCwnd TCPACKSkippedSynRecv TCPACKSkippedPAWS TCPACKSkippedSeq TCPACKSkippedFinWait2 TCPACKSkippedTimeWait TCPACKSkippedChallenge TCPWinProbe TCPKeepAlive TCPMTUPFail TCPMTUPSuccess\n")), 63 "packet": newStaticProcInode(ctx, msrc, []byte("sk RefCnt Type Proto Iface R Rmem User Inode\n")), 64 "protocols": newStaticProcInode(ctx, msrc, []byte("protocol size sockets memory press maxhdr slab module cl co di ac io in de sh ss gs se re sp bi br ha uh gp em\n")), 65 // Linux sets psched values to: nsec per usec, psched 66 // tick in ns, 1000000, high res timer ticks per sec 67 // (ClockGetres returns 1ns resolution). 68 "psched": newStaticProcInode(ctx, msrc, []byte(fmt.Sprintf("%08x %08x %08x %08x\n", uint64(time.Microsecond/time.Nanosecond), 64, 1000000, uint64(time.Second/time.Nanosecond)))), 69 "ptype": newStaticProcInode(ctx, msrc, []byte("Type Device Function\n")), 70 "route": seqfile.NewSeqFileInode(ctx, &netRoute{s: s}, msrc), 71 "tcp": seqfile.NewSeqFileInode(ctx, &netTCP{k: k}, msrc), 72 "udp": seqfile.NewSeqFileInode(ctx, &netUDP{k: k}, msrc), 73 "unix": seqfile.NewSeqFileInode(ctx, &netUnix{k: k}, msrc), 74 } 75 76 if s.SupportsIPv6() { 77 contents["if_inet6"] = seqfile.NewSeqFileInode(ctx, &ifinet6{s: s}, msrc) 78 contents["ipv6_route"] = newStaticProcInode(ctx, msrc, []byte("")) 79 contents["tcp6"] = seqfile.NewSeqFileInode(ctx, &netTCP6{k: k}, msrc) 80 contents["udp6"] = newStaticProcInode(ctx, msrc, []byte(" sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n")) 81 } 82 } 83 d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) 84 return newProcInode(ctx, d, msrc, fs.SpecialDirectory, t) 85 } 86 87 // ifinet6 implements seqfile.SeqSource for /proc/net/if_inet6. 88 // 89 // +stateify savable 90 type ifinet6 struct { 91 s inet.Stack 92 } 93 94 func (n *ifinet6) contents() []string { 95 var lines []string 96 nics := n.s.Interfaces() 97 for id, naddrs := range n.s.InterfaceAddrs() { 98 nic, ok := nics[id] 99 if !ok { 100 // NIC was added after NICNames was called. We'll just 101 // ignore it. 102 continue 103 } 104 105 for _, a := range naddrs { 106 // IPv6 only. 107 if a.Family != linux.AF_INET6 { 108 continue 109 } 110 111 // Fields: 112 // IPv6 address displayed in 32 hexadecimal chars without colons 113 // Netlink device number (interface index) in hexadecimal (use nic id) 114 // Prefix length in hexadecimal 115 // Scope value (use 0) 116 // Interface flags 117 // Device name 118 lines = append(lines, fmt.Sprintf("%032x %02x %02x %02x %02x %8s\n", a.Addr, id, a.PrefixLen, 0, a.Flags, nic.Name)) 119 } 120 } 121 return lines 122 } 123 124 // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. 125 func (*ifinet6) NeedsUpdate(generation int64) bool { 126 return true 127 } 128 129 // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. 130 func (n *ifinet6) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) { 131 contents := n.contents() 132 minI := 0 133 if h != nil { 134 minI = h.(int) + 1 135 if minI > len(contents) { 136 minI = len(contents) 137 } 138 } 139 var data []seqfile.SeqData 140 for i, l := range contents[minI:] { 141 data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI}) 142 } 143 144 return data, 0 145 } 146 147 // netDev implements seqfile.SeqSource for /proc/net/dev. 148 // 149 // +stateify savable 150 type netDev struct { 151 s inet.Stack 152 } 153 154 // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. 155 func (n *netDev) NeedsUpdate(generation int64) bool { 156 return true 157 } 158 159 // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. See Linux's 160 // net/core/net-procfs.c:dev_seq_show. 161 func (n *netDev) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) { 162 interfaces := n.s.Interfaces() 163 contents := make([]string, 2, 2+len(interfaces)) 164 // Add the table header. From net/core/net-procfs.c:dev_seq_show. 165 contents[0] = "Inter-| Receive | Transmit\n" 166 contents[1] = " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n" 167 168 for _, i := range interfaces { 169 // Implements the same format as 170 // net/core/net-procfs.c:dev_seq_printf_stats. 171 var stats inet.StatDev 172 if err := n.s.Statistics(&stats, i.Name); err != nil { 173 log.Warningf("Failed to retrieve interface statistics for %v: %v", i.Name, err) 174 continue 175 } 176 l := fmt.Sprintf( 177 "%6s: %7d %7d %4d %4d %4d %5d %10d %9d %8d %7d %4d %4d %4d %5d %7d %10d\n", 178 i.Name, 179 // Received 180 stats[0], // bytes 181 stats[1], // packets 182 stats[2], // errors 183 stats[3], // dropped 184 stats[4], // fifo 185 stats[5], // frame 186 stats[6], // compressed 187 stats[7], // multicast 188 // Transmitted 189 stats[8], // bytes 190 stats[9], // packets 191 stats[10], // errors 192 stats[11], // dropped 193 stats[12], // fifo 194 stats[13], // frame 195 stats[14], // compressed 196 stats[15]) // multicast 197 contents = append(contents, l) 198 } 199 200 minI := 0 201 if h != nil { 202 minI = h.(int) + 1 203 if minI > len(contents) { 204 minI = len(contents) 205 } 206 } 207 var data []seqfile.SeqData 208 for i, l := range contents[minI:] { 209 data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI}) 210 } 211 212 return data, 0 213 } 214 215 // netSnmp implements seqfile.SeqSource for /proc/net/snmp. 216 // 217 // +stateify savable 218 type netSnmp struct { 219 s inet.Stack 220 } 221 222 // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. 223 func (n *netSnmp) NeedsUpdate(generation int64) bool { 224 return true 225 } 226 227 type snmpLine struct { 228 prefix string 229 header string 230 } 231 232 var snmp = []snmpLine{ 233 { 234 prefix: "Ip", 235 header: "Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates", 236 }, 237 { 238 prefix: "Icmp", 239 header: "InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps", 240 }, 241 { 242 prefix: "IcmpMsg", 243 }, 244 { 245 prefix: "Tcp", 246 header: "RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors", 247 }, 248 { 249 prefix: "Udp", 250 header: "InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti", 251 }, 252 { 253 prefix: "UdpLite", 254 header: "InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti", 255 }, 256 } 257 258 func toSlice(a interface{}) []uint64 { 259 v := reflect.Indirect(reflect.ValueOf(a)) 260 return v.Slice(0, v.Len()).Interface().([]uint64) 261 } 262 263 func sprintSlice(s []uint64) string { 264 if len(s) == 0 { 265 return "" 266 } 267 r := fmt.Sprint(s) 268 return r[1 : len(r)-1] // Remove "[]" introduced by fmt of slice. 269 } 270 271 // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. See Linux's 272 // net/core/net-procfs.c:dev_seq_show. 273 func (n *netSnmp) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) { 274 contents := make([]string, 0, len(snmp)*2) 275 types := []interface{}{ 276 &inet.StatSNMPIP{}, 277 &inet.StatSNMPICMP{}, 278 nil, // TODO(github.com/SagerNet/issue/628): Support IcmpMsg stats. 279 &inet.StatSNMPTCP{}, 280 &inet.StatSNMPUDP{}, 281 &inet.StatSNMPUDPLite{}, 282 } 283 for i, stat := range types { 284 line := snmp[i] 285 if stat == nil { 286 contents = append( 287 contents, 288 fmt.Sprintf("%s:\n", line.prefix), 289 fmt.Sprintf("%s:\n", line.prefix), 290 ) 291 continue 292 } 293 if err := n.s.Statistics(stat, line.prefix); err != nil { 294 if linuxerr.Equals(linuxerr.EOPNOTSUPP, err) { 295 log.Infof("Failed to retrieve %s of /proc/net/snmp: %v", line.prefix, err) 296 } else { 297 log.Warningf("Failed to retrieve %s of /proc/net/snmp: %v", line.prefix, err) 298 } 299 } 300 var values string 301 if line.prefix == "Tcp" { 302 tcp := stat.(*inet.StatSNMPTCP) 303 // "Tcp" needs special processing because MaxConn is signed. RFC 2012. 304 values = fmt.Sprintf("%s %d %s", sprintSlice(tcp[:3]), int64(tcp[3]), sprintSlice(tcp[4:])) 305 } else { 306 values = sprintSlice(toSlice(stat)) 307 } 308 contents = append( 309 contents, 310 fmt.Sprintf("%s: %s\n", line.prefix, line.header), 311 fmt.Sprintf("%s: %s\n", line.prefix, values), 312 ) 313 } 314 315 minI := 0 316 if h != nil { 317 minI = h.(int) + 1 318 if minI > len(contents) { 319 minI = len(contents) 320 } 321 } 322 data := make([]seqfile.SeqData, 0, len(snmp)*2) 323 for i, l := range contents[minI:] { 324 data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI}) 325 } 326 327 return data, 0 328 } 329 330 // netRoute implements seqfile.SeqSource for /proc/net/route. 331 // 332 // +stateify savable 333 type netRoute struct { 334 s inet.Stack 335 } 336 337 // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. 338 func (n *netRoute) NeedsUpdate(generation int64) bool { 339 return true 340 } 341 342 // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. 343 // See Linux's net/ipv4/fib_trie.c:fib_route_seq_show. 344 func (n *netRoute) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) { 345 interfaces := n.s.Interfaces() 346 contents := []string{"Iface\tDestination\tGateway\tFlags\tRefCnt\tUse\tMetric\tMask\tMTU\tWindow\tIRTT"} 347 for _, rt := range n.s.RouteTable() { 348 // /proc/net/route only includes ipv4 routes. 349 if rt.Family != linux.AF_INET { 350 continue 351 } 352 353 // /proc/net/route does not include broadcast or multicast routes. 354 if rt.Type == linux.RTN_BROADCAST || rt.Type == linux.RTN_MULTICAST { 355 continue 356 } 357 358 iface, ok := interfaces[rt.OutputInterface] 359 if !ok || iface.Name == "lo" { 360 continue 361 } 362 363 var ( 364 gw uint32 365 prefix uint32 366 flags = linux.RTF_UP 367 ) 368 if len(rt.GatewayAddr) == header.IPv4AddressSize { 369 flags |= linux.RTF_GATEWAY 370 gw = hostarch.ByteOrder.Uint32(rt.GatewayAddr) 371 } 372 if len(rt.DstAddr) == header.IPv4AddressSize { 373 prefix = hostarch.ByteOrder.Uint32(rt.DstAddr) 374 } 375 l := fmt.Sprintf( 376 "%s\t%08X\t%08X\t%04X\t%d\t%d\t%d\t%08X\t%d\t%d\t%d", 377 iface.Name, 378 prefix, 379 gw, 380 flags, 381 0, // RefCnt. 382 0, // Use. 383 0, // Metric. 384 (uint32(1)<<rt.DstLen)-1, 385 0, // MTU. 386 0, // Window. 387 0, // RTT. 388 ) 389 contents = append(contents, l) 390 } 391 392 minI := 0 393 if h != nil { 394 minI = h.(int) + 1 395 if minI > len(contents) { 396 minI = len(contents) 397 } 398 } 399 var data []seqfile.SeqData 400 for i, l := range contents[minI:] { 401 l = fmt.Sprintf("%-127s\n", l) 402 data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI}) 403 } 404 405 return data, 0 406 } 407 408 // netUnix implements seqfile.SeqSource for /proc/net/unix. 409 // 410 // +stateify savable 411 type netUnix struct { 412 k *kernel.Kernel 413 } 414 415 // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. 416 func (*netUnix) NeedsUpdate(generation int64) bool { 417 return true 418 } 419 420 // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. 421 func (n *netUnix) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) { 422 var buf bytes.Buffer 423 for _, se := range n.k.ListSockets() { 424 s := se.Sock.Get() 425 if s == nil { 426 log.Debugf("Couldn't resolve weakref with ID %v in socket table, racing with destruction?", se.ID) 427 continue 428 } 429 sfile := s.(*fs.File) 430 if family, _, _ := sfile.FileOperations.(socket.Socket).Type(); family != linux.AF_UNIX { 431 s.DecRef(ctx) 432 // Not a unix socket. 433 continue 434 } 435 sops := sfile.FileOperations.(*unix.SocketOperations) 436 437 addr, err := sops.Endpoint().GetLocalAddress() 438 if err != nil { 439 log.Warningf("Failed to retrieve socket name from %+v: %v", sfile, err) 440 addr.Addr = "<unknown>" 441 } 442 443 sockFlags := 0 444 if ce, ok := sops.Endpoint().(transport.ConnectingEndpoint); ok { 445 if ce.Listening() { 446 // For unix domain sockets, linux reports a single flag 447 // value if the socket is listening, of __SO_ACCEPTCON. 448 sockFlags = linux.SO_ACCEPTCON 449 } 450 } 451 452 // In the socket entry below, the value for the 'Num' field requires 453 // some consideration. Linux prints the address to the struct 454 // unix_sock representing a socket in the kernel, but may redact the 455 // value for unprivileged users depending on the kptr_restrict 456 // sysctl. 457 // 458 // One use for this field is to allow a privileged user to 459 // introspect into the kernel memory to determine information about 460 // a socket not available through procfs, such as the socket's peer. 461 // 462 // On gvisor, returning a pointer to our internal structures would 463 // be pointless, as it wouldn't match the memory layout for struct 464 // unix_sock, making introspection difficult. We could populate a 465 // struct unix_sock with the appropriate data, but even that 466 // requires consideration for which kernel version to emulate, as 467 // the definition of this struct changes over time. 468 // 469 // For now, we always redact this pointer. 470 fmt.Fprintf(&buf, "%#016p: %08X %08X %08X %04X %02X %5d", 471 (*unix.SocketOperations)(nil), // Num, pointer to kernel socket struct. 472 sfile.ReadRefs()-1, // RefCount, don't count our own ref. 473 0, // Protocol, always 0 for UDS. 474 sockFlags, // Flags. 475 sops.Endpoint().Type(), // Type. 476 sops.State(), // State. 477 sfile.InodeID(), // Inode. 478 ) 479 480 // Path 481 if len(addr.Addr) != 0 { 482 if addr.Addr[0] == 0 { 483 // Abstract path. 484 fmt.Fprintf(&buf, " @%s", string(addr.Addr[1:])) 485 } else { 486 fmt.Fprintf(&buf, " %s", string(addr.Addr)) 487 } 488 } 489 fmt.Fprintf(&buf, "\n") 490 491 s.DecRef(ctx) 492 } 493 494 minI := 0 495 if h != nil { 496 minI = h.(int) + 1 497 } 498 var data []seqfile.SeqData 499 if minI <= 0 { 500 data = append(data, seqfile.SeqData{ 501 Buf: []byte("Num RefCount Protocol Flags Type St Inode Path\n"), 502 Handle: 0, 503 }) 504 } 505 if minI <= 1 { 506 data = append(data, seqfile.SeqData{ 507 Buf: buf.Bytes(), 508 Handle: 1, 509 }) 510 } 511 return data, 0 512 } 513 514 func networkToHost16(n uint16) uint16 { 515 // n is in network byte order, so is big-endian. The most-significant byte 516 // should be stored in the lower address. 517 // 518 // We manually inline binary.BigEndian.Uint16() because Go does not support 519 // non-primitive consts, so binary.BigEndian is a (mutable) var, so calls to 520 // binary.BigEndian.Uint16() require a read of binary.BigEndian and an 521 // interface method call, defeating inlining. 522 buf := [2]byte{byte(n >> 8 & 0xff), byte(n & 0xff)} 523 return hostarch.ByteOrder.Uint16(buf[:]) 524 } 525 526 func writeInetAddr(w io.Writer, family int, i linux.SockAddr) { 527 switch family { 528 case linux.AF_INET: 529 var a linux.SockAddrInet 530 if i != nil { 531 a = *i.(*linux.SockAddrInet) 532 } 533 534 // linux.SockAddrInet.Port is stored in the network byte order and is 535 // printed like a number in host byte order. Note that all numbers in host 536 // byte order are printed with the most-significant byte first when 537 // formatted with %X. See get_tcp4_sock() and udp4_format_sock() in Linux. 538 port := networkToHost16(a.Port) 539 540 // linux.SockAddrInet.Addr is stored as a byte slice in big-endian order 541 // (i.e. most-significant byte in index 0). Linux represents this as a 542 // __be32 which is a typedef for an unsigned int, and is printed with 543 // %X. This means that for a little-endian machine, Linux prints the 544 // least-significant byte of the address first. To emulate this, we first 545 // invert the byte order for the address using hostarch.ByteOrder.Uint32, 546 // which makes it have the equivalent encoding to a __be32 on a little 547 // endian machine. Note that this operation is a no-op on a big endian 548 // machine. Then similar to Linux, we format it with %X, which will print 549 // the most-significant byte of the __be32 address first, which is now 550 // actually the least-significant byte of the original address in 551 // linux.SockAddrInet.Addr on little endian machines, due to the conversion. 552 addr := hostarch.ByteOrder.Uint32(a.Addr[:]) 553 554 fmt.Fprintf(w, "%08X:%04X ", addr, port) 555 case linux.AF_INET6: 556 var a linux.SockAddrInet6 557 if i != nil { 558 a = *i.(*linux.SockAddrInet6) 559 } 560 561 port := networkToHost16(a.Port) 562 addr0 := hostarch.ByteOrder.Uint32(a.Addr[0:4]) 563 addr1 := hostarch.ByteOrder.Uint32(a.Addr[4:8]) 564 addr2 := hostarch.ByteOrder.Uint32(a.Addr[8:12]) 565 addr3 := hostarch.ByteOrder.Uint32(a.Addr[12:16]) 566 fmt.Fprintf(w, "%08X%08X%08X%08X:%04X ", addr0, addr1, addr2, addr3, port) 567 } 568 } 569 570 func commonReadSeqFileDataTCP(ctx context.Context, n seqfile.SeqHandle, k *kernel.Kernel, h seqfile.SeqHandle, fa int, header []byte) ([]seqfile.SeqData, int64) { 571 // t may be nil here if our caller is not part of a task goroutine. This can 572 // happen for example if we're here for "sentryctl cat". When t is nil, 573 // degrade gracefully and retrieve what we can. 574 t := kernel.TaskFromContext(ctx) 575 576 var buf bytes.Buffer 577 for _, se := range k.ListSockets() { 578 s := se.Sock.Get() 579 if s == nil { 580 log.Debugf("Couldn't resolve weakref with ID %v in socket table, racing with destruction?", se.ID) 581 continue 582 } 583 sfile := s.(*fs.File) 584 sops, ok := sfile.FileOperations.(socket.Socket) 585 if !ok { 586 panic(fmt.Sprintf("Found non-socket file in socket table: %+v", sfile)) 587 } 588 if family, stype, _ := sops.Type(); !(family == fa && stype == linux.SOCK_STREAM) { 589 s.DecRef(ctx) 590 // Not tcp4 sockets. 591 continue 592 } 593 594 // Linux's documentation for the fields below can be found at 595 // https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt. 596 // For Linux's implementation, see net/ipv4/tcp_ipv4.c:get_tcp4_sock(). 597 // Note that the header doesn't contain labels for all the fields. 598 599 // Field: sl; entry number. 600 fmt.Fprintf(&buf, "%4d: ", se.ID) 601 602 // Field: local_adddress. 603 var localAddr linux.SockAddr 604 if t != nil { 605 if local, _, err := sops.GetSockName(t); err == nil { 606 localAddr = local 607 } 608 } 609 writeInetAddr(&buf, fa, localAddr) 610 611 // Field: rem_address. 612 var remoteAddr linux.SockAddr 613 if t != nil { 614 if remote, _, err := sops.GetPeerName(t); err == nil { 615 remoteAddr = remote 616 } 617 } 618 writeInetAddr(&buf, fa, remoteAddr) 619 620 // Field: state; socket state. 621 fmt.Fprintf(&buf, "%02X ", sops.State()) 622 623 // Field: tx_queue, rx_queue; number of packets in the transmit and 624 // receive queue. Unimplemented. 625 fmt.Fprintf(&buf, "%08X:%08X ", 0, 0) 626 627 // Field: tr, tm->when; timer active state and number of jiffies 628 // until timer expires. Unimplemented. 629 fmt.Fprintf(&buf, "%02X:%08X ", 0, 0) 630 631 // Field: retrnsmt; number of unrecovered RTO timeouts. 632 // Unimplemented. 633 fmt.Fprintf(&buf, "%08X ", 0) 634 635 // Field: uid. 636 uattr, err := sfile.Dirent.Inode.UnstableAttr(ctx) 637 if err != nil { 638 log.Warningf("Failed to retrieve unstable attr for socket file: %v", err) 639 fmt.Fprintf(&buf, "%5d ", 0) 640 } else { 641 creds := auth.CredentialsFromContext(ctx) 642 fmt.Fprintf(&buf, "%5d ", uint32(uattr.Owner.UID.In(creds.UserNamespace).OrOverflow())) 643 } 644 645 // Field: timeout; number of unanswered 0-window probes. 646 // Unimplemented. 647 fmt.Fprintf(&buf, "%8d ", 0) 648 649 // Field: inode. 650 fmt.Fprintf(&buf, "%8d ", sfile.InodeID()) 651 652 // Field: refcount. Don't count the ref we obtain while deferencing 653 // the weakref to this socket. 654 fmt.Fprintf(&buf, "%d ", sfile.ReadRefs()-1) 655 656 // Field: Socket struct address. Redacted due to the same reason as 657 // the 'Num' field in /proc/net/unix, see netUnix.ReadSeqFileData. 658 fmt.Fprintf(&buf, "%#016p ", (*socket.Socket)(nil)) 659 660 // Field: retransmit timeout. Unimplemented. 661 fmt.Fprintf(&buf, "%d ", 0) 662 663 // Field: predicted tick of soft clock (delayed ACK control data). 664 // Unimplemented. 665 fmt.Fprintf(&buf, "%d ", 0) 666 667 // Field: (ack.quick<<1)|ack.pingpong, Unimplemented. 668 fmt.Fprintf(&buf, "%d ", 0) 669 670 // Field: sending congestion window, Unimplemented. 671 fmt.Fprintf(&buf, "%d ", 0) 672 673 // Field: Slow start size threshold, -1 if threshold >= 0xFFFF. 674 // Unimplemented, report as large threshold. 675 fmt.Fprintf(&buf, "%d", -1) 676 677 fmt.Fprintf(&buf, "\n") 678 679 s.DecRef(ctx) 680 } 681 682 minI := 0 683 if h != nil { 684 minI = h.(int) + 1 685 } 686 var data []seqfile.SeqData 687 if minI <= 0 { 688 data = append(data, seqfile.SeqData{ 689 Buf: header, 690 Handle: 0, 691 }) 692 } 693 if minI <= 1 { 694 data = append(data, seqfile.SeqData{ 695 Buf: buf.Bytes(), 696 Handle: 1, 697 }) 698 } 699 return data, 0 700 } 701 702 // netTCP implements seqfile.SeqSource for /proc/net/tcp. 703 // 704 // +stateify savable 705 type netTCP struct { 706 k *kernel.Kernel 707 } 708 709 // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. 710 func (*netTCP) NeedsUpdate(generation int64) bool { 711 return true 712 } 713 714 // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. 715 func (n *netTCP) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) { 716 header := []byte(" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode \n") 717 return commonReadSeqFileDataTCP(ctx, n, n.k, h, linux.AF_INET, header) 718 } 719 720 // netTCP6 implements seqfile.SeqSource for /proc/net/tcp6. 721 // 722 // +stateify savable 723 type netTCP6 struct { 724 k *kernel.Kernel 725 } 726 727 // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. 728 func (*netTCP6) NeedsUpdate(generation int64) bool { 729 return true 730 } 731 732 // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. 733 func (n *netTCP6) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) { 734 header := []byte(" sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n") 735 return commonReadSeqFileDataTCP(ctx, n, n.k, h, linux.AF_INET6, header) 736 } 737 738 // netUDP implements seqfile.SeqSource for /proc/net/udp. 739 // 740 // +stateify savable 741 type netUDP struct { 742 k *kernel.Kernel 743 } 744 745 // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. 746 func (*netUDP) NeedsUpdate(generation int64) bool { 747 return true 748 } 749 750 // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. 751 func (n *netUDP) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) { 752 // t may be nil here if our caller is not part of a task goroutine. This can 753 // happen for example if we're here for "sentryctl cat". When t is nil, 754 // degrade gracefully and retrieve what we can. 755 t := kernel.TaskFromContext(ctx) 756 757 var buf bytes.Buffer 758 for _, se := range n.k.ListSockets() { 759 s := se.Sock.Get() 760 if s == nil { 761 log.Debugf("Couldn't resolve weakref with ID %v in socket table, racing with destruction?", se.ID) 762 continue 763 } 764 sfile := s.(*fs.File) 765 sops, ok := sfile.FileOperations.(socket.Socket) 766 if !ok { 767 panic(fmt.Sprintf("Found non-socket file in socket table: %+v", sfile)) 768 } 769 if family, stype, _ := sops.Type(); family != linux.AF_INET || stype != linux.SOCK_DGRAM { 770 s.DecRef(ctx) 771 // Not udp4 socket. 772 continue 773 } 774 775 // For Linux's implementation, see net/ipv4/udp.c:udp4_format_sock(). 776 777 // Field: sl; entry number. 778 fmt.Fprintf(&buf, "%5d: ", se.ID) 779 780 // Field: local_adddress. 781 var localAddr linux.SockAddrInet 782 if t != nil { 783 if local, _, err := sops.GetSockName(t); err == nil { 784 localAddr = *local.(*linux.SockAddrInet) 785 } 786 } 787 writeInetAddr(&buf, linux.AF_INET, &localAddr) 788 789 // Field: rem_address. 790 var remoteAddr linux.SockAddrInet 791 if t != nil { 792 if remote, _, err := sops.GetPeerName(t); err == nil { 793 remoteAddr = *remote.(*linux.SockAddrInet) 794 } 795 } 796 writeInetAddr(&buf, linux.AF_INET, &remoteAddr) 797 798 // Field: state; socket state. 799 fmt.Fprintf(&buf, "%02X ", sops.State()) 800 801 // Field: tx_queue, rx_queue; number of packets in the transmit and 802 // receive queue. Unimplemented. 803 fmt.Fprintf(&buf, "%08X:%08X ", 0, 0) 804 805 // Field: tr, tm->when. Always 0 for UDP. 806 fmt.Fprintf(&buf, "%02X:%08X ", 0, 0) 807 808 // Field: retrnsmt. Always 0 for UDP. 809 fmt.Fprintf(&buf, "%08X ", 0) 810 811 // Field: uid. 812 uattr, err := sfile.Dirent.Inode.UnstableAttr(ctx) 813 if err != nil { 814 log.Warningf("Failed to retrieve unstable attr for socket file: %v", err) 815 fmt.Fprintf(&buf, "%5d ", 0) 816 } else { 817 creds := auth.CredentialsFromContext(ctx) 818 fmt.Fprintf(&buf, "%5d ", uint32(uattr.Owner.UID.In(creds.UserNamespace).OrOverflow())) 819 } 820 821 // Field: timeout. Always 0 for UDP. 822 fmt.Fprintf(&buf, "%8d ", 0) 823 824 // Field: inode. 825 fmt.Fprintf(&buf, "%8d ", sfile.InodeID()) 826 827 // Field: ref; reference count on the socket inode. Don't count the ref 828 // we obtain while deferencing the weakref to this socket. 829 fmt.Fprintf(&buf, "%d ", sfile.ReadRefs()-1) 830 831 // Field: Socket struct address. Redacted due to the same reason as 832 // the 'Num' field in /proc/net/unix, see netUnix.ReadSeqFileData. 833 fmt.Fprintf(&buf, "%#016p ", (*socket.Socket)(nil)) 834 835 // Field: drops; number of dropped packets. Unimplemented. 836 fmt.Fprintf(&buf, "%d", 0) 837 838 fmt.Fprintf(&buf, "\n") 839 840 s.DecRef(ctx) 841 } 842 843 minI := 0 844 if h != nil { 845 minI = h.(int) + 1 846 } 847 var data []seqfile.SeqData 848 if minI <= 0 { 849 data = append(data, seqfile.SeqData{ 850 Buf: []byte(" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops \n"), 851 Handle: 0, 852 }) 853 } 854 if minI <= 1 { 855 data = append(data, seqfile.SeqData{ 856 Buf: buf.Bytes(), 857 Handle: 1, 858 }) 859 } 860 return data, 0 861 } 862 863 // LINT.ThenChange(../../fsimpl/proc/task_net.go)