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.net.module.util.netlink; 18 19 import static android.system.OsConstants.AF_INET; 20 import static android.system.OsConstants.AF_INET6; 21 22 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; 23 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; 24 import static com.android.net.module.util.netlink.NetlinkConstants.RTNL_FAMILY_IP6MR; 25 26 import android.annotation.SuppressLint; 27 import android.net.IpPrefix; 28 import android.net.RouteInfo; 29 import android.system.OsConstants; 30 31 import androidx.annotation.NonNull; 32 import androidx.annotation.Nullable; 33 import androidx.annotation.VisibleForTesting; 34 35 import java.net.Inet4Address; 36 import java.net.Inet6Address; 37 import java.net.InetAddress; 38 import java.nio.ByteBuffer; 39 40 /** 41 * A NetlinkMessage subclass for rtnetlink route messages. 42 * 43 * RtNetlinkRouteMessage.parse() must be called with a ByteBuffer that contains exactly one 44 * netlink message. 45 * 46 * see also: 47 * 48 * include/uapi/linux/rtnetlink.h 49 * 50 * @hide 51 */ 52 public class RtNetlinkRouteMessage extends NetlinkMessage { 53 public static final short RTA_DST = 1; 54 public static final short RTA_SRC = 2; 55 public static final short RTA_IIF = 3; 56 public static final short RTA_OIF = 4; 57 public static final short RTA_GATEWAY = 5; 58 public static final short RTA_CACHEINFO = 12; 59 public static final short RTA_EXPIRES = 23; 60 61 public static final short RTNH_F_UNRESOLVED = 32; // The multicast route is unresolved 62 63 public static final String TAG = "NetlinkRouteMessage"; 64 65 // For multicast routes, whether the route is resolved or unresolved 66 private boolean mIsResolved; 67 // The interface index for incoming interface, this is set for multicast 68 // routes, see common/net/ipv4/ipmr_base.c mr_fill_mroute 69 private int mIifIndex; // Incoming interface of a route, for resolved multicast routes 70 private int mOifIndex; 71 @NonNull 72 private StructRtMsg mRtmsg; 73 @Nullable 74 private IpPrefix mSource; // Source address of a route, for all multicast routes 75 @Nullable 76 private IpPrefix mDestination; // Destination of a route, can be null for RTM_GETROUTE 77 @Nullable 78 private InetAddress mGateway; 79 @Nullable 80 private StructRtaCacheInfo mRtaCacheInfo; 81 private long mSinceLastUseMillis; // Milliseconds since the route was used, 82 // for resolved multicast routes 83 84 85 @VisibleForTesting RtNetlinkRouteMessage(final StructNlMsgHdr header, final StructRtMsg rtMsg, final IpPrefix source, final IpPrefix destination, final InetAddress gateway, int iif, int oif, final StructRtaCacheInfo cacheInfo)86 public RtNetlinkRouteMessage(final StructNlMsgHdr header, final StructRtMsg rtMsg, 87 final IpPrefix source, final IpPrefix destination, final InetAddress gateway, 88 int iif, int oif, final StructRtaCacheInfo cacheInfo) { 89 super(header); 90 mRtmsg = rtMsg; 91 mSource = source; 92 mDestination = destination; 93 mGateway = gateway; 94 mIifIndex = iif; 95 mOifIndex = oif; 96 mRtaCacheInfo = cacheInfo; 97 mSinceLastUseMillis = -1; 98 } 99 RtNetlinkRouteMessage(StructNlMsgHdr header, StructRtMsg rtMsg)100 public RtNetlinkRouteMessage(StructNlMsgHdr header, StructRtMsg rtMsg) { 101 this(header, rtMsg, null /* source */, null /* destination */, null /* gateway */, 102 0 /* iif */, 0 /* oif */, null /* cacheInfo */); 103 } 104 105 /** 106 * Returns the rtnetlink family. 107 */ getRtmFamily()108 public short getRtmFamily() { 109 return mRtmsg.family; 110 } 111 112 /** 113 * Returns if the route is resolved. This is always true for unicast, 114 * and may be false only for multicast routes. 115 */ isResolved()116 public boolean isResolved() { 117 return mIsResolved; 118 } 119 getIifIndex()120 public int getIifIndex() { 121 return mIifIndex; 122 } 123 getInterfaceIndex()124 public int getInterfaceIndex() { 125 return mOifIndex; 126 } 127 128 @NonNull getRtMsgHeader()129 public StructRtMsg getRtMsgHeader() { 130 return mRtmsg; 131 } 132 133 @NonNull getDestination()134 public IpPrefix getDestination() { 135 return mDestination; 136 } 137 138 /** 139 * Get source address of a route. This is for multicast routes. 140 */ 141 @NonNull getSource()142 public IpPrefix getSource() { 143 return mSource; 144 } 145 146 @Nullable getGateway()147 public InetAddress getGateway() { 148 return mGateway; 149 } 150 151 @Nullable getRtaCacheInfo()152 public StructRtaCacheInfo getRtaCacheInfo() { 153 return mRtaCacheInfo; 154 } 155 156 /** 157 * RTA_EXPIRES attribute returned by kernel to indicate the clock ticks 158 * from the route was last used to now, converted to milliseconds. 159 * This is set for multicast routes. 160 * 161 * Note that this value is not updated with the passage of time. It always 162 * returns the value that was read when the netlink message was parsed. 163 */ getSinceLastUseMillis()164 public long getSinceLastUseMillis() { 165 return mSinceLastUseMillis; 166 } 167 168 /** 169 * Check whether the address families of destination and gateway match rtm_family in 170 * StructRtmsg. 171 * 172 * For example, IPv4-mapped IPv6 addresses as an IPv6 address will be always converted to IPv4 173 * address, that's incorrect when upper layer creates a new {@link RouteInfo} class instance 174 * for IPv6 route with the converted IPv4 gateway. 175 */ matchRouteAddressFamily(@onNull final InetAddress address, int family)176 private static boolean matchRouteAddressFamily(@NonNull final InetAddress address, 177 int family) { 178 return ((address instanceof Inet4Address) && (family == AF_INET)) 179 || ((address instanceof Inet6Address) && 180 (family == AF_INET6 || family == RTNL_FAMILY_IP6MR)); 181 } 182 183 /** 184 * Parse rtnetlink route message from {@link ByteBuffer}. This method must be called with a 185 * ByteBuffer that contains exactly one netlink message. 186 * 187 * @param header netlink message header. 188 * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. 189 */ 190 @SuppressLint("NewApi") 191 @Nullable parse(@onNull final StructNlMsgHdr header, @NonNull final ByteBuffer byteBuffer)192 public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header, 193 @NonNull final ByteBuffer byteBuffer) { 194 final StructRtMsg rtmsg = StructRtMsg.parse(byteBuffer); 195 if (rtmsg == null) return null; 196 final RtNetlinkRouteMessage routeMsg = new RtNetlinkRouteMessage(header, rtmsg); 197 int rtmFamily = routeMsg.mRtmsg.family; 198 routeMsg.mIsResolved = ((routeMsg.mRtmsg.flags & RTNH_F_UNRESOLVED) == 0); 199 200 // RTA_DST 201 final int baseOffset = byteBuffer.position(); 202 StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(RTA_DST, byteBuffer); 203 if (nlAttr != null) { 204 final InetAddress destination = nlAttr.getValueAsInetAddress(); 205 // If the RTA_DST attribute is malformed, return null. 206 if (destination == null) return null; 207 // If the address family of destination doesn't match rtm_family, return null. 208 if (!matchRouteAddressFamily(destination, rtmFamily)) return null; 209 routeMsg.mDestination = new IpPrefix(destination, routeMsg.mRtmsg.dstLen); 210 } else if (rtmFamily == AF_INET) { 211 routeMsg.mDestination = new IpPrefix(IPV4_ADDR_ANY, 0); 212 } else if (rtmFamily == AF_INET6 || rtmFamily == RTNL_FAMILY_IP6MR) { 213 routeMsg.mDestination = new IpPrefix(IPV6_ADDR_ANY, 0); 214 } else { 215 return null; 216 } 217 218 // RTA_SRC 219 byteBuffer.position(baseOffset); 220 nlAttr = StructNlAttr.findNextAttrOfType(RTA_SRC, byteBuffer); 221 if (nlAttr != null) { 222 final InetAddress source = nlAttr.getValueAsInetAddress(); 223 // If the RTA_SRC attribute is malformed, return null. 224 if (source == null) return null; 225 // If the address family of destination doesn't match rtm_family, return null. 226 if (!matchRouteAddressFamily(source, rtmFamily)) return null; 227 routeMsg.mSource = new IpPrefix(source, routeMsg.mRtmsg.srcLen); 228 } 229 230 // RTA_GATEWAY 231 byteBuffer.position(baseOffset); 232 nlAttr = StructNlAttr.findNextAttrOfType(RTA_GATEWAY, byteBuffer); 233 if (nlAttr != null) { 234 routeMsg.mGateway = nlAttr.getValueAsInetAddress(); 235 // If the RTA_GATEWAY attribute is malformed, return null. 236 if (routeMsg.mGateway == null) return null; 237 // If the address family of gateway doesn't match rtm_family, return null. 238 if (!matchRouteAddressFamily(routeMsg.mGateway, rtmFamily)) return null; 239 } 240 241 // RTA_IIF 242 byteBuffer.position(baseOffset); 243 nlAttr = StructNlAttr.findNextAttrOfType(RTA_IIF, byteBuffer); 244 if (nlAttr != null) { 245 Integer iifInteger = nlAttr.getValueAsInteger(); 246 if (iifInteger == null) { 247 return null; 248 } 249 routeMsg.mIifIndex = iifInteger; 250 } 251 252 // RTA_OIF 253 byteBuffer.position(baseOffset); 254 nlAttr = StructNlAttr.findNextAttrOfType(RTA_OIF, byteBuffer); 255 if (nlAttr != null) { 256 // Any callers that deal with interface names are responsible for converting 257 // the interface index to a name themselves. This may not succeed or may be 258 // incorrect, because the interface might have been deleted, or even deleted 259 // and re-added with a different index, since the netlink message was sent. 260 routeMsg.mOifIndex = nlAttr.getValueAsInt(0 /* 0 isn't a valid ifindex */); 261 } 262 263 // RTA_CACHEINFO 264 byteBuffer.position(baseOffset); 265 nlAttr = StructNlAttr.findNextAttrOfType(RTA_CACHEINFO, byteBuffer); 266 if (nlAttr != null) { 267 routeMsg.mRtaCacheInfo = StructRtaCacheInfo.parse(nlAttr.getValueAsByteBuffer()); 268 } 269 270 // RTA_EXPIRES 271 byteBuffer.position(baseOffset); 272 nlAttr = StructNlAttr.findNextAttrOfType(RTA_EXPIRES, byteBuffer); 273 if (nlAttr != null) { 274 final Long sinceLastUseCentis = nlAttr.getValueAsLong(); 275 // If the RTA_EXPIRES attribute is malformed, return null. 276 if (sinceLastUseCentis == null) return null; 277 // RTA_EXPIRES returns time in clock ticks of USER_HZ(100), which is centiseconds 278 routeMsg.mSinceLastUseMillis = sinceLastUseCentis * 10; 279 } 280 281 return routeMsg; 282 } 283 284 /** 285 * Write a rtnetlink address message to {@link ByteBuffer}. 286 */ pack(ByteBuffer byteBuffer)287 public void pack(ByteBuffer byteBuffer) { 288 getHeader().pack(byteBuffer); 289 mRtmsg.pack(byteBuffer); 290 291 if (mSource != null) { 292 final StructNlAttr source = new StructNlAttr(RTA_SRC, mSource.getAddress()); 293 source.pack(byteBuffer); 294 } 295 296 if (mDestination != null) { 297 final StructNlAttr destination = new StructNlAttr(RTA_DST, mDestination.getAddress()); 298 destination.pack(byteBuffer); 299 } 300 301 if (mGateway != null) { 302 final StructNlAttr gateway = new StructNlAttr(RTA_GATEWAY, mGateway.getAddress()); 303 gateway.pack(byteBuffer); 304 } 305 if (mIifIndex != 0) { 306 final StructNlAttr iifindex = new StructNlAttr(RTA_IIF, mIifIndex); 307 iifindex.pack(byteBuffer); 308 } 309 if (mOifIndex != 0) { 310 final StructNlAttr oifindex = new StructNlAttr(RTA_OIF, mOifIndex); 311 oifindex.pack(byteBuffer); 312 } 313 if (mRtaCacheInfo != null) { 314 final StructNlAttr cacheInfo = new StructNlAttr(RTA_CACHEINFO, 315 mRtaCacheInfo.writeToBytes()); 316 cacheInfo.pack(byteBuffer); 317 } 318 if (mSinceLastUseMillis >= 0) { 319 final long sinceLastUseCentis = mSinceLastUseMillis / 10; 320 final StructNlAttr expires = new StructNlAttr(RTA_EXPIRES, sinceLastUseCentis); 321 expires.pack(byteBuffer); 322 } 323 } 324 325 @Override toString()326 public String toString() { 327 return "RtNetlinkRouteMessage{ " 328 + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " 329 + "Rtmsg{" + mRtmsg.toString() + "}, " 330 + (mSource == null ? "" : "source{" + mSource.getAddress().getHostAddress() + "}, ") 331 + (mDestination == null ? 332 "" : "destination{" + mDestination.getAddress().getHostAddress() + "}, ") 333 + "gateway{" + (mGateway == null ? "" : mGateway.getHostAddress()) + "}, " 334 + (mIifIndex == 0 ? "" : "iifindex{" + mIifIndex + "}, ") 335 + "oifindex{" + mOifIndex + "}, " 336 + "rta_cacheinfo{" + (mRtaCacheInfo == null ? "" : mRtaCacheInfo.toString()) + "} " 337 + (mSinceLastUseMillis < 0 ? "" : "sinceLastUseMillis{" + mSinceLastUseMillis + "}") 338 + "}"; 339 } 340 } 341