github.com/vishvananda/netlink@v1.3.1/socket_linux.go (about) 1 package netlink 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "syscall" 8 9 "github.com/vishvananda/netlink/nl" 10 "golang.org/x/sys/unix" 11 ) 12 13 const ( 14 sizeofSocketID = 0x30 15 sizeofSocketRequest = sizeofSocketID + 0x8 16 sizeofSocket = sizeofSocketID + 0x18 17 sizeofUnixSocketRequest = 0x18 // 24 byte 18 sizeofUnixSocket = 0x10 // 16 byte 19 ) 20 21 type socketRequest struct { 22 Family uint8 23 Protocol uint8 24 Ext uint8 25 pad uint8 26 States uint32 27 ID SocketID 28 } 29 30 type writeBuffer struct { 31 Bytes []byte 32 pos int 33 } 34 35 func (b *writeBuffer) Write(c byte) { 36 b.Bytes[b.pos] = c 37 b.pos++ 38 } 39 40 func (b *writeBuffer) Next(n int) []byte { 41 s := b.Bytes[b.pos : b.pos+n] 42 b.pos += n 43 return s 44 } 45 46 func (r *socketRequest) Serialize() []byte { 47 b := writeBuffer{Bytes: make([]byte, sizeofSocketRequest)} 48 b.Write(r.Family) 49 b.Write(r.Protocol) 50 b.Write(r.Ext) 51 b.Write(r.pad) 52 native.PutUint32(b.Next(4), r.States) 53 networkOrder.PutUint16(b.Next(2), r.ID.SourcePort) 54 networkOrder.PutUint16(b.Next(2), r.ID.DestinationPort) 55 if r.Family == unix.AF_INET6 { 56 copy(b.Next(16), r.ID.Source) 57 copy(b.Next(16), r.ID.Destination) 58 } else { 59 copy(b.Next(16), r.ID.Source.To4()) 60 copy(b.Next(16), r.ID.Destination.To4()) 61 } 62 native.PutUint32(b.Next(4), r.ID.Interface) 63 native.PutUint32(b.Next(4), r.ID.Cookie[0]) 64 native.PutUint32(b.Next(4), r.ID.Cookie[1]) 65 return b.Bytes 66 } 67 68 func (r *socketRequest) Len() int { return sizeofSocketRequest } 69 70 // According to linux/include/uapi/linux/unix_diag.h 71 type unixSocketRequest struct { 72 Family uint8 73 Protocol uint8 74 pad uint16 75 States uint32 76 INode uint32 77 Show uint32 78 Cookie [2]uint32 79 } 80 81 func (r *unixSocketRequest) Serialize() []byte { 82 b := writeBuffer{Bytes: make([]byte, sizeofUnixSocketRequest)} 83 b.Write(r.Family) 84 b.Write(r.Protocol) 85 native.PutUint16(b.Next(2), r.pad) 86 native.PutUint32(b.Next(4), r.States) 87 native.PutUint32(b.Next(4), r.INode) 88 native.PutUint32(b.Next(4), r.Show) 89 native.PutUint32(b.Next(4), r.Cookie[0]) 90 native.PutUint32(b.Next(4), r.Cookie[1]) 91 return b.Bytes 92 } 93 94 func (r *unixSocketRequest) Len() int { return sizeofUnixSocketRequest } 95 96 type readBuffer struct { 97 Bytes []byte 98 pos int 99 } 100 101 func (b *readBuffer) Read() byte { 102 c := b.Bytes[b.pos] 103 b.pos++ 104 return c 105 } 106 107 func (b *readBuffer) Next(n int) []byte { 108 s := b.Bytes[b.pos : b.pos+n] 109 b.pos += n 110 return s 111 } 112 113 func (s *Socket) deserialize(b []byte) error { 114 if len(b) < sizeofSocket { 115 return fmt.Errorf("socket data short read (%d); want %d", len(b), sizeofSocket) 116 } 117 rb := readBuffer{Bytes: b} 118 s.Family = rb.Read() 119 s.State = rb.Read() 120 s.Timer = rb.Read() 121 s.Retrans = rb.Read() 122 s.ID.SourcePort = networkOrder.Uint16(rb.Next(2)) 123 s.ID.DestinationPort = networkOrder.Uint16(rb.Next(2)) 124 if s.Family == unix.AF_INET6 { 125 s.ID.Source = net.IP(rb.Next(16)) 126 s.ID.Destination = net.IP(rb.Next(16)) 127 } else { 128 s.ID.Source = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read()) 129 rb.Next(12) 130 s.ID.Destination = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read()) 131 rb.Next(12) 132 } 133 s.ID.Interface = native.Uint32(rb.Next(4)) 134 s.ID.Cookie[0] = native.Uint32(rb.Next(4)) 135 s.ID.Cookie[1] = native.Uint32(rb.Next(4)) 136 s.Expires = native.Uint32(rb.Next(4)) 137 s.RQueue = native.Uint32(rb.Next(4)) 138 s.WQueue = native.Uint32(rb.Next(4)) 139 s.UID = native.Uint32(rb.Next(4)) 140 s.INode = native.Uint32(rb.Next(4)) 141 return nil 142 } 143 144 func (u *UnixSocket) deserialize(b []byte) error { 145 if len(b) < sizeofUnixSocket { 146 return fmt.Errorf("unix diag data short read (%d); want %d", len(b), sizeofUnixSocket) 147 } 148 rb := readBuffer{Bytes: b} 149 u.Type = rb.Read() 150 u.Family = rb.Read() 151 u.State = rb.Read() 152 u.pad = rb.Read() 153 u.INode = native.Uint32(rb.Next(4)) 154 u.Cookie[0] = native.Uint32(rb.Next(4)) 155 u.Cookie[1] = native.Uint32(rb.Next(4)) 156 return nil 157 } 158 159 // SocketGet returns the Socket identified by its local and remote addresses. 160 // 161 // If the returned error is [ErrDumpInterrupted], the search for a result may 162 // be incomplete and the caller should retry. 163 func (h *Handle) SocketGet(local, remote net.Addr) (*Socket, error) { 164 var protocol uint8 165 var localIP, remoteIP net.IP 166 var localPort, remotePort uint16 167 switch l := local.(type) { 168 case *net.TCPAddr: 169 r, ok := remote.(*net.TCPAddr) 170 if !ok { 171 return nil, ErrNotImplemented 172 } 173 localIP = l.IP 174 localPort = uint16(l.Port) 175 remoteIP = r.IP 176 remotePort = uint16(r.Port) 177 protocol = unix.IPPROTO_TCP 178 case *net.UDPAddr: 179 r, ok := remote.(*net.UDPAddr) 180 if !ok { 181 return nil, ErrNotImplemented 182 } 183 localIP = l.IP 184 localPort = uint16(l.Port) 185 remoteIP = r.IP 186 remotePort = uint16(r.Port) 187 protocol = unix.IPPROTO_UDP 188 default: 189 return nil, ErrNotImplemented 190 } 191 192 var family uint8 193 if localIP.To4() != nil && remoteIP.To4() != nil { 194 family = unix.AF_INET 195 } 196 197 if family == 0 && localIP.To16() != nil && remoteIP.To16() != nil { 198 family = unix.AF_INET6 199 } 200 201 if family == 0 { 202 return nil, ErrNotImplemented 203 } 204 205 req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP) 206 req.AddData(&socketRequest{ 207 Family: family, 208 Protocol: protocol, 209 States: 0xffffffff, 210 ID: SocketID{ 211 SourcePort: localPort, 212 DestinationPort: remotePort, 213 Source: localIP, 214 Destination: remoteIP, 215 Cookie: [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE}, 216 }, 217 }) 218 219 msgs, err := req.Execute(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY) 220 if err != nil { 221 return nil, err 222 } 223 if len(msgs) == 0 { 224 return nil, errors.New("no message nor error from netlink") 225 } 226 if len(msgs) > 2 { 227 return nil, fmt.Errorf("multiple (%d) matching sockets", len(msgs)) 228 } 229 230 sock := &Socket{} 231 if err := sock.deserialize(msgs[0]); err != nil { 232 return nil, err 233 } 234 return sock, nil 235 } 236 237 // SocketGet returns the Socket identified by its local and remote addresses. 238 // 239 // If the returned error is [ErrDumpInterrupted], the search for a result may 240 // be incomplete and the caller should retry. 241 func SocketGet(local, remote net.Addr) (*Socket, error) { 242 return pkgHandle.SocketGet(local, remote) 243 } 244 245 // SocketDestroy kills the Socket identified by its local and remote addresses. 246 func (h *Handle) SocketDestroy(local, remote net.Addr) error { 247 localTCP, ok := local.(*net.TCPAddr) 248 if !ok { 249 return ErrNotImplemented 250 } 251 remoteTCP, ok := remote.(*net.TCPAddr) 252 if !ok { 253 return ErrNotImplemented 254 } 255 localIP := localTCP.IP.To4() 256 if localIP == nil { 257 return ErrNotImplemented 258 } 259 remoteIP := remoteTCP.IP.To4() 260 if remoteIP == nil { 261 return ErrNotImplemented 262 } 263 264 s, err := nl.Subscribe(unix.NETLINK_INET_DIAG) 265 if err != nil { 266 return err 267 } 268 defer s.Close() 269 req := h.newNetlinkRequest(nl.SOCK_DESTROY, unix.NLM_F_ACK) 270 req.AddData(&socketRequest{ 271 Family: unix.AF_INET, 272 Protocol: unix.IPPROTO_TCP, 273 ID: SocketID{ 274 SourcePort: uint16(localTCP.Port), 275 DestinationPort: uint16(remoteTCP.Port), 276 Source: localIP, 277 Destination: remoteIP, 278 Cookie: [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE}, 279 }, 280 }) 281 282 _, err = req.Execute(unix.NETLINK_INET_DIAG, 0) 283 return err 284 } 285 286 // SocketDestroy kills the Socket identified by its local and remote addresses. 287 func SocketDestroy(local, remote net.Addr) error { 288 return pkgHandle.SocketDestroy(local, remote) 289 } 290 291 // SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info. 292 // 293 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 294 // or incomplete. 295 func (h *Handle) SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) { 296 // Construct the request 297 req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP) 298 req.AddData(&socketRequest{ 299 Family: family, 300 Protocol: unix.IPPROTO_TCP, 301 Ext: (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)), 302 States: uint32(0xfff), // all states 303 }) 304 305 // Do the query and parse the result 306 var result []*InetDiagTCPInfoResp 307 executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool { 308 sockInfo := &Socket{} 309 var err error 310 if err = sockInfo.deserialize(msg); err != nil { 311 return false 312 } 313 var attrs []syscall.NetlinkRouteAttr 314 if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil { 315 return false 316 } 317 318 var res *InetDiagTCPInfoResp 319 if res, err = attrsToInetDiagTCPInfoResp(attrs, sockInfo); err != nil { 320 return false 321 } 322 323 result = append(result, res) 324 return true 325 }) 326 327 if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) { 328 return nil, executeErr 329 } 330 return result, executeErr 331 } 332 333 // SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info. 334 // 335 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 336 // or incomplete. 337 func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) { 338 return pkgHandle.SocketDiagTCPInfo(family) 339 } 340 341 // SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket. 342 // 343 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 344 // or incomplete. 345 func (h *Handle) SocketDiagTCP(family uint8) ([]*Socket, error) { 346 // Construct the request 347 req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP) 348 req.AddData(&socketRequest{ 349 Family: family, 350 Protocol: unix.IPPROTO_TCP, 351 Ext: (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)), 352 States: uint32(0xfff), // all states 353 }) 354 355 // Do the query and parse the result 356 var result []*Socket 357 executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool { 358 sockInfo := &Socket{} 359 if err := sockInfo.deserialize(msg); err != nil { 360 return false 361 } 362 result = append(result, sockInfo) 363 return true 364 }) 365 if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) { 366 return nil, executeErr 367 } 368 return result, executeErr 369 } 370 371 // SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket. 372 // 373 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 374 // or incomplete. 375 func SocketDiagTCP(family uint8) ([]*Socket, error) { 376 return pkgHandle.SocketDiagTCP(family) 377 } 378 379 // SocketDiagUDPInfo requests INET_DIAG_INFO for UDP protocol for specified family type and return with extension info. 380 // 381 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 382 // or incomplete. 383 func (h *Handle) SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) { 384 // Construct the request 385 var extensions uint8 386 extensions = 1 << (INET_DIAG_VEGASINFO - 1) 387 extensions |= 1 << (INET_DIAG_INFO - 1) 388 extensions |= 1 << (INET_DIAG_MEMINFO - 1) 389 390 req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP) 391 req.AddData(&socketRequest{ 392 Family: family, 393 Protocol: unix.IPPROTO_UDP, 394 Ext: extensions, 395 States: uint32(0xfff), // all states 396 }) 397 398 // Do the query and parse the result 399 var result []*InetDiagUDPInfoResp 400 executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool { 401 sockInfo := &Socket{} 402 if err := sockInfo.deserialize(msg); err != nil { 403 return false 404 } 405 406 var attrs []syscall.NetlinkRouteAttr 407 var err error 408 if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil { 409 return false 410 } 411 412 var res *InetDiagUDPInfoResp 413 if res, err = attrsToInetDiagUDPInfoResp(attrs, sockInfo); err != nil { 414 return false 415 } 416 417 result = append(result, res) 418 return true 419 }) 420 if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) { 421 return nil, executeErr 422 } 423 return result, executeErr 424 } 425 426 // SocketDiagUDPInfo requests INET_DIAG_INFO for UDP protocol for specified family type and return with extension info. 427 // 428 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 429 // or incomplete. 430 func SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) { 431 return pkgHandle.SocketDiagUDPInfo(family) 432 } 433 434 // SocketDiagUDP requests INET_DIAG_INFO for UDP protocol for specified family type and return related socket. 435 // 436 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 437 // or incomplete. 438 func (h *Handle) SocketDiagUDP(family uint8) ([]*Socket, error) { 439 // Construct the request 440 req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP) 441 req.AddData(&socketRequest{ 442 Family: family, 443 Protocol: unix.IPPROTO_UDP, 444 Ext: (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)), 445 States: uint32(0xfff), // all states 446 }) 447 448 // Do the query and parse the result 449 var result []*Socket 450 executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool { 451 sockInfo := &Socket{} 452 if err := sockInfo.deserialize(msg); err != nil { 453 return false 454 } 455 result = append(result, sockInfo) 456 return true 457 }) 458 if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) { 459 return nil, executeErr 460 } 461 return result, executeErr 462 } 463 464 // SocketDiagUDP requests INET_DIAG_INFO for UDP protocol for specified family type and return related socket. 465 // 466 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 467 // or incomplete. 468 func SocketDiagUDP(family uint8) ([]*Socket, error) { 469 return pkgHandle.SocketDiagUDP(family) 470 } 471 472 // UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info. 473 // 474 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 475 // or incomplete. 476 func (h *Handle) UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) { 477 // Construct the request 478 var extensions uint8 479 extensions = 1 << UNIX_DIAG_NAME 480 extensions |= 1 << UNIX_DIAG_PEER 481 extensions |= 1 << UNIX_DIAG_RQLEN 482 req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP) 483 req.AddData(&unixSocketRequest{ 484 Family: unix.AF_UNIX, 485 States: ^uint32(0), // all states 486 Show: uint32(extensions), 487 }) 488 489 var result []*UnixDiagInfoResp 490 executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool { 491 sockInfo := &UnixSocket{} 492 if err := sockInfo.deserialize(msg); err != nil { 493 return false 494 } 495 496 // Diagnosis also delivers sockets with AF_INET family, filter those 497 if sockInfo.Family != unix.AF_UNIX { 498 return false 499 } 500 501 var attrs []syscall.NetlinkRouteAttr 502 var err error 503 if attrs, err = nl.ParseRouteAttr(msg[sizeofUnixSocket:]); err != nil { 504 return false 505 } 506 507 var res *UnixDiagInfoResp 508 if res, err = attrsToUnixDiagInfoResp(attrs, sockInfo); err != nil { 509 return false 510 } 511 result = append(result, res) 512 return true 513 }) 514 if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) { 515 return nil, executeErr 516 } 517 return result, executeErr 518 } 519 520 // UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info. 521 // 522 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 523 // or incomplete. 524 func UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) { 525 return pkgHandle.UnixSocketDiagInfo() 526 } 527 528 // UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets. 529 // 530 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 531 // or incomplete. 532 func (h *Handle) UnixSocketDiag() ([]*UnixSocket, error) { 533 // Construct the request 534 req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP) 535 req.AddData(&unixSocketRequest{ 536 Family: unix.AF_UNIX, 537 States: ^uint32(0), // all states 538 }) 539 540 var result []*UnixSocket 541 executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool { 542 sockInfo := &UnixSocket{} 543 if err := sockInfo.deserialize(msg); err != nil { 544 return false 545 } 546 547 // Diagnosis also delivers sockets with AF_INET family, filter those 548 if sockInfo.Family == unix.AF_UNIX { 549 result = append(result, sockInfo) 550 } 551 return true 552 }) 553 if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) { 554 return nil, executeErr 555 } 556 return result, executeErr 557 } 558 559 // UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets. 560 // 561 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 562 // or incomplete. 563 func UnixSocketDiag() ([]*UnixSocket, error) { 564 return pkgHandle.UnixSocketDiag() 565 } 566 567 func attrsToInetDiagTCPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagTCPInfoResp, error) { 568 info := &InetDiagTCPInfoResp{ 569 InetDiagMsg: sockInfo, 570 } 571 for _, a := range attrs { 572 switch a.Attr.Type { 573 case INET_DIAG_INFO: 574 info.TCPInfo = &TCPInfo{} 575 if err := info.TCPInfo.deserialize(a.Value); err != nil { 576 return nil, err 577 } 578 case INET_DIAG_BBRINFO: 579 info.TCPBBRInfo = &TCPBBRInfo{} 580 if err := info.TCPBBRInfo.deserialize(a.Value); err != nil { 581 return nil, err 582 } 583 } 584 } 585 586 return info, nil 587 } 588 589 func attrsToInetDiagUDPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagUDPInfoResp, error) { 590 info := &InetDiagUDPInfoResp{ 591 InetDiagMsg: sockInfo, 592 } 593 for _, a := range attrs { 594 switch a.Attr.Type { 595 case INET_DIAG_MEMINFO: 596 info.Memory = &MemInfo{} 597 if err := info.Memory.deserialize(a.Value); err != nil { 598 return nil, err 599 } 600 } 601 } 602 603 return info, nil 604 } 605 606 func attrsToUnixDiagInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *UnixSocket) (*UnixDiagInfoResp, error) { 607 info := &UnixDiagInfoResp{ 608 DiagMsg: sockInfo, 609 } 610 for _, a := range attrs { 611 switch a.Attr.Type { 612 case UNIX_DIAG_NAME: 613 name := string(a.Value[:a.Attr.Len]) 614 info.Name = &name 615 case UNIX_DIAG_PEER: 616 peer := native.Uint32(a.Value) 617 info.Peer = &peer 618 case UNIX_DIAG_RQLEN: 619 info.Queue = &QueueInfo{ 620 RQueue: native.Uint32(a.Value[:4]), 621 WQueue: native.Uint32(a.Value[4:]), 622 } 623 // default: 624 // fmt.Println("unknown unix attribute type", a.Attr.Type, "with data", a.Value) 625 } 626 } 627 628 return info, nil 629 }