blob: 78d30b2623d0dba0724422b92233774e7b414ee1 [file] [log] [blame]
Erik Klined26a2c22018-05-11 19:33:19 +09001/*
2 * Copyright (C) 2018 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 "netdutils/InternetAddresses.h"
18
19#include <android-base/stringprintf.h>
20#include <arpa/inet.h>
21#include <netdb.h>
22#include <sys/socket.h>
23#include <sys/types.h>
24
25namespace android {
26
27using base::StringPrintf;
28
29namespace netdutils {
30
31std::string IPAddress::toString() const noexcept {
Erik Kline603df202018-09-10 18:16:26 +090032 char repr[INET6_ADDRSTRLEN] = "\0";
Erik Klined26a2c22018-05-11 19:33:19 +090033
34 switch (mData.family) {
35 case AF_UNSPEC:
36 return "<unspecified>";
37 case AF_INET: {
Erik Klined26a2c22018-05-11 19:33:19 +090038 const in_addr v4 = mData.ip.v4;
39 inet_ntop(AF_INET, &v4, repr, sizeof(repr));
40 break;
41 }
42 case AF_INET6: {
Erik Klined26a2c22018-05-11 19:33:19 +090043 const in6_addr v6 = mData.ip.v6;
44 inet_ntop(AF_INET6, &v6, repr, sizeof(repr));
45 break;
46 }
47 default:
48 return "<unknown_family>";
49 }
50
51 if (mData.family == AF_INET6 && mData.scope_id > 0) {
52 return StringPrintf("%s%%%u", repr, mData.scope_id);
53 }
54
55 return repr;
56}
57
58bool IPAddress::forString(const std::string& repr, IPAddress* ip) {
59 const addrinfo hints = {
60 .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
61 };
62 addrinfo* res;
63 const int ret = getaddrinfo(repr.c_str(), nullptr, &hints, &res);
Luke Huang25599322019-06-14 00:34:05 +080064 ScopedAddrinfo res_cleanup(res);
Erik Klined26a2c22018-05-11 19:33:19 +090065 if (ret != 0) {
Erik Klined26a2c22018-05-11 19:33:19 +090066 return false;
67 }
68
69 bool rval = true;
70 switch (res[0].ai_family) {
71 case AF_INET: {
72 sockaddr_in* sin = (sockaddr_in*) res[0].ai_addr;
73 if (ip) *ip = IPAddress(sin->sin_addr);
74 break;
75 }
76 case AF_INET6: {
77 sockaddr_in6* sin6 = (sockaddr_in6*) res[0].ai_addr;
78 if (ip) *ip = IPAddress(sin6->sin6_addr, sin6->sin6_scope_id);
79 break;
80 }
81 default:
82 rval = false;
83 break;
84 }
85
Erik Klined26a2c22018-05-11 19:33:19 +090086 return rval;
87}
88
89IPPrefix::IPPrefix(const IPAddress& ip, int length) : IPPrefix(ip) {
90 // Silently treat CIDR lengths like "-1" as meaning the full bit length
91 // appropriate to the address family.
92 if (length < 0) return;
93 if (length >= mData.cidrlen) return;
94
95 switch (mData.family) {
96 case AF_UNSPEC:
97 break;
98 case AF_INET: {
99 const in_addr_t mask = (length > 0) ? (~0U) << (IPV4_ADDR_BITS - length) : 0U;
100 mData.ip.v4.s_addr &= htonl(mask);
101 mData.cidrlen = static_cast<uint8_t>(length);
102 break;
103 }
104 case AF_INET6: {
105 // The byte in which this CIDR length falls.
Erik Kline603df202018-09-10 18:16:26 +0900106 const int which = length / 8;
Erik Klined26a2c22018-05-11 19:33:19 +0900107 const int mask = (length % 8 == 0) ? 0 : 0xff << (8 - length % 8);
108 mData.ip.v6.s6_addr[which] &= mask;
109 for (int i = which + 1; i < IPV6_ADDR_LEN; i++) {
110 mData.ip.v6.s6_addr[i] = 0U;
111 }
112 mData.cidrlen = static_cast<uint8_t>(length);
113 break;
114 }
115 default:
116 // TODO: Complain bitterly about possible data corruption?
117 return;
118 }
119}
120
nuccachenf52f7a52018-07-17 18:07:23 +0800121bool IPPrefix::isUninitialized() const noexcept {
122 static const internal_::compact_ipdata empty{};
123 return mData == empty;
124}
125
Erik Klined26a2c22018-05-11 19:33:19 +0900126std::string IPPrefix::toString() const noexcept {
127 return StringPrintf("%s/%d", ip().toString().c_str(), mData.cidrlen);
128}
129
130std::string IPSockAddr::toString() const noexcept {
131 switch (mData.family) {
132 case AF_INET6:
133 return StringPrintf("[%s]:%u", ip().toString().c_str(), mData.port);
134 default:
135 return StringPrintf("%s:%u", ip().toString().c_str(), mData.port);
136 }
137}
138
139} // namespace netdutils
140} // namespace android