1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.net.module.util.netlink; 18 19 import static android.os.Process.INVALID_UID; 20 import static android.system.OsConstants.AF_INET; 21 import static android.system.OsConstants.AF_INET6; 22 import static android.system.OsConstants.ENOENT; 23 import static android.system.OsConstants.IPPROTO_TCP; 24 import static android.system.OsConstants.IPPROTO_UDP; 25 import static android.system.OsConstants.NETLINK_INET_DIAG; 26 27 import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE; 28 import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DESTROY; 29 import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; 30 import static com.android.net.module.util.netlink.NetlinkConstants.hexify; 31 import static com.android.net.module.util.netlink.NetlinkConstants.stringForAddressFamily; 32 import static com.android.net.module.util.netlink.NetlinkConstants.stringForProtocol; 33 import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFSIZE; 34 import static com.android.net.module.util.netlink.NetlinkUtils.IO_TIMEOUT_MS; 35 import static com.android.net.module.util.netlink.NetlinkUtils.TCP_ALIVE_STATE_FILTER; 36 import static com.android.net.module.util.netlink.NetlinkUtils.connectSocketToNetlink; 37 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; 38 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; 39 40 import android.net.util.SocketUtils; 41 import android.os.Process; 42 import android.os.SystemClock; 43 import android.system.ErrnoException; 44 import android.util.Log; 45 import android.util.Range; 46 47 import androidx.annotation.NonNull; 48 import androidx.annotation.Nullable; 49 import androidx.annotation.VisibleForTesting; 50 51 import java.io.FileDescriptor; 52 import java.io.IOException; 53 import java.io.InterruptedIOException; 54 import java.net.Inet4Address; 55 import java.net.Inet6Address; 56 import java.net.InetAddress; 57 import java.net.InetSocketAddress; 58 import java.net.SocketException; 59 import java.net.UnknownHostException; 60 import java.nio.ByteBuffer; 61 import java.nio.ByteOrder; 62 import java.util.List; 63 import java.util.Set; 64 import java.util.function.Predicate; 65 66 /** 67 * A NetlinkMessage subclass for netlink inet_diag messages. 68 * 69 * see also: <linux_src>/include/uapi/linux/inet_diag.h 70 * 71 * @hide 72 */ 73 public class InetDiagMessage extends NetlinkMessage { 74 public static final String TAG = "InetDiagMessage"; 75 private static final int TIMEOUT_MS = 500; 76 77 /** 78 * Construct an inet_diag_req_v2 message. This method will throw 79 * {@link IllegalArgumentException} if local and remote are not both null or both non-null. 80 */ inetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote, int family, short flags)81 public static byte[] inetDiagReqV2(int protocol, InetSocketAddress local, 82 InetSocketAddress remote, int family, short flags) { 83 return inetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */, 84 0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES); 85 } 86 87 /** 88 * Construct an inet_diag_req_v2 message. This method will throw 89 * {@code IllegalArgumentException} if local and remote are not both null or both non-null. 90 * 91 * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, 92 * IPPROTO_UDP, or IPPROTO_UDPLITE. 93 * @param local local socket address of the target socket. This will be packed into a 94 * {@link StructInetDiagSockId}. Request to diagnose for all sockets if both of 95 * local or remote address is null. 96 * @param remote remote socket address of the target socket. This will be packed into a 97 * {@link StructInetDiagSockId}. Request to diagnose for all sockets if both of 98 * local or remote address is null. 99 * @param family the ip family of the request message. This should be set to either AF_INET or 100 * AF_INET6 for IPv4 or IPv6 sockets respectively. 101 * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h. 102 * @param pad for raw socket protocol specification. 103 * @param idiagExt a set of flags defining what kind of extended information to report. 104 * @param state a bit mask that defines a filter of socket states. 105 * 106 * @return bytes array representation of the message 107 */ inetDiagReqV2(int protocol, @Nullable InetSocketAddress local, @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt, int state)108 public static byte[] inetDiagReqV2(int protocol, @Nullable InetSocketAddress local, 109 @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt, 110 int state) throws IllegalArgumentException { 111 // Request for all sockets if no specific socket is requested. Specify the local and remote 112 // socket address information for target request socket. 113 if ((local == null) != (remote == null)) { 114 throw new IllegalArgumentException( 115 "Local and remote must be both null or both non-null"); 116 } 117 final StructInetDiagSockId id = ((local != null && remote != null) 118 ? new StructInetDiagSockId(local, remote) : null); 119 return inetDiagReqV2(protocol, id, family, 120 SOCK_DIAG_BY_FAMILY, flags, pad, idiagExt, state); 121 } 122 123 /** 124 * Construct an inet_diag_req_v2 message. 125 * 126 * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, 127 * IPPROTO_UDP, or IPPROTO_UDPLITE. 128 * @param id inet_diag_sockid. See {@link StructInetDiagSockId} 129 * @param family the ip family of the request message. This should be set to either AF_INET or 130 * AF_INET6 for IPv4 or IPv6 sockets respectively. 131 * @param type message types. 132 * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h. 133 * @param pad for raw socket protocol specification. 134 * @param idiagExt a set of flags defining what kind of extended information to report. 135 * @param state a bit mask that defines a filter of socket states. 136 * @return bytes array representation of the message 137 */ inetDiagReqV2(int protocol, @Nullable StructInetDiagSockId id, int family, short type, short flags, int pad, int idiagExt, int state)138 public static byte[] inetDiagReqV2(int protocol, @Nullable StructInetDiagSockId id, int family, 139 short type, short flags, int pad, int idiagExt, int state) { 140 final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE]; 141 final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); 142 byteBuffer.order(ByteOrder.nativeOrder()); 143 144 final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr(); 145 nlMsgHdr.nlmsg_len = bytes.length; 146 nlMsgHdr.nlmsg_type = type; 147 nlMsgHdr.nlmsg_flags = flags; 148 nlMsgHdr.pack(byteBuffer); 149 final StructInetDiagReqV2 inetDiagReqV2 = 150 new StructInetDiagReqV2(protocol, id, family, pad, idiagExt, state); 151 152 inetDiagReqV2.pack(byteBuffer); 153 return bytes; 154 } 155 156 public StructInetDiagMsg inetDiagMsg; 157 158 @VisibleForTesting InetDiagMessage(@onNull StructNlMsgHdr header)159 public InetDiagMessage(@NonNull StructNlMsgHdr header) { 160 super(header); 161 inetDiagMsg = new StructInetDiagMsg(); 162 } 163 164 /** 165 * Parse an inet_diag_req_v2 message from buffer. 166 */ 167 @Nullable parse(@onNull StructNlMsgHdr header, @NonNull ByteBuffer byteBuffer)168 public static InetDiagMessage parse(@NonNull StructNlMsgHdr header, 169 @NonNull ByteBuffer byteBuffer) { 170 final InetDiagMessage msg = new InetDiagMessage(header); 171 msg.inetDiagMsg = StructInetDiagMsg.parse(byteBuffer); 172 if (msg.inetDiagMsg == null) { 173 return null; 174 } 175 return msg; 176 } 177 closeSocketQuietly(final FileDescriptor fd)178 private static void closeSocketQuietly(final FileDescriptor fd) { 179 try { 180 SocketUtils.closeSocket(fd); 181 } catch (IOException ignored) { 182 } 183 } 184 lookupUidByFamily(int protocol, InetSocketAddress local, InetSocketAddress remote, int family, short flags, FileDescriptor fd)185 private static int lookupUidByFamily(int protocol, InetSocketAddress local, 186 InetSocketAddress remote, int family, short flags, 187 FileDescriptor fd) 188 throws ErrnoException, InterruptedIOException { 189 byte[] msg = inetDiagReqV2(protocol, local, remote, family, flags); 190 NetlinkUtils.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS); 191 ByteBuffer response = NetlinkUtils.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS); 192 193 final NetlinkMessage nlMsg = NetlinkMessage.parse(response, NETLINK_INET_DIAG); 194 if (nlMsg == null) { 195 return INVALID_UID; 196 } 197 final StructNlMsgHdr hdr = nlMsg.getHeader(); 198 if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { 199 return INVALID_UID; 200 } 201 if (nlMsg instanceof InetDiagMessage) { 202 return ((InetDiagMessage) nlMsg).inetDiagMsg.idiag_uid; 203 } 204 return INVALID_UID; 205 } 206 207 private static final int[] FAMILY = {AF_INET6, AF_INET}; 208 lookupUid(int protocol, InetSocketAddress local, InetSocketAddress remote, FileDescriptor fd)209 private static int lookupUid(int protocol, InetSocketAddress local, 210 InetSocketAddress remote, FileDescriptor fd) 211 throws ErrnoException, InterruptedIOException { 212 int uid; 213 214 for (int family : FAMILY) { 215 /** 216 * For exact match lookup, swap local and remote for UDP lookups due to kernel 217 * bug which will not be fixed. See aosp/755889 and 218 * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html 219 */ 220 if (protocol == IPPROTO_UDP) { 221 uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd); 222 } else { 223 uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd); 224 } 225 if (uid != INVALID_UID) { 226 return uid; 227 } 228 } 229 230 /** 231 * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the 232 * socket is not connected (and even if the socket is connected to a different destination). 233 * If we want this API to work for such packets, then on miss we need to do a second lookup 234 * with only the local address and port filled in. 235 * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard. 236 */ 237 if (protocol == IPPROTO_UDP) { 238 try { 239 InetSocketAddress wildcard = new InetSocketAddress( 240 Inet6Address.getByName("::"), 0); 241 uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6, 242 (short) (NLM_F_REQUEST | NLM_F_DUMP), fd); 243 if (uid != INVALID_UID) { 244 return uid; 245 } 246 wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0); 247 uid = lookupUidByFamily(protocol, local, wildcard, AF_INET, 248 (short) (NLM_F_REQUEST | NLM_F_DUMP), fd); 249 if (uid != INVALID_UID) { 250 return uid; 251 } 252 } catch (UnknownHostException e) { 253 Log.e(TAG, e.toString()); 254 } 255 } 256 return INVALID_UID; 257 } 258 259 /** 260 * Use an inet_diag socket to look up the UID associated with the input local and remote 261 * address/port and protocol of a connection. 262 */ getConnectionOwnerUid(int protocol, InetSocketAddress local, InetSocketAddress remote)263 public static int getConnectionOwnerUid(int protocol, InetSocketAddress local, 264 InetSocketAddress remote) { 265 int uid = INVALID_UID; 266 FileDescriptor fd = null; 267 try { 268 fd = NetlinkUtils.netlinkSocketForProto(NETLINK_INET_DIAG); 269 NetlinkUtils.connectSocketToNetlink(fd); 270 uid = lookupUid(protocol, local, remote, fd); 271 } catch (ErrnoException | SocketException | IllegalArgumentException 272 | InterruptedIOException e) { 273 Log.e(TAG, e.toString()); 274 } finally { 275 closeSocketQuietly(fd); 276 } 277 return uid; 278 } 279 280 /** 281 * Construct an inet_diag_req_v2 message for querying alive TCP sockets from kernel. 282 */ buildInetDiagReqForAliveTcpSockets(int family)283 public static byte[] buildInetDiagReqForAliveTcpSockets(int family) { 284 return inetDiagReqV2(IPPROTO_TCP, 285 null /* local addr */, 286 null /* remote addr */, 287 family, 288 (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP) /* flag */, 289 0 /* pad */, 290 1 << NetlinkConstants.INET_DIAG_MEMINFO /* idiagExt */, 291 TCP_ALIVE_STATE_FILTER); 292 } 293 sendNetlinkDestroyRequest(FileDescriptor fd, int proto, InetDiagMessage diagMsg)294 private static void sendNetlinkDestroyRequest(FileDescriptor fd, int proto, 295 InetDiagMessage diagMsg) throws InterruptedIOException, ErrnoException { 296 final byte[] destroyMsg = InetDiagMessage.inetDiagReqV2( 297 proto, 298 diagMsg.inetDiagMsg.id, 299 diagMsg.inetDiagMsg.idiag_family, 300 SOCK_DESTROY, 301 (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_ACK), 302 0 /* pad */, 303 0 /* idiagExt */, 304 1 << diagMsg.inetDiagMsg.idiag_state 305 ); 306 NetlinkUtils.sendMessage(fd, destroyMsg, 0, destroyMsg.length, IO_TIMEOUT_MS); 307 NetlinkUtils.receiveNetlinkAck(fd); 308 } 309 sendNetlinkDumpRequest(FileDescriptor fd, int proto, int states, int family)310 private static void sendNetlinkDumpRequest(FileDescriptor fd, int proto, int states, int family) 311 throws InterruptedIOException, ErrnoException { 312 final byte[] dumpMsg = InetDiagMessage.inetDiagReqV2( 313 proto, 314 null /* id */, 315 family, 316 SOCK_DIAG_BY_FAMILY, 317 (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP), 318 0 /* pad */, 319 0 /* idiagExt */, 320 states); 321 NetlinkUtils.sendMessage(fd, dumpMsg, 0, dumpMsg.length, IO_TIMEOUT_MS); 322 } 323 processNetlinkDumpAndDestroySockets(FileDescriptor dumpFd, FileDescriptor destroyFd, int proto, Predicate<InetDiagMessage> filter)324 private static int processNetlinkDumpAndDestroySockets(FileDescriptor dumpFd, 325 FileDescriptor destroyFd, int proto, Predicate<InetDiagMessage> filter) 326 throws InterruptedIOException, ErrnoException { 327 int destroyedSockets = 0; 328 329 while (true) { 330 final ByteBuffer buf = NetlinkUtils.recvMessage( 331 dumpFd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); 332 333 while (buf.remaining() > 0) { 334 final int position = buf.position(); 335 final NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_INET_DIAG); 336 if (nlMsg == null) { 337 // Move to the position where parse started for error log. 338 buf.position(position); 339 Log.e(TAG, "Failed to parse netlink message: " + hexify(buf)); 340 break; 341 } 342 343 if (nlMsg.getHeader().nlmsg_type == NLMSG_DONE) { 344 return destroyedSockets; 345 } 346 347 if (!(nlMsg instanceof InetDiagMessage)) { 348 Log.wtf(TAG, "Received unexpected netlink message: " + nlMsg); 349 continue; 350 } 351 352 final InetDiagMessage diagMsg = (InetDiagMessage) nlMsg; 353 if (filter.test(diagMsg)) { 354 try { 355 sendNetlinkDestroyRequest(destroyFd, proto, diagMsg); 356 destroyedSockets++; 357 } catch (InterruptedIOException | ErrnoException e) { 358 if (!(e instanceof ErrnoException 359 && ((ErrnoException) e).errno == ENOENT)) { 360 Log.e(TAG, "Failed to destroy socket: diagMsg=" + diagMsg + ", " + e); 361 } 362 } 363 } 364 } 365 } 366 } 367 368 /** 369 * Returns whether the InetDiagMessage is for adb socket or not 370 */ 371 @VisibleForTesting isAdbSocket(final InetDiagMessage msg)372 public static boolean isAdbSocket(final InetDiagMessage msg) { 373 // This is inaccurate since adb could run with ROOT_UID or other services can run with 374 // SHELL_UID. But this check covers most cases and enough. 375 // Note that getting service.adb.tcp.port system property is prohibited by sepolicy 376 // TODO: skip the socket only if there is a listen socket owned by SHELL_UID with the same 377 // source port as this socket 378 return msg.inetDiagMsg.idiag_uid == Process.SHELL_UID; 379 } 380 381 /** 382 * Returns whether the range contains the uid in the InetDiagMessage or not 383 */ 384 @VisibleForTesting containsUid(InetDiagMessage msg, Set<Range<Integer>> ranges)385 public static boolean containsUid(InetDiagMessage msg, Set<Range<Integer>> ranges) { 386 for (final Range<Integer> range: ranges) { 387 if (range.contains(msg.inetDiagMsg.idiag_uid)) { 388 return true; 389 } 390 } 391 return false; 392 } 393 isLoopbackAddress(InetAddress addr)394 private static boolean isLoopbackAddress(InetAddress addr) { 395 if (addr.isLoopbackAddress()) return true; 396 if (!(addr instanceof Inet6Address)) return false; 397 398 // Following check is for v4-mapped v6 address. StructInetDiagSockId contains v4-mapped v6 399 // address as Inet6Address, See StructInetDiagSockId#parse 400 final byte[] addrBytes = addr.getAddress(); 401 for (int i = 0; i < 10; i++) { 402 if (addrBytes[i] != 0) return false; 403 } 404 return addrBytes[10] == (byte) 0xff 405 && addrBytes[11] == (byte) 0xff 406 && addrBytes[12] == 127; 407 } 408 409 /** 410 * Returns whether the socket address in the InetDiagMessage is loopback or not 411 */ 412 @VisibleForTesting isLoopback(InetDiagMessage msg)413 public static boolean isLoopback(InetDiagMessage msg) { 414 final InetAddress srcAddr = msg.inetDiagMsg.id.locSocketAddress.getAddress(); 415 final InetAddress dstAddr = msg.inetDiagMsg.id.remSocketAddress.getAddress(); 416 return isLoopbackAddress(srcAddr) 417 || isLoopbackAddress(dstAddr) 418 || srcAddr.equals(dstAddr); 419 } 420 destroySockets(int proto, int states, Predicate<InetDiagMessage> filter)421 private static void destroySockets(int proto, int states, Predicate<InetDiagMessage> filter) 422 throws ErrnoException, SocketException, InterruptedIOException { 423 FileDescriptor dumpFd = null; 424 FileDescriptor destroyFd = null; 425 426 try { 427 dumpFd = NetlinkUtils.createNetLinkInetDiagSocket(); 428 destroyFd = NetlinkUtils.createNetLinkInetDiagSocket(); 429 connectSocketToNetlink(dumpFd); 430 connectSocketToNetlink(destroyFd); 431 432 for (int family : List.of(AF_INET, AF_INET6)) { 433 try { 434 sendNetlinkDumpRequest(dumpFd, proto, states, family); 435 } catch (InterruptedIOException | ErrnoException e) { 436 Log.e(TAG, "Failed to send netlink dump request: " + e); 437 continue; 438 } 439 final int destroyedSockets = processNetlinkDumpAndDestroySockets( 440 dumpFd, destroyFd, proto, filter); 441 Log.d(TAG, "Destroyed " + destroyedSockets + " sockets" 442 + ", proto=" + stringForProtocol(proto) 443 + ", family=" + stringForAddressFamily(family) 444 + ", states=" + states); 445 } 446 } finally { 447 closeSocketQuietly(dumpFd); 448 closeSocketQuietly(destroyFd); 449 } 450 } 451 452 /** 453 * Close tcp sockets that match the following condition 454 * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV 455 * 2. Owner uid of socket is not in the exemptUids 456 * 3. Owner uid of socket is in the ranges 457 * 4. Socket is not loopback 458 * 5. Socket is not adb socket 459 * 460 * @param ranges target uid ranges 461 * @param exemptUids uids to skip close socket 462 */ destroyLiveTcpSockets(Set<Range<Integer>> ranges, Set<Integer> exemptUids)463 public static void destroyLiveTcpSockets(Set<Range<Integer>> ranges, Set<Integer> exemptUids) 464 throws SocketException, InterruptedIOException, ErrnoException { 465 final long startTimeMs = SystemClock.elapsedRealtime(); 466 destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, 467 (diagMsg) -> !exemptUids.contains(diagMsg.inetDiagMsg.idiag_uid) 468 && containsUid(diagMsg, ranges) 469 && !isLoopback(diagMsg) 470 && !isAdbSocket(diagMsg)); 471 final long durationMs = SystemClock.elapsedRealtime() - startTimeMs; 472 Log.d(TAG, "Destroyed live tcp sockets for uids=" + ranges + " exemptUids=" + exemptUids 473 + " in " + durationMs + "ms"); 474 } 475 476 /** 477 * Close tcp sockets that match the following condition 478 * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV 479 * 2. Owner uid of socket is in the targetUids 480 * 3. Socket is not loopback 481 * 4. Socket is not adb socket 482 * 483 * @param ownerUids target uids to close sockets 484 */ destroyLiveTcpSocketsByOwnerUids(Set<Integer> ownerUids)485 public static void destroyLiveTcpSocketsByOwnerUids(Set<Integer> ownerUids) 486 throws SocketException, InterruptedIOException, ErrnoException { 487 final long startTimeMs = SystemClock.elapsedRealtime(); 488 destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, 489 (diagMsg) -> ownerUids.contains(diagMsg.inetDiagMsg.idiag_uid) 490 && !isLoopback(diagMsg) 491 && !isAdbSocket(diagMsg)); 492 final long durationMs = SystemClock.elapsedRealtime() - startTimeMs; 493 Log.d(TAG, "Destroyed live tcp sockets for uids=" + ownerUids + " in " + durationMs + "ms"); 494 } 495 496 @Override toString()497 public String toString() { 498 return "InetDiagMessage{ " 499 + "nlmsghdr{" 500 + (mHeader == null ? "" : mHeader.toString(NETLINK_INET_DIAG)) + "}, " 501 + "inet_diag_msg{" 502 + (inetDiagMsg == null ? "" : inetDiagMsg.toString()) + "} " 503 + "}"; 504 } 505 } 506