1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45 
46 #include "defs.h"
47 #include "ipcalc.h"
48 
49 /* ipv4 prefix 0.0.0.0/0 */
50 const struct olsr_ip_prefix ipv4_internet_route =
51 {
52     .prefix.v4.s_addr = 0,
53     .prefix_len = 0
54 };
55 
56 /* ipv6 prefix ::ffff:0:0/96 */
57 const struct olsr_ip_prefix ipv6_mappedv4_route =
58 {
59     .prefix.v6.s6_addr = { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0 },
60     .prefix_len = 96
61 };
62 
63 /* ipv6 prefix 2000::/3 */
64 const struct olsr_ip_prefix ipv6_internet_route =
65 {
66     .prefix.v6.s6_addr = { 0x20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
67     .prefix_len = 3
68 };
69 
70 /* ip address zero */
71 const union olsr_ip_addr olsr_ip_zero =
72 {
73     .v6.s6_addr = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
74 };
75 
76 /* Default IPv6 multicast addresses FF02::6D(linklocal manet routers, see RFC 5498) */
77 const union olsr_ip_addr ipv6_def_multicast = {
78     .v6.s6_addr = { 0xFF, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0, 0x6D }
79 };
80 
81 /* Host-byte-order! */
82 int
prefix_to_netmask(uint8_t * a,int len,uint8_t prefixlen)83 prefix_to_netmask(uint8_t * a, int len, uint8_t prefixlen)
84 {
85 #if !defined(NODEBUG) && defined(DEBUG)
86   struct ipaddr_str buf;
87   const uint8_t *a_start = a;
88 #endif /* !defined(NODEBUG) && defined(DEBUG) */
89   int p;
90   const uint8_t *a_end;
91 
92   if (len <= 0 || !a) {
93     return 0;
94   }
95 
96   a_end = a + len;
97   for (p = prefixlen; a < a_end && p > 8; p -= 8) {
98     *a++ = 0xff;
99   }
100   if (a >= a_end) {
101     return 0;
102   }
103   *a++ = 0xff << (8 - p);
104   while (a < a_end) {
105     *a++ = 0;
106   }
107 
108 #ifdef DEBUG
109   OLSR_PRINTF(3, "Prefix %d = Netmask: %s\n", prefixlen, inet_ntop(olsr_cnf->ip_version, a_start, buf.buf, sizeof(buf.buf)));
110 #endif /* DEBUG */
111   return 1;
112 }
113 
114 uint8_t
netmask_to_prefix(const uint8_t * adr,int len)115 netmask_to_prefix(const uint8_t * adr, int len)
116 {
117   struct ipaddr_str buf;
118   const uint8_t *const a_end = adr + len;
119   uint16_t prefix = 0;
120   const uint8_t *a;
121   for (a = adr; a < a_end && *a == 0xff; a++) {
122     prefix += 8;
123   }
124   if (a < a_end) {
125     /* handle the last byte */
126     switch (*a) {
127     case 0:
128       prefix += 0;
129       break;
130     case 128:
131       prefix += 1;
132       break;
133     case 192:
134       prefix += 2;
135       break;
136     case 224:
137       prefix += 3;
138       break;
139     case 240:
140       prefix += 4;
141       break;
142     case 248:
143       prefix += 5;
144       break;
145     case 252:
146       prefix += 6;
147       break;
148     case 254:
149       prefix += 7;
150       break;
151     case 255:
152       prefix += 8;
153       break;                    /* Shouldn't happen */
154     default:
155       OLSR_PRINTF(0, "%s: Got bogus netmask %s\n", __func__, olsr_ip_to_string(&buf, (const union olsr_ip_addr *)(const void *)adr));
156       prefix = UCHAR_MAX;
157       break;
158     }
159   }
160 #ifdef DEBUG
161   OLSR_PRINTF(3, "Netmask: %s = Prefix %d\n", olsr_ip_to_string(&buf, (const union olsr_ip_addr *)(const void *)adr), prefix);
162 #endif /* DEBUG */
163   return prefix;
164 }
165 
166 const char *
olsr_ip_prefix_to_string(const struct olsr_ip_prefix * prefix)167 olsr_ip_prefix_to_string(const struct olsr_ip_prefix *prefix)
168 {
169   /* We need for IPv6 an IP address + '/' + prefix and for IPv4 an IP address + '/' + a netmask */
170   static char buf[MAX(INET6_ADDRSTRLEN + 1 + 3, INET_ADDRSTRLEN + 1 + INET_ADDRSTRLEN)];
171   const char *rv;
172 
173   if (olsr_cnf->ip_version == AF_INET) {
174     /* IPv4 */
175     int len;
176     union olsr_ip_addr netmask;
177     rv = inet_ntop(AF_INET, &prefix->prefix.v4, buf, sizeof(buf));
178     len = strlen(buf);
179     buf[len++] = '/';
180     olsr_prefix_to_netmask(&netmask, prefix->prefix_len);
181     inet_ntop(AF_INET, &netmask.v4, buf + len, sizeof(buf) - len);
182   } else {
183     /* IPv6 */
184     int len;
185     rv = inet_ntop(AF_INET6, &prefix->prefix.v6, buf, sizeof(buf));
186     len = strlen(buf);
187     buf[len++] = '/';
188     snprintf(buf + len, sizeof(buf) - len, "%d", prefix->prefix_len);
189   }
190   return rv;
191 }
192 
193 int
olsr_string_to_prefix(int ipversion,struct olsr_ip_prefix * dst,const char * string)194 olsr_string_to_prefix(int ipversion, struct olsr_ip_prefix *dst, const char *string) {
195   static char buf[MAX(INET6_ADDRSTRLEN + 1 + 3, INET_ADDRSTRLEN + 1 + INET_ADDRSTRLEN)];
196   char *ptr;
197 
198   strscpy(buf, string, sizeof(buf));
199   dst->prefix_len = ipversion == AF_INET ? 32 : 128;
200 
201   ptr = strchr(buf, '/');
202   if (!ptr) {
203     ptr = strchr(buf, ' ');
204   }
205 
206   if (ptr) {
207     *ptr++ = 0;
208     if (olsr_cnf->ip_version == AF_INET && strchr(ptr, '.')) {
209       uint8_t subnetbuf[4];
210       if (inet_pton(AF_INET, ptr, subnetbuf) != 1) {
211         return -1;
212       }
213 
214       dst->prefix_len = netmask_to_prefix(subnetbuf, sizeof(subnetbuf));
215     }
216     else {
217       dst->prefix_len = atoi(ptr);
218     }
219   }
220   return inet_pton(ipversion, buf, &dst->prefix) == 1 ? 0 : -1;
221 }
222 
223 /* we need to handle one value specifically since shifting
224  * 32 bits of a 32 bit integer is the same as shifting 0 bits.
225  * The result is in host-byte-order.
226  */
227 static INLINE uint32_t
prefix_to_netmask4(uint8_t prefixlen)228 prefix_to_netmask4(uint8_t prefixlen)
229 {
230   return prefixlen == 0 ? 0 : (~0U << (32 - prefixlen));
231 }
232 
233 /* see if the ipaddr is in the net. That is equivalent to the fact that the net part
234  * of both are equal. So we must compare the first <prefixlen> bits. Network-byte-order!
235  */
236 int
ip_in_net(const union olsr_ip_addr * ipaddr,const struct olsr_ip_prefix * net)237 ip_in_net(const union olsr_ip_addr *ipaddr, const struct olsr_ip_prefix *net)
238 {
239   int rv;
240   if (olsr_cnf->ip_version == AF_INET) {
241     uint32_t netmask = htonl(prefix_to_netmask4(net->prefix_len));
242     rv = (ipaddr->v4.s_addr & netmask) == (net->prefix.v4.s_addr & netmask);
243   } else {
244     /* IPv6 */
245     uint32_t netmask;
246     const uint32_t *i = (const uint32_t *)&ipaddr->v6;
247     const uint32_t *n = (const uint32_t *)&net->prefix.v6;
248     unsigned int prefix_len;
249     /* First we compare whole unsigned int's */
250     for (prefix_len = net->prefix_len; prefix_len > 32; prefix_len -= 32) {
251       if (*i != *n) {
252         return false;
253       }
254       i++;
255       n++;
256     }
257     /* And the remaining is the same as in the IPv4 case */
258     netmask = htonl(prefix_to_netmask4(prefix_len));
259     rv = (*i & netmask) == (*n & netmask);
260   }
261   return rv;
262 }
263 
is_prefix_inetgw(const struct olsr_ip_prefix * prefix)264 bool is_prefix_inetgw(const struct olsr_ip_prefix *prefix) {
265   if (olsr_cnf->ip_version == AF_INET && ip_prefix_is_v4_inetgw(prefix)) {
266     return true;
267   }
268   if (olsr_cnf->ip_version == AF_INET6) {
269     if (ip_prefix_is_v6_inetgw(prefix) || ip_prefix_is_mappedv4_inetgw(prefix)) {
270       return true;
271     }
272   }
273   return false;
274 }
275 
276 /*
277  * Local Variables:
278  * c-basic-offset: 2
279  * indent-tabs-mode: nil
280  * End:
281  */
282