bb2f2deff80407255141b0838bec654451e253db
[oweals/tinc.git] / src / protocol_subnet.c
1 /*
2     protocol_subnet.c -- handle the meta-protocol, subnets
3     Copyright (C) 1999-2003 Ivo Timmermans <ivo@o2w.nl>,
4                   2000-2003 Guus Sliepen <guus@sliepen.eu.org>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: protocol_subnet.c,v 1.1.4.15 2003/07/24 12:08:16 guus Exp $
21 */
22
23 #include "system.h"
24
25 #include "conf.h"
26 #include "connection.h"
27 #include "logger.h"
28 #include "net.h"
29 #include "netutl.h"
30 #include "node.h"
31 #include "protocol.h"
32 #include "subnet.h"
33 #include "utils.h"
34 #include "xalloc.h"
35
36 bool send_add_subnet(connection_t *c, const subnet_t *subnet)
37 {
38         bool x;
39         char *netstr;
40
41         cp();
42
43         x = send_request(c, "%d %lx %s %s", ADD_SUBNET, random(),
44                                          subnet->owner->name, netstr = net2str(subnet));
45
46         free(netstr);
47
48         return x;
49 }
50
51 bool add_subnet_h(connection_t *c)
52 {
53         char subnetstr[MAX_STRING_SIZE];
54         char name[MAX_STRING_SIZE];
55         node_t *owner;
56         subnet_t *s;
57
58         cp();
59
60         if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
61                 logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_SUBNET", c->name,
62                            c->hostname);
63                 return false;
64         }
65
66         /* Check if owner name is a valid */
67
68         if(!check_id(name)) {
69                 logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
70                            c->hostname, _("invalid name"));
71                 return false;
72         }
73
74         /* Check if subnet string is valid */
75
76         s = str2net(subnetstr);
77
78         if(!s) {
79                 logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
80                            c->hostname, _("invalid subnet string"));
81                 return false;
82         }
83
84         if(seen_request(c->buffer))
85                 return true;
86
87         /* Check if the owner of the new subnet is in the connection list */
88
89         owner = lookup_node(name);
90
91         if(!owner) {
92                 owner = new_node();
93                 owner->name = xstrdup(name);
94                 node_add(owner);
95         }
96
97         /* Check if we already know this subnet */
98
99         if(lookup_subnet(owner, s)) {
100                 free_subnet(s);
101                 return true;
102         }
103
104         /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */
105
106         if(owner == myself) {
107                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
108                                    "ADD_SUBNET", c->name, c->hostname);
109                 s->owner = myself;
110                 send_del_subnet(c, s);
111                 return true;
112         }
113
114         /* If everything is correct, add the subnet to the list of the owner */
115
116         subnet_add(owner, s);
117
118         /* Tell the rest */
119
120         forward_request(c);
121
122         return true;
123 }
124
125 bool send_del_subnet(connection_t *c, const subnet_t *s)
126 {
127         bool x;
128         char *netstr;
129
130         cp();
131
132         netstr = net2str(s);
133
134         x = send_request(c, "%d %lx %s %s", DEL_SUBNET, random(), s->owner->name, netstr);
135
136         free(netstr);
137
138         return x;
139 }
140
141 bool del_subnet_h(connection_t *c)
142 {
143         char subnetstr[MAX_STRING_SIZE];
144         char name[MAX_STRING_SIZE];
145         node_t *owner;
146         subnet_t *s, *find;
147
148         cp();
149
150         if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
151                 logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_SUBNET", c->name,
152                            c->hostname);
153                 return false;
154         }
155
156         /* Check if owner name is a valid */
157
158         if(!check_id(name)) {
159                 logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
160                            c->hostname, _("invalid name"));
161                 return false;
162         }
163
164         /* Check if the owner of the new subnet is in the connection list */
165
166         owner = lookup_node(name);
167
168         if(!owner) {
169                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"),
170                                    "DEL_SUBNET", c->name, c->hostname, name);
171                 return true;
172         }
173
174         /* Check if subnet string is valid */
175
176         s = str2net(subnetstr);
177
178         if(!s) {
179                 logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
180                            c->hostname, _("invalid subnet string"));
181                 return false;
182         }
183
184         if(seen_request(c->buffer))
185                 return true;
186
187         /* If everything is correct, delete the subnet from the list of the owner */
188
189         s->owner = owner;
190
191         find = lookup_subnet(owner, s);
192
193         free_subnet(s);
194
195         if(!find) {
196                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which does not appear in his subnet tree"),
197                                    "DEL_SUBNET", c->name, c->hostname, name);
198                 return true;
199         }
200
201         /* If we are the owner of this subnet, retaliate with an ADD_SUBNET */
202
203         if(owner == myself) {
204                 ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
205                                    "DEL_SUBNET", c->name, c->hostname);
206                 send_add_subnet(c, find);
207                 return true;
208         }
209
210         /* Tell the rest */
211
212         forward_request(c);
213
214         /* Finally, delete it. */
215
216         subnet_del(owner, find);
217
218         return true;
219 }