Merge "[XFRM_MSG_NEWSA] Support xfrm_stats and xfrm_usersa_info" into main
This commit is contained in:
commit
4e6bd8f7d4
4 changed files with 406 additions and 0 deletions
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 com.android.net.module.util.Struct;
|
||||
|
||||
/**
|
||||
* Struct xfrm_lifetime_cur
|
||||
*
|
||||
* <p>see include/uapi/linux/xfrm.h
|
||||
*
|
||||
* <pre>
|
||||
* struct xfrm_stats {
|
||||
* __u32 replay_window;
|
||||
* __u32 replay;
|
||||
* __u32 integrity_failed;
|
||||
* };
|
||||
* </pre>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructXfrmStats extends Struct {
|
||||
public static final int STRUCT_SIZE = 12;
|
||||
|
||||
/** Number of packets that fall out of the replay window */
|
||||
@Field(order = 0, type = Type.U32)
|
||||
public final long replayWindow;
|
||||
|
||||
/** Number of replayed packets */
|
||||
@Field(order = 1, type = Type.U32)
|
||||
public final long replay;
|
||||
|
||||
/** Number of packets that failed authentication */
|
||||
@Field(order = 2, type = Type.U32)
|
||||
public final long integrityFailed;
|
||||
|
||||
// Constructor that allows Strutc.parse(Class<T>, ByteBuffer) to work
|
||||
public StructXfrmStats(long replayWindow, long replay, long integrityFailed) {
|
||||
this.replayWindow = replayWindow;
|
||||
this.replay = replay;
|
||||
this.integrityFailed = integrityFailed;
|
||||
}
|
||||
|
||||
// Constructor to build a new message
|
||||
public StructXfrmStats() {
|
||||
this(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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 android.system.OsConstants;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.net.module.util.Struct;
|
||||
import com.android.net.module.util.Struct.Computed;
|
||||
import com.android.net.module.util.Struct.Field;
|
||||
import com.android.net.module.util.Struct.Type;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Struct xfrm_usersa_info
|
||||
*
|
||||
* <p>see include/uapi/linux/xfrm.h
|
||||
*
|
||||
* <pre>
|
||||
* struct xfrm_usersa_info {
|
||||
* struct xfrm_selector sel;
|
||||
* struct xfrm_id id;
|
||||
* xfrm_address_t saddr;
|
||||
* struct xfrm_lifetime_cfg lft;
|
||||
* struct xfrm_lifetime_cur curlft;
|
||||
* struct xfrm_stats stats;
|
||||
* __u32 seq;
|
||||
* __u32 reqid;
|
||||
* __u16 family;
|
||||
* __u8 mode;
|
||||
* __u8 replay_window;
|
||||
* __u8 flags;
|
||||
* };
|
||||
* </pre>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructXfrmUsersaInfo extends Struct {
|
||||
private static final int NESTED_STRUCTS_SIZE =
|
||||
StructXfrmSelector.STRUCT_SIZE
|
||||
+ StructXfrmId.STRUCT_SIZE
|
||||
+ StructXfrmAddressT.STRUCT_SIZE
|
||||
+ StructXfrmLifetimeCfg.STRUCT_SIZE
|
||||
+ StructXfrmLifetimeCur.STRUCT_SIZE
|
||||
+ StructXfrmStats.STRUCT_SIZE;
|
||||
|
||||
public static final int STRUCT_SIZE = NESTED_STRUCTS_SIZE + 20;
|
||||
|
||||
@Computed private final StructXfrmSelector mXfrmSelector;
|
||||
@Computed private final StructXfrmId mXfrmId;
|
||||
@Computed private final StructXfrmAddressT mSourceXfrmAddressT;
|
||||
@Computed private final StructXfrmLifetimeCfg mXfrmLifetime;
|
||||
@Computed private final StructXfrmLifetimeCur mXfrmCurrentLifetime;
|
||||
@Computed private final StructXfrmStats mXfrmStats;
|
||||
|
||||
@Field(order = 0, type = Type.ByteArray, arraysize = NESTED_STRUCTS_SIZE)
|
||||
public final byte[] nestedStructs;
|
||||
|
||||
@Field(order = 1, type = Type.U32)
|
||||
public final long seq;
|
||||
|
||||
@Field(order = 2, type = Type.U32)
|
||||
public final long reqId;
|
||||
|
||||
@Field(order = 3, type = Type.U16)
|
||||
public final int family;
|
||||
|
||||
@Field(order = 4, type = Type.U8)
|
||||
public final short mode;
|
||||
|
||||
@Field(order = 5, type = Type.U8)
|
||||
public final short replayWindowLegacy;
|
||||
|
||||
@Field(order = 6, type = Type.U8, padding = 7)
|
||||
public final short flags;
|
||||
|
||||
// Constructor that allows Strutc.parse(Class<T>, ByteBuffer) to work
|
||||
public StructXfrmUsersaInfo(
|
||||
@NonNull final byte[] nestedStructs,
|
||||
long seq,
|
||||
long reqId,
|
||||
int family,
|
||||
short mode,
|
||||
short replayWindowLegacy,
|
||||
short flags) {
|
||||
this.nestedStructs = nestedStructs.clone();
|
||||
this.seq = seq;
|
||||
this.reqId = reqId;
|
||||
this.family = family;
|
||||
this.mode = mode;
|
||||
this.replayWindowLegacy = replayWindowLegacy;
|
||||
this.flags = flags;
|
||||
|
||||
final ByteBuffer nestedStructsBuff = ByteBuffer.wrap(nestedStructs);
|
||||
nestedStructsBuff.order(ByteOrder.nativeOrder());
|
||||
|
||||
// The parsing order matters
|
||||
mXfrmSelector = Struct.parse(StructXfrmSelector.class, nestedStructsBuff);
|
||||
mXfrmId = Struct.parse(StructXfrmId.class, nestedStructsBuff);
|
||||
mSourceXfrmAddressT = Struct.parse(StructXfrmAddressT.class, nestedStructsBuff);
|
||||
mXfrmLifetime = Struct.parse(StructXfrmLifetimeCfg.class, nestedStructsBuff);
|
||||
mXfrmCurrentLifetime = Struct.parse(StructXfrmLifetimeCur.class, nestedStructsBuff);
|
||||
mXfrmStats = Struct.parse(StructXfrmStats.class, nestedStructsBuff);
|
||||
}
|
||||
|
||||
// Constructor to build a new message for TESTING
|
||||
StructXfrmUsersaInfo(
|
||||
@NonNull final InetAddress dAddr,
|
||||
@NonNull final InetAddress sAddr,
|
||||
@NonNull final BigInteger addTime,
|
||||
int selectorFamily,
|
||||
long spi,
|
||||
long seq,
|
||||
long reqId,
|
||||
short proto,
|
||||
short mode,
|
||||
short replayWindowLegacy,
|
||||
short flags) {
|
||||
this.seq = seq;
|
||||
this.reqId = reqId;
|
||||
this.family = dAddr instanceof Inet4Address ? OsConstants.AF_INET : OsConstants.AF_INET6;
|
||||
this.mode = mode;
|
||||
this.replayWindowLegacy = replayWindowLegacy;
|
||||
this.flags = flags;
|
||||
|
||||
mXfrmSelector = new StructXfrmSelector(selectorFamily);
|
||||
mXfrmId = new StructXfrmId(dAddr, spi, proto);
|
||||
mSourceXfrmAddressT = new StructXfrmAddressT(sAddr);
|
||||
mXfrmLifetime = new StructXfrmLifetimeCfg();
|
||||
mXfrmCurrentLifetime =
|
||||
new StructXfrmLifetimeCur(
|
||||
BigInteger.ZERO, BigInteger.ZERO, addTime, BigInteger.ZERO);
|
||||
mXfrmStats = new StructXfrmStats();
|
||||
|
||||
final ByteBuffer nestedStructsBuff = ByteBuffer.allocate(NESTED_STRUCTS_SIZE);
|
||||
nestedStructsBuff.order(ByteOrder.nativeOrder());
|
||||
|
||||
mXfrmSelector.writeToByteBuffer(nestedStructsBuff);
|
||||
mXfrmId.writeToByteBuffer(nestedStructsBuff);
|
||||
mSourceXfrmAddressT.writeToByteBuffer(nestedStructsBuff);
|
||||
mXfrmLifetime.writeToByteBuffer(nestedStructsBuff);
|
||||
mXfrmCurrentLifetime.writeToByteBuffer(nestedStructsBuff);
|
||||
mXfrmStats.writeToByteBuffer(nestedStructsBuff);
|
||||
|
||||
this.nestedStructs = nestedStructsBuff.array();
|
||||
}
|
||||
|
||||
// Constructor to build a new message
|
||||
public StructXfrmUsersaInfo(
|
||||
@NonNull final InetAddress dAddr,
|
||||
@NonNull final InetAddress sAddr,
|
||||
long spi,
|
||||
long seq,
|
||||
long reqId,
|
||||
short proto,
|
||||
short mode,
|
||||
short replayWindowLegacy,
|
||||
short flags) {
|
||||
// Use AF_UNSPEC for all SAs selectors. In transport mode, kernel picks selector family
|
||||
// based on usersa->family, while in tunnel mode, the XFRM_STATE_AF_UNSPEC flag allows
|
||||
// dual-stack SAs.
|
||||
this(
|
||||
dAddr,
|
||||
sAddr,
|
||||
BigInteger.ZERO,
|
||||
OsConstants.AF_UNSPEC,
|
||||
spi,
|
||||
seq,
|
||||
reqId,
|
||||
proto,
|
||||
mode,
|
||||
replayWindowLegacy,
|
||||
flags);
|
||||
}
|
||||
|
||||
/** Return the destination address */
|
||||
public InetAddress getDestAddress() {
|
||||
return mXfrmId.getDestAddress(family);
|
||||
}
|
||||
|
||||
/** Return the source address */
|
||||
public InetAddress getSrcAddress() {
|
||||
return mSourceXfrmAddressT.getAddress(family);
|
||||
}
|
||||
|
||||
/** Return the SPI */
|
||||
public long getSpi() {
|
||||
return mXfrmId.spi;
|
||||
}
|
||||
|
||||
/** Return the current lifetime */
|
||||
public StructXfrmLifetimeCur getCurrentLifetime() {
|
||||
return mXfrmCurrentLifetime;
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,9 @@ public abstract class XfrmNetlinkMessage extends NetlinkMessage {
|
|||
public static final short XFRM_MSG_NEWSA = 16;
|
||||
public static final short XFRM_MSG_GETSA = 18;
|
||||
|
||||
public static final int XFRM_MODE_TRANSPORT = 0;
|
||||
public static final int XFRM_MODE_TUNNEL = 1;
|
||||
|
||||
public static final BigInteger XFRM_INF = new BigInteger("FFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
public XfrmNetlinkMessage(@NonNull final StructNlMsgHdr header) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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.XFRM_MODE_TRANSPORT;
|
||||
|
||||
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.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class StructXfrmUsersaInfoTest {
|
||||
private static final String EXPECTED_HEX_STRING =
|
||||
"00000000000000000000000000000000"
|
||||
+ "00000000000000000000000000000000"
|
||||
+ "00000000000000000A00000000000000"
|
||||
+ "000000000000000020010DB800000000"
|
||||
+ "0000000000000111AABBCCDD32000000"
|
||||
+ "20010DB8000000000000000000000222"
|
||||
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
+ "00000000000000000000000000000000"
|
||||
+ "00000000000000000000000000000000"
|
||||
+ "00000000000000000000000000000000"
|
||||
+ "FD464C65000000000000000000000000"
|
||||
+ "00000000000000000000000000000000"
|
||||
+ "024000000A0000000000000000000000";
|
||||
private static final byte[] EXPECTED_HEX = HexDump.hexStringToByteArray(EXPECTED_HEX_STRING);
|
||||
|
||||
private static final InetAddress DEST_ADDRESS =
|
||||
InetAddresses.parseNumericAddress("2001:db8::111");
|
||||
private static final InetAddress SOURCE_ADDRESS =
|
||||
InetAddresses.parseNumericAddress("2001:db8::222");
|
||||
private static final BigInteger ADD_TIME;
|
||||
private static final int SELECTOR_FAMILY = OsConstants.AF_INET6;
|
||||
private static final int FAMILY = OsConstants.AF_INET6;
|
||||
private static final long SPI = 0xaabbccddL;
|
||||
private static final long SEQ = 0L;
|
||||
private static final long REQ_ID = 16386L;
|
||||
private static final short PROTO = IPPROTO_ESP;
|
||||
private static final short MODE = XFRM_MODE_TRANSPORT;
|
||||
private static final short REPLAY_WINDOW_LEGACY = 0;
|
||||
private static final short FLAGS = 0;
|
||||
|
||||
static {
|
||||
final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||
cal.set(2023, Calendar.NOVEMBER, 9, 2, 42, 05);
|
||||
final long timestampSeconds = TimeUnit.MILLISECONDS.toSeconds(cal.getTimeInMillis());
|
||||
ADD_TIME = BigInteger.valueOf(timestampSeconds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncode() throws Exception {
|
||||
final StructXfrmUsersaInfo struct =
|
||||
new StructXfrmUsersaInfo(
|
||||
DEST_ADDRESS,
|
||||
SOURCE_ADDRESS,
|
||||
ADD_TIME,
|
||||
SELECTOR_FAMILY,
|
||||
SPI,
|
||||
SEQ,
|
||||
REQ_ID,
|
||||
PROTO,
|
||||
MODE,
|
||||
REPLAY_WINDOW_LEGACY,
|
||||
FLAGS);
|
||||
|
||||
final 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 StructXfrmUsersaInfo struct =
|
||||
StructXfrmUsersaInfo.parse(StructXfrmUsersaInfo.class, buffer);
|
||||
|
||||
assertEquals(DEST_ADDRESS, struct.getDestAddress());
|
||||
assertEquals(SOURCE_ADDRESS, struct.getSrcAddress());
|
||||
assertEquals(SPI, struct.getSpi());
|
||||
assertEquals(SEQ, struct.seq);
|
||||
assertEquals(REQ_ID, struct.reqId);
|
||||
assertEquals(FAMILY, struct.family);
|
||||
assertEquals(MODE, struct.mode);
|
||||
assertEquals(REPLAY_WINDOW_LEGACY, struct.replayWindowLegacy);
|
||||
assertEquals(FLAGS, struct.flags);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue