• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Interface(const std::string & name)27 Interface::Interface(const std::string& name) : mName(name) {
28 }
29 
init()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 
setAllMulti()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 
resolveAddresses()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 
configureIcmpSocket()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 
configureIpSocket()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