1 /*
2  * Copyright (C) 2019 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 "common/libs/utils/network.h"
18 
19 #ifdef __linux__
20 #include <linux/if_ether.h>
21 // Kernel headers don't mix well with userspace headers, but there is no
22 // userspace header that provides the if_tun.h #defines.  Include the kernel
23 // header, but move conflicting definitions out of the way using macros.
24 #define ethhdr __kernel_ethhdr
25 #include <linux/if_tun.h>
26 #undef ethhdr
27 #endif
28 
29 #include <arpa/inet.h>
30 #include <fcntl.h>
31 #include <ifaddrs.h>
32 #include <net/if.h>
33 
34 #include <cstdint>
35 #include <cstring>
36 #include <functional>
37 #include <iomanip>
38 #include <ios>
39 #include <memory>
40 #include <ostream>
41 #include <set>
42 #include <sstream>
43 #include <streambuf>
44 #include <string>
45 #include <utility>
46 #include <vector>
47 
48 #include <android-base/logging.h>
49 #include <android-base/strings.h>
50 #include <fmt/format.h>
51 
52 #include "common/libs/utils/subprocess.h"
53 
54 namespace cuttlefish {
55 namespace {
56 
57 #ifdef __linux__
58 // This should be the size of virtio_net_hdr_v1, from linux/virtio_net.h, but
59 // the version of that header that ships with android in Pie does not include
60 // that struct (it was added in Q).
61 // This is what that struct looks like:
62 // struct virtio_net_hdr_v1 {
63 // u8 flags;
64 // u8 gso_type;
65 // u16 hdr_len;
66 // u16 gso_size;
67 // u16 csum_start;
68 // u16 csum_offset;
69 // u16 num_buffers;
70 // };
71 static constexpr int SIZE_OF_VIRTIO_NET_HDR_V1 = 12;
72 #endif
73 
74 /**
75  * Generate mac address following:
76  * 00:1a:11:e0:cf:index
77  * ________ __    ______
78  *    |      |          |
79  *    |       type (e0, e1, etc)
80 */
GenerateMacForInstance(int index,uint8_t type,std::uint8_t out[6])81 void GenerateMacForInstance(int index, uint8_t type, std::uint8_t out[6]) {
82   // the first octet must be even
83   out[0] = 0x00;
84   out[1] = 0x1a;
85   out[2] = 0x11;
86   out[3] = type;
87   out[4] = 0xcf;
88   out[5] = static_cast<std::uint8_t>(index);
89 }
90 
91 }  // namespace
92 
NetworkInterfaceExists(const std::string & interface_name)93 bool NetworkInterfaceExists(const std::string& interface_name) {
94   struct ifaddrs *ifa_list{}, *ifa{};
95   bool ret = false;
96   getifaddrs(&ifa_list);
97   for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
98     if (strcmp(ifa->ifa_name, interface_name.c_str()) == 0) {
99       ret = true;
100       break;
101     }
102   }
103   freeifaddrs(ifa_list);
104   return ret;
105 }
106 
107 #ifdef __linux__
OpenTapInterface(const std::string & interface_name)108 SharedFD OpenTapInterface(const std::string& interface_name) {
109   constexpr auto TUNTAP_DEV = "/dev/net/tun";
110 
111   auto tap_fd = SharedFD::Open(TUNTAP_DEV, O_RDWR | O_NONBLOCK);
112   if (!tap_fd->IsOpen()) {
113     LOG(ERROR) << "Unable to open tun device: " << tap_fd->StrError();
114     return tap_fd;
115   }
116 
117   struct ifreq ifr;
118   memset(&ifr, 0, sizeof(ifr));
119   ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
120   strncpy(ifr.ifr_name, interface_name.c_str(), IFNAMSIZ);
121 
122   int err = tap_fd->Ioctl(TUNSETIFF, &ifr);
123   if (err < 0) {
124     LOG(ERROR) << "Unable to connect to " << interface_name
125                << " tap interface: " << tap_fd->StrError();
126     tap_fd->Close();
127     return SharedFD();
128   }
129 
130   // The interface's configuration may have been modified or just not set
131   // correctly on creation. While qemu checks this and enforces the right
132   // configuration, crosvm does not, so it needs to be set before it's passed to
133   // it.
134   tap_fd->Ioctl(TUNSETOFFLOAD,
135                 reinterpret_cast<void*>(TUN_F_CSUM | TUN_F_UFO | TUN_F_TSO4 |
136                                         TUN_F_TSO6));
137   int len = SIZE_OF_VIRTIO_NET_HDR_V1;
138   tap_fd->Ioctl(TUNSETVNETHDRSZ, &len);
139   return tap_fd;
140 }
141 
TapInterfacesInUse()142 std::set<std::string> TapInterfacesInUse() {
143   Command cmd("/bin/bash");
144   cmd.AddParameter("-c");
145   cmd.AddParameter("egrep -h -e \"^iff:.*\" /proc/*/fdinfo/*");
146   std::string stdin_str, stdout_str, stderr_str;
147   RunWithManagedStdio(std::move(cmd), &stdin_str, &stdout_str, &stderr_str);
148   auto lines = android::base::Split(stdout_str, "\n");
149   std::set<std::string> tap_interfaces;
150   for (const auto& line : lines) {
151     if (line == "") {
152       continue;
153     }
154     if (!android::base::StartsWith(line, "iff:\t")) {
155       LOG(ERROR) << "Unexpected line \"" << line << "\"";
156       continue;
157     }
158     tap_interfaces.insert(line.substr(std::string("iff:\t").size()));
159   }
160   return tap_interfaces;
161 }
162 #endif
163 
MacAddressToString(const std::uint8_t mac[6])164 std::string MacAddressToString(const std::uint8_t mac[6]) {
165   std::vector<std::uint8_t> mac_vec(mac, mac + 6);
166   return fmt::format("{:0>2x}", fmt::join(mac_vec, ":"));
167 }
168 
Ipv6ToString(const std::uint8_t ip[16])169 std::string Ipv6ToString(const std::uint8_t ip[16]) {
170   char ipv6_str[INET6_ADDRSTRLEN + 1];
171   inet_ntop(AF_INET6, ip, ipv6_str, sizeof(ipv6_str));
172   return std::string(ipv6_str);
173 }
174 
GenerateMobileMacForInstance(int index,std::uint8_t out[6])175 void GenerateMobileMacForInstance(int index, std::uint8_t out[6]) {
176   GenerateMacForInstance(index, 0xe0, out);
177 }
178 
GenerateEthMacForInstance(int index,std::uint8_t out[6])179 void GenerateEthMacForInstance(int index, std::uint8_t out[6]) {
180   GenerateMacForInstance(index, 0xe1, out);
181 }
182 
GenerateWifiMacForInstance(int index,std::uint8_t out[6])183 void GenerateWifiMacForInstance(int index, std::uint8_t out[6]) {
184   GenerateMacForInstance(index, 0xe2, out);
185 }
186 
187 /**
188  * Linux uses mac to generate link-local IPv6 address following:
189  *
190  * 1. Get mac address (for example 00:1a:11:ee:cf:01)
191  * 2. Throw ff:fe as a 3th and 4th octets (00:1a:11 :ff:fe: ee:cf:01)
192  * 3. Flip 2th bit in the first octet (02: 1a:11:ff:fe:ee:cf:01)
193  * 4. Use IPv6 format (021a:11ff:feee:cf01)
194  * 5. Add prefix fe80:: (fe80::021a:11ff:feee:cf01 or fe80:0000:0000:0000:021a:11ff:feee:cf00)
195 */
GenerateCorrespondingIpv6ForMac(const std::uint8_t mac[6],std::uint8_t out[16])196 void GenerateCorrespondingIpv6ForMac(const std::uint8_t mac[6], std::uint8_t out[16]) {
197   out[0] = 0xfe;
198   out[1] = 0x80;
199 
200   // 2 - 7 octets are zero
201 
202   // need to invert 2th bit of the first octet
203   out[8] = mac[0] ^ (1 << 1);
204   out[9] = mac[1];
205 
206   out[10] = mac[2];
207   out[11] = 0xff;
208 
209   out[12] = 0xfe;
210   out[13] = mac[3];
211 
212   out[14] = mac[4];
213   out[15] = mac[5];
214 }
215 
216 }  // namespace cuttlefish
217