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