1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
/*
* Copyright (C) 2021 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.server.connectivity;
import android.util.Log;
import android.util.Range;
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.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
/** Value type for DSCP setting and rewriting to DSCP policy BPF maps. */
public class DscpPolicyValue extends Struct {
private static final String TAG = DscpPolicyValue.class.getSimpleName();
@Field(order = 0, type = Type.ByteArray, arraysize = 16)
public final byte[] src46;
@Field(order = 1, type = Type.ByteArray, arraysize = 16)
public final byte[] dst46;
@Field(order = 2, type = Type.U32)
public final long ifIndex;
@Field(order = 3, type = Type.UBE16)
public final int srcPort;
@Field(order = 4, type = Type.UBE16)
public final int dstPortStart;
@Field(order = 5, type = Type.UBE16)
public final int dstPortEnd;
@Field(order = 6, type = Type.U8)
public final short proto;
@Field(order = 7, type = Type.U8)
public final short dscp;
@Field(order = 8, type = Type.U8, padding = 3)
public final short mask;
private static final int SRC_IP_MASK = 0x1;
private static final int DST_IP_MASK = 0x02;
private static final int SRC_PORT_MASK = 0x4;
private static final int DST_PORT_MASK = 0x8;
private static final int PROTO_MASK = 0x10;
private boolean ipEmpty(final byte[] ip) {
for (int i = 0; i < ip.length; i++) {
if (ip[i] != 0) return false;
}
return true;
}
// TODO: move to frameworks/libs/net and have this and BpfCoordinator import it.
private byte[] toIpv4MappedAddressBytes(InetAddress ia) {
final byte[] addr6 = new byte[16];
if (ia != null) {
final byte[] addr4 = ia.getAddress();
addr6[10] = (byte) 0xff;
addr6[11] = (byte) 0xff;
addr6[12] = addr4[0];
addr6[13] = addr4[1];
addr6[14] = addr4[2];
addr6[15] = addr4[3];
}
return addr6;
}
private byte[] toAddressField(InetAddress addr) {
if (addr == null) {
return EMPTY_ADDRESS_FIELD;
} else if (addr instanceof Inet4Address) {
return toIpv4MappedAddressBytes(addr);
} else {
return addr.getAddress();
}
}
private static final byte[] EMPTY_ADDRESS_FIELD =
InetAddress.parseNumericAddress("::").getAddress();
private short makeMask(final byte[] src46, final byte[] dst46, final int srcPort,
final int dstPortStart, final short proto, final short dscp) {
short mask = 0;
if (src46 != EMPTY_ADDRESS_FIELD) {
mask |= SRC_IP_MASK;
}
if (dst46 != EMPTY_ADDRESS_FIELD) {
mask |= DST_IP_MASK;
}
if (srcPort != -1) {
mask |= SRC_PORT_MASK;
}
if (dstPortStart != -1 && dstPortEnd != -1) {
mask |= DST_PORT_MASK;
}
if (proto != -1) {
mask |= PROTO_MASK;
}
return mask;
}
private DscpPolicyValue(final InetAddress src46, final InetAddress dst46, final long ifIndex,
final int srcPort, final int dstPortStart, final int dstPortEnd, final short proto,
final short dscp) {
this.src46 = toAddressField(src46);
this.dst46 = toAddressField(dst46);
this.ifIndex = ifIndex;
// These params need to be stored as 0 because uints are used in BpfMap.
// If they are -1 BpfMap write will throw errors.
this.srcPort = srcPort != -1 ? srcPort : 0;
this.dstPortStart = dstPortStart != -1 ? dstPortStart : 0;
this.dstPortEnd = dstPortEnd != -1 ? dstPortEnd : 0;
this.proto = proto != -1 ? proto : 0;
this.dscp = dscp;
// Use member variables for IP since byte[] is needed and api variables for everything else
// so -1 is passed into mask if parameter is not present.
this.mask = makeMask(this.src46, this.dst46, srcPort, dstPortStart, proto, dscp);
}
public DscpPolicyValue(final InetAddress src46, final InetAddress dst46, final long ifIndex,
final int srcPort, final Range<Integer> dstPort, final short proto,
final short dscp) {
this(src46, dst46, ifIndex, srcPort, dstPort != null ? dstPort.getLower() : -1,
dstPort != null ? dstPort.getUpper() : -1, proto, dscp);
}
public static final DscpPolicyValue NONE = new DscpPolicyValue(
null /* src46 */, null /* dst46 */, 0 /* ifIndex */, -1 /* srcPort */,
-1 /* dstPortStart */, -1 /* dstPortEnd */, (short) -1 /* proto */,
(short) 0 /* dscp */);
@Override
public String toString() {
String srcIpString = "empty";
String dstIpString = "empty";
// Separate try/catch for IP's so it's easier to debug.
try {
srcIpString = InetAddress.getByAddress(src46).getHostAddress();
} catch (UnknownHostException e) {
Log.e(TAG, "Invalid SRC IP address", e);
}
try {
dstIpString = InetAddress.getByAddress(src46).getHostAddress();
} catch (UnknownHostException e) {
Log.e(TAG, "Invalid DST IP address", e);
}
try {
return String.format(
"src46: %s, dst46: %s, ifIndex: %d, srcPort: %d, dstPortStart: %d,"
+ " dstPortEnd: %d, protocol: %d, dscp %s", srcIpString, dstIpString,
ifIndex, srcPort, dstPortStart, dstPortEnd, proto, dscp);
} catch (IllegalArgumentException e) {
return String.format("String format error: " + e);
}
}
}
|