blob: b4d9cc0b31512ae6be1149dea92e6625b8a83689 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.netlink;
import android.annotation.NonNull;
import android.system.OsConstants;
import java.nio.ByteBuffer;
/**
* Various constants and static helper methods for netlink communications.
*
* Values taken from:
*
* include/uapi/linux/netfilter/nfnetlink.h
* include/uapi/linux/netfilter/nfnetlink_conntrack.h
* include/uapi/linux/netlink.h
* include/uapi/linux/rtnetlink.h
*
* @hide
*/
public class NetlinkConstants {
private NetlinkConstants() {}
public static final int NLA_ALIGNTO = 4;
/**
* Flag for dumping struct tcp_info.
* Corresponding to enum definition in external/strace/linux/inet_diag.h.
*/
public static final int INET_DIAG_MEMINFO = 1;
public static final int SOCKDIAG_MSG_HEADER_SIZE =
StructNlMsgHdr.STRUCT_SIZE + StructInetDiagMsg.STRUCT_SIZE;
public static final int alignedLengthOf(short length) {
final int intLength = (int) length & 0xffff;
return alignedLengthOf(intLength);
}
public static final int alignedLengthOf(int length) {
if (length <= 0) { return 0; }
return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO);
}
public static String stringForAddressFamily(int family) {
if (family == OsConstants.AF_INET) { return "AF_INET"; }
if (family == OsConstants.AF_INET6) { return "AF_INET6"; }
if (family == OsConstants.AF_NETLINK) { return "AF_NETLINK"; }
return String.valueOf(family);
}
public static String stringForProtocol(int protocol) {
if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; }
if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; }
return String.valueOf(protocol);
}
public static String hexify(byte[] bytes) {
if (bytes == null) { return "(null)"; }
return toHexString(bytes, 0, bytes.length);
}
public static String hexify(ByteBuffer buffer) {
if (buffer == null) { return "(null)"; }
return toHexString(
buffer.array(), buffer.position(), buffer.remaining());
}
// Known values for struct nlmsghdr nlm_type.
public static final short NLMSG_NOOP = 1; // Nothing
public static final short NLMSG_ERROR = 2; // Error
public static final short NLMSG_DONE = 3; // End of a dump
public static final short NLMSG_OVERRUN = 4; // Data lost
public static final short NLMSG_MAX_RESERVED = 15; // Max reserved value
public static final short RTM_NEWLINK = 16;
public static final short RTM_DELLINK = 17;
public static final short RTM_GETLINK = 18;
public static final short RTM_SETLINK = 19;
public static final short RTM_NEWADDR = 20;
public static final short RTM_DELADDR = 21;
public static final short RTM_GETADDR = 22;
public static final short RTM_NEWROUTE = 24;
public static final short RTM_DELROUTE = 25;
public static final short RTM_GETROUTE = 26;
public static final short RTM_NEWNEIGH = 28;
public static final short RTM_DELNEIGH = 29;
public static final short RTM_GETNEIGH = 30;
public static final short RTM_NEWRULE = 32;
public static final short RTM_DELRULE = 33;
public static final short RTM_GETRULE = 34;
public static final short RTM_NEWNDUSEROPT = 68;
// Netfilter netlink message types are presented by two bytes: high byte subsystem and
// low byte operation. See the macro NFNL_SUBSYS_ID and NFNL_MSG_TYPE in
// include/uapi/linux/netfilter/nfnetlink.h
public static final short NFNL_SUBSYS_CTNETLINK = 1;
public static final short IPCTNL_MSG_CT_NEW = 0;
public static final short IPCTNL_MSG_CT_GET = 1;
public static final short IPCTNL_MSG_CT_DELETE = 2;
public static final short IPCTNL_MSG_CT_GET_CTRZERO = 3;
public static final short IPCTNL_MSG_CT_GET_STATS_CPU = 4;
public static final short IPCTNL_MSG_CT_GET_STATS = 5;
public static final short IPCTNL_MSG_CT_GET_DYING = 6;
public static final short IPCTNL_MSG_CT_GET_UNCONFIRMED = 7;
/* see include/uapi/linux/sock_diag.h */
public static final short SOCK_DIAG_BY_FAMILY = 20;
// Netlink groups.
public static final int RTNLGRP_ND_USEROPT = 20;
public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1);
/**
* Convert a netlink message type to a string for control message.
*/
@NonNull
private static String stringForCtlMsgType(short nlmType) {
switch (nlmType) {
case NLMSG_NOOP: return "NLMSG_NOOP";
case NLMSG_ERROR: return "NLMSG_ERROR";
case NLMSG_DONE: return "NLMSG_DONE";
case NLMSG_OVERRUN: return "NLMSG_OVERRUN";
default: return "unknown control message type: " + String.valueOf(nlmType);
}
}
/**
* Convert a netlink message type to a string for NETLINK_ROUTE.
*/
@NonNull
private static String stringForRtMsgType(short nlmType) {
switch (nlmType) {
case RTM_NEWLINK: return "RTM_NEWLINK";
case RTM_DELLINK: return "RTM_DELLINK";
case RTM_GETLINK: return "RTM_GETLINK";
case RTM_SETLINK: return "RTM_SETLINK";
case RTM_NEWADDR: return "RTM_NEWADDR";
case RTM_DELADDR: return "RTM_DELADDR";
case RTM_GETADDR: return "RTM_GETADDR";
case RTM_NEWROUTE: return "RTM_NEWROUTE";
case RTM_DELROUTE: return "RTM_DELROUTE";
case RTM_GETROUTE: return "RTM_GETROUTE";
case RTM_NEWNEIGH: return "RTM_NEWNEIGH";
case RTM_DELNEIGH: return "RTM_DELNEIGH";
case RTM_GETNEIGH: return "RTM_GETNEIGH";
case RTM_NEWRULE: return "RTM_NEWRULE";
case RTM_DELRULE: return "RTM_DELRULE";
case RTM_GETRULE: return "RTM_GETRULE";
case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT";
default: return "unknown RTM type: " + String.valueOf(nlmType);
}
}
/**
* Convert a netlink message type to a string for NETLINK_INET_DIAG.
*/
@NonNull
private static String stringForInetDiagMsgType(short nlmType) {
switch (nlmType) {
case SOCK_DIAG_BY_FAMILY: return "SOCK_DIAG_BY_FAMILY";
default: return "unknown SOCK_DIAG type: " + String.valueOf(nlmType);
}
}
/**
* Convert a netlink message type to a string for NETLINK_NETFILTER.
*/
@NonNull
private static String stringForNfMsgType(short nlmType) {
final byte subsysId = (byte) (nlmType >> 8);
final byte msgType = (byte) nlmType;
switch (subsysId) {
case NFNL_SUBSYS_CTNETLINK:
switch (msgType) {
case IPCTNL_MSG_CT_NEW: return "IPCTNL_MSG_CT_NEW";
case IPCTNL_MSG_CT_GET: return "IPCTNL_MSG_CT_GET";
case IPCTNL_MSG_CT_DELETE: return "IPCTNL_MSG_CT_DELETE";
case IPCTNL_MSG_CT_GET_CTRZERO: return "IPCTNL_MSG_CT_GET_CTRZERO";
case IPCTNL_MSG_CT_GET_STATS_CPU: return "IPCTNL_MSG_CT_GET_STATS_CPU";
case IPCTNL_MSG_CT_GET_STATS: return "IPCTNL_MSG_CT_GET_STATS";
case IPCTNL_MSG_CT_GET_DYING: return "IPCTNL_MSG_CT_GET_DYING";
case IPCTNL_MSG_CT_GET_UNCONFIRMED: return "IPCTNL_MSG_CT_GET_UNCONFIRMED";
}
break;
}
return "unknown NETFILTER type: " + String.valueOf(nlmType);
}
/**
* Convert a netlink message type to a string by netlink family.
*/
@NonNull
public static String stringForNlMsgType(short nlmType, int nlFamily) {
// Reserved control messages. The netlink family is ignored.
// See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h.
if (nlmType <= NLMSG_MAX_RESERVED) return stringForCtlMsgType(nlmType);
// Netlink family messages. The netlink family is required. Note that the reason for using
// if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are
// not constant.
if (nlFamily == OsConstants.NETLINK_ROUTE) return stringForRtMsgType(nlmType);
if (nlFamily == OsConstants.NETLINK_INET_DIAG) return stringForInetDiagMsgType(nlmType);
if (nlFamily == OsConstants.NETLINK_NETFILTER) return stringForNfMsgType(nlmType);
return "unknown type: " + String.valueOf(nlmType);
}
private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F' };
/**
* Convert a byte array to a hexadecimal string.
*/
public static String toHexString(byte[] array, int offset, int length) {
char[] buf = new char[length * 2];
int bufIndex = 0;
for (int i = offset; i < offset + length; i++) {
byte b = array[i];
buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
}
return new String(buf);
}
}