Merge "[XFRM_MSG_GETSA] Support XFRM_MSG_GETSA message" into main
This commit is contained in:
commit
684f92b9fb
6 changed files with 260 additions and 3 deletions
|
|
@ -16,12 +16,17 @@
|
|||
|
||||
package com.android.net.module.util.netlink;
|
||||
|
||||
import static com.android.net.module.util.netlink.xfrm.XfrmNetlinkMessage.NETLINK_XFRM;
|
||||
|
||||
import android.system.OsConstants;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.net.module.util.netlink.xfrm.XfrmNetlinkMessage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* NetlinkMessage base class for other, more specific netlink message types.
|
||||
|
|
@ -75,6 +80,8 @@ public class NetlinkMessage {
|
|||
parsed = parseInetDiagMessage(nlmsghdr, byteBuffer);
|
||||
} else if (nlFamily == OsConstants.NETLINK_NETFILTER) {
|
||||
parsed = parseNfMessage(nlmsghdr, byteBuffer);
|
||||
} else if (nlFamily == NETLINK_XFRM) {
|
||||
parsed = parseXfrmMessage(nlmsghdr, byteBuffer);
|
||||
} else {
|
||||
parsed = null;
|
||||
}
|
||||
|
|
@ -168,4 +175,19 @@ public class NetlinkMessage {
|
|||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static NetlinkMessage parseXfrmMessage(
|
||||
@NonNull final StructNlMsgHdr nlmsghdr, @NonNull final ByteBuffer byteBuffer) {
|
||||
return (NetlinkMessage) XfrmNetlinkMessage.parseXfrmInternal(nlmsghdr, byteBuffer);
|
||||
}
|
||||
|
||||
/** A convenient method to create a ByteBuffer for encoding a new message */
|
||||
protected static ByteBuffer newNlMsgByteBuffer(int payloadLen) {
|
||||
final int length = StructNlMsgHdr.STRUCT_SIZE + payloadLen;
|
||||
final ByteBuffer byteBuffer = ByteBuffer.allocate(length);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
return byteBuffer;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,14 @@ public class StructNlMsgHdr {
|
|||
nlmsg_pid = 0;
|
||||
}
|
||||
|
||||
public StructNlMsgHdr(int payloadLen, short type, short flags, int seq) {
|
||||
nlmsg_len = StructNlMsgHdr.STRUCT_SIZE + payloadLen;
|
||||
nlmsg_type = type;
|
||||
nlmsg_flags = flags;
|
||||
nlmsg_seq = seq;
|
||||
nlmsg_pid = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write netlink message header to ByteBuffer.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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.xfrm;
|
||||
|
||||
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
||||
import static com.android.net.module.util.netlink.xfrm.XfrmNetlinkMessage.XFRM_MSG_GETSA;
|
||||
|
||||
import android.system.OsConstants;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.net.module.util.Struct;
|
||||
import com.android.net.module.util.netlink.StructNlMsgHdr;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* An XfrmNetlinkMessage subclass for XFRM_MSG_GETSA messages.
|
||||
*
|
||||
* <p>see include/uapi/linux/xfrm.h
|
||||
*
|
||||
* <p>XFRM_MSG_GETSA syntax
|
||||
*
|
||||
* <ul>
|
||||
* <li>TLV: xfrm_usersa_id
|
||||
* <li>Optional Attributes: XFRMA_MARK, XFRMA_SRCADDR
|
||||
* </ul>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class XfrmNetlinkGetSaMessage extends XfrmNetlinkMessage {
|
||||
@NonNull private final StructXfrmUsersaId mXfrmUsersaId;
|
||||
|
||||
private XfrmNetlinkGetSaMessage(
|
||||
@NonNull final StructNlMsgHdr header, @NonNull final StructXfrmUsersaId xfrmUsersaId) {
|
||||
super(header);
|
||||
mXfrmUsersaId = xfrmUsersaId;
|
||||
}
|
||||
|
||||
private XfrmNetlinkGetSaMessage(
|
||||
@NonNull final StructNlMsgHdr header,
|
||||
@NonNull final InetAddress destAddress,
|
||||
long spi,
|
||||
short proto) {
|
||||
super(header);
|
||||
|
||||
final int family =
|
||||
destAddress instanceof Inet4Address ? OsConstants.AF_INET : OsConstants.AF_INET6;
|
||||
mXfrmUsersaId = new StructXfrmUsersaId(destAddress, spi, family, proto);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void packPayload(@NonNull final ByteBuffer byteBuffer) {
|
||||
mXfrmUsersaId.writeToByteBuffer(byteBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse XFRM_MSG_GETSA message from ByteBuffer.
|
||||
*
|
||||
* <p>This method should be called from NetlinkMessage#parse(ByteBuffer, int) for generic
|
||||
* message validation and processing
|
||||
*
|
||||
* @param nlmsghdr netlink message header.
|
||||
* @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. MUST be
|
||||
* host order
|
||||
*/
|
||||
@Nullable
|
||||
static XfrmNetlinkGetSaMessage parseInternal(
|
||||
@NonNull final StructNlMsgHdr nlmsghdr, @NonNull final ByteBuffer byteBuffer) {
|
||||
final StructXfrmUsersaId xfrmUsersaId = Struct.parse(StructXfrmUsersaId.class, byteBuffer);
|
||||
if (xfrmUsersaId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Attributes not supported. Don't bother handling them.
|
||||
|
||||
return new XfrmNetlinkGetSaMessage(nlmsghdr, xfrmUsersaId);
|
||||
}
|
||||
|
||||
/** A convenient method to create a XFRM_MSG_GETSA message. */
|
||||
public static byte[] newXfrmNetlinkGetSaMessage(
|
||||
@NonNull final InetAddress destAddress, long spi, short proto) {
|
||||
final int payloadLen = StructXfrmUsersaId.STRUCT_SIZE;
|
||||
|
||||
final StructNlMsgHdr nlmsghdr =
|
||||
new StructNlMsgHdr(payloadLen, XFRM_MSG_GETSA, NLM_F_REQUEST, 0);
|
||||
final XfrmNetlinkGetSaMessage message =
|
||||
new XfrmNetlinkGetSaMessage(nlmsghdr, destAddress, spi, proto);
|
||||
|
||||
final ByteBuffer byteBuffer = newNlMsgByteBuffer(payloadLen);
|
||||
message.pack(byteBuffer);
|
||||
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
public StructXfrmUsersaId getStructXfrmUsersaId() {
|
||||
return mXfrmUsersaId;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,10 +17,13 @@
|
|||
package com.android.net.module.util.netlink.xfrm;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.net.module.util.netlink.NetlinkMessage;
|
||||
import com.android.net.module.util.netlink.StructNlMsgHdr;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/** 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
|
||||
|
|
@ -28,12 +31,45 @@ import com.android.net.module.util.netlink.StructNlMsgHdr;
|
|||
// struct size changes, it should be caught by CTS and then developers should add
|
||||
// kernel-version-based behvaiours.
|
||||
public abstract class XfrmNetlinkMessage extends NetlinkMessage {
|
||||
// TODO: STOPSHIP: b/308011229 Remove it when OsConstants.IPPROTO_ESP is exposed
|
||||
// TODO: b/312498032 Remove it when OsConstants.IPPROTO_ESP is stable
|
||||
public static final int IPPROTO_ESP = 50;
|
||||
// TODO: b/312498032 Remove it when OsConstants.NETLINK_XFRM is stable
|
||||
public static final int NETLINK_XFRM = 6;
|
||||
|
||||
/* see include/uapi/linux/xfrm.h */
|
||||
public static final short XFRM_MSG_NEWSA = 16;
|
||||
public static final short XFRM_MSG_GETSA = 18;
|
||||
|
||||
public XfrmNetlinkMessage(@NonNull final StructNlMsgHdr header) {
|
||||
super(header);
|
||||
}
|
||||
|
||||
// TODO: Add the support for parsing messages
|
||||
/**
|
||||
* Parse XFRM message from ByteBuffer.
|
||||
*
|
||||
* <p>This method should be called from NetlinkMessage#parse(ByteBuffer, int) for generic
|
||||
* message validation and processing
|
||||
*
|
||||
* @param nlmsghdr netlink message header.
|
||||
* @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. MUST be
|
||||
* host order
|
||||
*/
|
||||
@Nullable
|
||||
public static XfrmNetlinkMessage parseXfrmInternal(
|
||||
@NonNull final StructNlMsgHdr nlmsghdr, @NonNull final ByteBuffer byteBuffer) {
|
||||
switch (nlmsghdr.nlmsg_type) {
|
||||
case XFRM_MSG_GETSA:
|
||||
return XfrmNetlinkGetSaMessage.parseInternal(nlmsghdr, byteBuffer);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void packPayload(@NonNull final ByteBuffer byteBuffer);
|
||||
|
||||
/** Write a XFRM message to {@link ByteBuffer}. */
|
||||
public void pack(@NonNull final ByteBuffer byteBuffer) {
|
||||
getHeader().pack(byteBuffer);
|
||||
packPayload(byteBuffer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class StructXfrmUsersaIdTest {
|
|||
public void testEncode() throws Exception {
|
||||
final StructXfrmUsersaId struct = new StructXfrmUsersaId(DEST_ADDRESS, SPI, FAMILY, PROTO);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(EXPECTED_HEX.length);
|
||||
final ByteBuffer buffer = ByteBuffer.allocate(EXPECTED_HEX.length);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
struct.writeToByteBuffer(buffer);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.xfrm;
|
||||
|
||||
import static com.android.net.module.util.netlink.xfrm.XfrmNetlinkMessage.IPPROTO_ESP;
|
||||
import static com.android.net.module.util.netlink.xfrm.XfrmNetlinkMessage.NETLINK_XFRM;
|
||||
|
||||
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 com.android.net.module.util.netlink.NetlinkMessage;
|
||||
|
||||
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 XfrmNetlinkGetSaMessageTest {
|
||||
private static final String EXPECTED_HEX_STRING =
|
||||
"28000000120001000000000000000000"
|
||||
+ "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 byte[] result =
|
||||
XfrmNetlinkGetSaMessage.newXfrmNetlinkGetSaMessage(DEST_ADDRESS, SPI, PROTO);
|
||||
assertArrayEquals(EXPECTED_HEX, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecode() throws Exception {
|
||||
final ByteBuffer buffer = ByteBuffer.wrap(EXPECTED_HEX);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
final XfrmNetlinkGetSaMessage message =
|
||||
(XfrmNetlinkGetSaMessage) NetlinkMessage.parse(buffer, NETLINK_XFRM);
|
||||
final StructXfrmUsersaId struct = message.getStructXfrmUsersaId();
|
||||
|
||||
assertEquals(DEST_ADDRESS, struct.getDestAddress());
|
||||
assertEquals(SPI, struct.spi);
|
||||
assertEquals(FAMILY, struct.family);
|
||||
assertEquals(PROTO, struct.proto);
|
||||
assertEquals(0, buffer.remaining());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue