]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/ipaddr.cc
update ceph source to reef 18.2.0
[ceph.git] / ceph / src / common / ipaddr.cc
CommitLineData
f67539c2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
7c673cae 3
7c673cae 4#include <arpa/inet.h>
31f18b77 5#include <ifaddrs.h>
7c673cae
FG
6#include <stdlib.h>
7#include <string.h>
31f18b77
FG
8#if defined(__FreeBSD__)
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <netinet/in.h>
12#endif
7c673cae 13
31f18b77 14#include "include/ipaddr.h"
11fdf7f2
TL
15#include "msg/msg_types.h"
16#include "common/pick_address.h"
7c673cae 17
f67539c2
TL
18using std::string;
19
11fdf7f2 20void netmask_ipv4(const struct in_addr *addr,
7c673cae
FG
21 unsigned int prefix_len,
22 struct in_addr *out) {
23 uint32_t mask;
24
25 if (prefix_len >= 32) {
26 // also handle 32 in this branch, because >>32 is not defined by
27 // the C standards
28 mask = ~uint32_t(0);
29 } else {
30 mask = htonl(~(~uint32_t(0) >> prefix_len));
31 }
32 out->s_addr = addr->s_addr & mask;
33}
34
522d829b
TL
35bool matches_ipv4_in_subnet(const struct ifaddrs& addrs,
36 const struct sockaddr_in* net,
37 unsigned int prefix_len)
11fdf7f2 38{
522d829b 39 if (addrs.ifa_addr == nullptr)
11fdf7f2 40 return false;
7c673cae 41
522d829b
TL
42 if (addrs.ifa_addr->sa_family != net->sin_family)
43 return false;
44 struct in_addr want;
7c673cae 45 netmask_ipv4(&net->sin_addr, prefix_len, &want);
522d829b
TL
46 struct in_addr *cur = &((struct sockaddr_in*)addrs.ifa_addr)->sin_addr;
47 struct in_addr temp;
48 netmask_ipv4(cur, prefix_len, &temp);
49 return temp.s_addr == want.s_addr;
7c673cae
FG
50}
51
11fdf7f2
TL
52void netmask_ipv6(const struct in6_addr *addr,
53 unsigned int prefix_len,
54 struct in6_addr *out) {
7c673cae
FG
55 if (prefix_len > 128)
56 prefix_len = 128;
57
58 memcpy(out->s6_addr, addr->s6_addr, prefix_len/8);
59 if (prefix_len < 128)
60 out->s6_addr[prefix_len/8] = addr->s6_addr[prefix_len/8] & ~( 0xFF >> (prefix_len % 8) );
61 if (prefix_len/8 < 15)
62 memset(out->s6_addr+prefix_len/8+1, 0, 16-prefix_len/8-1);
63}
64
522d829b
TL
65bool matches_ipv6_in_subnet(const struct ifaddrs& addrs,
66 const struct sockaddr_in6* net,
67 unsigned int prefix_len)
68{
69 if (addrs.ifa_addr == nullptr)
70 return false;
7c673cae 71
522d829b
TL
72 if (addrs.ifa_addr->sa_family != net->sin6_family)
73 return false;
74 struct in6_addr want;
7c673cae 75 netmask_ipv6(&net->sin6_addr, prefix_len, &want);
522d829b
TL
76 struct in6_addr temp;
77 struct in6_addr *cur = &((struct sockaddr_in6*)addrs.ifa_addr)->sin6_addr;
78 if (IN6_IS_ADDR_LINKLOCAL(cur))
79 return false;
80 netmask_ipv6(cur, prefix_len, &temp);
81 return IN6_ARE_ADDR_EQUAL(&temp, &want);
7c673cae
FG
82}
83
7c673cae
FG
84bool parse_network(const char *s, struct sockaddr_storage *network, unsigned int *prefix_len) {
85 char *slash = strchr((char*)s, '/');
86 if (!slash) {
87 // no slash
88 return false;
89 }
90 if (*(slash+1) == '\0') {
91 // slash is the last character
92 return false;
93 }
94
95 char *end;
96 long int num = strtol(slash+1, &end, 10);
97 if (*end != '\0') {
98 // junk after the prefix_len
99 return false;
100 }
101 if (num < 0) {
102 return false;
103 }
104 *prefix_len = num;
105
106 // copy the part before slash to get nil termination
107 char *addr = (char*)alloca(slash-s + 1);
108 strncpy(addr, s, slash-s);
109 addr[slash-s] = '\0';
110
111 // caller expects ports etc to be zero
112 memset(network, 0, sizeof(*network));
113
114 // try parsing as ipv4
115 int ok;
116 ok = inet_pton(AF_INET, addr, &((struct sockaddr_in*)network)->sin_addr);
117 if (ok) {
118 network->ss_family = AF_INET;
119 return true;
120 }
121
122 // try parsing as ipv6
123 ok = inet_pton(AF_INET6, addr, &((struct sockaddr_in6*)network)->sin6_addr);
124 if (ok) {
125 network->ss_family = AF_INET6;
126 return true;
127 }
128
129 return false;
130}
11fdf7f2
TL
131
132bool parse_network(const char *s,
133 entity_addr_t *network,
134 unsigned int *prefix_len)
135{
136 sockaddr_storage ss;
137 bool ret = parse_network(s, &ss, prefix_len);
138 if (ret) {
139 network->set_type(entity_addr_t::TYPE_LEGACY);
140 network->set_sockaddr((sockaddr *)&ss);
141 }
142 return ret;
143}
144
145bool network_contains(
146 const struct entity_addr_t& network,
147 unsigned int prefix_len,
148 const struct entity_addr_t& addr)
149{
150 if (addr.get_family() != network.get_family()) {
151 return false;
152 }
153 switch (network.get_family()) {
154 case AF_INET:
155 {
156 struct in_addr a, b;
157 netmask_ipv4(
158 &((const sockaddr_in*)network.get_sockaddr())->sin_addr, prefix_len, &a);
159 netmask_ipv4(
160 &((const sockaddr_in*)addr.get_sockaddr())->sin_addr, prefix_len, &b);
161 if (memcmp(&a, &b, sizeof(a)) == 0) {
162 return true;
163 }
164 }
165 break;
166 case AF_INET6:
167 {
168 struct in6_addr a, b;
169 netmask_ipv6(
170 &((const sockaddr_in6*)network.get_sockaddr())->sin6_addr, prefix_len, &a);
171 netmask_ipv6(
172 &((const sockaddr_in6*)addr.get_sockaddr())->sin6_addr, prefix_len, &b);
173 if (memcmp(&a, &b, sizeof(a)) == 0) {
174 return true;
175 }
176 }
177 break;
178 }
179 return false;
180}