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