gateway: introduce and use removeGatewayFromList function
[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 /* ip address zero */
67 const union olsr_ip_addr olsr_ip_zero =
68 {
69     .v6.s6_addr = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
70 };
71
72 /* Default IPv6 multicast addresses FF02::6D(linklocal manet routers, see RFC 5498) */
73 const union olsr_ip_addr ipv6_def_multicast = {
74     .v6.s6_addr = { 0xFF, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0, 0x6D }
75 };
76
77 /* Host-byte-order! */
78 int
79 prefix_to_netmask(uint8_t * a, int len, uint8_t prefixlen)
80 {
81 #if !defined(NODEBUG) && defined(DEBUG)
82   struct ipaddr_str buf;
83   const uint8_t *a_start = a;
84 #endif /* !defined(NODEBUG) && defined(DEBUG) */
85   int p;
86   const uint8_t *a_end;
87
88   a_end = a + len;
89   for (p = prefixlen; a < a_end && p > 8; p -= 8) {
90     *a++ = 0xff;
91   }
92   if (a >= a_end) {
93     return 0;
94   }
95   *a++ = 0xff << (8 - p);
96   while (a < a_end) {
97     *a++ = 0;
98   }
99
100 #ifdef DEBUG
101   OLSR_PRINTF(3, "Prefix %d = Netmask: %s\n", prefixlen, inet_ntop(olsr_cnf->ip_version, a_start, buf.buf, sizeof(buf.buf)));
102 #endif /* DEBUG */
103   return 1;
104 }
105
106 uint8_t
107 netmask_to_prefix(const uint8_t * adr, int len)
108 {
109   struct ipaddr_str buf;
110   const uint8_t *const a_end = adr + len;
111   uint16_t prefix = 0;
112   const uint8_t *a;
113   for (a = adr; a < a_end && *a == 0xff; a++) {
114     prefix += 8;
115   }
116   if (a < a_end) {
117     /* handle the last byte */
118     switch (*a) {
119     case 0:
120       prefix += 0;
121       break;
122     case 128:
123       prefix += 1;
124       break;
125     case 192:
126       prefix += 2;
127       break;
128     case 224:
129       prefix += 3;
130       break;
131     case 240:
132       prefix += 4;
133       break;
134     case 248:
135       prefix += 5;
136       break;
137     case 252:
138       prefix += 6;
139       break;
140     case 254:
141       prefix += 7;
142       break;
143     case 255:
144       prefix += 8;
145       break;                    /* Shouldn't happen */
146     default:
147       OLSR_PRINTF(0, "%s: Got bogus netmask %s\n", __func__, olsr_ip_to_string(&buf, (const union olsr_ip_addr *)(const void *)adr));
148       prefix = UCHAR_MAX;
149       break;
150     }
151   }
152 #ifdef DEBUG
153   OLSR_PRINTF(3, "Netmask: %s = Prefix %d\n", olsr_ip_to_string(&buf, (const union olsr_ip_addr *)(const void *)adr), prefix);
154 #endif /* DEBUG */
155   return prefix;
156 }
157
158 const char *
159 olsr_ip_prefix_to_string(const struct olsr_ip_prefix *prefix)
160 {
161   /* We need for IPv6 an IP address + '/' + prefix and for IPv4 an IP address + '/' + a netmask */
162   static char buf[MAX(INET6_ADDRSTRLEN + 1 + 3, INET_ADDRSTRLEN + 1 + INET_ADDRSTRLEN)];
163   const char *rv;
164
165   if (olsr_cnf->ip_version == AF_INET) {
166     /* IPv4 */
167     int len;
168     union olsr_ip_addr netmask;
169     rv = inet_ntop(AF_INET, &prefix->prefix.v4, buf, sizeof(buf));
170     len = strlen(buf);
171     buf[len++] = '/';
172     olsr_prefix_to_netmask(&netmask, prefix->prefix_len);
173     inet_ntop(AF_INET, &netmask.v4, buf + len, sizeof(buf) - len);
174   } else {
175     /* IPv6 */
176     int len;
177     rv = inet_ntop(AF_INET6, &prefix->prefix.v6, buf, sizeof(buf));
178     len = strlen(buf);
179     buf[len++] = '/';
180     snprintf(buf + len, sizeof(buf) - len, "/%d", prefix->prefix_len);
181   }
182   return rv;
183 }
184
185 int
186 olsr_string_to_prefix(int ipversion, struct olsr_ip_prefix *dst, const char *string) {
187   static char buf[MAX(INET6_ADDRSTRLEN + 1 + 3, INET_ADDRSTRLEN + 1 + INET_ADDRSTRLEN)];
188   char *ptr;
189
190   strscpy(buf, string, sizeof(buf));
191   dst->prefix_len = ipversion == AF_INET ? 32 : 128;
192
193   ptr = strchr(buf, '/');
194   if (!ptr) {
195     ptr = strchr(buf, ' ');
196   }
197
198   if (ptr) {
199     *ptr++ = 0;
200     if (olsr_cnf->ip_version == AF_INET && strchr(ptr, '.')) {
201       uint8_t subnetbuf[4];
202       if (inet_pton(AF_INET, ptr, subnetbuf) != 1) {
203         return -1;
204       }
205
206       dst->prefix_len = netmask_to_prefix(subnetbuf, sizeof(subnetbuf));
207     }
208     else {
209       dst->prefix_len = atoi(ptr);
210     }
211   }
212   return inet_pton(ipversion, buf, &dst->prefix) == 1 ? 0 : -1;
213 }
214
215 /* we need to handle one value specifically since shifting
216  * 32 bits of a 32 bit integer is the same as shifting 0 bits.
217  * The result is in host-byte-order.
218  */
219 static INLINE uint32_t
220 prefix_to_netmask4(uint8_t prefixlen)
221 {
222   return prefixlen == 0 ? 0 : (~0U << (32 - prefixlen));
223 }
224
225 /* see if the ipaddr is in the net. That is equivalent to the fact that the net part
226  * of both are equal. So we must compare the first <prefixlen> bits. Network-byte-order!
227  */
228 int
229 ip_in_net(const union olsr_ip_addr *ipaddr, const struct olsr_ip_prefix *net)
230 {
231   int rv;
232   if (olsr_cnf->ip_version == AF_INET) {
233     uint32_t netmask = htonl(prefix_to_netmask4(net->prefix_len));
234     rv = (ipaddr->v4.s_addr & netmask) == (net->prefix.v4.s_addr & netmask);
235   } else {
236     /* IPv6 */
237     uint32_t netmask;
238     const uint32_t *i = (const uint32_t *)&ipaddr->v6;
239     const uint32_t *n = (const uint32_t *)&net->prefix.v6;
240     unsigned int prefix_len;
241     /* First we compare whole unsigned int's */
242     for (prefix_len = net->prefix_len; prefix_len > 32; prefix_len -= 32) {
243       if (*i != *n) {
244         return false;
245       }
246       i++;
247       n++;
248     }
249     /* And the remaining is the same as in the IPv4 case */
250     netmask = htonl(prefix_to_netmask4(prefix_len));
251     rv = (*i & netmask) == (*n & netmask);
252   }
253   return rv;
254 }
255
256 bool is_prefix_inetgw(const struct olsr_ip_prefix *prefix) {
257   if (olsr_cnf->ip_version == AF_INET && ip_prefix_is_v4_inetgw(prefix)) {
258     return true;
259   }
260   if (olsr_cnf->ip_version == AF_INET6) {
261     if (ip_prefix_is_v6_inetgw(prefix) || ip_prefix_is_mappedv4_inetgw(prefix)) {
262       return true;
263     }
264   }
265   return false;
266 }
267
268 /*
269  * Local Variables:
270  * c-basic-offset: 2
271  * indent-tabs-mode: nil
272  * End:
273  */