]>
git.proxmox.com Git - ceph.git/blob - ceph/src/common/ipaddr.cc
1 #include "include/ipaddr.h"
3 #include <sys/socket.h>
9 static void netmask_ipv4(const struct in_addr
*addr
,
10 unsigned int prefix_len
,
11 struct in_addr
*out
) {
14 if (prefix_len
>= 32) {
15 // also handle 32 in this branch, because >>32 is not defined by
19 mask
= htonl(~(~uint32_t(0) >> prefix_len
));
21 out
->s_addr
= addr
->s_addr
& mask
;
25 const 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
;
30 netmask_ipv4(&net
->sin_addr
, prefix_len
, &want
);
32 for (; addrs
!= NULL
; addrs
= addrs
->ifa_next
) {
34 if (addrs
->ifa_addr
== NULL
)
37 if (strcmp(addrs
->ifa_name
, "lo") == 0)
40 if (addrs
->ifa_addr
->sa_family
!= net
->sin_family
)
43 struct in_addr
*cur
= &((struct sockaddr_in
*)addrs
->ifa_addr
)->sin_addr
;
44 netmask_ipv4(cur
, prefix_len
, &temp
);
46 if (temp
.s_addr
== want
.s_addr
) {
47 return addrs
->ifa_addr
;
55 static void netmask_ipv6(const struct in6_addr
*addr
,
56 unsigned int prefix_len
,
57 struct in6_addr
*out
) {
61 memcpy(out
->s6_addr
, addr
->s6_addr
, prefix_len
/8);
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);
69 const 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
;
74 netmask_ipv6(&net
->sin6_addr
, prefix_len
, &want
);
76 for (; addrs
!= NULL
; addrs
= addrs
->ifa_next
) {
78 if (addrs
->ifa_addr
== NULL
)
81 if (strcmp(addrs
->ifa_name
, "lo") == 0)
84 if (addrs
->ifa_addr
->sa_family
!= net
->sin6_family
)
87 struct in6_addr
*cur
= &((struct sockaddr_in6
*)addrs
->ifa_addr
)->sin6_addr
;
88 netmask_ipv6(cur
, prefix_len
, &temp
);
90 if (IN6_ARE_ADDR_EQUAL(&temp
, &want
))
91 return addrs
->ifa_addr
;
98 const 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
) {
103 return find_ipv4_in_subnet(addrs
, (struct sockaddr_in
*)net
, prefix_len
);
106 return find_ipv6_in_subnet(addrs
, (struct sockaddr_in6
*)net
, prefix_len
);
113 bool parse_network(const char *s
, struct sockaddr_storage
*network
, unsigned int *prefix_len
) {
114 char *slash
= strchr((char*)s
, '/');
119 if (*(slash
+1) == '\0') {
120 // slash is the last character
125 long int num
= strtol(slash
+1, &end
, 10);
127 // junk after the prefix_len
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';
140 // caller expects ports etc to be zero
141 memset(network
, 0, sizeof(*network
));
143 // try parsing as ipv4
145 ok
= inet_pton(AF_INET
, addr
, &((struct sockaddr_in
*)network
)->sin_addr
);
147 network
->ss_family
= AF_INET
;
151 // try parsing as ipv6
152 ok
= inet_pton(AF_INET6
, addr
, &((struct sockaddr_in6
*)network
)->sin6_addr
);
154 network
->ss_family
= AF_INET6
;