Home | History | Annotate | Download | only in ipv6proxy
      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