blob: c481c1cc1a524568fbcefb4841879dc5fa454340 [file] [log] [blame]
Hugo Benichi2ac4d072019-05-28 14:51:23 +09001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "arc/network/net_util.h"
6
Garrick Evans260ff302019-07-25 11:22:50 +09007#include <fstream>
8#include <iostream>
9#include <random>
10
11#include <base/logging.h>
Garrick Evansc7ae82c2019-09-04 16:25:10 +090012#include <base/strings/stringprintf.h>
13
Hugo Benichi2ac4d072019-05-28 14:51:23 +090014namespace arc_networkd {
15
Garrick Evans6f4fa3a2020-02-10 16:15:09 +090016uint32_t Ipv4Netmask(uint32_t prefix_len) {
17 return htonl((0xffffffffull << (32 - prefix_len)) & 0xffffffff);
18}
19
20uint32_t Ipv4BroadcastAddr(uint32_t base, uint32_t prefix_len) {
21 return (base | ~Ipv4Netmask(prefix_len));
22}
23
Hugo Benichi2ac4d072019-05-28 14:51:23 +090024std::string IPv4AddressToString(uint32_t addr) {
25 char buf[INET_ADDRSTRLEN] = {0};
26 struct in_addr ia;
27 ia.s_addr = addr;
28 return !inet_ntop(AF_INET, &ia, buf, sizeof(buf)) ? "" : buf;
29}
30
31std::string IPv4AddressToCidrString(uint32_t addr, uint32_t prefix_length) {
32 return IPv4AddressToString(addr) + "/" + std::to_string(prefix_length);
33}
34
Garrick Evans54861622019-07-19 09:05:09 +090035std::string MacAddressToString(const MacAddress& addr) {
36 return base::StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1],
37 addr[2], addr[3], addr[4], addr[5]);
38}
39
Garrick Evans260ff302019-07-25 11:22:50 +090040bool FindFirstIPv6Address(const std::string& ifname, struct in6_addr* address) {
41 struct ifaddrs* ifap;
42 struct ifaddrs* p;
43 bool found = false;
44
45 // Iterate through the linked list of all interface addresses to find
46 // the first IPv6 address for |ifname|.
47 if (getifaddrs(&ifap) < 0)
48 return false;
49
50 for (p = ifap; p; p = p->ifa_next) {
51 if (p->ifa_name != ifname || p->ifa_addr->sa_family != AF_INET6) {
52 continue;
53 }
54
55 if (address) {
56 struct sockaddr_in6* sa =
57 reinterpret_cast<struct sockaddr_in6*>(p->ifa_addr);
58 memcpy(address, &sa->sin6_addr, sizeof(*address));
59 }
60 found = true;
61 break;
62 }
63
64 freeifaddrs(ifap);
65 return found;
66}
67
68bool GenerateRandomIPv6Prefix(struct in6_addr* prefix, int len) {
69 std::mt19937 rng;
70 rng.seed(std::random_device()());
71 std::uniform_int_distribution<std::mt19937::result_type> randbyte(0, 255);
72
73 // TODO(cernekee): handle different prefix lengths
74 if (len != 64) {
75 LOG(DFATAL) << "Unexpected prefix length";
76 return false;
77 }
78
79 for (int i = 8; i < 16; i++)
80 prefix->s6_addr[i] = randbyte(rng);
81
82 // Set the universal/local flag, similar to a RFC 4941 address.
83 prefix->s6_addr[8] |= 0x40;
84 return true;
85}
86
87std::ostream& operator<<(std::ostream& stream, const struct in_addr& addr) {
88 char buf[INET_ADDRSTRLEN];
89 inet_ntop(AF_INET, &addr, buf, sizeof(buf));
90 stream << buf;
91 return stream;
92}
93
94std::ostream& operator<<(std::ostream& stream, const struct in6_addr& addr) {
95 char buf[INET6_ADDRSTRLEN];
96 inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
97 stream << buf;
98 return stream;
99}
100
Hugo Benichidcc32392020-02-27 09:14:40 +0900101std::ostream& operator<<(std::ostream& stream, const struct sockaddr& addr) {
102 switch (addr.sa_family) {
103 case AF_INET:
104 return stream << (const struct sockaddr_in&)addr;
105 case AF_INET6:
106 return stream << (const struct sockaddr_in6&)addr;
107 case AF_UNIX:
108 return stream << (const struct sockaddr_un&)addr;
109 case AF_VSOCK:
110 return stream << (const struct sockaddr_vm&)addr;
111 default:
112 return stream << "{family: " << addr.sa_family << ", (unknown)}";
113 }
114}
115
116std::ostream& operator<<(std::ostream& stream,
117 const struct sockaddr_storage& addr) {
118 return stream << (const struct sockaddr&)addr;
119}
120
121std::ostream& operator<<(std::ostream& stream, const struct sockaddr_in& addr) {
122 char buf[INET_ADDRSTRLEN] = {0};
123 inet_ntop(AF_INET, &addr.sin_addr, buf, sizeof(buf));
124 return stream << "{family: AF_INET, port: " << ntohs(addr.sin_port)
125 << ", addr: " << buf << "}";
126}
127
128std::ostream& operator<<(std::ostream& stream,
129 const struct sockaddr_in6& addr) {
130 char buf[INET6_ADDRSTRLEN] = {0};
131 inet_ntop(AF_INET6, &addr.sin6_addr, buf, sizeof(buf));
132 return stream << "{family: AF_INET6, port: " << ntohs(addr.sin6_port)
133 << ", addr: " << buf << "}";
134}
135
136std::ostream& operator<<(std::ostream& stream, const struct sockaddr_un& addr) {
137 const size_t sun_path_length = sizeof(addr) - sizeof(sa_family_t);
138 // Add room for one extra char to ensure |buf| is a null terminated string
139 char buf[sun_path_length + 1] = {0};
140 memcpy(buf, addr.sun_path, sun_path_length);
141 if (buf[0] == '\0') {
142 buf[0] = '@';
143 }
144 return stream << "{family: AF_UNIX, path: " << buf << "}";
145}
146
147std::ostream& operator<<(std::ostream& stream, const struct sockaddr_vm& addr) {
148 return stream << "{family: AF_VSOCK, port: " << addr.svm_port
149 << ", cid: " << addr.svm_cid << "}";
150}
151
Jason Jeremy Iman16f91722020-01-14 09:53:28 +0900152uint16_t FoldChecksum(uint32_t sum) {
153 while (sum >> 16)
154 sum = (sum & 0xffff) + (sum >> 16);
155 return ~sum;
156}
157
158uint32_t NetChecksum(const void* data, ssize_t len) {
159 uint32_t sum = 0;
160 const uint16_t* word = reinterpret_cast<const uint16_t*>(data);
161 for (; len > 1; len -= 2)
162 sum += *word++;
163 if (len)
164 sum += *word & htons(0x0000ffff);
165 return sum;
166}
167
168uint16_t Ipv4Checksum(const iphdr* ip) {
169 uint32_t sum = NetChecksum(ip, sizeof(iphdr));
170 return FoldChecksum(sum);
171}
172
173uint16_t Udpv4Checksum(const iphdr* ip, const udphdr* udp) {
174 uint8_t pseudo_header[12];
175 memset(pseudo_header, 0, sizeof(pseudo_header));
176
177 // Fill in the pseudo-header.
178 memcpy(pseudo_header, &ip->saddr, sizeof(in_addr));
179 memcpy(pseudo_header + 4, &ip->daddr, sizeof(in_addr));
180 memcpy(pseudo_header + 9, &ip->protocol, sizeof(uint8_t));
181 memcpy(pseudo_header + 10, &udp->len, sizeof(uint16_t));
182
183 // Compute pseudo-header checksum
184 uint32_t sum = NetChecksum(pseudo_header, sizeof(pseudo_header));
185
186 // UDP
187 sum += NetChecksum(udp, ntohs(udp->len));
188
189 return FoldChecksum(sum);
190}
191
192uint16_t Icmpv6Checksum(const ip6_hdr* ip6, const icmp6_hdr* icmp6) {
193 uint32_t sum = 0;
194 // Src and Dst IP
195 for (size_t i = 0; i < (sizeof(struct in6_addr) >> 1); ++i)
196 sum += ip6->ip6_src.s6_addr16[i];
197 for (size_t i = 0; i < (sizeof(struct in6_addr) >> 1); ++i)
198 sum += ip6->ip6_dst.s6_addr16[i];
199
200 // Upper-Layer Packet Length
201 sum += ip6->ip6_plen;
202 // Next Header
203 sum += IPPROTO_ICMPV6 << 8;
204
205 // ICMP
206 sum += NetChecksum(icmp6, ntohs(ip6->ip6_plen));
207
208 return FoldChecksum(sum);
209}
210
Hugo Benichi2ac4d072019-05-28 14:51:23 +0900211} // namespace arc_networkd