diff --git a/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmAddressT.java b/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmAddressT.java new file mode 100644 index 0000000000..4c1988745a --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmAddressT.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 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 com.android.net.module.util.netlink; + +import android.system.OsConstants; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Struct xfrm_address_t + * + *

see include/uapi/linux/xfrm.h + * + *

+ * typedef union {
+ *      __be32 a4;
+ *      __be32 a6[4];
+ *      struct in6_addr in6;
+ * } xfrm_address_t;
+ * 
+ * + * @hide + */ +public class IpSecStructXfrmAddressT extends Struct { + private static final int IPV4_ADDRESS_LEN = 4; + + public static final int STRUCT_SIZE = 16; + + @Field(order = 0, type = Type.ByteArray, arraysize = STRUCT_SIZE) + public final byte[] address; + + // Constructor that allows Strutc.parse(Class, ByteBuffer) to work + public IpSecStructXfrmAddressT(@NonNull byte[] address) { + this.address = address.clone(); + } + + // Constructor to build a new message + public IpSecStructXfrmAddressT(@NonNull InetAddress inetAddress) { + this.address = new byte[STRUCT_SIZE]; + final byte[] addressBytes = inetAddress.getAddress(); + System.arraycopy(addressBytes, 0, address, 0, addressBytes.length); + } + + /** Return the address in InetAddress */ + public InetAddress getAddress(int family) { + final byte[] addressBytes; + if (family == OsConstants.AF_INET6) { + addressBytes = this.address; + } else if (family == OsConstants.AF_INET) { + addressBytes = new byte[IPV4_ADDRESS_LEN]; + System.arraycopy(this.address, 0, addressBytes, 0, addressBytes.length); + } else { + throw new IllegalArgumentException("Invalid IP family " + family); + } + + try { + return InetAddress.getByAddress(addressBytes); + } catch (UnknownHostException e) { + // This should never happen + throw new IllegalArgumentException( + "Illegal length of IP address " + addressBytes.length, e); + } + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmUsersaId.java b/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmUsersaId.java new file mode 100644 index 0000000000..6f7b656b9c --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmUsersaId.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.InetAddress; + +/** + * Struct xfrm_usersa_id + * + *

see include/uapi/linux/xfrm.h + * + *

+ * struct xfrm_usersa_id {
+ *      xfrm_address_t      daddr;
+ *      __be32              spi;
+ *      __u16               family;
+ *      __u8                proto;
+ * };
+ * 
+ * + * @hide + */ +public class IpSecStructXfrmUsersaId extends Struct { + public static final int STRUCT_SIZE = 24; + + @Field(order = 0, type = Type.ByteArray, arraysize = 16) + public final byte[] nestedStructDAddr; // xfrm_address_t + + @Field(order = 1, type = Type.UBE32) + public final long spi; + + @Field(order = 2, type = Type.U16) + public final int family; + + @Field(order = 3, type = Type.U8, padding = 1) + public final short proto; + + @Computed private final IpSecStructXfrmAddressT mDestXfrmAddressT; + + // Constructor that allows Strutc.parse(Class, ByteBuffer) to work + public IpSecStructXfrmUsersaId( + @NonNull byte[] nestedStructDAddr, long spi, int family, short proto) { + this.nestedStructDAddr = nestedStructDAddr.clone(); + this.spi = spi; + this.family = family; + this.proto = proto; + + mDestXfrmAddressT = new IpSecStructXfrmAddressT(this.nestedStructDAddr); + } + + // Constructor to build a new message + public IpSecStructXfrmUsersaId( + @NonNull InetAddress destAddress, long spi, int family, short proto) { + this(new IpSecStructXfrmAddressT(destAddress).writeToBytes(), spi, family, proto); + } + + /** Return the destination address */ + public InetAddress getDestAddress() { + return mDestXfrmAddressT.getAddress(family); + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/IpSecXfrmNetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/IpSecXfrmNetlinkMessage.java new file mode 100644 index 0000000000..8ad784b169 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/IpSecXfrmNetlinkMessage.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; + +/** Base calss for XFRM netlink messages */ +// Developer notes: The Linux kernel includes a number of XFRM structs that are not standard netlink +// attributes (e.g., xfrm_usersa_id). These structs are unlikely to change size, so this XFRM +// netlink message implementation assumes their sizes will remain stable. If any non-attribute +// struct size changes, it should be caught by CTS and then developers should add +// kernel-version-based behvaiours. +public abstract class IpSecXfrmNetlinkMessage extends NetlinkMessage { + // TODO: STOPSHIP: b/308011229 Remove it when OsConstants.IPPROTO_ESP is exposed + public static final int IPPROTO_ESP = 50; + + public IpSecXfrmNetlinkMessage(@NonNull StructNlMsgHdr header) { + super(header); + } + + // TODO: Add the support for parsing messages +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/IpSecStructXfrmUsersaIdTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/IpSecStructXfrmUsersaIdTest.java new file mode 100644 index 0000000000..4266f68eec --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/IpSecStructXfrmUsersaIdTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 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 com.android.net.module.util.netlink; + +import static com.android.net.module.util.netlink.IpSecXfrmNetlinkMessage.IPPROTO_ESP; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.HexDump; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IpSecStructXfrmUsersaIdTest { + private static final String EXPECTED_HEX_STRING = + "C0000201000000000000000000000000" + "7768440002003200"; + private static final byte[] EXPECTED_HEX = HexDump.hexStringToByteArray(EXPECTED_HEX_STRING); + + private static final InetAddress DEST_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1"); + private static final long SPI = 0x77684400; + private static final int FAMILY = OsConstants.AF_INET; + private static final short PROTO = IPPROTO_ESP; + + @Test + public void testEncode() throws Exception { + final IpSecStructXfrmUsersaId struct = + new IpSecStructXfrmUsersaId(DEST_ADDRESS, SPI, FAMILY, PROTO); + + ByteBuffer buffer = ByteBuffer.allocate(EXPECTED_HEX.length); + buffer.order(ByteOrder.nativeOrder()); + struct.writeToByteBuffer(buffer); + + assertArrayEquals(EXPECTED_HEX, buffer.array()); + } + + @Test + public void testDecode() throws Exception { + final ByteBuffer buffer = ByteBuffer.wrap(EXPECTED_HEX); + buffer.order(ByteOrder.nativeOrder()); + + final IpSecStructXfrmUsersaId struct = + IpSecStructXfrmUsersaId.parse(IpSecStructXfrmUsersaId.class, buffer); + + assertEquals(DEST_ADDRESS, struct.getDestAddress()); + assertEquals(SPI, struct.spi); + assertEquals(FAMILY, struct.family); + assertEquals(PROTO, struct.proto); + } +}