1 /* Copyright 2008 Bernhard R. Fischer, Daniel Haslinger.
2 *
3 * This file is part of OnionCat.
4 *
5 * OnionCat is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License.
8 *
9 * OnionCat is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with OnionCat. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*! @file
19 * This file contains functions for managing IPv6 routing and
20 * forwarding.
21 *
22 * @author Bernhard R. Fischer <rahra _at_ cypherpunk at>
23 * @version 2008/09/03-01
24 */
25
26
27 #include "ocat.h"
28
29
30 /*! IPv6 Routing table. Each entry contains 3 values:
31 * destination network, prefix length, gateway
32 */
33 static IPv6Route_t *v6route_ = NULL;
34 static int v6route_cnt_ = 0;
35 static pthread_mutex_t v6route_mutex_ = PTHREAD_MUTEX_INITIALIZER;
36
37
38 /*! Reduce IPv6 address to prefix, i.e. cut off host id.
39 * @param net IPv6 address
40 * @param prefixlen Prefix length
41 */
ipv6_reduce(struct in6_addr * net,int prefixlen)42 void ipv6_reduce(struct in6_addr *net, int prefixlen)
43 {
44 int i;
45 char m;
46
47 // safety check
48 if (prefixlen < 0 || prefixlen >= 128)
49 return;
50
51 for (i = 0; i < ((128 - prefixlen) >> 3); i++)
52 net->s6_addr[15 - i] = 0;
53
54 m = 0xff << (8 - (prefixlen % 8));
55 net->s6_addr[prefixlen >> 3] &= m;
56
57 }
58
59
60 /*! Lookup IPv6 route.
61 */
ipv6_lookup_route(const struct in6_addr * dest)62 struct in6_addr *ipv6_lookup_route(const struct in6_addr *dest)
63 {
64 struct in6_addr addr;
65 int i, n;
66
67 pthread_mutex_lock(&v6route_mutex_);
68 n = v6route_cnt_;
69 for (i = 0; i < n; i++)
70 {
71 addr = *dest;
72 ipv6_reduce(&addr, v6route_[i].prefixlen);
73 if (IN6_ARE_ADDR_EQUAL(&v6route_[i].dest, &addr))
74 {
75 log_debug("IPv6 route found");
76 break;
77 }
78 }
79 pthread_mutex_unlock(&v6route_mutex_);
80 return i < n ? &v6route_[i].gw : NULL;
81 }
82
83
84 /*! Add an IPv6 route to IPv6 routing table.
85 * @return -1 if table is full else return index of entry.
86 */
ipv6_add_route(const IPv6Route_t * route)87 int ipv6_add_route(const IPv6Route_t *route)
88 {
89 int r = -1;
90 IPv6Route_t *rt;
91
92 pthread_mutex_lock(&v6route_mutex_);
93 if ((rt = realloc(v6route_, sizeof(IPv6Route_t) * (v6route_cnt_ + 1))))
94 {
95 v6route_ = rt;
96 r = v6route_cnt_;
97 memcpy(&v6route_[v6route_cnt_++], route, sizeof(IPv6Route_t));
98 }
99 pthread_mutex_unlock(&v6route_mutex_);
100 return r;
101 }
102
103
ipv6_print(IPv6Route_t * route,void * f)104 void ipv6_print(IPv6Route_t *route, void *f)
105 {
106 char addr[INET6_ADDRSTRLEN];
107
108 inet_ntop(AF_INET6, &route->dest, addr, INET6_ADDRSTRLEN);
109 fprintf(f, "IN6 %s %3d ", addr, route->prefixlen);
110 inet_ntop(AF_INET6, &route->gw, addr, INET6_ADDRSTRLEN);
111 fprintf(f, "%s %p\n", addr, route);
112 }
113
114
ipv6_print_routes(FILE * f)115 void ipv6_print_routes(FILE *f)
116 {
117 int i;
118
119 pthread_mutex_lock(&v6route_mutex_);
120 for (i = 0; i < v6route_cnt_; i++)
121 ipv6_print(&v6route_[i], f);
122 pthread_mutex_unlock(&v6route_mutex_);
123 }
124
125
126 /*! Parse IPv6 route and add it to routing table.
127 * @return index of routing table entry (>= 0) or an integer < 0 on failure.
128 */
ipv6_parse_route(const char * rs)129 int ipv6_parse_route(const char *rs)
130 {
131 char buf[strlen(rs) + 1], *s, *b;
132 IPv6Route_t route6;
133
134 if (!rs)
135 return E_RT_NULLPTR;
136
137 log_debug("IPv6 route parser: \"%s\"", rs);
138
139 strlcpy(buf, rs, strlen(rs) + 1);
140 if (!(s = strtok_r(buf, " \t", &b)))
141 return E_RT_SYNTAX;
142
143 if (inet_pton(AF_INET6, s, &route6.dest) != 1)
144 return E_RT_SYNTAX;
145
146 if (!(s = strtok_r(NULL, " \t", &b)))
147 return E_RT_SYNTAX;
148
149 errno = 0;
150 route6.prefixlen = strtol(s, NULL, 10);
151 if (errno)
152 return E_RT_SYNTAX;
153 if ((route6.prefixlen < 0) || (route6.prefixlen > 128))
154 return E_RT_ILLNM;
155
156 if (!(s = strtok_r(NULL, " \t", &b)))
157 return E_RT_SYNTAX;
158
159 if (inet_pton(AF_INET6, s, &route6.gw) != 1)
160 return E_RT_SYNTAX;
161
162 if (!has_tor_prefix(&route6.gw))
163 return E_RT_NOTORGW;
164
165 if (IN6_ARE_ADDR_EQUAL(&route6.gw, &CNF(ocat_addr)))
166 return E_RT_GWSELF;
167
168 ipv6_reduce(&route6.dest, route6.prefixlen);
169 if (ipv6_lookup_route(&route6.dest))
170 return E_RT_DUP;
171
172 return ipv6_add_route(&route6);
173 }
174
175