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