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