]>
Commit | Line | Data |
---|---|---|
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 |
18 | using std::string; |
19 | ||
11fdf7f2 | 20 | void 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 |
35 | bool 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 |
52 | void 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 |
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; | |
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 |
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 | } | |
11fdf7f2 TL |
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 | } |