1 /* 2 * Copyright (C) 2020 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 android.net.ip; 18 19 import static android.system.OsConstants.AF_INET6; 20 import static android.system.OsConstants.AF_PACKET; 21 import static android.system.OsConstants.ENODEV; 22 import static android.system.OsConstants.ETH_P_IPV6; 23 import static android.system.OsConstants.IPPROTO_RAW; 24 import static android.system.OsConstants.SOCK_DGRAM; 25 import static android.system.OsConstants.SOCK_NONBLOCK; 26 import static android.system.OsConstants.SOCK_RAW; 27 28 import static com.android.net.module.util.SocketUtils.closeSocketQuietly; 29 30 import android.net.util.SocketUtils; 31 import android.os.Handler; 32 import android.system.ErrnoException; 33 import android.system.Os; 34 import android.util.Log; 35 36 import com.android.net.module.util.InterfaceParams; 37 import com.android.net.module.util.PacketReader; 38 import com.android.networkstack.tethering.util.TetheringUtils; 39 40 import java.io.FileDescriptor; 41 import java.net.Inet6Address; 42 import java.net.InetSocketAddress; 43 import java.net.SocketAddress; 44 import java.net.SocketException; 45 import java.net.UnknownHostException; 46 import java.util.Arrays; 47 48 /** 49 * Basic IPv6 Neighbor Advertisement Forwarder. 50 * 51 * Forward NA packets from upstream iface to tethered iface 52 * and NS packets from tethered iface to upstream iface. 53 * 54 * @hide 55 */ 56 public class NeighborPacketForwarder extends PacketReader { 57 private final String mTag; 58 59 private FileDescriptor mFd; 60 61 // TODO: get these from NetworkStackConstants. 62 private static final int IPV6_ADDR_LEN = 16; 63 private static final int IPV6_DST_ADDR_OFFSET = 24; 64 private static final int IPV6_HEADER_LEN = 40; 65 private static final int ETH_HEADER_LEN = 14; 66 67 private InterfaceParams mListenIfaceParams, mSendIfaceParams; 68 69 private final int mType; 70 public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136; 71 public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135; 72 NeighborPacketForwarder(Handler h, InterfaceParams tetheredInterface, int type)73 public NeighborPacketForwarder(Handler h, InterfaceParams tetheredInterface, int type) { 74 super(h); 75 mTag = NeighborPacketForwarder.class.getSimpleName() + "-" 76 + tetheredInterface.name + "-" + type; 77 mType = type; 78 79 if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) { 80 mSendIfaceParams = tetheredInterface; 81 } else { 82 mListenIfaceParams = tetheredInterface; 83 } 84 } 85 86 /** Set new upstream iface and start/stop based on new params. */ setUpstreamIface(InterfaceParams upstreamParams)87 public void setUpstreamIface(InterfaceParams upstreamParams) { 88 final InterfaceParams oldUpstreamParams; 89 90 if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) { 91 oldUpstreamParams = mListenIfaceParams; 92 mListenIfaceParams = upstreamParams; 93 } else { 94 oldUpstreamParams = mSendIfaceParams; 95 mSendIfaceParams = upstreamParams; 96 } 97 98 if (oldUpstreamParams == null && upstreamParams != null) { 99 start(); 100 } else if (oldUpstreamParams != null && upstreamParams == null) { 101 stop(); 102 } else if (oldUpstreamParams != null && upstreamParams != null 103 && oldUpstreamParams.index != upstreamParams.index) { 104 stop(); 105 start(); 106 } 107 } 108 109 @Override createFd()110 protected FileDescriptor createFd() { 111 try { 112 // ICMPv6 packets from modem do not have eth header, so RAW socket cannot be used. 113 // To keep uniformity in both directions PACKET socket can be used. 114 mFd = Os.socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0); 115 116 // TODO: convert setup*Socket to setupICMPv6BpfFilter with filter type? 117 if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) { 118 TetheringUtils.setupNaSocket(mFd); 119 } else if (mType == ICMPV6_NEIGHBOR_SOLICITATION) { 120 TetheringUtils.setupNsSocket(mFd); 121 } 122 123 SocketAddress bindAddress = SocketUtils.makePacketSocketAddress( 124 ETH_P_IPV6, mListenIfaceParams.index); 125 Os.bind(mFd, bindAddress); 126 } catch (ErrnoException | SocketException e) { 127 // An ENODEV(No such device) will rise if tethering stopped before this function, this 128 // may happen when enable/disable tethering quickly. 129 if (e instanceof ErrnoException && ((ErrnoException) e).errno == ENODEV) { 130 Log.w(mTag, "Failed to create socket because tethered interface is gone", e); 131 } else { 132 Log.wtf(mTag, "Failed to create socket", e); 133 } 134 closeSocketQuietly(mFd); 135 return null; 136 } 137 138 return mFd; 139 } 140 getIpv6DestinationAddress(byte[] recvbuf)141 private Inet6Address getIpv6DestinationAddress(byte[] recvbuf) { 142 Inet6Address dstAddr; 143 try { 144 dstAddr = (Inet6Address) Inet6Address.getByAddress(Arrays.copyOfRange(recvbuf, 145 IPV6_DST_ADDR_OFFSET, IPV6_DST_ADDR_OFFSET + IPV6_ADDR_LEN)); 146 } catch (UnknownHostException | ClassCastException impossible) { 147 throw new AssertionError("16-byte array not valid IPv6 address?"); 148 } 149 return dstAddr; 150 } 151 152 @Override handlePacket(byte[] recvbuf, int length)153 protected void handlePacket(byte[] recvbuf, int length) { 154 if (mSendIfaceParams == null) { 155 return; 156 } 157 158 // The BPF filter should already have checked the length of the packet, but... 159 if (length < IPV6_HEADER_LEN) { 160 return; 161 } 162 Inet6Address destv6 = getIpv6DestinationAddress(recvbuf); 163 if (!destv6.isMulticastAddress()) { 164 return; 165 } 166 InetSocketAddress dest = new InetSocketAddress(destv6, 0); 167 168 FileDescriptor fd = null; 169 try { 170 fd = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW); 171 SocketUtils.bindSocketToInterface(fd, mSendIfaceParams.name); 172 173 int ret = Os.sendto(fd, recvbuf, 0, length, 0, dest); 174 } catch (ErrnoException | SocketException e) { 175 Log.e(mTag, "handlePacket error: " + e); 176 } finally { 177 closeSocketQuietly(fd); 178 } 179 } 180 } 181