1 /* 2 * Copyright (C) 2019 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.net.MacAddress; 20 21 import androidx.annotation.NonNull; 22 import androidx.annotation.Nullable; 23 24 import static java.nio.ByteOrder.nativeOrder; 25 26 import java.io.UnsupportedEncodingException; 27 import java.net.InetAddress; 28 import java.net.UnknownHostException; 29 import java.nio.ByteBuffer; 30 import java.nio.ByteOrder; 31 import java.util.Arrays; 32 33 /** 34 * struct nlattr 35 * 36 * see: <linux_src>/include/uapi/linux/netlink.h 37 * 38 * @hide 39 */ 40 public class StructNlAttr { 41 // Already aligned. 42 public static final int NLA_HEADERLEN = 4; 43 public static final int NLA_F_NESTED = (1 << 15); 44 45 /** 46 * Set carries nested attributes bit. 47 */ makeNestedType(short type)48 public static short makeNestedType(short type) { 49 return (short) (type | NLA_F_NESTED); 50 } 51 52 /** 53 * Peek and parse the netlink attribute from {@link ByteBuffer}. 54 * 55 * Return a (length, type) object only, without consuming any bytes in 56 * |byteBuffer| and without copying or interpreting any value bytes. 57 * This is used for scanning over a packed set of struct nlattr's, 58 * looking for instances of a particular type. 59 */ peek(ByteBuffer byteBuffer)60 public static StructNlAttr peek(ByteBuffer byteBuffer) { 61 if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) { 62 return null; 63 } 64 final int baseOffset = byteBuffer.position(); 65 66 final StructNlAttr struct = new StructNlAttr(); 67 final ByteOrder originalOrder = byteBuffer.order(); 68 byteBuffer.order(ByteOrder.nativeOrder()); 69 try { 70 struct.nla_len = byteBuffer.getShort(); 71 struct.nla_type = byteBuffer.getShort(); 72 } finally { 73 byteBuffer.order(originalOrder); 74 } 75 76 byteBuffer.position(baseOffset); 77 if (struct.nla_len < NLA_HEADERLEN) { 78 // Malformed. 79 return null; 80 } 81 return struct; 82 } 83 84 /** 85 * Parse a netlink attribute from a {@link ByteBuffer}. 86 * 87 * @param byteBuffer The buffer from which to parse the netlink attriute. 88 * @return the parsed netlink attribute, or {@code null} if the netlink attribute 89 * could not be parsed successfully (for example, if it was truncated). 90 */ parse(ByteBuffer byteBuffer)91 public static StructNlAttr parse(ByteBuffer byteBuffer) { 92 final StructNlAttr struct = peek(byteBuffer); 93 if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) { 94 return null; 95 } 96 97 final int baseOffset = byteBuffer.position(); 98 byteBuffer.position(baseOffset + NLA_HEADERLEN); 99 100 int valueLen = ((int) struct.nla_len) & 0xffff; 101 valueLen -= NLA_HEADERLEN; 102 if (valueLen > 0) { 103 struct.nla_value = new byte[valueLen]; 104 byteBuffer.get(struct.nla_value, 0, valueLen); 105 byteBuffer.position(baseOffset + struct.getAlignedLength()); 106 } 107 return struct; 108 } 109 110 /** 111 * Find next netlink attribute with a given type from {@link ByteBuffer}. 112 * 113 * @param attrType The given netlink attribute type is requested for. 114 * @param byteBuffer The buffer from which to find the netlink attribute. 115 * @return the found netlink attribute, or {@code null} if the netlink attribute could not be 116 * found or parsed successfully (for example, if it was truncated). 117 */ 118 @Nullable findNextAttrOfType(short attrType, @Nullable ByteBuffer byteBuffer)119 public static StructNlAttr findNextAttrOfType(short attrType, 120 @Nullable ByteBuffer byteBuffer) { 121 while (byteBuffer != null && byteBuffer.remaining() > 0) { 122 final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer); 123 if (nlAttr == null) { 124 break; 125 } 126 if (nlAttr.nla_type == attrType) { 127 return StructNlAttr.parse(byteBuffer); 128 } 129 if (byteBuffer.remaining() < nlAttr.getAlignedLength()) { 130 break; 131 } 132 byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength()); 133 } 134 return null; 135 } 136 137 public short nla_len = (short) NLA_HEADERLEN; 138 public short nla_type; 139 public byte[] nla_value; 140 StructNlAttr()141 public StructNlAttr() {} 142 StructNlAttr(short type, byte value)143 public StructNlAttr(short type, byte value) { 144 nla_type = type; 145 setValue(new byte[1]); 146 nla_value[0] = value; 147 } 148 StructNlAttr(short type, short value)149 public StructNlAttr(short type, short value) { 150 this(type, value, ByteOrder.nativeOrder()); 151 } 152 StructNlAttr(short type, short value, ByteOrder order)153 public StructNlAttr(short type, short value, ByteOrder order) { 154 nla_type = type; 155 setValue(new byte[Short.BYTES]); 156 final ByteBuffer buf = getValueAsByteBuffer(); 157 // ByteBuffer returned by getValueAsByteBuffer is always in native byte order. 158 try { 159 buf.order(order); 160 buf.putShort(value); 161 } finally { 162 buf.order(nativeOrder()); 163 } 164 } 165 StructNlAttr(short type, int value)166 public StructNlAttr(short type, int value) { 167 this(type, value, ByteOrder.nativeOrder()); 168 } 169 StructNlAttr(short type, int value, ByteOrder order)170 public StructNlAttr(short type, int value, ByteOrder order) { 171 nla_type = type; 172 setValue(new byte[Integer.BYTES]); 173 final ByteBuffer buf = getValueAsByteBuffer(); 174 // ByteBuffer returned by getValueAsByteBuffer is always in native byte order. 175 try { 176 buf.order(order); 177 buf.putInt(value); 178 } finally { 179 buf.order(nativeOrder()); 180 } 181 } 182 StructNlAttr(short type, long value)183 public StructNlAttr(short type, long value) { 184 this(type, value, ByteOrder.nativeOrder()); 185 } 186 StructNlAttr(short type, long value, ByteOrder order)187 public StructNlAttr(short type, long value, ByteOrder order) { 188 nla_type = type; 189 setValue(new byte[Long.BYTES]); 190 final ByteBuffer buf = getValueAsByteBuffer(); 191 // ByteBuffer returned by getValueAsByteBuffer is always in native byte order. 192 try { 193 buf.order(order); 194 buf.putLong(value); 195 } finally { 196 buf.order(nativeOrder()); 197 } 198 } 199 StructNlAttr(short type, @NonNull final byte[] value)200 public StructNlAttr(short type, @NonNull final byte[] value) { 201 nla_type = type; 202 setValue(value); 203 } 204 StructNlAttr(short type, @NonNull final InetAddress ip)205 public StructNlAttr(short type, @NonNull final InetAddress ip) { 206 nla_type = type; 207 setValue(ip.getAddress()); 208 } 209 StructNlAttr(short type, @NonNull final MacAddress mac)210 public StructNlAttr(short type, @NonNull final MacAddress mac) { 211 nla_type = type; 212 setValue(mac.toByteArray()); 213 } 214 StructNlAttr(short type, @NonNull final String string)215 public StructNlAttr(short type, @NonNull final String string) { 216 nla_type = type; 217 byte[] value = null; 218 try { 219 final byte[] stringBytes = string.getBytes("UTF-8"); 220 // Append '\0' at the end of interface name string bytes. 221 value = Arrays.copyOf(stringBytes, stringBytes.length + 1); 222 } catch (UnsupportedEncodingException ignored) { 223 // Do nothing. 224 } finally { 225 setValue(value); 226 } 227 } 228 StructNlAttr(short type, StructNlAttr... nested)229 public StructNlAttr(short type, StructNlAttr... nested) { 230 this(); 231 nla_type = makeNestedType(type); 232 233 int payloadLength = 0; 234 for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength(); 235 setValue(new byte[payloadLength]); 236 237 final ByteBuffer buf = getValueAsByteBuffer(); 238 for (StructNlAttr nla : nested) { 239 nla.pack(buf); 240 } 241 } 242 243 /** 244 * Get aligned attribute length. 245 */ getAlignedLength()246 public int getAlignedLength() { 247 return NetlinkConstants.alignedLengthOf(nla_len); 248 } 249 250 /** 251 * Get attribute value as BE16. 252 */ getValueAsBe16(short defaultValue)253 public short getValueAsBe16(short defaultValue) { 254 final ByteBuffer byteBuffer = getValueAsByteBuffer(); 255 if (byteBuffer == null || byteBuffer.remaining() != Short.BYTES) { 256 return defaultValue; 257 } 258 final ByteOrder originalOrder = byteBuffer.order(); 259 try { 260 byteBuffer.order(ByteOrder.BIG_ENDIAN); 261 return byteBuffer.getShort(); 262 } finally { 263 byteBuffer.order(originalOrder); 264 } 265 } 266 267 /** 268 * Get attribute value as BE32. 269 */ getValueAsBe32(int defaultValue)270 public int getValueAsBe32(int defaultValue) { 271 final ByteBuffer byteBuffer = getValueAsByteBuffer(); 272 if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { 273 return defaultValue; 274 } 275 final ByteOrder originalOrder = byteBuffer.order(); 276 try { 277 byteBuffer.order(ByteOrder.BIG_ENDIAN); 278 return byteBuffer.getInt(); 279 } finally { 280 byteBuffer.order(originalOrder); 281 } 282 } 283 284 /** 285 * Get attribute value as ByteBuffer. 286 */ getValueAsByteBuffer()287 public ByteBuffer getValueAsByteBuffer() { 288 if (nla_value == null) return null; 289 final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value); 290 // By convention, all buffers in this library are in native byte order because netlink is in 291 // native byte order. It's the order that is used by NetlinkSocket.recvMessage and the only 292 // order accepted by NetlinkMessage.parse. 293 byteBuffer.order(ByteOrder.nativeOrder()); 294 return byteBuffer; 295 } 296 297 /** 298 * Get attribute value as byte. 299 */ getValueAsByte(byte defaultValue)300 public byte getValueAsByte(byte defaultValue) { 301 final ByteBuffer byteBuffer = getValueAsByteBuffer(); 302 if (byteBuffer == null || byteBuffer.remaining() != Byte.BYTES) { 303 return defaultValue; 304 } 305 return getValueAsByteBuffer().get(); 306 } 307 308 /** 309 * Get attribute value as Integer, or null if malformed (e.g., length is not 4 bytes). 310 * The attribute value is assumed to be in native byte order. 311 */ getValueAsInteger()312 public Integer getValueAsInteger() { 313 final ByteBuffer byteBuffer = getValueAsByteBuffer(); 314 if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { 315 return null; 316 } 317 return byteBuffer.getInt(); 318 } 319 320 /** 321 * Get attribute value as Long, or null if malformed (e.g., length is not 8 bytes). 322 * The attribute value is assumed to be in native byte order. 323 */ getValueAsLong()324 public Long getValueAsLong() { 325 final ByteBuffer byteBuffer = getValueAsByteBuffer(); 326 if (byteBuffer == null || byteBuffer.remaining() != Long.BYTES) { 327 return null; 328 } 329 return byteBuffer.getLong(); 330 } 331 332 /** 333 * Get attribute value as Int, default value if malformed. 334 */ getValueAsInt(int defaultValue)335 public int getValueAsInt(int defaultValue) { 336 final Integer value = getValueAsInteger(); 337 return (value != null) ? value : defaultValue; 338 } 339 340 /** 341 * Get attribute value as InetAddress. 342 * 343 * @return the InetAddress instance representation of attribute value or null if IP address 344 * is of illegal length. 345 */ 346 @Nullable getValueAsInetAddress()347 public InetAddress getValueAsInetAddress() { 348 if (nla_value == null) return null; 349 350 try { 351 return InetAddress.getByAddress(nla_value); 352 } catch (UnknownHostException ignored) { 353 return null; 354 } 355 } 356 357 /** 358 * Get attribute value as MacAddress. 359 * 360 * @return the MacAddress instance representation of attribute value or null if the given byte 361 * array is not a valid representation(e.g, not all link layers have 6-byte link-layer 362 * addresses) 363 */ 364 @Nullable getValueAsMacAddress()365 public MacAddress getValueAsMacAddress() { 366 if (nla_value == null) return null; 367 368 try { 369 return MacAddress.fromBytes(nla_value); 370 } catch (IllegalArgumentException ignored) { 371 return null; 372 } 373 } 374 375 /** 376 * Get attribute value as a unicode string. 377 * 378 * @return a unicode string or null if UTF-8 charset is not supported. 379 */ 380 @Nullable getValueAsString()381 public String getValueAsString() { 382 if (nla_value == null) return null; 383 // Check the attribute value length after removing string termination flag '\0'. 384 // This assumes that all netlink strings are null-terminated. 385 if (nla_value.length < (nla_len - NLA_HEADERLEN - 1)) return null; 386 387 try { 388 final byte[] array = Arrays.copyOf(nla_value, nla_len - NLA_HEADERLEN - 1); 389 return new String(array, "UTF-8"); 390 } catch (UnsupportedEncodingException | NegativeArraySizeException ignored) { 391 return null; 392 } 393 } 394 395 /** 396 * Write the netlink attribute to {@link ByteBuffer}. 397 */ pack(ByteBuffer byteBuffer)398 public void pack(ByteBuffer byteBuffer) { 399 final ByteOrder originalOrder = byteBuffer.order(); 400 final int originalPosition = byteBuffer.position(); 401 402 byteBuffer.order(ByteOrder.nativeOrder()); 403 try { 404 byteBuffer.putShort(nla_len); 405 byteBuffer.putShort(nla_type); 406 if (nla_value != null) byteBuffer.put(nla_value); 407 } finally { 408 byteBuffer.order(originalOrder); 409 } 410 byteBuffer.position(originalPosition + getAlignedLength()); 411 } 412 setValue(byte[] value)413 private void setValue(byte[] value) { 414 nla_value = value; 415 nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0)); 416 } 417 418 @Override toString()419 public String toString() { 420 return "StructNlAttr{ " 421 + "nla_len{" + nla_len + "}, " 422 + "nla_type{" + nla_type + "}, " 423 + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, " 424 + "}"; 425 } 426 } 427