• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 import android.annotation.SuppressLint;
26 import android.net.IpPrefix;
27 import android.system.OsConstants;
28 
29 import androidx.annotation.NonNull;
30 import androidx.annotation.Nullable;
31 import androidx.annotation.VisibleForTesting;
32 
33 import java.net.Inet4Address;
34 import java.net.Inet6Address;
35 import java.net.InetAddress;
36 import java.nio.ByteBuffer;
37 
38 /**
39  * A NetlinkMessage subclass for rtnetlink route messages.
40  *
41  * RtNetlinkRouteMessage.parse() must be called with a ByteBuffer that contains exactly one
42  * netlink message.
43  *
44  * see also:
45  *
46  *     include/uapi/linux/rtnetlink.h
47  *
48  * @hide
49  */
50 public class RtNetlinkRouteMessage extends NetlinkMessage {
51     public static final short RTA_DST           = 1;
52     public static final short RTA_OIF           = 4;
53     public static final short RTA_GATEWAY       = 5;
54 
55     private int mIfindex;
56     @NonNull
57     private StructRtMsg mRtmsg;
58     @NonNull
59     private IpPrefix mDestination;
60     @Nullable
61     private InetAddress mGateway;
62 
RtNetlinkRouteMessage(StructNlMsgHdr header)63     private RtNetlinkRouteMessage(StructNlMsgHdr header) {
64         super(header);
65         mRtmsg = null;
66         mDestination = null;
67         mGateway = null;
68         mIfindex = 0;
69     }
70 
getInterfaceIndex()71     public int getInterfaceIndex() {
72         return mIfindex;
73     }
74 
75     @NonNull
getRtMsgHeader()76     public StructRtMsg getRtMsgHeader() {
77         return mRtmsg;
78     }
79 
80     @NonNull
getDestination()81     public IpPrefix getDestination() {
82         return mDestination;
83     }
84 
85     @Nullable
getGateway()86     public InetAddress getGateway() {
87         return mGateway;
88     }
89 
90     /**
91      * Check whether the address families of destination and gateway match rtm_family in
92      * StructRtmsg.
93      *
94      * For example, IPv4-mapped IPv6 addresses as an IPv6 address will be always converted to IPv4
95      * address, that's incorrect when upper layer creates a new {@link RouteInfo} class instance
96      * for IPv6 route with the converted IPv4 gateway.
97      */
matchRouteAddressFamily(@onNull final InetAddress address, int family)98     private static boolean matchRouteAddressFamily(@NonNull final InetAddress address,
99             int family) {
100         return ((address instanceof Inet4Address) && (family == AF_INET))
101                 || ((address instanceof Inet6Address) && (family == AF_INET6));
102     }
103 
104     /**
105      * Parse rtnetlink route message from {@link ByteBuffer}. This method must be called with a
106      * ByteBuffer that contains exactly one netlink message.
107      *
108      * @param header netlink message header.
109      * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes.
110      */
111     @SuppressLint("NewApi")
112     @Nullable
parse(@onNull final StructNlMsgHdr header, @NonNull final ByteBuffer byteBuffer)113     public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header,
114             @NonNull final ByteBuffer byteBuffer) {
115         final RtNetlinkRouteMessage routeMsg = new RtNetlinkRouteMessage(header);
116 
117         routeMsg.mRtmsg = StructRtMsg.parse(byteBuffer);
118         if (routeMsg.mRtmsg == null) return null;
119         int rtmFamily = routeMsg.mRtmsg.family;
120 
121         // RTA_DST
122         final int baseOffset = byteBuffer.position();
123         StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(RTA_DST, byteBuffer);
124         if (nlAttr != null) {
125             final InetAddress destination = nlAttr.getValueAsInetAddress();
126             // If the RTA_DST attribute is malformed, return null.
127             if (destination == null) return null;
128             // If the address family of destination doesn't match rtm_family, return null.
129             if (!matchRouteAddressFamily(destination, rtmFamily)) return null;
130             routeMsg.mDestination = new IpPrefix(destination, routeMsg.mRtmsg.dstLen);
131         } else if (rtmFamily == AF_INET) {
132             routeMsg.mDestination = new IpPrefix(IPV4_ADDR_ANY, 0);
133         } else if (rtmFamily == AF_INET6) {
134             routeMsg.mDestination = new IpPrefix(IPV6_ADDR_ANY, 0);
135         } else {
136             return null;
137         }
138 
139         // RTA_GATEWAY
140         byteBuffer.position(baseOffset);
141         nlAttr = StructNlAttr.findNextAttrOfType(RTA_GATEWAY, byteBuffer);
142         if (nlAttr != null) {
143             routeMsg.mGateway = nlAttr.getValueAsInetAddress();
144             // If the RTA_GATEWAY attribute is malformed, return null.
145             if (routeMsg.mGateway == null) return null;
146             // If the address family of gateway doesn't match rtm_family, return null.
147             if (!matchRouteAddressFamily(routeMsg.mGateway, rtmFamily)) return null;
148         }
149 
150         // RTA_OIF
151         byteBuffer.position(baseOffset);
152         nlAttr = StructNlAttr.findNextAttrOfType(RTA_OIF, byteBuffer);
153         if (nlAttr != null) {
154             // Any callers that deal with interface names are responsible for converting
155             // the interface index to a name themselves. This may not succeed or may be
156             // incorrect, because the interface might have been deleted, or even deleted
157             // and re-added with a different index, since the netlink message was sent.
158             routeMsg.mIfindex = nlAttr.getValueAsInt(0 /* 0 isn't a valid ifindex */);
159         }
160 
161         return routeMsg;
162     }
163 
164     /**
165      * Write a rtnetlink address message to {@link ByteBuffer}.
166      */
167     @VisibleForTesting
pack(ByteBuffer byteBuffer)168     protected void pack(ByteBuffer byteBuffer) {
169         getHeader().pack(byteBuffer);
170         mRtmsg.pack(byteBuffer);
171 
172         final StructNlAttr destination = new StructNlAttr(RTA_DST, mDestination.getAddress());
173         destination.pack(byteBuffer);
174 
175         if (mGateway != null) {
176             final StructNlAttr gateway = new StructNlAttr(RTA_GATEWAY, mGateway.getAddress());
177             gateway.pack(byteBuffer);
178         }
179         if (mIfindex != 0) {
180             final StructNlAttr ifindex = new StructNlAttr(RTA_OIF, mIfindex);
181             ifindex.pack(byteBuffer);
182         }
183     }
184 
185     @Override
toString()186     public String toString() {
187         return "RtNetlinkRouteMessage{ "
188                 + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, "
189                 + "Rtmsg{" + mRtmsg.toString() + "}, "
190                 + "destination{" + mDestination.getAddress().getHostAddress() + "}, "
191                 + "gateway{" + (mGateway == null ? "" : mGateway.getHostAddress()) + "}, "
192                 + "ifindex{" + mIfindex + "} "
193                 + "}";
194     }
195 }
196