1 /* 2 * Copyright (C) 2017 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 #include "interface.h" 18 19 #include <errno.h> 20 #include <linux/if_ether.h> 21 #include <net/if.h> 22 #include <string.h> 23 #include <sys/ioctl.h> 24 25 #include "log.h" 26 27 Interface::Interface(const std::string& name) : mName(name) { 28 } 29 30 bool Interface::init() { 31 // setAllMulti will set the ALLMULTI flag for the interface, this allows us 32 // to capture all the traffic needed to perform proxying. 33 return setAllMulti() && 34 resolveAddresses() && 35 configureIpSocket() && 36 configureIcmpSocket(); 37 } 38 39 bool Interface::setAllMulti() { 40 struct ifreq request; 41 memset(&request, 0, sizeof(request)); 42 strncpy(request.ifr_name, mName.c_str(), sizeof(request.ifr_name)); 43 request.ifr_name[sizeof(request.ifr_name) - 1] = '\0'; 44 45 Socket socket; 46 Result res = socket.open(AF_INET, SOCK_DGRAM, IPPROTO_IP); 47 if (!res) { 48 loge("Failed to open IP socket for interface %s: %s\n", 49 mName.c_str(), strerror(errno)); 50 return false; 51 } 52 int status = ::ioctl(socket.get(), SIOCGIFFLAGS, &request); 53 if (status != 0) { 54 loge("Failed to get interface flags for %s: %s\n", 55 mName.c_str(), strerror(errno)); 56 return false; 57 } 58 59 if ((request.ifr_flags & IFF_ALLMULTI) != 0) { 60 // AllMulti is already enabled, nothing to do 61 return true; 62 } 63 64 request.ifr_flags |= IFF_ALLMULTI; 65 66 status = ::ioctl(socket.get(), SIOCSIFFLAGS, &request); 67 if (status != 0) { 68 loge("Failed to enable AllMulti flag for %s: %s\n", 69 mName.c_str(), strerror(errno)); 70 return false; 71 } 72 return true; 73 } 74 75 bool Interface::resolveAddresses() { 76 Result res = mLinkAddr.resolveEth(mName); 77 if (!res) { 78 loge("Unable to resolve interface %s: %s\n", 79 mName.c_str(), res.c_str()); 80 return false; 81 } 82 mIndex = if_nametoindex(mName.c_str()); 83 if (mIndex == 0) { 84 loge("Unable to get interface index for '%s': %s\n", 85 mName.c_str(), strerror(errno)); 86 return false; 87 } 88 return true; 89 } 90 91 bool Interface::configureIcmpSocket() { 92 Result res = mIcmpSocket.open(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 93 if (!res) { 94 loge("Error opening socket: %s\n", res.c_str()); 95 return false; 96 } 97 98 // The ICMP messages we are going to send need a hop limit of 255 to be 99 // accepted. 100 res = mIcmpSocket.setMulticastHopLimit(255); 101 if (!res) { 102 loge("Error setting socket hop limit: %s\n", res.c_str()); 103 return false; 104 } 105 res = mIcmpSocket.setUnicastHopLimit(255); 106 if (!res) { 107 loge("Error setting socket hop limit: %s\n", res.c_str()); 108 return false; 109 } 110 111 // We only care about one specific interface 112 res = mIcmpSocket.setInterface(mName); 113 if (!res) { 114 loge("Error socket interface: %s\n", res.c_str()); 115 return false; 116 } 117 118 // Make sure the socket allows transparent proxying, this allows sending of 119 // packets with a source address that is different from the interface. 120 res = mIcmpSocket.setTransparent(true); 121 if (!res) { 122 loge("Error socket interface: %s\n", res.c_str()); 123 return false; 124 } 125 126 return true; 127 } 128 129 bool Interface::configureIpSocket() { 130 Result res = mIpSocket.open(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6); 131 if (!res) { 132 loge("Error opening socket: %s\n", res.c_str()); 133 return false; 134 } 135 136 res = mIpSocket.bind(mLinkAddr); 137 if (!res) { 138 loge("Error binding socket: %s\n", res.c_str()); 139 return false; 140 } 141 return true; 142 } 143 144