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 /*! ocatipv4route.c
19 * This file contains functions for managing IPv4 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 #define NMBIT(i,n) ((i&n)&~(n<<1))
30 #define BRANCH(i,n) (NMBIT(i,n)!=0)
31
32
33 static IPv4Route_t *rroot_ = NULL;
34 static pthread_mutex_t route_mutex_ = PTHREAD_MUTEX_INITIALIZER;
35
36
37 /*! Add an IPv4 route to IPv4 routing table.
38 * @return 0 on success or < 0 on failure.
39 */
ipv4_add_route(IPv4Route_t * route,IPv4Route_t ** root,uint32_t cur_nm)40 int ipv4_add_route(IPv4Route_t *route, IPv4Route_t **root, uint32_t cur_nm)
41 {
42 if (!(*root))
43 {
44 if (!(*root = calloc(1, sizeof(IPv4Route_t))))
45 {
46 log_msg(LOG_EMERG, "ipv4_add_route: %s", strerror(errno));
47 return E_RT_NOMEM;
48 }
49 (*root)->dest = route->dest & cur_nm;
50 (*root)->netmask = cur_nm;
51 }
52
53 if (route->netmask == cur_nm /*(*root)->netmask*/)
54 {
55 if (IN6_ARE_ADDR_EQUAL(&(*root)->gw, &in6addr_any))
56 {
57 memcpy(&(*root)->gw, &route->gw, sizeof(struct in6_addr));
58 return 0;
59 }
60
61 if (IN6_ARE_ADDR_EQUAL(&(*root)->gw, &route->gw))
62 return 0;
63
64 log_msg(LOG_ERR, "route already exists");
65 return E_RT_DUP;
66 }
67
68 // break recursion in case of error
69 if (cur_nm == 0xffffffff)
70 {
71 log_msg(LOG_ERR, "netmask error in netmask of route: %08x", route->netmask);
72 return E_RT_ILLNM;
73 }
74
75 //now branch to subs
76 cur_nm >>= 1;
77 cur_nm |= 0x80000000;
78
79 return ipv4_add_route(route, &(*root)->next[BRANCH(route->dest, cur_nm)], cur_nm);
80 }
81
82
ipv4_lookup_route__(uint32_t ip,IPv4Route_t * route,uint32_t cur_nm)83 IPv4Route_t *ipv4_lookup_route__(uint32_t ip, IPv4Route_t *route, uint32_t cur_nm)
84 {
85 if (!route)
86 {
87 log_debug("NULL route");
88 return NULL;
89 }
90
91 cur_nm >>= 1;
92 cur_nm |= 0x80000000;
93
94 if (route->next[BRANCH(ip, cur_nm)])
95 return ipv4_lookup_route__(ip, route->next[BRANCH(ip, cur_nm)], cur_nm);
96
97 //if (memcmp(&route->gw, &in6addr_any, sizeof(struct in6_addr)))
98 if (!IN6_ARE_ADDR_EQUAL(&route->gw, &in6addr_any))
99 return route;
100
101 return NULL;
102 }
103
104
105 /*! Lookup a route to an ip address in routing table.
106 * @param Ip to find a route for. The Ip must be given in host byte order.
107 * @return Pointer to IPv6 TOR address. */
ipv4_lookup_route(uint32_t ip)108 struct in6_addr *ipv4_lookup_route(uint32_t ip)
109 {
110 IPv4Route_t *r;
111
112 pthread_mutex_lock(&route_mutex_);
113 r = ipv4_lookup_route__(ip, rroot_, 0);
114 pthread_mutex_unlock(&route_mutex_);
115
116 return r ? &r->gw : NULL;
117 }
118
119
ipv4_traverse(IPv4Route_t * route,void (func)(IPv4Route_t *,void *),void * p)120 void ipv4_traverse(IPv4Route_t *route, void (func)(IPv4Route_t*, void*), void *p)
121 {
122 if (!route)
123 return;
124
125 func(route, p);
126 ipv4_traverse(route->next[0], func, p);
127 ipv4_traverse(route->next[1], func, p);
128 }
129
130
ipv4_print(IPv4Route_t * route,void * f)131 void ipv4_print(IPv4Route_t *route, void *f)
132 {
133 char addr[INET6_ADDRSTRLEN];
134 struct in_addr iaddr;
135
136 //if (!memcmp(&route->gw, &in6addr_any, sizeof(struct in6_addr)))
137 if (IN6_ARE_ADDR_EQUAL(&route->gw, &in6addr_any))
138 return;
139
140 iaddr.s_addr = htonl(route->dest);
141 fprintf(f, "IN %s ", inet_ntoa(iaddr));
142 iaddr.s_addr = htonl(route->netmask);
143 fprintf(f, "%s ", inet_ntoa(iaddr));
144 inet_ntop(AF_INET6, &route->gw, addr, INET6_ADDRSTRLEN);
145 fprintf(f, "%s %p\n", addr, route);
146 }
147
148
print_routes(FILE * f)149 void print_routes(FILE *f)
150 {
151 ipv4_traverse(rroot_, ipv4_print, f);
152 }
153
154
parse_route(const char * rs)155 int parse_route(const char *rs)
156 {
157 char buf[strlen(rs) + 1], *s, *b;
158 IPv4Route_t route;
159 int r;
160
161 if (!rs)
162 return E_RT_NULLPTR;
163
164 log_debug("IPv4 route parser: \"%s\"", rs);
165
166 strlcpy(buf, rs, strlen(rs) + 1);
167 if (!(s = strtok_r(buf, " \t", &b)))
168 return E_RT_SYNTAX;
169
170 if (inet_pton(AF_INET, s, &route.dest) != 1)
171 return E_RT_SYNTAX;
172
173 if (!(s = strtok_r(NULL, " \t", &b)))
174 return E_RT_SYNTAX;
175
176 if (inet_pton(AF_INET, s, &route.netmask) != 1)
177 return E_RT_SYNTAX;
178
179 if (!(s = strtok_r(NULL, " \t", &b)))
180 return E_RT_SYNTAX;
181
182 if (inet_pton(AF_INET6, s, &route.gw) != 1)
183 return E_RT_SYNTAX;
184
185 if (!has_tor_prefix(&route.gw))
186 return E_RT_NOTORGW;
187
188 if (IN6_ARE_ADDR_EQUAL(&route.gw, &CNF(ocat_addr)))
189 return E_RT_GWSELF;
190
191 route.netmask = ntohl(route.netmask);
192 route.dest = ntohl(route.dest);
193
194 pthread_mutex_lock(&route_mutex_);
195 r = ipv4_add_route(&route, &rroot_, 0);
196 pthread_mutex_unlock(&route_mutex_);
197
198 return r;
199 }
200
201