(network string, ip netip.Addr, srcPort int)
| 91 | } |
| 92 | |
| 93 | func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (uid uint32, inode uint32, err error) { |
| 94 | request := &inetDiagRequest{ |
| 95 | States: 0xffffffff, |
| 96 | Cookie: [2]uint32{0xffffffff, 0xffffffff}, |
| 97 | } |
| 98 | |
| 99 | if ip.Is4() { |
| 100 | request.Family = unix.AF_INET |
| 101 | } else { |
| 102 | request.Family = unix.AF_INET6 |
| 103 | } |
| 104 | |
| 105 | if strings.HasPrefix(network, "tcp") { |
| 106 | request.Protocol = unix.IPPROTO_TCP |
| 107 | } else if strings.HasPrefix(network, "udp") { |
| 108 | request.Protocol = unix.IPPROTO_UDP |
| 109 | } else { |
| 110 | return 0, 0, ErrInvalidNetwork |
| 111 | } |
| 112 | |
| 113 | copy(request.Src[:], ip.AsSlice()) |
| 114 | |
| 115 | binary.BigEndian.PutUint16(request.SrcPort[:], uint16(srcPort)) |
| 116 | |
| 117 | conn, err := netlink.Dial(unix.NETLINK_INET_DIAG, nil) |
| 118 | if err != nil { |
| 119 | return 0, 0, err |
| 120 | } |
| 121 | defer conn.Close() |
| 122 | |
| 123 | message := netlink.Message{ |
| 124 | Header: netlink.Header{ |
| 125 | Type: SOCK_DIAG_BY_FAMILY, |
| 126 | Flags: netlink.Request | netlink.Dump, |
| 127 | }, |
| 128 | Data: (*(*[inetDiagRequestSize]byte)(unsafe.Pointer(request)))[:], |
| 129 | } |
| 130 | |
| 131 | messages, err := conn.Execute(message) |
| 132 | if err != nil { |
| 133 | return 0, 0, err |
| 134 | } |
| 135 | |
| 136 | err = ErrNotFound |
| 137 | for _, msg := range messages { |
| 138 | if len(msg.Data) < inetDiagResponseSize { |
| 139 | continue |
| 140 | } |
| 141 | |
| 142 | response := (*inetDiagResponse)(unsafe.Pointer(&msg.Data[0])) |
| 143 | |
| 144 | // always set to allow fallback when check fails |
| 145 | uid, inode, err = response.UID, response.INode, nil |
| 146 | |
| 147 | // check src port |
| 148 | if binary.BigEndian.Uint16(response.SrcPort[:]) != uint16(srcPort) { |
| 149 | continue |
| 150 | } |
no test coverage detected