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