1 /*
2  * Copyright (C) 2015 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 android.system.OsConstants;
20 
21 import androidx.annotation.NonNull;
22 
23 import java.nio.ByteBuffer;
24 
25 /**
26  * Various constants and static helper methods for netlink communications.
27  *
28  * Values taken from:
29  *
30  *     include/uapi/linux/netfilter/nfnetlink.h
31  *     include/uapi/linux/netfilter/nfnetlink_conntrack.h
32  *     include/uapi/linux/netlink.h
33  *     include/uapi/linux/rtnetlink.h
34  *
35  * @hide
36  */
37 public class NetlinkConstants {
NetlinkConstants()38     private NetlinkConstants() {}
39 
40     public static final int NLA_ALIGNTO = 4;
41     /**
42      * Flag for dumping struct tcp_info.
43      * Corresponding to enum definition in external/strace/linux/inet_diag.h.
44      */
45     public static final int INET_DIAG_MEMINFO = 1;
46 
47     public static final int SOCKDIAG_MSG_HEADER_SIZE =
48             StructNlMsgHdr.STRUCT_SIZE + StructInetDiagMsg.STRUCT_SIZE;
49 
50     /**
51      * Get the aligned length based on a Short type number.
52      */
alignedLengthOf(short length)53     public static final int alignedLengthOf(short length) {
54         final int intLength = (int) length & 0xffff;
55         return alignedLengthOf(intLength);
56     }
57 
58     /**
59      * Get the aligned length based on a Integer type number.
60      */
alignedLengthOf(int length)61     public static final int alignedLengthOf(int length) {
62         if (length <= 0) return 0;
63         return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO);
64     }
65 
66     /**
67      * Convert a address family type to a string.
68      */
stringForAddressFamily(int family)69     public static String stringForAddressFamily(int family) {
70         if (family == OsConstants.AF_INET) return "AF_INET";
71         if (family == OsConstants.AF_INET6) return "AF_INET6";
72         if (family == OsConstants.AF_NETLINK) return "AF_NETLINK";
73         if (family == OsConstants.AF_UNSPEC) return "AF_UNSPEC";
74         return String.valueOf(family);
75     }
76 
77     /**
78      * Convert a protocol type to a string.
79      */
stringForProtocol(int protocol)80     public static String stringForProtocol(int protocol) {
81         if (protocol == OsConstants.IPPROTO_TCP) return "IPPROTO_TCP";
82         if (protocol == OsConstants.IPPROTO_UDP) return "IPPROTO_UDP";
83         return String.valueOf(protocol);
84     }
85 
86     /**
87      * Convert a byte array to a hexadecimal string.
88      */
hexify(byte[] bytes)89     public static String hexify(byte[] bytes) {
90         if (bytes == null) return "(null)";
91         return toHexString(bytes, 0, bytes.length);
92     }
93 
94     /**
95      * Convert a {@link ByteBuffer} to a hexadecimal string.
96      */
hexify(ByteBuffer buffer)97     public static String hexify(ByteBuffer buffer) {
98         if (buffer == null) return "(null)";
99         return toHexString(
100                 buffer.array(), buffer.position(), buffer.remaining());
101     }
102 
103     // Known values for struct nlmsghdr nlm_type.
104     public static final short NLMSG_NOOP                    = 1;   // Nothing
105     public static final short NLMSG_ERROR                   = 2;   // Error
106     public static final short NLMSG_DONE                    = 3;   // End of a dump
107     public static final short NLMSG_OVERRUN                 = 4;   // Data lost
108     public static final short NLMSG_MAX_RESERVED            = 15;  // Max reserved value
109 
110     public static final short RTM_NEWLINK                   = 16;
111     public static final short RTM_DELLINK                   = 17;
112     public static final short RTM_GETLINK                   = 18;
113     public static final short RTM_SETLINK                   = 19;
114     public static final short RTM_NEWADDR                   = 20;
115     public static final short RTM_DELADDR                   = 21;
116     public static final short RTM_GETADDR                   = 22;
117     public static final short RTM_NEWROUTE                  = 24;
118     public static final short RTM_DELROUTE                  = 25;
119     public static final short RTM_GETROUTE                  = 26;
120     public static final short RTM_NEWNEIGH                  = 28;
121     public static final short RTM_DELNEIGH                  = 29;
122     public static final short RTM_GETNEIGH                  = 30;
123     public static final short RTM_NEWRULE                   = 32;
124     public static final short RTM_DELRULE                   = 33;
125     public static final short RTM_GETRULE                   = 34;
126     public static final short RTM_NEWPREFIX                 = 52;
127     public static final short RTM_NEWNDUSEROPT              = 68;
128 
129     // Netfilter netlink message types are presented by two bytes: high byte subsystem and
130     // low byte operation. See the macro NFNL_SUBSYS_ID and NFNL_MSG_TYPE in
131     // include/uapi/linux/netfilter/nfnetlink.h
132     public static final short NFNL_SUBSYS_CTNETLINK         = 1;
133 
134     public static final short IPCTNL_MSG_CT_NEW             = 0;
135     public static final short IPCTNL_MSG_CT_GET             = 1;
136     public static final short IPCTNL_MSG_CT_DELETE          = 2;
137     public static final short IPCTNL_MSG_CT_GET_CTRZERO     = 3;
138     public static final short IPCTNL_MSG_CT_GET_STATS_CPU   = 4;
139     public static final short IPCTNL_MSG_CT_GET_STATS       = 5;
140     public static final short IPCTNL_MSG_CT_GET_DYING       = 6;
141     public static final short IPCTNL_MSG_CT_GET_UNCONFIRMED = 7;
142 
143     /* see include/uapi/linux/sock_diag.h */
144     public static final short SOCK_DIAG_BY_FAMILY = 20;
145     public static final short SOCK_DESTROY = 21;
146 
147     // Netlink groups.
148     public static final int RTMGRP_LINK = 1;
149     public static final int RTMGRP_IPV4_IFADDR = 0x10;
150     public static final int RTMGRP_IPV6_IFADDR = 0x100;
151     public static final int RTMGRP_IPV6_ROUTE  = 0x400;
152     public static final int RTNLGRP_IPV6_PREFIX = 18;
153     public static final int RTMGRP_IPV6_PREFIX = 1 << (RTNLGRP_IPV6_PREFIX - 1);
154     public static final int RTNLGRP_ND_USEROPT = 20;
155     public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1);
156 
157     // Netlink family
158     public static final short RTNL_FAMILY_IP6MR = 129;
159 
160     // Device flags.
161     public static final int IFF_UP       = 1 << 0;
162     public static final int IFF_LOWER_UP = 1 << 16;
163 
164     // Known values for struct rtmsg rtm_protocol.
165     public static final short RTPROT_KERNEL     = 2;
166     public static final short RTPROT_RA         = 9;
167 
168     // Known values for struct rtmsg rtm_scope.
169     public static final short RT_SCOPE_UNIVERSE = 0;
170 
171     // Known values for struct rtmsg rtm_type.
172     public static final short RTN_UNICAST       = 1;
173 
174     // Known values for struct rtmsg rtm_flags.
175     public static final int RTM_F_CLONED        = 0x200;
176 
177     /**
178      * Convert a netlink message type to a string for control message.
179      */
180     @NonNull
stringForCtlMsgType(short nlmType)181     private static String stringForCtlMsgType(short nlmType) {
182         switch (nlmType) {
183             case NLMSG_NOOP: return "NLMSG_NOOP";
184             case NLMSG_ERROR: return "NLMSG_ERROR";
185             case NLMSG_DONE: return "NLMSG_DONE";
186             case NLMSG_OVERRUN: return "NLMSG_OVERRUN";
187             default: return "unknown control message type: " + String.valueOf(nlmType);
188         }
189     }
190 
191     /**
192      * Convert a netlink message type to a string for NETLINK_ROUTE.
193      */
194     @NonNull
stringForRtMsgType(short nlmType)195     private static String stringForRtMsgType(short nlmType) {
196         switch (nlmType) {
197             case RTM_NEWLINK: return "RTM_NEWLINK";
198             case RTM_DELLINK: return "RTM_DELLINK";
199             case RTM_GETLINK: return "RTM_GETLINK";
200             case RTM_SETLINK: return "RTM_SETLINK";
201             case RTM_NEWADDR: return "RTM_NEWADDR";
202             case RTM_DELADDR: return "RTM_DELADDR";
203             case RTM_GETADDR: return "RTM_GETADDR";
204             case RTM_NEWROUTE: return "RTM_NEWROUTE";
205             case RTM_DELROUTE: return "RTM_DELROUTE";
206             case RTM_GETROUTE: return "RTM_GETROUTE";
207             case RTM_NEWNEIGH: return "RTM_NEWNEIGH";
208             case RTM_DELNEIGH: return "RTM_DELNEIGH";
209             case RTM_GETNEIGH: return "RTM_GETNEIGH";
210             case RTM_NEWRULE: return "RTM_NEWRULE";
211             case RTM_DELRULE: return "RTM_DELRULE";
212             case RTM_GETRULE: return "RTM_GETRULE";
213             case RTM_NEWPREFIX: return "RTM_NEWPREFIX";
214             case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT";
215             default: return "unknown RTM type: " + String.valueOf(nlmType);
216         }
217     }
218 
219     /**
220      * Convert a netlink message type to a string for NETLINK_INET_DIAG.
221      */
222     @NonNull
stringForInetDiagMsgType(short nlmType)223     private static String stringForInetDiagMsgType(short nlmType) {
224         switch (nlmType) {
225             case SOCK_DIAG_BY_FAMILY: return "SOCK_DIAG_BY_FAMILY";
226             default: return "unknown SOCK_DIAG type: " + String.valueOf(nlmType);
227         }
228     }
229 
230     /**
231      * Convert a netlink message type to a string for NETLINK_NETFILTER.
232      */
233     @NonNull
stringForNfMsgType(short nlmType)234     private static String stringForNfMsgType(short nlmType) {
235         final byte subsysId = (byte) (nlmType >> 8);
236         final byte msgType = (byte) nlmType;
237         switch (subsysId) {
238             case NFNL_SUBSYS_CTNETLINK:
239                 switch (msgType) {
240                     case IPCTNL_MSG_CT_NEW: return "IPCTNL_MSG_CT_NEW";
241                     case IPCTNL_MSG_CT_GET: return "IPCTNL_MSG_CT_GET";
242                     case IPCTNL_MSG_CT_DELETE: return "IPCTNL_MSG_CT_DELETE";
243                     case IPCTNL_MSG_CT_GET_CTRZERO: return "IPCTNL_MSG_CT_GET_CTRZERO";
244                     case IPCTNL_MSG_CT_GET_STATS_CPU: return "IPCTNL_MSG_CT_GET_STATS_CPU";
245                     case IPCTNL_MSG_CT_GET_STATS: return "IPCTNL_MSG_CT_GET_STATS";
246                     case IPCTNL_MSG_CT_GET_DYING: return "IPCTNL_MSG_CT_GET_DYING";
247                     case IPCTNL_MSG_CT_GET_UNCONFIRMED: return "IPCTNL_MSG_CT_GET_UNCONFIRMED";
248                 }
249                 break;
250         }
251         return "unknown NETFILTER type: " + String.valueOf(nlmType);
252     }
253 
254     /**
255      * Convert a netlink message type to a string by netlink family.
256      */
257     @NonNull
stringForNlMsgType(short nlmType, int nlFamily)258     public static String stringForNlMsgType(short nlmType, int nlFamily) {
259         // Reserved control messages. The netlink family is ignored.
260         // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h.
261         if (nlmType <= NLMSG_MAX_RESERVED) return stringForCtlMsgType(nlmType);
262 
263         // Netlink family messages. The netlink family is required. Note that the reason for using
264         // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are
265         // not constant.
266         if (nlFamily == OsConstants.NETLINK_ROUTE) return stringForRtMsgType(nlmType);
267         if (nlFamily == OsConstants.NETLINK_INET_DIAG) return stringForInetDiagMsgType(nlmType);
268         if (nlFamily == OsConstants.NETLINK_NETFILTER) return stringForNfMsgType(nlmType);
269 
270         return "unknown type: " + String.valueOf(nlmType);
271     }
272 
273     private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
274             'A', 'B', 'C', 'D', 'E', 'F' };
275     /**
276      * Convert a byte array to a hexadecimal string.
277      */
toHexString(byte[] array, int offset, int length)278     public static String toHexString(byte[] array, int offset, int length) {
279         char[] buf = new char[length * 2];
280 
281         int bufIndex = 0;
282         for (int i = offset; i < offset + length; i++) {
283             byte b = array[i];
284             buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
285             buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
286         }
287 
288         return new String(buf);
289     }
290 }
291