blob: f5ff73103c39b2a2568c25afd88f49b9c5497f45 [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
Jason Jeremy Iman16f91722020-01-14 09:53:28 +0900101uint16_t FoldChecksum(uint32_t sum) {
102 while (sum >> 16)
103 sum = (sum & 0xffff) + (sum >> 16);
104 return ~sum;
105}
106
107uint32_t NetChecksum(const void* data, ssize_t len) {
108 uint32_t sum = 0;
109 const uint16_t* word = reinterpret_cast<const uint16_t*>(data);
110 for (; len > 1; len -= 2)
111 sum += *word++;
112 if (len)
113 sum += *word & htons(0x0000ffff);
114 return sum;
115}
116
117uint16_t Ipv4Checksum(const iphdr* ip) {
118 uint32_t sum = NetChecksum(ip, sizeof(iphdr));
119 return FoldChecksum(sum);
120}
121
122uint16_t Udpv4Checksum(const iphdr* ip, const udphdr* udp) {
123 uint8_t pseudo_header[12];
124 memset(pseudo_header, 0, sizeof(pseudo_header));
125
126 // Fill in the pseudo-header.
127 memcpy(pseudo_header, &ip->saddr, sizeof(in_addr));
128 memcpy(pseudo_header + 4, &ip->daddr, sizeof(in_addr));
129 memcpy(pseudo_header + 9, &ip->protocol, sizeof(uint8_t));
130 memcpy(pseudo_header + 10, &udp->len, sizeof(uint16_t));
131
132 // Compute pseudo-header checksum
133 uint32_t sum = NetChecksum(pseudo_header, sizeof(pseudo_header));
134
135 // UDP
136 sum += NetChecksum(udp, ntohs(udp->len));
137
138 return FoldChecksum(sum);
139}
140
141uint16_t Icmpv6Checksum(const ip6_hdr* ip6, const icmp6_hdr* icmp6) {
142 uint32_t sum = 0;
143 // Src and Dst IP
144 for (size_t i = 0; i < (sizeof(struct in6_addr) >> 1); ++i)
145 sum += ip6->ip6_src.s6_addr16[i];
146 for (size_t i = 0; i < (sizeof(struct in6_addr) >> 1); ++i)
147 sum += ip6->ip6_dst.s6_addr16[i];
148
149 // Upper-Layer Packet Length
150 sum += ip6->ip6_plen;
151 // Next Header
152 sum += IPPROTO_ICMPV6 << 8;
153
154 // ICMP
155 sum += NetChecksum(icmp6, ntohs(ip6->ip6_plen));
156
157 return FoldChecksum(sum);
158}
159
Hugo Benichi2ac4d072019-05-28 14:51:23 +0900160} // namespace arc_networkd