]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/ipaddr.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / common / ipaddr.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <arpa/inet.h>
5 #include <ifaddrs.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #if defined(__FreeBSD__)
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #endif
13
14 #include "include/ipaddr.h"
15 #include "msg/msg_types.h"
16 #include "common/pick_address.h"
17
18 using std::string;
19
20 void netmask_ipv4(const struct in_addr *addr,
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
35 bool matches_ipv4_in_subnet(const struct ifaddrs& addrs,
36 const struct sockaddr_in* net,
37 unsigned int prefix_len)
38 {
39 if (addrs.ifa_addr == nullptr)
40 return false;
41
42 if (addrs.ifa_addr->sa_family != net->sin_family)
43 return false;
44 struct in_addr want;
45 netmask_ipv4(&net->sin_addr, prefix_len, &want);
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;
50 }
51
52 void netmask_ipv6(const struct in6_addr *addr,
53 unsigned int prefix_len,
54 struct in6_addr *out) {
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
65 bool 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;
71
72 if (addrs.ifa_addr->sa_family != net->sin6_family)
73 return false;
74 struct in6_addr want;
75 netmask_ipv6(&net->sin6_addr, prefix_len, &want);
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);
82 }
83
84 bool 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 }
131
132 bool 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
145 bool 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 }