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