571304ac620acf9d3d8e636f225182113e2a30aa
[tinc] / src / protocol_edge.c
1 /*
2     protocol_edge.c -- handle the meta-protocol, edges
3     Copyright (C) 1999-2005 Ivo Timmermans,
4                   2000-2009 Guus Sliepen <guus@tinc-vpn.org>
5                   2009      Michael Tokarev <mjt@corpit.ru>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21     $Id$
22 */
23
24 #include "system.h"
25
26 #include "avl_tree.h"
27 #include "conf.h"
28 #include "connection.h"
29 #include "edge.h"
30 #include "graph.h"
31 #include "logger.h"
32 #include "meta.h"
33 #include "net.h"
34 #include "netutl.h"
35 #include "node.h"
36 #include "protocol.h"
37 #include "utils.h"
38 #include "xalloc.h"
39
40 bool send_add_edge(connection_t *c, const edge_t *e)
41 {
42         bool x;
43         char *address, *port;
44
45         cp();
46
47         sockaddr2str(&e->address, &address, &port);
48
49         x = send_request(c, "%d %x %s %s %s %s %lx %d", ADD_EDGE, rand(),
50                                          e->from->name, e->to->name, address, port,
51                                          e->options, e->weight);
52         free(address);
53         free(port);
54
55         return x;
56 }
57
58 bool add_edge_h(connection_t *c)
59 {
60         edge_t *e;
61         node_t *from, *to;
62         char from_name[MAX_STRING_SIZE];
63         char to_name[MAX_STRING_SIZE];
64         char to_address[MAX_STRING_SIZE];
65         char to_port[MAX_STRING_SIZE];
66         sockaddr_t address;
67         long int options;
68         int weight;
69
70         cp();
71
72         if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
73                           from_name, to_name, to_address, to_port, &options, &weight) != 6) {
74                 logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_EDGE", c->name,
75                            c->hostname);
76                 return false;
77         }
78
79         /* Check if names are valid */
80
81         if(!check_id(from_name)) {
82                 logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name,
83                            c->hostname, _("invalid name"));
84                 return false;
85         }
86
87         if(!check_id(to_name)) {
88                 logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name,
89                            c->hostname, _("invalid name"));
90                 return false;
91         }
92
93         if(seen_request(c->buffer))
94                 return true;
95
96         /* Lookup nodes */
97
98         from = lookup_node(from_name);
99         to = lookup_node(to_name);
100
101         if(tunnelserver &&
102            from != myself && from != c->node &&
103            to != myself && to != c->node) {
104                 /* ignore indirect edge registrations for tunnelserver */
105                 ifdebug(PROTOCOL) logger(LOG_WARNING,
106                    _("Ignoring indirect %s from %s (%s)"),
107                    "ADD_EDGE", c->name, c->hostname);
108                 return true;
109         }
110
111         if(!from) {
112                 from = new_node();
113                 from->name = xstrdup(from_name);
114                 node_add(from);
115         }
116
117         if(!to) {
118                 to = new_node();
119                 to->name = xstrdup(to_name);
120                 node_add(to);
121         }
122
123
124         /* Convert addresses */
125
126         address = str2sockaddr(to_address, to_port);
127
128         /* Check if edge already exists */
129
130         e = lookup_edge(from, to);
131
132         if(e) {
133                 if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
134                         if(from == myself) {
135                                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not match existing entry"),
136                                                    "ADD_EDGE", c->name, c->hostname);
137                                 send_add_edge(c, e);
138                                 return true;
139                         } else {
140                                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) which does not match existing entry"),
141                                                    "ADD_EDGE", c->name, c->hostname);
142                                 edge_del(e);
143                                 graph();
144                         }
145                 } else
146                         return true;
147         } else if(from == myself) {
148                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not exist"),
149                                    "ADD_EDGE", c->name, c->hostname);
150                 e = new_edge();
151                 e->from = from;
152                 e->to = to;
153                 send_del_edge(c, e);
154                 free_edge(e);
155                 return true;
156         }
157
158         e = new_edge();
159         e->from = from;
160         e->to = to;
161         e->address = address;
162         e->options = options;
163         e->weight = weight;
164         edge_add(e);
165
166         /* Tell the rest about the new edge */
167
168         if(!tunnelserver)
169                 forward_request(c);
170
171         /* Run MST before or after we tell the rest? */
172
173         graph();
174
175         return true;
176 }
177
178 bool send_del_edge(connection_t *c, const edge_t *e)
179 {
180         cp();
181
182         return send_request(c, "%d %x %s %s", DEL_EDGE, rand(),
183                                                 e->from->name, e->to->name);
184 }
185
186 bool del_edge_h(connection_t *c)
187 {
188         edge_t *e;
189         char from_name[MAX_STRING_SIZE];
190         char to_name[MAX_STRING_SIZE];
191         node_t *from, *to;
192
193         cp();
194
195         if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) {
196                 logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE", c->name,
197                            c->hostname);
198                 return false;
199         }
200
201         /* Check if names are valid */
202
203         if(!check_id(from_name)) {
204                 logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name,
205                            c->hostname, _("invalid name"));
206                 return false;
207         }
208
209         if(!check_id(to_name)) {
210                 logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name,
211                            c->hostname, _("invalid name"));
212                 return false;
213         }
214
215         if(seen_request(c->buffer))
216                 return true;
217
218         /* Lookup nodes */
219
220         from = lookup_node(from_name);
221         to = lookup_node(to_name);
222
223         if(tunnelserver &&
224            from != myself && from != c->node &&
225            to != myself && to != c->node) {
226                 /* ignore indirect edge registrations for tunnelserver */
227                 ifdebug(PROTOCOL) logger(LOG_WARNING,
228                    _("Ignoring indirect %s from %s (%s)"),
229                    "DEL_EDGE", c->name, c->hostname);
230                 return true;
231         }
232
233         if(!from) {
234                 ifdebug(PROTOCOL) logger(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"),
235                                    "DEL_EDGE", c->name, c->hostname);
236                 return true;
237         }
238
239         if(!to) {
240                 ifdebug(PROTOCOL) logger(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"),
241                                    "DEL_EDGE", c->name, c->hostname);
242                 return true;
243         }
244
245         /* Check if edge exists */
246
247         e = lookup_edge(from, to);
248
249         if(!e) {
250                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) which does not appear in the edge tree"),
251                                    "DEL_EDGE", c->name, c->hostname);
252                 return true;
253         }
254
255         if(e->from == myself) {
256                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
257                                    "DEL_EDGE", c->name, c->hostname);
258                 send_add_edge(c, e);    /* Send back a correction */
259                 return true;
260         }
261
262         /* Tell the rest about the deleted edge */
263
264         if(!tunnelserver)
265                 forward_request(c);
266
267         /* Delete the edge */
268
269         edge_del(e);
270
271         /* Run MST before or after we tell the rest? */
272
273         graph();
274
275         /* If the node is not reachable anymore but we remember it had an edge to us, clean it up */
276
277         if(!to->status.reachable) {
278                 e = lookup_edge(to, myself);
279                 if(e) {
280                         if(!tunnelserver)
281                                 send_del_edge(broadcast, e);
282                         edge_del(e);
283                 }
284         }
285
286         return true;
287 }