Simplify inet gw detection
[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 /* ipv6 prefix ::ffff:0:0/96 */
46 const struct olsr_ip_prefix mapped_v4_gw =
47 {
48     .prefix.v6.s6_addr = { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0 },
49     .prefix_len = 96
50 };
51
52 /* ipv6 prefix 2000::/3 */
53 const struct olsr_ip_prefix ipv6_internet_route =
54 {
55     .prefix.v6.s6_addr = { 0x20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
56     .prefix_len = 3
57 };
58
59 int
60 prefix_to_netmask(uint8_t * a, int len, uint8_t prefixlen)
61 {
62 #if !defined(NODEBUG) && defined(DEBUG)
63   struct ipaddr_str buf;
64   const uint8_t *a_start = a;
65 #endif
66   int p;
67   const uint8_t *a_end;
68
69   a_end = a + len;
70   for (p = prefixlen; a < a_end && p > 8; p -= 8) {
71     *a++ = 0xff;
72   }
73   if (a >= a_end) {
74     return 0;
75   }
76   *a++ = 0xff << (8 - p);
77   while (a < a_end) {
78     *a++ = 0;
79   }
80
81 #ifdef DEBUG
82   OLSR_PRINTF(3, "Prefix %d = Netmask: %s\n", prefixlen, inet_ntop(olsr_cnf->ip_version, a_start, buf.buf, sizeof(buf.buf)));
83 #endif
84   return 1;
85 }
86
87 uint8_t
88 netmask_to_prefix(const uint8_t * adr, int len)
89 {
90   struct ipaddr_str buf;
91   const uint8_t *const a_end = adr + len;
92   uint16_t prefix = 0;
93   const uint8_t *a;
94   for (a = adr; a < a_end && *a == 0xff; a++) {
95     prefix += 8;
96   }
97   if (a < a_end) {
98     /* handle the last byte */
99     switch (*a) {
100     case 0:
101       prefix += 0;
102       break;
103     case 128:
104       prefix += 1;
105       break;
106     case 192:
107       prefix += 2;
108       break;
109     case 224:
110       prefix += 3;
111       break;
112     case 240:
113       prefix += 4;
114       break;
115     case 248:
116       prefix += 5;
117       break;
118     case 252:
119       prefix += 6;
120       break;
121     case 254:
122       prefix += 7;
123       break;
124     case 255:
125       prefix += 8;
126       break;                    /* Shouldn't happen */
127     default:
128       OLSR_PRINTF(0, "%s: Got bogus netmask %s\n", __func__, olsr_ip_to_string(&buf, (const union olsr_ip_addr *)(const void *)adr));
129       prefix = UCHAR_MAX;
130       break;
131     }
132   }
133 #ifdef DEBUG
134   OLSR_PRINTF(3, "Netmask: %s = Prefix %d\n", olsr_ip_to_string(&buf, (const union olsr_ip_addr *)(const void *)adr), prefix);
135 #endif
136   return prefix;
137 }
138
139 const char *
140 olsr_ip_prefix_to_string(const struct olsr_ip_prefix *prefix)
141 {
142   /* We need for IPv6 an IP address + '/' + prefix and for IPv4 an IP address + '/' + a netmask */
143   static char buf[MAX(INET6_ADDRSTRLEN + 1 + 3, INET_ADDRSTRLEN + 1 + INET_ADDRSTRLEN)];
144   const char *rv;
145
146   if (olsr_cnf->ip_version == AF_INET) {
147     /* IPv4 */
148     int len;
149     union olsr_ip_addr netmask;
150     rv = inet_ntop(AF_INET, &prefix->prefix.v4, buf, sizeof(buf));
151     len = strlen(buf);
152     buf[len++] = '/';
153     olsr_prefix_to_netmask(&netmask, prefix->prefix_len);
154     inet_ntop(AF_INET, &netmask.v4, buf + len, sizeof(buf) - len);
155   } else {
156     /* IPv6 */
157     int len;
158     rv = inet_ntop(AF_INET6, &prefix->prefix.v6, buf, sizeof(buf));
159     len = strlen(buf);
160     buf[len++] = '/';
161     snprintf(buf + len, sizeof(buf) - len, "/%d", prefix->prefix_len);
162   }
163   return rv;
164 }
165
166 int
167 olsr_string_to_prefix(int ipversion, struct olsr_ip_prefix *dst, const char *string) {
168   static char buf[MAX(INET6_ADDRSTRLEN + 1 + 3, INET_ADDRSTRLEN + 1 + INET_ADDRSTRLEN)];
169   char *prefix;
170
171   strscpy(buf, string, sizeof(buf));
172   dst->prefix_len = ipversion == AF_INET ? 32 : 128;
173
174   prefix = strchr(buf, '/');
175   if (prefix) {
176     *prefix++ = 0;
177     dst->prefix_len = atoi(prefix);
178   }
179
180   return inet_pton(ipversion, buf, &dst->prefix);
181 }
182
183 /* see if the ipaddr is in the net. That is equivalent to the fact that the net part
184  * of both are equal. So we must compare the first <prefixlen> bits.
185  */
186 int
187 ip_in_net(const union olsr_ip_addr *ipaddr, const struct olsr_ip_prefix *net)
188 {
189   int rv;
190   if (olsr_cnf->ip_version == AF_INET) {
191     uint32_t netmask = prefix_to_netmask4(net->prefix_len);
192     rv = (ipaddr->v4.s_addr & netmask) == (net->prefix.v4.s_addr & netmask);
193   } else {
194     /* IPv6 */
195     uint32_t netmask;
196     const uint32_t *i = (const uint32_t *)&ipaddr->v6;
197     const uint32_t *n = (const uint32_t *)&net->prefix.v6;
198     unsigned int prefix_len;
199     /* First we compare whole unsigned int's */
200     for (prefix_len = net->prefix_len; prefix_len > 32; prefix_len -= 32) {
201       if (*i != *n) {
202         return false;
203       }
204       i++;
205       n++;
206     }
207     /* And the remaining is the same as in the IPv4 case */
208     netmask = prefix_to_netmask4(prefix_len);
209     rv = (*i & netmask) == (*n & netmask);
210   }
211   return rv;
212 }
213
214 bool ip_is_inetgw_prefix(union olsr_ip_addr *net, int prefixlen) {
215   if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
216     return memcmp(&ipv6_internet_route.prefix, net, olsr_cnf->ipsize) == 0;
217   }
218   if (olsr_cnf->ip_version == AF_INET6 && prefixlen == mapped_v4_gw.prefix_len) {
219     return memcmp(&mapped_v4_gw.prefix, net, olsr_cnf->ipsize) == 0;
220   }
221   if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
222     return memcmp(&in6addr_any, net, olsr_cnf->ipsize) == 0;
223   }
224   return false;
225 }
226
227 /*
228  * Local Variables:
229  * c-basic-offset: 2
230  * indent-tabs-mode: nil
231  * End:
232  */